Skip to content

Commit 2dfa2a7

Browse files
authored
fix #133 webp generate-thumbnail failed (#134)
* fix #133 webp generate-thumbnail failed * add uniitest * fix
1 parent a4366d2 commit 2dfa2a7

File tree

14 files changed

+106
-22
lines changed

14 files changed

+106
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,4 @@ cython_debug/
158158
# and can be added to the global gitignore or merged into this file. For a more nuclear
159159
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160160
#.idea/
161+
.DS_Store

src/ffmpeg_media_type/exceptions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
class FfmpegMediaTypeError(Exception):
1+
class FFmpegMediaTypeError(Exception):
22
"""
33
Base class for exceptions in this module.
44
"""
5+
6+
7+
class FFMpegMediaCorruptedError(FFmpegMediaTypeError):
8+
"""
9+
Exception raised when the media file is corrupted.
10+
"""

src/ffmpeg_media_type/info.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from pathlib import Path
33
from urllib.parse import urlparse
44

5+
from ffmpeg_media_type.exceptions import FFMpegMediaCorruptedError
6+
57
from .schema import FFMpegSupport, MediaInfo
68
from .utils.cache import load
79
from .utils.ffprobe import ffprobe
@@ -52,7 +54,8 @@ def detect(uri: str | Path) -> MediaInfo:
5254
the media type information
5355
5456
Raises:
55-
FfmpegMediaTypeError: If the ffmpeg command fails.
57+
FFmpegMediaTypeError: If the ffmpeg command fails.
58+
FFMpegMediaCorruptedError: If the media file is corrupted.
5659
"""
5760
uri = str(uri)
5861
info = ffprobe(uri)
@@ -63,7 +66,8 @@ def detect(uri: str | Path) -> MediaInfo:
6366

6467
# NOTE: handle ffmpeg's image compatibility
6568
if format_name == "image2":
66-
assert info.streams[0].codec_name
69+
if not info.streams[0].codec_name:
70+
raise FFMpegMediaCorruptedError(f"Corrupted image file {uri}")
6771
format_name = info.streams[0].codec_name
6872

6973
# NOTE: detect file extension
@@ -81,8 +85,11 @@ def detect(uri: str | Path) -> MediaInfo:
8185
else:
8286
suggest_ext = None
8387

84-
# NOTE: we classify gif as image
88+
# NOTE: we classify gif and mjpeg as imageg
8589
if not duration or format_name in ("gif", "mjpeg"):
90+
if not (info.streams[0].width and info.streams[0].height):
91+
raise FFMpegMediaCorruptedError(f"Corrupted image file {uri}")
92+
8693
return MediaInfo(
8794
type="image",
8895
width=info.streams[0].width or 0,
@@ -99,6 +106,9 @@ def detect(uri: str | Path) -> MediaInfo:
99106
width = stream.width
100107
height = stream.height
101108

109+
if not (width and height):
110+
raise FFMpegMediaCorruptedError(f"Corrupted image file {uri}")
111+
102112
return MediaInfo(
103113
type="video",
104114
width=width or 0,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
3+
<head>
4+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5+
<meta http-equiv="Content-Style-Type" content="text/css" />
6+
<meta http-equiv="Content-Script-Type" content="text/javascript" />
7+
8+
<meta http-equiv="refresh" content="0;URL=http://web.gekisaka.jp/frontpage?from=cf403">
9+
<title>ERROR: The request could not be satisfied</title>
10+
</head>
11+
<body>
12+
13+
<h1>ERROR</h1>
14+
<h2>The request could not be satisfied.</h2>
15+
<hr noshade="" size="1px">Request blocked.
16+
<br clear="all">
17+
<hr noshade="" size="1px">
18+
<pre>Generated by cloudfront (CloudFront)
19+
</pre>
20+
21+
</body>
22+
</html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# serializer version: 1
2+
# name: test_detect[tmpz1wcuugh.webp]
3+
"<ExceptionInfo FFMpegMediaCorruptedError('Corrupted image file src/ffmpeg_media_type/test_data/133-raise-exception/tmpz1wcuugh.webp') tblen=2>"
4+
# ---

src/ffmpeg_media_type/tests/test_info.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,22 @@
77
from syrupy.extensions.json import JSONSnapshotExtension
88

99
from ..conftest import sample_test_media_files
10+
from ..exceptions import FFmpegMediaTypeError
1011
from ..info import detect, generate_thumbnail
1112

1213

1314
@pytest.mark.parametrize("case", sample_test_media_files())
1415
def test_detect(case: Path, snapshot: SnapshotAssertion) -> None:
1516
# NOTE:
1617
# because we use docker to run ffmpeg, the input path need to be relative to the current working directory
17-
info = detect(str(case.relative_to(Path.cwd())))
18-
snapshot(extension_class=JSONSnapshotExtension) == asdict(info)
1918

20-
if info.type in ("video", "image"):
21-
assert os.path.exists(generate_thumbnail(str(case.relative_to(Path.cwd())), "tmp.png"))
19+
if "raise-exception" in str(case):
20+
with pytest.raises(FFmpegMediaTypeError) as e:
21+
info = detect(str(case.relative_to(Path.cwd())))
22+
assert snapshot == str(e)
23+
else:
24+
info = detect(str(case.relative_to(Path.cwd())))
25+
assert snapshot(extension_class=JSONSnapshotExtension) == asdict(info)
26+
27+
if info.type in ("video", "image"):
28+
assert os.path.exists(generate_thumbnail(str(case.relative_to(Path.cwd())), "tmp.png"))

src/ffmpeg_media_type/utils/ffprobe.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def ffprobe(input_url: str | Path) -> FFProbeInfo:
1818
the media information
1919
2020
Raises:
21-
FfmpegMediaTypeError: If the FFprobe command fails.
21+
FFmpegMediaTypeError: If the FFprobe command fails.
2222
"""
2323

