Skip to content

Commit 778dc1c

Browse files
authored
feat: get mediainfo mini (#14)
1 parent 3c6aceb commit 778dc1c

File tree

11 files changed

+241
-83
lines changed

11 files changed

+241
-83
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ make run
2828

2929
or you can use docker to run the project, see [docker-compose.yml](./deploy/docker-compose.yml) for more details.
3030

31+
### CLI
32+
33+
```
34+
35+
```
36+
3137
### Configuration
3238

3339
#### Server Config:

animepipeline/cli/__init__.py

Whitespace-only changes.

animepipeline/cli/btf/__init__.py

Whitespace-only changes.

animepipeline/cli/rename/__init__.py

Whitespace-only changes.

animepipeline/loop.py

+8-11
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from animepipeline.bt import QBittorrentManager
99
from animepipeline.config import NyaaConfig, RSSConfig, ServerConfig
1010
from animepipeline.encode import FinalRipClient
11-
from animepipeline.mediainfo import FileNameInfo, gen_file_name
11+
from animepipeline.mediainfo import FileNameInfo, rename_file
1212
from animepipeline.pool import AsyncTaskExecutor
1313
from animepipeline.post import TGChannelSender
1414
from animepipeline.rss import TorrentInfo, parse_nyaa
@@ -218,26 +218,23 @@ async def pipeline_finalrip(self, task_info: TaskInfo) -> None:
218218

219219
# rename temp file
220220
try:
221-
gen_name = gen_file_name(
221+
finalrip_downloaded_path = rename_file(
222222
FileNameInfo(
223-
path=temp_saved_path, episode=task_info.episode, name=task_info.name, uploader=task_info.uploader
223+
path=temp_saved_path,
224+
episode=task_info.episode,
225+
name=task_info.name,
226+
uploader=task_info.uploader,
227+
type="WEBRip",
224228
)
225229
)
226-
finalrip_downloaded_path = Path(task_info.download_path) / gen_name
227230
except Exception as e:
228231
logger.error(f"Failed to generate file name: {e}")
229232
raise e
230233

231-
if finalrip_downloaded_path.exists():
232-
finalrip_downloaded_path.unlink()
233-
logger.warning(f"Encode File already exists, remove it: {finalrip_downloaded_path}")
234-
235-
temp_saved_path.rename(finalrip_downloaded_path)
236-
237234
logger.info(f'FinalRip Encode Done for "{finalrip_downloaded_path.name}"')
238235

239236
# update task status
240-
task_status.finalrip_downloaded_path = gen_name
237+
task_status.finalrip_downloaded_path = finalrip_downloaded_path.name
241238
await self.json_store.update_task(task_info.hash, task_status)
242239

243240
async def pipeline_post(self, task_info: TaskInfo) -> None:

animepipeline/mediainfo/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from animepipeline.mediainfo.gen_file_name import gen_file_name, FileNameInfo # noqa
1+
from animepipeline.mediainfo.mediainfomini import gen_file_name, FileNameInfo, rename_file, get_media_info # noqa

animepipeline/mediainfo/gen_file_name.py

-68
This file was deleted.
+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import json
2+
from datetime import datetime
3+
from pathlib import Path
4+
from typing import List, Tuple, Union
5+
6+
import pymediainfo
7+
from loguru import logger
8+
9+
from animepipeline.mediainfo.type import FileNameInfo, MediaInfo
10+
11+
12+
def get_media_info(video_path: Union[str, Path]) -> MediaInfo:
13+
"""
14+
Get the mini media info of the video file
15+
16+
:param video_path:
17+
"""
18+
logger.info(f"Get media info of {video_path}...")
19+
20+
video_path = Path(video_path)
21+
22+
encode_media_info = pymediainfo.MediaInfo.parse(video_path, output="JSON")
23+
encode_tracks = json.loads(encode_media_info)["media"]["track"]
24+
25+
release_name = video_path.name
26+
27+
try:
28+
release_date = datetime.strptime(encode_tracks[0]["Encoded_Date"], "%Y-%m-%d %H:%M:%S UTC")
29+
if release_date.year < 2020:
30+
raise ValueError("Wow, the release year < 2020, please check the file")
31+
except Exception as e:
32+
logger.warning(f'Failed to get "Encoded_Date" of {video_path}, set to current time, {e}')
33+
release_date = datetime.now()
34+
35+
try:
36+
release_size = encode_tracks[0]["FileSize_String"]
37+
except Exception:
38+
logger.warning(f'Failed to get "FileSize_String" of {video_path}')
39+
release_size = encode_tracks[0]["FileSize"]
40+
release_size = round(int(release_size) / (1024 * 1024), 2)
41+
if release_size > 1000:
42+
release_size = round(release_size / 1024, 2)
43+
release_size = str(release_size) + " GiB"
44+
else:
45+
release_size = str(release_size) + " MiB"
46+
47+
try:
48+
release_format = encode_tracks[0]["Format"]
49+
except Exception as e:
50+
logger.error(f'Failed to get "Format" of {video_path}, set to "Unknown", {e}')
51+
raise e
52+
53+
try:
54+
overall_bitrate = encode_tracks[0]["OverallBitRate_String"]
55+
except Exception:
56+
logger.warning(f'Failed to get "OverallBitRate_String" of {video_path}')
57+
try:
58+
overall_bitrate = encode_tracks[0]["OverallBitRate"]
59+
overall_bitrate = round(int(overall_bitrate) / 1000, 2)
60+
if overall_bitrate > 10000:
61+
overall_bitrate = round(overall_bitrate / 1000, 2)
62+
if overall_bitrate > 1000:
63+
overall_bitrate = round(overall_bitrate / 1000, 2)
64+
overall_bitrate = str(overall_bitrate) + " Gb/s"
65+
else:
66+
overall_bitrate = str(overall_bitrate) + " Mb/s"
67+
else:
68+
overall_bitrate = str(overall_bitrate) + " kb/s"
69+
except Exception as e:
70+
logger.error(f'Failed to get "OverallBitRate" of {video_path}, set to "Unknown", {e}')
71+
raise e
72+
73+
# VIDEO TRACK
74+
resolution = (0, 0)
75+
bit_depth = 0
76+
frame_rate = 0.0
77+
video_format = "Unknown"
78+
format_profile = "Unknown"
79+
80+
video_track_id = 0
81+
try:
82+
for _, video_track in enumerate(encode_tracks):
83+
if video_track["@type"] == "Video":
84+
resolution = (int(video_track["Width"]), int(video_track["Height"]))
85+
bit_depth = int(video_track["BitDepth"])
86+
frame_rate = float(video_track["FrameRate"])
87+
video_format = video_track["Format"]
88+
format_profile = video_track["Format_Profile"]
89+
video_track_id += 1
90+
except Exception as e:
91+
logger.warning(f"Exceptional video track: {video_track_id} of {video_path}, {e}")
92+
93+
if video_track_id != 1:
94+
logger.warning(f"There may be multiple video tracks or no video tracks, please check {video_path}")
95+
96+
# AUDIO TRACK
97+
audios: List[Tuple[str, int, str]] = []
98+
99+
audio_track_id = 1
100+
try:
101+
for _, audio_track in enumerate(encode_tracks):
102+
if audio_track["@type"] == "Audio":
103+
language = audio_track.get("Language_String", audio_track.get("Language", "Ambiguous!!!"))
104+
audios.append((language, int(audio_track["Channels"]), audio_track["Format"]))
105+
audio_track_id += 1
106+
except Exception as e:
107+
logger.warning(f"Exceptional audio track: {audio_track_id} of {video_path}, {e}")
108+
109+
# SUBTITLE TRACK
110+
subtitles: List[Tuple[str, str]] = []
111+
112+
subtitle_track_id = 1
113+
try:
114+
for _, subtitle_track in enumerate(encode_tracks):
115+
if subtitle_track["@type"] == "Text":
116+
language = subtitle_track.get("Language_String", subtitle_track.get("Language", "Ambiguous!!!"))
117+
subtitles.append((language, subtitle_track["Format"]))
118+
subtitle_track_id += 1
119+
except Exception as e:
120+
logger.warning(f"Exceptional subtitle track: {subtitle_track_id} of {video_path}, {e}")
121+
122+
return MediaInfo(
123+
release_name=release_name,
124+
release_date=release_date,
125+
release_size=release_size,
126+
release_format=release_format,
127+
overall_bitrate=overall_bitrate,
128+
resolution=resolution,
129+
bit_depth=bit_depth,
130+
frame_rate=frame_rate,
131+
format=video_format,
132+
format_profile=format_profile,
133+
audios=audios,
134+
subtitles=subtitles,
135+
)
136+
137+
138+
def gen_file_name(anime_info: FileNameInfo) -> str:
139+
"""
140+
Auto generate the file name, based on the media info of the file
141+
142+
anime_info: FileNameInfo (path: xx.mkv, episode: 1, name: Fate/Kaleid Liner Prisma Illya, uploader: TensoRaws, type: WEBRip)
143+
144+
-> [TensoRaws] Fate/Kaleid Liner Prisma Illya [01] [WEBRip 1080p HEVC-10bit FLAC].mkv
145+
146+
:param anime_info: FileNameInfo
147+
:return:
148+
"""
149+
media_info = get_media_info(anime_info.path)
150+
resolution_heigh = str(media_info.resolution[1]) + "p"
151+
bit_depth = str(media_info.bit_depth) + "bit"
152+
153+
video_format = media_info.format
154+
155+
audio_format_list = [audio[2] for audio in media_info.audios]
156+
audio_format = "FLAC" if "FLAC" in audio_format_list else audio_format_list[0]
157+
158+
file_format = Path(anime_info.path).suffix
159+
160+
return f"[{anime_info.uploader}] {anime_info.name} [{str(anime_info.episode).zfill(2)}] [{anime_info.type} {resolution_heigh} {video_format}-{bit_depth} {audio_format}]{file_format}"
161+
162+
163+
def rename_file(anime_info: FileNameInfo) -> Path:
164+
"""
165+
Rename the file name, based on the media info of the file
166+
167+
:param anime_info: FileNameInfo
168+
:return:
169+
"""
170+
anime_path = Path(anime_info.path)
171+
172+
gen_name = gen_file_name(anime_info)
173+
gen_path = anime_path.parent / gen_name
174+
175+
if gen_path.exists():
176+
gen_path.unlink()
177+
logger.warning(f"Encode File already exists, remove it: {gen_path}")
178+
179+
anime_path.rename(gen_path)
180+
181+
return gen_path

animepipeline/mediainfo/type.py

+19
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from datetime import datetime
2+
from typing import List, Tuple
3+
14
from pydantic import BaseModel, FilePath
25

36

@@ -6,3 +9,19 @@ class FileNameInfo(BaseModel):
69
episode: int
710
name: str
811
uploader: str
12+
type: str = "WEBRip"
13+
14+
15+
class MediaInfo(BaseModel):
16+
release_name: str
17+
release_date: datetime
18+
release_size: str # 1.35 GiB
19+
release_format: str # Matroska
20+
overall_bitrate: str # 1919.8 Mb/s
21+
resolution: Tuple[int, int] # (1920, 1080)
22+
bit_depth: int # 10
23+
frame_rate: float # 23.976
24+
format: str # HEVC
25+
format_profile: str # Main@L5@Main
26+
audios: List[Tuple[str, int, str]] # Chinese, 2 channels, FLAC
27+
subtitles: List[Tuple[str, str]] # CHS, PGS

animepipeline/template/__init__.py

Whitespace-only changes.

tests/test_mediainfo.py

+26-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
from animepipeline.mediainfo.gen_file_name import gen_file_name
1+
import shutil
2+
3+
from animepipeline.mediainfo import gen_file_name, get_media_info, rename_file
24
from animepipeline.mediainfo.type import FileNameInfo
35

4-
from .util import TEST_VIDEO_PATH
6+
from .util import ASSETS_PATH, TEST_VIDEO_PATH
7+
8+
9+
def test_get_media_info() -> None:
10+
media_info = get_media_info(video_path=TEST_VIDEO_PATH)
11+
print(media_info)
512

613

714
def test_gen_file_name() -> None:
@@ -13,4 +20,20 @@ def test_gen_file_name() -> None:
1320
)
1421

1522
name = gen_file_name(anime_info=anime_info)
16-
assert name == "[TensoRaws] test 114 [01] [144p AVC-8bit AAC].mp4"
23+
assert name == "[TensoRaws] test 114 [01] [WEBRip 144p AVC-8bit AAC].mp4"
24+
25+
26+
def test_rename_file() -> None:
27+
# copy TEST_VIDEO_PATH to a new file
28+
if not (ASSETS_PATH / "copy_test_144p.mp4").exists():
29+
shutil.copy(TEST_VIDEO_PATH, ASSETS_PATH / "copy_test_144p.mp4")
30+
31+
anime_info = FileNameInfo(
32+
path=str(ASSETS_PATH / "copy_test_144p.mp4"),
33+
episode=1,
34+
name="test 114",
35+
uploader="TensoRaws",
36+
)
37+
38+
p = rename_file(anime_info=anime_info)
39+
assert p.name == "[TensoRaws] test 114 [01] [WEBRip 144p AVC-8bit AAC].mp4"

0 commit comments

Comments
 (0)