mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-02 05:17:23 +08:00
fix(metainfo): align Python title recovery with Rust 0.3.13 (#7265)
* chore: bump moviepilot-rust to 0.3.13 * fix(metainfo): preserve anime titles in Python fallback --------- Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com> Co-authored-by: jxxghp <jxxghp@gmail.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
import logging
|
||||
import re
|
||||
import traceback
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
import anitopy
|
||||
|
||||
@@ -35,6 +35,19 @@ TV_EPISODE_BRACKET_RE = re.compile(r"\[TV\s+(\d{1,4})", re.IGNORECASE)
|
||||
FOUR_K_BRACKET_RE = re.compile(r'\[4k]', re.IGNORECASE)
|
||||
NUMERIC_BRACKET_RE = re.compile(r"\[\d+", re.IGNORECASE)
|
||||
MIXED_CHINESE_TOKEN_RE = re.compile(r'[\d|#::\-()()\u4e00-\u9fff]')
|
||||
# 分类词仅在占据整个标签时排除,片名内部的 Movie、TV 和动画仍属于名称。
|
||||
ANIME_CATEGORY_LABEL_RE = re.compile(
|
||||
r"^[★☆\s]*(?:(?:\d{2,4}年)?(?:\d{1,2}月|月)?新?番|(?:\d{2,4}年)?(?:日剧|美剧)|"
|
||||
r"动漫|动画(?:片)?|Animations?(?:\(动画片\))?|Anime|Movie|"
|
||||
r"TV(?:\s+(?:Series|\d{1,4}(?:-\d{1,4})?(?:\s+Fin)?))?)[★☆\s]*$",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
SUBTITLE_LABEL_RE = re.compile(
|
||||
r"字幕|双语|雙語|简体|繁体|简繁|繁日|中日|国语|国配|招募|片源|翻译|翻譯|校对|校對|内封|外挂|中字"
|
||||
)
|
||||
LATIN_TITLE_RE = re.compile(r"[A-Za-z]")
|
||||
# 多词英文片名可能被 anitopy 误归为发布组,只在预处理后的标题位置允许恢复。
|
||||
RELEASE_GROUP_TITLE_RE = re.compile(r"[A-Za-z0-9]+(?:\s+[A-Za-z0-9]+)+")
|
||||
|
||||
|
||||
class MetaAnime(MetaBase):
|
||||
@@ -74,15 +87,7 @@ class MetaAnime(MetaBase):
|
||||
title = self.__prepare_title(title)
|
||||
anitopy_info = anitopy.parse(title)
|
||||
if anitopy_info:
|
||||
name = anitopy_info.get("anime_title")
|
||||
if not name or name in self._anime_no_words or (len(name) < 5 and not text_tools.contains_chinese(name)):
|
||||
anitopy_info = anitopy.parse("[ANIME]" + title)
|
||||
if anitopy_info:
|
||||
name = anitopy_info.get("anime_title")
|
||||
if not name or name in self._anime_no_words or (len(name) < 5 and not text_tools.contains_chinese(name)):
|
||||
name_match = BRACKET_TITLE_RE.search(title)
|
||||
if name_match and name_match.group(1):
|
||||
name = name_match.group(1).strip()
|
||||
name = self._resolve_anime_name(title, original_title, anitopy_info, anitopy_info_origin)
|
||||
if name:
|
||||
_split_flag = True
|
||||
if name.find("/") != -1:
|
||||
@@ -212,6 +217,92 @@ class MetaAnime(MetaBase):
|
||||
except Exception as e:
|
||||
logger.error(f"解析动漫信息失败:{str(e)} - {traceback.format_exc()}")
|
||||
|
||||
@classmethod
|
||||
def _invalid_anime_name(cls, name: Optional[str], release_groups: tuple[str, ...]) -> bool:
|
||||
"""
|
||||
排除字幕、完整分类标签和已识别的发布组,保留片名内部的分类词。
|
||||
|
||||
:param name: 第三方解析器或方括号提供的候选标题
|
||||
:param release_groups: 当前发布名中已识别的制作组名称
|
||||
:return: 候选项是否不能作为真实片名
|
||||
"""
|
||||
return (
|
||||
not name
|
||||
or name in cls._anime_no_words
|
||||
or (len(name) < 5 and not text_tools.contains_chinese(name))
|
||||
or bool(SUBTITLE_LABEL_RE.search(name))
|
||||
or bool(ANIME_CATEGORY_LABEL_RE.fullmatch(name))
|
||||
or name.casefold() in release_groups
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _resolve_anime_name(
|
||||
cls, prepared: str, original: str, parsed: dict[str, Any], parsed_origin: dict[str, Any],
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
从原始解析和方括号恢复真实标题,只替换名称而不改写资源规格与季集字段。
|
||||
|
||||
:param prepared: 预处理后交给 anitopy 的发布名
|
||||
:param original: 保留双语片名和发布组的原始发布名
|
||||
:param parsed: 预处理后的第三方解析结果
|
||||
:param parsed_origin: 原始发布名的第三方解析结果
|
||||
:return: 有效标题;只有分类或规格标签时返回 None
|
||||
"""
|
||||
matched_group = ReleaseGroupsMatcher().match(title=original)
|
||||
release_groups = tuple(
|
||||
group.casefold() for group in (matched_group, parsed_origin.get("release_group")) if group
|
||||
)
|
||||
origin_name = parsed_origin.get("anime_title")
|
||||
for name in (parsed.get("anime_title"), cls._recovered_anime_name(origin_name)):
|
||||
if not cls._invalid_anime_name(name, release_groups):
|
||||
return name
|
||||
retry_name: Optional[str] = anitopy.parse("[ANIME]" + prepared).get("anime_title")
|
||||
if not cls._invalid_anime_name(retry_name, release_groups):
|
||||
return retry_name
|
||||
# 只允许预处理后第一个方括号中的多词英文名突破第三方发布组误判。
|
||||
first_bracket = BRACKET_TITLE_RE.search(prepared)
|
||||
configured_groups = (matched_group.casefold(),) if matched_group else ()
|
||||
if first_bracket:
|
||||
name = first_bracket.group(1).strip()
|
||||
if RELEASE_GROUP_TITLE_RE.fullmatch(name) and not cls._invalid_anime_name(name, configured_groups):
|
||||
return name
|
||||
return cls._bracket_anime_name(original, release_groups)
|
||||
|
||||
@staticmethod
|
||||
def _recovered_anime_name(name: Optional[str]) -> Optional[str]:
|
||||
"""
|
||||
双语方括号名称恢复时优先保留英文片名,与既有预处理的结果一致。
|
||||
|
||||
:param name: 原始解析器或方括号给出的候选名称
|
||||
:return: 可用英文名称,或不含英文时的右侧名称;空值保持不变
|
||||
"""
|
||||
if not name or "/" not in name:
|
||||
return name
|
||||
parts = [part.strip() for part in name.split("/")]
|
||||
return next((part for part in parts if LATIN_TITLE_RE.search(part)), parts[-1])
|
||||
|
||||
@classmethod
|
||||
def _bracket_anime_name(cls, original: str, release_groups: tuple[str, ...]) -> Optional[str]:
|
||||
"""
|
||||
第三方解析失败时,从原始方括号中跳过发布组、分类和资源规格后恢复标题。
|
||||
|
||||
:param original: 未丢失中文或双语名称的原始发布名
|
||||
:param release_groups: 已识别发布组的大小写折叠值
|
||||
:return: 第一个有效候选名称,没有真实片名时返回 None
|
||||
"""
|
||||
for match in BRACKET_TITLE_RE.finditer(original.replace("【", "[").replace("】", "]")):
|
||||
name = cls._recovered_anime_name(match.group(1).strip("[] "))
|
||||
if not name or cls._invalid_anime_name(name, release_groups) or name.isdigit():
|
||||
continue
|
||||
metadata = anitopy.parse(f"[{name}]")
|
||||
if any(field in metadata for field in (
|
||||
"video_resolution", "video_term", "audio_term", "source", "file_extension", "file_checksum",
|
||||
"anime_year", "episode_number",
|
||||
)):
|
||||
continue
|
||||
return name
|
||||
return None
|
||||
|
||||
def __init_anime_fps(self, anitopy_info: dict[str, object], original_title: str) -> None:
|
||||
"""
|
||||
从原始标题中提取帧率信息,与MetaVideo保持完全一致的实现。
|
||||
|
||||
@@ -47,7 +47,7 @@ dependencies = [
|
||||
"langgraph-checkpoint~=4.2.0",
|
||||
# 宿主飞书渠道已改用自研 OpenAPI 与长连接客户端,此 SDK 暂时保留给插件使用。
|
||||
"lark-oapi~=1.6.8",
|
||||
"moviepilot-rust~=0.3.12",
|
||||
"moviepilot-rust~=0.3.13",
|
||||
"mutagen~=1.47.0",
|
||||
"openai~=2.41.1",
|
||||
"orjson==3.12.0",
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
"app/chain/transfer/workflow.py:TransferWorkflowOwner._collect_transfer_candidates": 16,
|
||||
"app/chain/transfer/workflow.py:TransferWorkflowOwner._execute_transfer_tasks": 18,
|
||||
"app/chain/workflow.py:WorkflowExecutor.evaluate_target_state": 16,
|
||||
"app/domain/meta/metaanime.py:MetaAnime.__init__": 46,
|
||||
"app/domain/meta/metaanime.py:MetaAnime.__init__": 42,
|
||||
"app/domain/meta/metaanime.py:MetaAnime.__prepare_title": 16,
|
||||
"app/domain/meta/metabase.py:MetaBase.init_subtitle": 41,
|
||||
"app/domain/meta/metamusic.py:MetaMusic._parse_music_scene_tokens": 19,
|
||||
|
||||
145
tests/test_anime_category_titles.py
Normal file
145
tests/test_anime_category_titles.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
验证分类标签和包含分类词的真实动漫片名在 Python 回退中的边界。
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from app.domain.metainfo import MetaInfo
|
||||
from app.schemas.types import MediaType
|
||||
from tests.cases.meta import meta_cases
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subtitle", ["CHS", "CHT"])
|
||||
def test_python_fallback_preserves_movie_title_after_release_group(subtitle: str) -> None:
|
||||
"""
|
||||
完整发布名中的 Movie 属于片名,回退解析不能把字幕组当作标题。
|
||||
"""
|
||||
title = (
|
||||
"[黑白字幕组]我心里危险的东西剧场版 / "
|
||||
"Boku no Kokoro no Yabai Yatsu Movie "
|
||||
f"[2026] [WEB-DL 1080p AVC-8bit AAC][{subtitle}]"
|
||||
"(检索用:我内心的糟糕念头 剧场版)"
|
||||
)
|
||||
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
|
||||
meta = MetaInfo(title)
|
||||
|
||||
assert meta.en_name == "Boku No Kokoro No Yabai Yatsu Movie"
|
||||
assert meta.original_name == "Boku No Kokoro No Yabai Yatsu Movie"
|
||||
assert meta.cn_name != "黑白字幕组"
|
||||
assert meta.year == "2026"
|
||||
assert meta.resource_pix == "1080p"
|
||||
assert meta.audio_encode == "AAC"
|
||||
assert meta.resource_team == "黑白字幕组"
|
||||
assert meta.begin_season is None
|
||||
assert meta.begin_episode is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("body", "expected_name", "episode"),
|
||||
[
|
||||
("[星空电影 / Starry Sky Movie][2026]", "Starry Sky Movie", None),
|
||||
("[Starry Sky Movie / 星空电影][2026]", "Starry Sky Movie", None),
|
||||
("[Starry Sky Movie][2026]", "Starry Sky Movie", None),
|
||||
("[动画之旅][2026]", "动画之旅", None),
|
||||
("[Movie][星空之旅 / Starry Sky][2026]", "Starry Sky", None),
|
||||
("[TV Series][动画之旅 / Animation Journey][2026][01]", "Animation Journey", 1),
|
||||
("[TV Animation Club][2026][01]", "Tv Animation Club", 1),
|
||||
("[My Anime Story][2026][01]", "My Anime Story", 1),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("subtitle", ["CHS", "CHT"])
|
||||
def test_python_fallback_distinguishes_categories_from_titles(
|
||||
body: str, expected_name: str, episode: Optional[int], subtitle: str,
|
||||
) -> None:
|
||||
"""
|
||||
双语和中文标题应保留分类词,独立 Movie 和 TV Series 标签应跳过。
|
||||
"""
|
||||
title = f"[测试字幕组]{body}[1080p][AVC][AAC][{subtitle}]"
|
||||
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
|
||||
meta = MetaInfo(title)
|
||||
|
||||
assert meta.name == expected_name
|
||||
assert meta.original_name == expected_name
|
||||
assert meta.year == "2026"
|
||||
assert meta.begin_season is None
|
||||
assert meta.begin_episode == episode
|
||||
assert meta.resource_pix == "1080p"
|
||||
assert meta.video_encode == "AVC"
|
||||
assert meta.audio_encode == "AAC"
|
||||
assert meta.resource_team == "测试字幕组"
|
||||
if episode is not None:
|
||||
assert meta.type == MediaType.TV
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"label",
|
||||
[
|
||||
"Movie", "TV", "TV Series", "TV 01-26 Fin", "Animation", "Animations(动画片)",
|
||||
"Anime", "7月新番", "月番", "★7月新番", "★04月新番★", "2022年7月番", "22年日剧", "动画",
|
||||
],
|
||||
)
|
||||
def test_python_fallback_skips_complete_category_labels(label: str) -> None:
|
||||
"""
|
||||
月份、星号和 TV 集数等完整分类标签仍不能覆盖后续真实片名。
|
||||
"""
|
||||
title = f"[测试字幕组][{label}][Starry Sky][2026][01][1080p][AVC][AAC][CHS]"
|
||||
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
|
||||
meta = MetaInfo(title)
|
||||
|
||||
assert meta.name == "Starry Sky"
|
||||
assert meta.year == "2026"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("noise", ["[WEB-DL 1080p AVC-8bit AAC]", "[2026][01-26]"])
|
||||
def test_python_fallback_skips_resource_brackets_before_title(noise: str) -> None:
|
||||
"""
|
||||
名称恢复应跨过资源规格和集数标签,不能将其当作真实标题。
|
||||
"""
|
||||
title = f"[Group]{noise}[动画之旅][2026][01][1080p][AVC][AAC][CHS]"
|
||||
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
|
||||
meta = MetaInfo(title)
|
||||
|
||||
assert meta.name == "动画之旅"
|
||||
assert meta.year == "2026"
|
||||
assert meta.begin_episode == 1
|
||||
assert meta.resource_pix == "1080p"
|
||||
assert meta.audio_encode == "AAC"
|
||||
assert meta.resource_team == "Group"
|
||||
|
||||
|
||||
def test_python_fallback_does_not_use_group_or_category_as_missing_title() -> None:
|
||||
"""
|
||||
没有真实片名时保留空名称,不用字幕组、分类或资源规格伪造片名。
|
||||
"""
|
||||
title = "[Group][Movie][TV Series][2026][1080p][AVC][AAC][CHS]"
|
||||
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
|
||||
meta = MetaInfo(title)
|
||||
|
||||
assert not meta.name
|
||||
assert meta.year == "2026"
|
||||
assert meta.resource_team == "Group"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("prefix", "expected_name"),
|
||||
[
|
||||
("[Animations(动画片)]", "Jade Dynasty"),
|
||||
("[GM-Team][国漫][寻剑", "Sword Quest"),
|
||||
("[GM-Team][国漫][斗破苍穹", "Fights Break Sphere V"),
|
||||
("[Gal to Kyouryuu]", "Gal To Kyouryuu"),
|
||||
],
|
||||
)
|
||||
def test_python_fallback_preserves_existing_bracket_title_recovery(
|
||||
prefix: str, expected_name: str,
|
||||
) -> None:
|
||||
"""
|
||||
名称恢复继续兼容嵌套方括号、国漫分类和被误识别为发布组的唯一片名。
|
||||
"""
|
||||
title = next(case["title"] for case in meta_cases if case.get("title", "").startswith(prefix))
|
||||
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
|
||||
meta = MetaInfo(title)
|
||||
|
||||
assert meta.name == expected_name
|
||||
32
uv.lock
generated
32
uv.lock
generated
@@ -1853,7 +1853,7 @@ requires-dist = [
|
||||
{ name = "langgraph", specifier = "~=1.2.14" },
|
||||
{ name = "langgraph-checkpoint", specifier = "~=4.2.0" },
|
||||
{ name = "lark-oapi", specifier = "~=1.6.8" },
|
||||
{ name = "moviepilot-rust", specifier = "~=0.3.12" },
|
||||
{ name = "moviepilot-rust", specifier = "~=0.3.13" },
|
||||
{ name = "mutagen", specifier = "~=1.47.0" },
|
||||
{ name = "openai", specifier = "~=2.41.1" },
|
||||
{ name = "orjson", specifier = "==3.12.0" },
|
||||
@@ -1943,23 +1943,23 @@ runtime-standard = [
|
||||
|
||||
[[package]]
|
||||
name = "moviepilot-rust"
|
||||
version = "0.3.12"
|
||||
version = "0.3.13"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/7c/2005d139b1951ccfea04576846005f20d1bd27c24d02364018d739e2239d/moviepilot_rust-0.3.12-cp314-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9259e546aae5502dc5b4643ef7f3dafbabb84106b8c539991b9b3a70fbd6e3ea", size = 5607089, upload-time = "2026-10-24T12:15:17.312Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/2d/a2ed912146eb79cbaed5e539ea7d62f31ae82107b3d4254b24f1389135d4/moviepilot_rust-0.3.12-cp314-abi3-macosx_11_0_arm64.whl", hash = "sha256:ff3c8d014d8de47262604bad46758c45fe9ef9a722500a0694088e502c1ffeb1", size = 5515273, upload-time = "2026-10-24T12:15:19.423Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/f2/39aaa333c8599a339632b4ded513b1c2f155d40c71bee04459436eda8e03/moviepilot_rust-0.3.12-cp314-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d7ccb4a8f32fb1c6065f8a7db20830685ad207b691c07ebb710edeb255cc38f", size = 5613380, upload-time = "2026-10-24T12:15:21.3Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/20/bddb877f1dd44786515b70680ad9b8d16f40805720409621244d54b26619/moviepilot_rust-0.3.12-cp314-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57555f89968806c6931346a30034b9958b9963c64e467acd007bf650e34a5", size = 5802147, upload-time = "2026-10-24T12:15:22.917Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/9b/0a896d68738d2c35ed438b90c8ca6f0d2ef0c6130c4037aa0156c226da50/moviepilot_rust-0.3.12-cp314-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a7674771a6464138f2b93925492985f6e09c31485d6dc6c58f94da74675b0340", size = 5821017, upload-time = "2026-10-24T12:15:24.881Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/90/e5150ed1fd83cf60362e5035dff30f7aef8706d94e1a60d1b30b1bc401fa/moviepilot_rust-0.3.12-cp314-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:2259cef80c66f1fcbf5a90e398f782a985066978862006606684ee72591fb8f0", size = 6042347, upload-time = "2026-10-24T12:15:26.936Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/66/1af24c113e4d1d8679a2c5a0df581f9fd95117d574f82dbd07416abac315/moviepilot_rust-0.3.12-cp314-abi3-win_amd64.whl", hash = "sha256:87d1a74881c25c91373379eb09590f09161e4d5935b6aa36cceab50394f41152", size = 5609890, upload-time = "2026-10-24T12:15:28.775Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/4c/e0f826fd1b7f3a25659a357282adcf165515eb8cbcffa167262f93117fc4/moviepilot_rust-0.3.12-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d574cce37efc2f2cc2f5fc77f7e4263dc66853d498d557d7e4542f4d4a640b97", size = 5592561, upload-time = "2026-10-24T12:15:30.893Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/82/ff183e64a9cfc78a8eb45ea6146057b3a23c954287f180e9d40a8dc9bffa/moviepilot_rust-0.3.12-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fee57d765107e62e64b6dfcb616f56f2dfce1eec889226629d453705a31d8a6c", size = 5509114, upload-time = "2026-10-24T12:15:32.718Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/0f/6830a2c7f85faba4a580f800e7bad4ae8b949dd60e4894a1dbc3a89d02fa/moviepilot_rust-0.3.12-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d8e095858480027fcd37e8383de8a86ee46f93cee1ac4609eb3fb0a9003ce23", size = 5613119, upload-time = "2026-10-24T12:15:34.538Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/db/c41ea279b37f05e23fcba1f269d3a26acdbd77ea9df77d729c0567429218/moviepilot_rust-0.3.12-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50df659acb4f47445c4e0e96d297edfafef2eb5250daff28ba1dfd6661454775", size = 5801030, upload-time = "2026-10-24T12:15:36.342Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/6a/26173518d4a423a35d1ae0c53b3c0d01eca04fc34a259e39a2ecf0ccc5fb/moviepilot_rust-0.3.12-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2056ed52a432c281776456e212e5766145b6bee54318689f1a0e4772f3300a2f", size = 5819388, upload-time = "2026-10-24T12:15:38.172Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/5c/8a84b00bdd6625ff6ccac3d724256a61a79aabc9a0d379d6911ecbe09428/moviepilot_rust-0.3.12-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b802e8c76af7f52325372d0b28346cb621015a84150d65645665f5b3bb53145f", size = 6042300, upload-time = "2026-10-24T12:15:39.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/ed/3b2c84bca9f18e8a1c92f61f85ad35844f607b4d9404e8777c6a75248c4b/moviepilot_rust-0.3.12-cp314-cp314t-win_amd64.whl", hash = "sha256:4ae4367f23c02235d1510ce9f2984194939309cc7fcc8ebd189605fc5ac69282", size = 5609923, upload-time = "2026-10-24T12:15:41.645Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/70/984b00ca015f98d92ca2ae1655c0edcea807d495a018be2b5d3d02208e21/moviepilot_rust-0.3.13-cp314-abi3-macosx_10_12_x86_64.whl", hash = "sha256:645231ce93147876cfe9c9d5319b77068af4295c1257e12564ca030dd5c328c2", size = 5607172, upload-time = "2026-11-01T02:22:04.1Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/dd/143dff43940773159fc88829f0a14aabae5260b420d9a9eadf0d293f00ea/moviepilot_rust-0.3.13-cp314-abi3-macosx_11_0_arm64.whl", hash = "sha256:af0b1b080feadeeb544d8b1643d4328838b52d5700b363b107de7611fb3ca8ab", size = 5515072, upload-time = "2026-11-01T02:22:05.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/a8/1774c3e23094cfc19462b66d4edaa09d0068237be511bac5859d19130bdf/moviepilot_rust-0.3.13-cp314-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:76e06e4eccfef2be1faf2d50a705fc683ade9893d15c0d17bf0deccc649abd0c", size = 5612830, upload-time = "2026-11-01T02:22:07.217Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/23/cc03dac49ddaff706e8a6b30b39ff3b0af09912fc24f271923cad88d765b/moviepilot_rust-0.3.13-cp314-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a5ed99f677b33dddfde42ef3e4f47f9737294ac0262f3c8150d5d395f4efef2b", size = 5801775, upload-time = "2026-11-01T02:22:08.714Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/c3/e4d8e2306efab4430fd80dee9ae7dfbc2520c1a391c1d4b10878eb7cdef2/moviepilot_rust-0.3.13-cp314-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:46714b568d9f5f5d563ea743ad6c16b7a29baba2476e22f93da6d7e5d77a867b", size = 5819978, upload-time = "2026-11-01T02:22:10.103Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/51/683be6fb7660e96a5fdae81e5464c4ca4cbe849aad2a684c64bda4802e2f/moviepilot_rust-0.3.13-cp314-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:be34b6c76b8a448d5f9b1662309c5a2653fb2ee5b2571be0251cd42f492ebd6a", size = 6042149, upload-time = "2026-11-01T02:22:11.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/5b/2c4aa089c6b43761b06127391367cbaca03f2d01a16615a9143738fa8159/moviepilot_rust-0.3.13-cp314-abi3-win_amd64.whl", hash = "sha256:f01c2c5552628d92266b9cfce3790d6a4f9fa7d1b1ddeb10766efe581b8b76b1", size = 5610144, upload-time = "2026-11-01T02:22:13.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/c9/483820184ca8d234a78706a8ea10e72a5831f0d74f69acfef4c7e324724e/moviepilot_rust-0.3.13-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:9c0cee82c53743afcb0a0ee9d0c04dc875f49c25c26ad3922c89a11fe06a6e40", size = 5592497, upload-time = "2026-11-01T02:22:15.429Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/ad/526fa77ee8e42c0807b2ef7104ac488ab9578635e2b117bc59f4853f3fdf/moviepilot_rust-0.3.13-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fa7d5a5f49ba2b27ab99ee380a3efee63ad54e39d767940c85d45d726eae48e", size = 5509671, upload-time = "2026-11-01T02:22:17.091Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/8c/c9a20272b1200fee15d9882323bc560914733a7c219f13c4ad4511a8731e/moviepilot_rust-0.3.13-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:47ea6e373c934e3359781033e0295b8b8fb18cd904bf2a947270df4d02f917be", size = 5612320, upload-time = "2026-11-01T02:22:18.522Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/b9/764536f2ab1045d310555668bc2ca03632dd691a67f28911964e98cf74ce/moviepilot_rust-0.3.13-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9c27181920e74cf7cbdc01595cf9778ca5c1505e3edefc636b1d5ea22f5565a5", size = 5801436, upload-time = "2026-11-01T02:22:20.212Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/ed/72821a22dbe9d849648b621c4c85f3176488a2572e3fc67c5511256bd735/moviepilot_rust-0.3.13-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d61f6ede4becf1fcc54e4762e3da3d243ff796daa5ab0d79e23d68e0e17090c9", size = 5820822, upload-time = "2026-11-01T02:22:21.843Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/9c/6ada4e57ef08bc1ceb1f47fd8682ace73b95a2ce63338e9ebc32aff7f7c4/moviepilot_rust-0.3.13-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:871a5ce5949d2b27247fd58a908002ecb5e783b07e226f65bc37d0e086113ea9", size = 6042509, upload-time = "2026-11-01T02:22:23.588Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/7e/ba9e1adc72838f4ea6a39b03879f03abcae5e66e534e209e572f97391705/moviepilot_rust-0.3.13-cp314-cp314t-win_amd64.whl", hash = "sha256:b368f393aa1708bb08e27ead6e55a51457b7d4876fc4f4865a7bfda9cf826931", size = 5609820, upload-time = "2026-11-01T02:22:25.124Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user