2424
input_url = hotfix_animate_webp(input_url)

src/ffmpeg_media_type/utils/hotfix_webp.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def is_webp_animated(file_path: str) -> bool:
7878
True if the WebP file is animated, False otherwise.
7979
8080
Raises:
81-
FfmpegMediaTypeError: If the webpmux command fails.
81+
FFmpegMediaTypeError: If the webpmux command fails.
8282
"""
8383

8484
# Running the webpmux command to get information about the WebP file
@@ -103,7 +103,7 @@ def extract_animated_webp_frame(uri: str) -> str:
103103
The URI of the fixed webp file.
104104
105105
Raises:
106-
FfmpegMediaTypeError: If the webpmux command fails.
106+
FFmpegMediaTypeError: If the webpmux command fails.
107107
108108
Notes:
109109
Will raise Exception if the webp file is not animated.
@@ -125,7 +125,7 @@ def is_webp_need_fix(uri: str | Path) -> bool:
125125
True if the WebP file is animated, False otherwise.
126126
127127
Raises:
128-
FfmpegMediaTypeError: If the ffprobe command fails.
128+
FFmpegMediaTypeError: If the ffprobe command fails.
129129
"""
130130

131131
ffprobe_cmd = ["ffprobe"] + [
@@ -162,7 +162,7 @@ def hotfix_animate_webp(uri: str | Path) -> str:
162162
The URI of the fixed WebP file if it was animated, otherwise the original URI.
163163
164164
Raises:
165-
FfmpegMediaTypeError: If the webpmux command fails.
165+
FFmpegMediaTypeError: If the webpmux command fails.
166166
167167
Notes:
168168
Some WebP files (e.g. animated WebP files) may not be supported by ffmpeg.

src/ffmpeg_media_type/utils/shell.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from shlex import join
33
from tempfile import NamedTemporaryFile
44

5-
from ..exceptions import FfmpegMediaTypeError
5+
from ..exceptions import FFmpegMediaTypeError
66

77

88
def call(cmds: list[str]) -> str:
@@ -13,15 +13,15 @@ def call(cmds: list[str]) -> str:
1313
cmds: List of command and arguments.
1414
1515
Raises:
16-
FfmpegMediaTypeError: If the command fails.
16+
FFmpegMediaTypeError: If the command fails.
1717
1818
Returns:
1919
stdout of the command.
2020
"""
2121
try:
2222
r = subprocess.run(cmds, stdout=subprocess.PIPE, check=True)
2323
except subprocess.CalledProcessError as e:
24-
raise FfmpegMediaTypeError(f"command failed: {join(e.cmd)}")
24+
raise FFmpegMediaTypeError(f"command failed: {join(e.cmd)}")
2525

2626
return r.stdout.decode("utf-8")
2727

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"format": {
3+
"duration": "0.040000",
4+
"format_long_name": "image2 sequence",
5+
"format_name": "image2",
6+
"probe_score": 50,
7+
"size": "790",
8+
"start_time": "0.000000"
9+
},
10+
"streams": [
11+
{
12+
"codec_long_name": "WebP",
13+
"codec_name": "webp",
14+
"codec_type": "video",
15+
"height": 0,
16+
"index": 0,
17+
"pix_fmt": null,
18+
"profile": null,
19+
"r_frame_rate": "25/1",
20+
"tags": {
21+
"rotate": 0
22+
},
23+
"width": 0
24+
}
25+
]
26+
}

src/ffmpeg_media_type/utils/tests/__snapshots__/test_thumbnail.ambr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,6 @@
5050
# name: test_thumbnail[silent_video.mp4]
5151
True
5252
# ---
53+
# name: test_thumbnail[tmpz1wcuugh.webp]
54+
False
55+
# ---

src/ffmpeg_media_type/utils/tests/test_hotfix_webp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from syrupy.assertion import SnapshotAssertion
55

66
from ...conftest import sample_test_media_files
7-
from ...exceptions import FfmpegMediaTypeError
7+
from ...exceptions import FFmpegMediaTypeError
88
from ..hotfix_webp import extract_animated_webp_frame, hotfix_animate_webp, is_webp_animated
99

1010

@@ -18,7 +18,7 @@ def test_extract_animated_webp_frame(case: Path, snapshot: SnapshotAssertion) ->
1818
try:
1919
extract_animated_webp_frame(str(case))
2020
assert snapshot == True
21-
except FfmpegMediaTypeError:
21+
except FFmpegMediaTypeError:
2222
assert snapshot == False
2323

2424

src/ffmpeg_media_type/utils/tests/test_thumbnail.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from syrupy.assertion import SnapshotAssertion
55

66
from ...conftest import sample_test_media_files
7-
from ...exceptions import FfmpegMediaTypeError
7+
from ...exceptions import FFmpegMediaTypeError
88
from ..thumbnail import generate_thumbnail
99

1010

@@ -13,5 +13,5 @@ def test_thumbnail(case: Path, snapshot: SnapshotAssertion) -> None:
1313
try:
1414
generate_thumbnail(case)
1515
assert snapshot == True
16-
except FfmpegMediaTypeError:
16+
except FFmpegMediaTypeError:
1717
assert snapshot == False

src/ffmpeg_media_type/utils/thumbnail.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55

66

77
def generate_thumbnail(
8-
video_path: str | Path, suffix: str = ".png", *, width: int = 320, height: int = -1, time_offset: float = 0
8+
video_path: str | Path,
9+
suffix: str = ".png",
10+
*,
11+
width: int = 320,
12+
height: int = -1,
13+
time_offset: float = 0,
914
) -> str:
1015
"""
1116
Generate a thumbnail from a video file at a specified time offset.
@@ -18,7 +23,7 @@ def generate_thumbnail(
1823
time_offset: the time offset in seconds to generate the thumbnail
1924
2025
Raises:
21-
FfmpegMediaTypeError: If the ffmpeg command fails.
26+
FFmpegMediaTypeError: If the ffmpeg command fails.
2227
2328
Returns:
2429
the path to the generated thumbnail

0 commit comments

Comments
 (0)