mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-03 05:44:44 +08:00
fix(plex): avoid detail reloads for continue watching
This commit is contained in:
committed by
InfinityPacer
parent
c1e738f615
commit
8c52755d4e
@@ -1005,6 +1005,8 @@ class Plex:
|
||||
"""
|
||||
获取同步范围内可以继续观看的媒体。
|
||||
|
||||
只使用列表已有字段,缺失的年份、图片或时长不触发逐条详情请求。
|
||||
|
||||
:param num: 最多返回条目数量,默认 12
|
||||
:return: 包含观看进度百分比的媒体列表;未连接或无法读取媒体库范围时返回 None,SDK 请求异常向上传播
|
||||
"""
|
||||
@@ -1023,6 +1025,9 @@ class Plex:
|
||||
params=params)
|
||||
ret_resume: List[_SchemaMediaServerPlayItem] = []
|
||||
for item in items:
|
||||
if isinstance(item, PlexPartialObject):
|
||||
# SDK 会为缺失属性同步重载详情,继续观看展示不能等待额外的媒体探测。
|
||||
item._autoReload = False
|
||||
item_type = MediaType.MOVIE.value if item.TYPE == "movie" else MediaType.TV.value
|
||||
if item_type == MediaType.MOVIE.value:
|
||||
title = item.title
|
||||
|
||||
81
tests/test_plex_resume.py
Normal file
81
tests/test_plex_resume.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
继续观看直接使用列表字段,缺失的可选信息不能触发逐条详情请求。
|
||||
"""
|
||||
|
||||
from types import SimpleNamespace
|
||||
from typing import Optional
|
||||
from unittest.mock import Mock
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
import pytest
|
||||
from plexapi.server import PlexServer
|
||||
|
||||
from app.modules.plex.plex import Plex
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("attributes", "expected_subtitle", "expected_image", "expected_percent"),
|
||||
[
|
||||
('type="movie" viewOffset="1000"', None, None, 0),
|
||||
('type="movie" year="2026" duration="10000" art="/art.jpg"', "2026", "/art.jpg", 0),
|
||||
('type="movie" year="2026" viewOffset="1000" art="/art.jpg"', "2026", "/art.jpg", 0),
|
||||
('type="movie" year="2026" art="/art.jpg" viewOffset="4000" duration="10000"',
|
||||
"2026", "/art.jpg", 40),
|
||||
('type="episode" grandparentTitle="剧集" parentIndex="1" index="2" '
|
||||
'grandparentArt="/show-art.jpg" viewOffset="1000"',
|
||||
"S1:E2 - 测试条目", "/show-art.jpg", 0),
|
||||
('type="episode" grandparentTitle="剧集" parentIndex="1" index="2" '
|
||||
'duration="10000" viewOffset="2500"', "S1:E2 - 测试条目", None, 25),
|
||||
],
|
||||
ids=["missing-year-duration-art", "missing-offset", "missing-duration", "complete-movie",
|
||||
"episode-fallback-art-missing-duration", "episode-missing-art"],
|
||||
)
|
||||
def test_resume_uses_hub_fields_without_detail_requests(
|
||||
attributes: str, expected_subtitle: Optional[str], expected_image: Optional[str], expected_percent: int,
|
||||
) -> None:
|
||||
"""
|
||||
使用真实 PlexAPI 解析列表,禁止缺字段时请求详情,同时保留图片回退与观看进度。
|
||||
"""
|
||||
session = Mock()
|
||||
|
||||
def respond(url: str, **_kwargs: object) -> SimpleNamespace:
|
||||
path = urlsplit(url).path
|
||||
if path == "/":
|
||||
text = '<MediaContainer machineIdentifier="test-server"/>'
|
||||
elif path == "/hubs/continueWatching/items":
|
||||
text = (
|
||||
'<MediaContainer size="1" totalSize="1">'
|
||||
f'<Video key="/library/metadata/1" ratingKey="1" title="测试条目" {attributes}/>'
|
||||
'</MediaContainer>'
|
||||
)
|
||||
else:
|
||||
raise AssertionError(f"列表展示不应额外请求 {path}")
|
||||
return SimpleNamespace(status_code=200, text=text)
|
||||
|
||||
session.get.side_effect = respond
|
||||
session.get.__name__ = "get"
|
||||
server = PlexServer("http://plex.test:32400", "test-token", session=session)
|
||||
session.get.reset_mock()
|
||||
client = Plex.__new__(Plex)
|
||||
client._plex = server
|
||||
client._host = "http://plex.test:32400/"
|
||||
client._playhost = None
|
||||
client._token = "test-token"
|
||||
client.get_librarys = Mock(return_value=[SimpleNamespace(id="2")])
|
||||
|
||||
result = client.get_resume(8)
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].id == "/library/metadata/1"
|
||||
assert result[0].subtitle == expected_subtitle
|
||||
assert result[0].percent == expected_percent
|
||||
assert result[0].image == (
|
||||
f"http://plex.test:32400{expected_image}?X-Plex-Token=test-token" if expected_image else None
|
||||
)
|
||||
assert "/server/test-server/details?key=/library/metadata/1" in result[0].link
|
||||
client.get_librarys.assert_called_once_with(hidden=True)
|
||||
session.get.assert_called_once()
|
||||
call = session.get.call_args
|
||||
assert urlsplit(call.args[0]).path == "/hubs/continueWatching/items"
|
||||
assert call.kwargs["params"] == {"contentDirectoryID": "2"}
|
||||
assert call.kwargs["headers"]["X-Plex-Container-Size"] == "8"
|
||||
Reference in New Issue
Block a user