mirror of
https://github.com/alexta69/metube.git
synced 2026-06-15 00:30:04 +00:00
Propagate missing playlist context fields (playlist_count, playlist_autonumber, n_entries, __last_playlist_index)
The playlist/channel processing loop now sets playlist_count,
playlist_autonumber, n_entries, and __last_playlist_index on each
video entry so that templates like %(playlist_autonumber)s,
%(playlist_count)s, and %(playlist_index&{} - |)s resolve correctly
instead of showing NA.
Also updates _compact_persisted_entry to preserve n_entries and
__last_playlist_index across restarts.
Fixes #692
Agent-Logs-Url: https://github.com/alexta69/metube/sessions/b5aeb55a-3197-4a14-b8b4-96c9a67796e8
Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
b17e1e5668
commit
981e6c1003
@@ -93,6 +93,35 @@ class ResolveOuttmplFieldsTests(unittest.TestCase):
|
|||||||
result = _resolve_outtmpl_fields("%(playlist_index+100)d", info, ("playlist",))
|
result = _resolve_outtmpl_fields("%(playlist_index+100)d", info, ("playlist",))
|
||||||
self.assertEqual(result, "103")
|
self.assertEqual(result, "103")
|
||||||
|
|
||||||
|
def test_playlist_count_and_autonumber(self):
|
||||||
|
info = {
|
||||||
|
"playlist_title": "My PL",
|
||||||
|
"playlist_index": "03",
|
||||||
|
"playlist_count": 10,
|
||||||
|
"playlist_autonumber": 3,
|
||||||
|
"n_entries": 10,
|
||||||
|
"__last_playlist_index": 10,
|
||||||
|
}
|
||||||
|
result = _resolve_outtmpl_fields(
|
||||||
|
"%(playlist_title)s/%(playlist_autonumber)s of %(playlist_count)s - %(title)s.%(ext)s",
|
||||||
|
info,
|
||||||
|
("playlist",),
|
||||||
|
)
|
||||||
|
# playlist_autonumber is auto-padded by yt-dlp using __last_playlist_index
|
||||||
|
self.assertEqual(result, "My PL/03 of 10 - %(title)s.%(ext)s")
|
||||||
|
|
||||||
|
def test_conditional_playlist_index(self):
|
||||||
|
info = {
|
||||||
|
"playlist_index": "5",
|
||||||
|
"playlist_count": 10,
|
||||||
|
}
|
||||||
|
result = _resolve_outtmpl_fields(
|
||||||
|
"%(playlist_index&{} - |)s%(title)s.%(ext)s",
|
||||||
|
info,
|
||||||
|
("playlist",),
|
||||||
|
)
|
||||||
|
self.assertEqual(result, "5 - %(title)s.%(ext)s")
|
||||||
|
|
||||||
|
|
||||||
class SanitizeEntryForPickleTests(unittest.TestCase):
|
class SanitizeEntryForPickleTests(unittest.TestCase):
|
||||||
def test_nested(self):
|
def test_nested(self):
|
||||||
@@ -250,8 +279,12 @@ class CompactPersistedEntryTests(unittest.TestCase):
|
|||||||
entry = {
|
entry = {
|
||||||
"playlist_index": "01",
|
"playlist_index": "01",
|
||||||
"playlist_title": "Playlist",
|
"playlist_title": "Playlist",
|
||||||
|
"playlist_count": 10,
|
||||||
|
"playlist_autonumber": 1,
|
||||||
"channel_index": "02",
|
"channel_index": "02",
|
||||||
"channel_title": "Channel",
|
"channel_title": "Channel",
|
||||||
|
"n_entries": 10,
|
||||||
|
"__last_playlist_index": 10,
|
||||||
"formats": [{"id": "huge"}],
|
"formats": [{"id": "huge"}],
|
||||||
"description": "big blob",
|
"description": "big blob",
|
||||||
}
|
}
|
||||||
@@ -263,8 +296,12 @@ class CompactPersistedEntryTests(unittest.TestCase):
|
|||||||
{
|
{
|
||||||
"playlist_index": "01",
|
"playlist_index": "01",
|
||||||
"playlist_title": "Playlist",
|
"playlist_title": "Playlist",
|
||||||
|
"playlist_count": 10,
|
||||||
|
"playlist_autonumber": 1,
|
||||||
"channel_index": "02",
|
"channel_index": "02",
|
||||||
"channel_title": "Channel",
|
"channel_title": "Channel",
|
||||||
|
"n_entries": 10,
|
||||||
|
"__last_playlist_index": 10,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -295,13 +295,16 @@ _PERSISTED_DOWNLOAD_FIELDS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_COMPACT_ENTRY_EXTRA_KEYS = frozenset(("n_entries", "__last_playlist_index"))
|
||||||
|
|
||||||
|
|
||||||
def _compact_persisted_entry(entry: Any) -> Optional[dict[str, Any]]:
|
def _compact_persisted_entry(entry: Any) -> Optional[dict[str, Any]]:
|
||||||
if not isinstance(entry, dict):
|
if not isinstance(entry, dict):
|
||||||
return None
|
return None
|
||||||
compact = {
|
compact = {
|
||||||
key: value
|
key: value
|
||||||
for key, value in entry.items()
|
for key, value in entry.items()
|
||||||
if key.startswith("playlist") or key.startswith("channel")
|
if key.startswith("playlist") or key.startswith("channel") or key in _COMPACT_ENTRY_EXTRA_KEYS
|
||||||
}
|
}
|
||||||
return compact or None
|
return compact or None
|
||||||
|
|
||||||
@@ -893,8 +896,9 @@ class DownloadQueue:
|
|||||||
# Convert generator to list if needed (for len() and slicing operations)
|
# Convert generator to list if needed (for len() and slicing operations)
|
||||||
if isinstance(entries, types.GeneratorType):
|
if isinstance(entries, types.GeneratorType):
|
||||||
entries = list(entries)
|
entries = list(entries)
|
||||||
log.info(f'{etype} detected with {len(entries)} entries')
|
total_entries = len(entries)
|
||||||
index_digits = len(str(len(entries)))
|
log.info(f'{etype} detected with {total_entries} entries')
|
||||||
|
index_digits = len(str(total_entries))
|
||||||
results = []
|
results = []
|
||||||
if playlist_item_limit > 0:
|
if playlist_item_limit > 0:
|
||||||
log.info(f'Item limit is set. Processing only first {playlist_item_limit} entries')
|
log.info(f'Item limit is set. Processing only first {playlist_item_limit} entries')
|
||||||
@@ -906,6 +910,10 @@ class DownloadQueue:
|
|||||||
etr["_type"] = "video"
|
etr["_type"] = "video"
|
||||||
etr[etype] = entry.get("id") or entry.get("channel_id") or entry.get("channel")
|
etr[etype] = entry.get("id") or entry.get("channel_id") or entry.get("channel")
|
||||||
etr[f"{etype}_index"] = '{{0:0{0:d}d}}'.format(index_digits).format(index)
|
etr[f"{etype}_index"] = '{{0:0{0:d}d}}'.format(index_digits).format(index)
|
||||||
|
etr[f"{etype}_count"] = total_entries
|
||||||
|
etr[f"{etype}_autonumber"] = index
|
||||||
|
etr["n_entries"] = total_entries
|
||||||
|
etr["__last_playlist_index"] = total_entries
|
||||||
for property in ("id", "title", "uploader", "uploader_id"):
|
for property in ("id", "title", "uploader", "uploader_id"):
|
||||||
if property in entry:
|
if property in entry:
|
||||||
etr[f"{etype}_{property}"] = entry[property]
|
etr[f"{etype}_{property}"] = entry[property]
|
||||||
|
|||||||
Reference in New Issue
Block a user