[FEATURE] Enhance music video presets using specialized map syntax (#808)
Enhances the music video presets by supporting the following syntax:
`subscriptions.yaml`
```
__preset__:
overrides:
music_video_directory: "/music_videos"
# Choose between Jellyfin/Kodi/Plex Music Videos preset:
# - Plex Music Videos:
# - Jellyfin Music Videos:
# - Kodi Music Videos:
#
"Plex Music Videos":
= Pop: # Sets genre tag to "Pop"
"Rick Astley": "https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
"Michael Jackson": "https://www.youtube.com/playlist?list=OLAK5uy_mnY03zP6abNWH929q2XhGzWD_2uKJ_n8E"
= Rock:
# Prefixing with '+' puts the subscription into 'map-mode'.
# Music video presets in map-mode support grouping videos into different
# categories, which get set on the album field.
#
# URLs can either be strings, or maps that can overload title, year, date
"+ Guns N' Roses":
Music Videos:
- "https://www.youtube.com/playlist?list=PLOTK54q5K4INNXaHKtmXYr6J7CajWjqeJ"
Concerts:
- title: "Live at The Ritz - New York City"
year: "1988"
url: "https://www.youtube.com/watch?v=OldpIhHPsbs"
- title: "Live at The Hollywood Bowl"
date: "2023-01-11"
url: "https://www.youtube.com/watch?v=Z7hutGlvq9I"
```
The 'map-mode' (denoted by `+`) lets you specify a map of music video categories. Under each category, a URL can be specified as-is or with additional metadata (title, year/date, url).
Music videos and concerts, especially older ones, are typically uploaded by random users with inconsistencies in their titles. This syntax aims to make it easy to specify individual URLs with the ability to overwrite their title and year, and group them by category.
This commit is contained in:
parent
5866c12104
commit
5e9472986a
25 changed files with 1064 additions and 18 deletions
|
|
@ -5,6 +5,18 @@ Static Variables
|
|||
Subscription Variables
|
||||
----------------------
|
||||
|
||||
subscription_array
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
For subscriptions in the form of
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
"Subscription Name":
|
||||
- "https://url1.com/..."
|
||||
- "https://url2.com/..."
|
||||
|
||||
Store all values into an array named ``subscription_array``.
|
||||
|
||||
subscription_has_download_archive
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns True if the subscription has any entries recorded in a download archive. False
|
||||
|
|
|
|||
|
|
@ -14,12 +14,32 @@ __preset__:
|
|||
overrides:
|
||||
music_video_directory: "/music_videos"
|
||||
|
||||
# Choose between Jellyfin/Kodi/Plex Music Videos
|
||||
# "Jellyfin Music Videos":
|
||||
# "Kodi Music Videos":
|
||||
# Choose between Jellyfin/Kodi/Plex Music Videos preset:
|
||||
# - Plex Music Videos:
|
||||
# - Jellyfin Music Videos:
|
||||
# - Kodi Music Videos:
|
||||
"Plex Music Videos":
|
||||
|
||||
= Pop: # Sets genre tag to "Pop"
|
||||
"Rick Astley": "https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||
"Michael Jackson": "https://www.youtube.com/playlist?list=OLAK5uy_mnY03zP6abNWH929q2XhGzWD_2uKJ_n8E"
|
||||
|
||||
= Blues:
|
||||
"Eric Clapton": "https://www.youtube.com/playlist?list=PLABGggHhsbEeaRtdzqnxYoEINsJE_4GF4"
|
||||
|
||||
= Rock:
|
||||
# Prefixing with '+' puts the subscription into 'map-mode'.
|
||||
# Music video presets in map-mode support grouping videos into different
|
||||
# categories, which get set on the album field.
|
||||
#
|
||||
# URLs can either be strings, or maps that can overload title, year, date
|
||||
"+ Guns N' Roses":
|
||||
Music Videos:
|
||||
- "https://www.youtube.com/playlist?list=PLOTK54q5K4INNXaHKtmXYr6J7CajWjqeJ"
|
||||
Concerts:
|
||||
- title: "Live at The Ritz - New York City"
|
||||
year: "1988"
|
||||
url: "https://www.youtube.com/watch?v=OldpIhHPsbs"
|
||||
- title: "Live at The Hollywood Bowl"
|
||||
date: "2023-01-11"
|
||||
url: "https://www.youtube.com/watch?v=Z7hutGlvq9I"
|
||||
|
|
@ -3,6 +3,7 @@ from typing import Set
|
|||
|
||||
from ytdl_sub.entries.script.function_scripts import CUSTOM_FUNCTION_SCRIPTS
|
||||
from ytdl_sub.entries.script.variable_definitions import VARIABLE_SCRIPTS
|
||||
from ytdl_sub.entries.script.variable_types import ArrayVariable
|
||||
from ytdl_sub.entries.script.variable_types import BooleanVariable
|
||||
from ytdl_sub.entries.script.variable_types import MapVariable
|
||||
from ytdl_sub.entries.script.variable_types import StringVariable
|
||||
|
|
@ -36,6 +37,21 @@ class SubscriptionVariables:
|
|||
"""
|
||||
return StringVariable(variable_name="subscription_value", definition="{ %string('') }")
|
||||
|
||||
@staticmethod
|
||||
def subscription_array() -> ArrayVariable:
|
||||
"""
|
||||
For subscriptions in the form of
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
"Subscription Name":
|
||||
- "https://url1.com/..."
|
||||
- "https://url2.com/..."
|
||||
|
||||
Store all values into an array named ``subscription_array``.
|
||||
"""
|
||||
return ArrayVariable(variable_name="subscription_array", definition="{ [] }")
|
||||
|
||||
@staticmethod
|
||||
def subscription_indent_i(index: int) -> StringVariable:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ presets:
|
|||
avatar_uncropped_thumbnail_file_name: ""
|
||||
banner_uncropped_thumbnail_file_name: ""
|
||||
|
||||
subscription_array: "{ [] }"
|
||||
subscription_value: ""
|
||||
subscription_value_2: ""
|
||||
subscription_value_3: ""
|
||||
|
|
|
|||
210
src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml
Normal file
210
src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
presets:
|
||||
# Preset for categorizing URls like so
|
||||
#
|
||||
# subscription_name:
|
||||
# category_1:
|
||||
# - https://...1
|
||||
# - https://...2
|
||||
# category_2:
|
||||
# - url: https://...1
|
||||
# metadata_field_1: 2011
|
||||
# metadata_field_2: 'abc"
|
||||
# ...
|
||||
#
|
||||
# Metadata field of `url` must exist, other ones can be anything.
|
||||
# Only supports a single level of nesting.
|
||||
_url_categorized:
|
||||
preset:
|
||||
- "_multi_url_bilateral"
|
||||
|
||||
overrides:
|
||||
# Parameters:
|
||||
# $0: url string or map containing url + metadata fields
|
||||
# $1: category key
|
||||
#
|
||||
# Output:
|
||||
# Map containing { url: ..., category: ..., metadata_field_1: ... }
|
||||
"%flat_array__url_to_map_format": >-
|
||||
{
|
||||
%elif(
|
||||
%is_map($0),
|
||||
%map_extend( $0, { "category": $1 } ),
|
||||
%is_string($0),
|
||||
{ "url": $0, "category": $1 },
|
||||
%throw("If using album categories, each URL must be either a string or map with metadata fields")
|
||||
)
|
||||
}
|
||||
|
||||
# Parameters:
|
||||
# $0: category key
|
||||
# $1: array of URLs in either string or map form
|
||||
#
|
||||
# Output:
|
||||
# Array containing [{ url: ..., category: ... }, ... ]
|
||||
"%flat_array__category_to_map_format": >-
|
||||
{
|
||||
%array_apply_fixed(
|
||||
%assert_then(
|
||||
%is_array( $1 ),
|
||||
$1,
|
||||
"If using album categories, each category must map to an array"
|
||||
),
|
||||
$0,
|
||||
%flat_array__url_to_map_format
|
||||
)
|
||||
}
|
||||
|
||||
# Parameters:
|
||||
# $0: map containing fields { url: <url_value>, category: ... }
|
||||
#
|
||||
# Output:
|
||||
# Nested map containing { <url_value>: { url: <url_value>, category: ... } }
|
||||
"%flat_array__url_keyed_map_format": >-
|
||||
{ { %map_get($0, "url"): $0 } }
|
||||
|
||||
# Creates an array in the form of [ { url: ..., category: ..., metadata_field_1: ... }, ... ]
|
||||
category_url_array: >-
|
||||
{ %array_flatten( %map_apply( subscription_map, %flat_array__category_to_map_format ) ) }
|
||||
|
||||
# Creates a map in the form of { <url value>: { category: ..., metadata_field_1: ... }, ... }
|
||||
category_url_map: >-
|
||||
{
|
||||
%array_reduce(
|
||||
%array_apply( category_url_array, %flat_array__url_keyed_map_format ),
|
||||
%map_extend
|
||||
)
|
||||
}
|
||||
|
||||
# Parameters:
|
||||
# $0: metadata field to fetch for the current url
|
||||
# $1: default value
|
||||
#
|
||||
# Output:
|
||||
# Metadata field value if it exists. Otherwise, return default value
|
||||
"%get_url_field": >-
|
||||
{ %map_get( %map( %map_get( category_url_map, ytdl_sub_input_url, {} ) ), $0, $1 ) }
|
||||
|
||||
# Parameters:
|
||||
# $0: metadata field to fetch for the current url
|
||||
#
|
||||
# Output:
|
||||
# True if field is specified. False otherwise.
|
||||
"%contains_url_field": >-
|
||||
{ %not( %is_null( %get_url_field( $0, null ) ) ) }
|
||||
|
||||
|
||||
# Parameters:
|
||||
# $0: integer to fetch the i'th url using 1-based indexing
|
||||
#
|
||||
# Output:
|
||||
# i'th url in the category map
|
||||
"%get_url_i": >-
|
||||
{
|
||||
%map_get(
|
||||
%map( %array_at( category_url_array, %int( %sub($0, 1) ), {} ) ),
|
||||
"url",
|
||||
%array_at(subscription_array, %int( %sub($0, 1) ), null)
|
||||
)
|
||||
}
|
||||
|
||||
subscription_map: "{ {} }"
|
||||
url: "{ %get_url_i(1) }"
|
||||
url2: "{ %get_url_i(2) }"
|
||||
url3: "{ %get_url_i(3) }"
|
||||
url4: "{ %get_url_i(4) }"
|
||||
url5: "{ %get_url_i(5) }"
|
||||
url6: "{ %get_url_i(6) }"
|
||||
url7: "{ %get_url_i(7) }"
|
||||
url8: "{ %get_url_i(8) }"
|
||||
url9: "{ %get_url_i(9) }"
|
||||
url10: "{ %get_url_i(10) }"
|
||||
url11: "{ %get_url_i(11) }"
|
||||
url12: "{ %get_url_i(12) }"
|
||||
url13: "{ %get_url_i(13) }"
|
||||
url14: "{ %get_url_i(14) }"
|
||||
url15: "{ %get_url_i(15) }"
|
||||
url16: "{ %get_url_i(16) }"
|
||||
url17: "{ %get_url_i(17) }"
|
||||
url18: "{ %get_url_i(18) }"
|
||||
url19: "{ %get_url_i(19) }"
|
||||
url20: "{ %get_url_i(20) }"
|
||||
url21: "{ %get_url_i(21) }"
|
||||
url22: "{ %get_url_i(22) }"
|
||||
url23: "{ %get_url_i(23) }"
|
||||
url24: "{ %get_url_i(24) }"
|
||||
url25: "{ %get_url_i(25) }"
|
||||
url26: "{ %get_url_i(26) }"
|
||||
url27: "{ %get_url_i(27) }"
|
||||
url28: "{ %get_url_i(28) }"
|
||||
url29: "{ %get_url_i(29) }"
|
||||
url30: "{ %get_url_i(30) }"
|
||||
url31: "{ %get_url_i(31) }"
|
||||
url32: "{ %get_url_i(32) }"
|
||||
url33: "{ %get_url_i(33) }"
|
||||
url34: "{ %get_url_i(34) }"
|
||||
url35: "{ %get_url_i(35) }"
|
||||
url36: "{ %get_url_i(36) }"
|
||||
url37: "{ %get_url_i(37) }"
|
||||
url38: "{ %get_url_i(38) }"
|
||||
url39: "{ %get_url_i(39) }"
|
||||
url40: "{ %get_url_i(40) }"
|
||||
url41: "{ %get_url_i(41) }"
|
||||
url42: "{ %get_url_i(42) }"
|
||||
url43: "{ %get_url_i(43) }"
|
||||
url44: "{ %get_url_i(44) }"
|
||||
url45: "{ %get_url_i(45) }"
|
||||
url46: "{ %get_url_i(46) }"
|
||||
url47: "{ %get_url_i(47) }"
|
||||
url48: "{ %get_url_i(48) }"
|
||||
url49: "{ %get_url_i(49) }"
|
||||
url50: "{ %get_url_i(50) }"
|
||||
url51: "{ %get_url_i(51) }"
|
||||
url52: "{ %get_url_i(52) }"
|
||||
url53: "{ %get_url_i(53) }"
|
||||
url54: "{ %get_url_i(54) }"
|
||||
url55: "{ %get_url_i(55) }"
|
||||
url56: "{ %get_url_i(56) }"
|
||||
url57: "{ %get_url_i(57) }"
|
||||
url58: "{ %get_url_i(58) }"
|
||||
url59: "{ %get_url_i(59) }"
|
||||
url60: "{ %get_url_i(60) }"
|
||||
url61: "{ %get_url_i(61) }"
|
||||
url62: "{ %get_url_i(62) }"
|
||||
url63: "{ %get_url_i(63) }"
|
||||
url64: "{ %get_url_i(64) }"
|
||||
url65: "{ %get_url_i(65) }"
|
||||
url66: "{ %get_url_i(66) }"
|
||||
url67: "{ %get_url_i(67) }"
|
||||
url68: "{ %get_url_i(68) }"
|
||||
url69: "{ %get_url_i(69) }"
|
||||
url70: "{ %get_url_i(70) }"
|
||||
url71: "{ %get_url_i(71) }"
|
||||
url72: "{ %get_url_i(72) }"
|
||||
url73: "{ %get_url_i(73) }"
|
||||
url74: "{ %get_url_i(74) }"
|
||||
url75: "{ %get_url_i(75) }"
|
||||
url76: "{ %get_url_i(76) }"
|
||||
url77: "{ %get_url_i(77) }"
|
||||
url78: "{ %get_url_i(78) }"
|
||||
url79: "{ %get_url_i(79) }"
|
||||
url80: "{ %get_url_i(80) }"
|
||||
url81: "{ %get_url_i(81) }"
|
||||
url82: "{ %get_url_i(82) }"
|
||||
url83: "{ %get_url_i(83) }"
|
||||
url84: "{ %get_url_i(84) }"
|
||||
url85: "{ %get_url_i(85) }"
|
||||
url86: "{ %get_url_i(86) }"
|
||||
url87: "{ %get_url_i(87) }"
|
||||
url88: "{ %get_url_i(88) }"
|
||||
url89: "{ %get_url_i(89) }"
|
||||
url90: "{ %get_url_i(90) }"
|
||||
url91: "{ %get_url_i(91) }"
|
||||
url92: "{ %get_url_i(92) }"
|
||||
url93: "{ %get_url_i(93) }"
|
||||
url94: "{ %get_url_i(94) }"
|
||||
url95: "{ %get_url_i(95) }"
|
||||
url96: "{ %get_url_i(96) }"
|
||||
url97: "{ %get_url_i(97) }"
|
||||
url98: "{ %get_url_i(98) }"
|
||||
url99: "{ %get_url_i(99) }"
|
||||
url100: "{ %get_url_i(100) }"
|
||||
|
|
@ -10,3 +10,11 @@ class MusicVideoPresets(PrebuiltPresets):
|
|||
"Jellyfin Music Videos",
|
||||
"Plex Music Videos",
|
||||
}
|
||||
|
||||
|
||||
class MusicVideoExtrasPresets(PrebuiltPresets):
|
||||
preset_names = {
|
||||
"Kodi Music Videos with Extras",
|
||||
"Jellyfin Music Videos with Extras",
|
||||
"Plex Music Videos with Extras",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
presets:
|
||||
_music_video_base:
|
||||
|
||||
preset:
|
||||
- "_multi_url"
|
||||
- "_url_categorized"
|
||||
|
||||
output_options:
|
||||
output_directory: "{music_video_directory}"
|
||||
|
|
@ -25,12 +26,38 @@ presets:
|
|||
subscription_indent_1: "{music_video_genre_default}"
|
||||
|
||||
# Music Video Overrides
|
||||
music_video_title: "{title}"
|
||||
music_video_album: "{music_video_album_default}"
|
||||
music_video_artist: "{subscription_name}"
|
||||
music_video_year: "{upload_year}"
|
||||
music_video_date: "{upload_date_standardized}"
|
||||
music_video_genre: "{subscription_indent_1}"
|
||||
music_video_album: >-
|
||||
{ %get_url_field("category", music_video_album_default) }
|
||||
music_video_title: >-
|
||||
{ %get_url_field("title", title) }
|
||||
music_video_date: >-
|
||||
{
|
||||
%elif(
|
||||
%contains_url_field("date"),
|
||||
%get_url_field("date", upload_date_standardized),
|
||||
|
||||
%contains_url_field("year"),
|
||||
%concat( %get_url_field("date", upload_year), "-01-01"),
|
||||
|
||||
upload_date_standardized
|
||||
)
|
||||
}
|
||||
music_video_year: >-
|
||||
{
|
||||
%int(%elif(
|
||||
%contains_url_field("date"),
|
||||
%slice( %get_url_field("date", upload_date_standardized), 0, 4 ),
|
||||
|
||||
%contains_url_field("year"),
|
||||
%get_url_field("date", upload_year),
|
||||
|
||||
upload_year
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
# Directory Overrides
|
||||
music_video_file_name: "{music_video_artist_sanitized}/{music_video_title_sanitized}"
|
||||
music_video_file_name_suffix: ""
|
||||
music_video_file_name: "{music_video_artist_sanitized}/{music_video_title_sanitized}{music_video_file_name_suffix}"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# Kodi Music Videos with Extras:
|
||||
# + Rick Astley:
|
||||
# Music Videos:
|
||||
# - url1
|
||||
# - url2
|
||||
# ...
|
||||
# Concerts:
|
||||
# - url: asfasdfasdf
|
||||
# year: 2023
|
||||
# title: sdfasff
|
||||
# exclude: asdffsdf
|
||||
# - url4
|
||||
# Extras:
|
||||
# - url5
|
||||
# - url6
|
||||
# Behind The Scenes:
|
||||
# - ...
|
||||
# Live:
|
||||
# - ...
|
||||
# Lyrics:
|
||||
# - ...
|
||||
|
||||
presets:
|
||||
_music_video_extras_base:
|
||||
preset:
|
||||
- "_url_categorized"
|
||||
- "_music_video_base"
|
||||
|
||||
overrides:
|
||||
music_video_album: >-
|
||||
{ %get_url_field("category", music_video_album_default) }
|
||||
music_video_title: >-
|
||||
{ %get_url_field("title", title) }
|
||||
|
||||
"Jellyfin Music Videos with Extras":
|
||||
preset:
|
||||
- "_base"
|
||||
- "_music_video_extras_base"
|
||||
- "_music_video_nfo"
|
||||
- "_music_video_tags"
|
||||
|
||||
"Kodi Music Videos with Extras":
|
||||
preset:
|
||||
- "_kodi_base"
|
||||
- "_music_video_extras_base"
|
||||
- "_music_video_nfo"
|
||||
- "_music_video_tags"
|
||||
|
||||
"Plex Music Videos with Extras":
|
||||
preset:
|
||||
- "_plex_video_base"
|
||||
- "_music_video_extras_base"
|
||||
- "_music_video_tags"
|
||||
|
||||
# overrides:
|
||||
# metadata_verify_plex_suffix: "{url_metadata}"
|
||||
# music_video_file_name_suffix: "-{music_video_album}"
|
||||
|
|
@ -143,10 +143,21 @@ class SubscriptionValueValidator(SubscriptionLeafValidator, StringValidator):
|
|||
presets=presets,
|
||||
indent_overrides=indent_overrides,
|
||||
)
|
||||
# subscription_value
|
||||
self._overrides_to_add[SubscriptionVariables.subscription_value().variable_name] = (
|
||||
self.value
|
||||
)
|
||||
|
||||
# subscription_value_0
|
||||
self._overrides_to_add[
|
||||
SubscriptionVariables.subscription_value_i(index=0).variable_name
|
||||
] = self.value
|
||||
|
||||
# And the array variable
|
||||
self._overrides_to_add[SubscriptionVariables.subscription_array().variable_name] = (
|
||||
ScriptUtils.to_script([self.value])
|
||||
)
|
||||
|
||||
|
||||
class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValidator):
|
||||
def __init__(
|
||||
|
|
@ -167,6 +178,7 @@ class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValid
|
|||
indent_overrides=indent_overrides,
|
||||
)
|
||||
|
||||
# Add indexed variables
|
||||
for idx, list_value in enumerate(self.list):
|
||||
# Write the first list value into subscription_value as well
|
||||
if idx == 0:
|
||||
|
|
@ -178,6 +190,11 @@ class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValid
|
|||
SubscriptionVariables.subscription_value_i(index=idx).variable_name
|
||||
] = list_value.value
|
||||
|
||||
# And the array variable
|
||||
self._overrides_to_add[SubscriptionVariables.subscription_array().variable_name] = (
|
||||
ScriptUtils.to_script([list_value.value for list_value in self.list])
|
||||
)
|
||||
|
||||
|
||||
class SubscriptionWithOverridesValidator(SubscriptionLeafValidator, DictFormatterValidator):
|
||||
def __init__(
|
||||
|
|
@ -220,7 +237,7 @@ class SubscriptionMapValidator(SubscriptionLeafValidator, LiteralDictValidator):
|
|||
indent_overrides=indent_overrides,
|
||||
)
|
||||
self._overrides_to_add[SubscriptionVariables.subscription_map().variable_name] = (
|
||||
ScriptUtils.to_script(self.dict)
|
||||
ScriptUtils.to_script(self.dict, sort_keys=False)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class ScriptUtils:
|
|||
return dict(variables, **sanitized_variables)
|
||||
|
||||
@classmethod
|
||||
def to_script(cls, value: Any) -> str:
|
||||
def to_script(cls, value: Any, sort_keys: bool = True) -> str:
|
||||
"""
|
||||
Converts a python value to a script value
|
||||
"""
|
||||
|
|
@ -50,7 +50,7 @@ class ScriptUtils:
|
|||
elif isinstance(value, float):
|
||||
out = f"{{%float({value})}}"
|
||||
else:
|
||||
dumped_json = json.dumps(value, ensure_ascii=False, sort_keys=True)
|
||||
dumped_json = json.dumps(value, ensure_ascii=False, sort_keys=sort_keys)
|
||||
# Remove triple-single-quotes from JSON to avoid parsing issues
|
||||
dumped_json = re.sub("'{3,}", "'", dumped_json)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
".ytdl-sub-subscription_test-download-archive.json": "b98a30417f259daeec888e1a5047b9ed",
|
||||
"subscription_test/Mock Entry 20-1.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-1.mp4": "34916dc26e723c3464adcc4687898ca8",
|
||||
"subscription_test/Mock Entry 20-1.nfo": "68a6a9e51a12e75d4c68e6e644b409d1",
|
||||
"subscription_test/Mock Entry 20-2.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-2.mp4": "01a910b7a023325aa9d4ad3a013a1e02",
|
||||
"subscription_test/Mock Entry 20-2.nfo": "1cbe51945c1a7a9ced0eb1222e9d2405",
|
||||
"subscription_test/Mock Entry 20-3.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-3.mp4": "812b6db9ff08bf1822e99e43d371400d",
|
||||
"subscription_test/Mock Entry 20-3.nfo": "ef07f30d3e882de3f7cb3ad675125352",
|
||||
"subscription_test/Mock Entry 21-1.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 21-1.mp4": "079832b6e49b283d80be402c9c928b90",
|
||||
"subscription_test/Mock Entry 21-1.nfo": "dc714fd9f3c3729f74927ad245b50d9d"
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
".ytdl-sub-subscription_test-download-archive.json": "bcb2e8e8139f5bf589e027f841aa9449",
|
||||
"subscription_test/Custom Title.info.json": "INFO_JSON",
|
||||
"subscription_test/Custom Title.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Custom Title.mp4": "d7c2b8e961a8fcb612bd0d69c96bf0f3",
|
||||
"subscription_test/Custom Title.nfo": "996f3993b2ba8a0614bef294492dde65",
|
||||
"subscription_test/Mock Entry 20-4.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-4.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-4.mp4": "10f239edf916f8fb9eb461f24a821578",
|
||||
"subscription_test/Mock Entry 20-4.nfo": "1e7cb1a09c15f155623f6cd796e874ff",
|
||||
"subscription_test/Mock Entry 20-5.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-5.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-5.mp4": "046878a073fb269ec61401cdeb834707",
|
||||
"subscription_test/Mock Entry 20-5.nfo": "f6100f194ae3c3b24211ff515d97ccdf",
|
||||
"subscription_test/Mock Entry 20-6.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-6.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-6.mp4": "a50ead5d08456f0bcb907f1912caefcf",
|
||||
"subscription_test/Mock Entry 20-6.nfo": "f51ae05104f5b98531535e75d623f941",
|
||||
"subscription_test/Mock Entry 20-7.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-7.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-7.mp4": "5b35f04254c38c33ba056274b6c3af9f",
|
||||
"subscription_test/Mock Entry 20-7.nfo": "852c02ea3ab196d808854ee94a9313d2"
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
".ytdl-sub-subscription_test-download-archive.json": "b98a30417f259daeec888e1a5047b9ed",
|
||||
"subscription_test/Mock Entry 20-1.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-1.mp4": "34916dc26e723c3464adcc4687898ca8",
|
||||
"subscription_test/Mock Entry 20-1.nfo": "68a6a9e51a12e75d4c68e6e644b409d1",
|
||||
"subscription_test/Mock Entry 20-2.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-2.mp4": "01a910b7a023325aa9d4ad3a013a1e02",
|
||||
"subscription_test/Mock Entry 20-2.nfo": "1cbe51945c1a7a9ced0eb1222e9d2405",
|
||||
"subscription_test/Mock Entry 20-3.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-3.mp4": "812b6db9ff08bf1822e99e43d371400d",
|
||||
"subscription_test/Mock Entry 20-3.nfo": "ef07f30d3e882de3f7cb3ad675125352",
|
||||
"subscription_test/Mock Entry 21-1.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 21-1.mp4": "079832b6e49b283d80be402c9c928b90",
|
||||
"subscription_test/Mock Entry 21-1.nfo": "dc714fd9f3c3729f74927ad245b50d9d"
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
".ytdl-sub-subscription_test-download-archive.json": "bcb2e8e8139f5bf589e027f841aa9449",
|
||||
"subscription_test/Custom Title.info.json": "INFO_JSON",
|
||||
"subscription_test/Custom Title.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Custom Title.mp4": "d7c2b8e961a8fcb612bd0d69c96bf0f3",
|
||||
"subscription_test/Custom Title.nfo": "996f3993b2ba8a0614bef294492dde65",
|
||||
"subscription_test/Mock Entry 20-4.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-4.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-4.mp4": "10f239edf916f8fb9eb461f24a821578",
|
||||
"subscription_test/Mock Entry 20-4.nfo": "1e7cb1a09c15f155623f6cd796e874ff",
|
||||
"subscription_test/Mock Entry 20-5.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-5.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-5.mp4": "046878a073fb269ec61401cdeb834707",
|
||||
"subscription_test/Mock Entry 20-5.nfo": "f6100f194ae3c3b24211ff515d97ccdf",
|
||||
"subscription_test/Mock Entry 20-6.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-6.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-6.mp4": "a50ead5d08456f0bcb907f1912caefcf",
|
||||
"subscription_test/Mock Entry 20-6.nfo": "f51ae05104f5b98531535e75d623f941",
|
||||
"subscription_test/Mock Entry 20-7.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-7.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-7.mp4": "5b35f04254c38c33ba056274b6c3af9f",
|
||||
"subscription_test/Mock Entry 20-7.nfo": "852c02ea3ab196d808854ee94a9313d2"
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
".ytdl-sub-subscription_test-download-archive.json": "6cb47203ec56d8318a0d428b5b4efa5d",
|
||||
"subscription_test/Mock Entry 20-1.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-1.mp4": "34916dc26e723c3464adcc4687898ca8",
|
||||
"subscription_test/Mock Entry 20-2.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-2.mp4": "01a910b7a023325aa9d4ad3a013a1e02",
|
||||
"subscription_test/Mock Entry 20-3.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-3.mp4": "812b6db9ff08bf1822e99e43d371400d",
|
||||
"subscription_test/Mock Entry 21-1.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 21-1.mp4": "079832b6e49b283d80be402c9c928b90"
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
".ytdl-sub-subscription_test-download-archive.json": "69a9960ce69e3813269412fa7cb1bd33",
|
||||
"subscription_test/Custom Title.info.json": "INFO_JSON",
|
||||
"subscription_test/Custom Title.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Custom Title.mp4": "d7c2b8e961a8fcb612bd0d69c96bf0f3",
|
||||
"subscription_test/Mock Entry 20-4.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-4.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-4.mp4": "10f239edf916f8fb9eb461f24a821578",
|
||||
"subscription_test/Mock Entry 20-5.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-5.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-5.mp4": "046878a073fb269ec61401cdeb834707",
|
||||
"subscription_test/Mock Entry 20-6.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-6.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-6.mp4": "a50ead5d08456f0bcb907f1912caefcf",
|
||||
"subscription_test/Mock Entry 20-7.info.json": "INFO_JSON",
|
||||
"subscription_test/Mock Entry 20-7.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||
"subscription_test/Mock Entry 20-7.mp4": "5b35f04254c38c33ba056274b6c3af9f"
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Mock Entry 20-1.info.json
|
||||
Mock Entry 20-1.jpg
|
||||
Mock Entry 20-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-1
|
||||
year: 2020
|
||||
Mock Entry 20-1.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-1
|
||||
Mock Entry 20-2.info.json
|
||||
Mock Entry 20-2.jpg
|
||||
Mock Entry 20-2.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-2
|
||||
year: 2020
|
||||
Mock Entry 20-2.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-2
|
||||
Mock Entry 20-3.info.json
|
||||
Mock Entry 20-3.jpg
|
||||
Mock Entry 20-3.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-07
|
||||
title: Mock Entry 20-3
|
||||
year: 2020
|
||||
Mock Entry 20-3.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-07
|
||||
title: Mock Entry 20-3
|
||||
Mock Entry 21-1.info.json
|
||||
Mock Entry 21-1.jpg
|
||||
Mock Entry 21-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
year: 2021
|
||||
Mock Entry 21-1.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Custom Title.info.json
|
||||
Custom Title.jpg
|
||||
Custom Title.mp4
|
||||
Video Tags:
|
||||
album: Concerts
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Custom Title
|
||||
year: 2021
|
||||
Custom Title.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Concerts
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Custom Title
|
||||
Mock Entry 20-4.info.json
|
||||
Mock Entry 20-4.jpg
|
||||
Mock Entry 20-4.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-06
|
||||
title: Mock Entry 20-4
|
||||
year: 2020
|
||||
Mock Entry 20-4.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-06
|
||||
title: Mock Entry 20-4
|
||||
Mock Entry 20-5.info.json
|
||||
Mock Entry 20-5.jpg
|
||||
Mock Entry 20-5.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-5
|
||||
year: 2020
|
||||
Mock Entry 20-5.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-5
|
||||
Mock Entry 20-6.info.json
|
||||
Mock Entry 20-6.jpg
|
||||
Mock Entry 20-6.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-6
|
||||
year: 2020
|
||||
Mock Entry 20-6.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-6
|
||||
Mock Entry 20-7.info.json
|
||||
Mock Entry 20-7.jpg
|
||||
Mock Entry 20-7.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-06-06
|
||||
title: Mock Entry 20-7
|
||||
year: 2020
|
||||
Mock Entry 20-7.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-06-06
|
||||
title: Mock Entry 20-7
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Mock Entry 20-1.info.json
|
||||
Mock Entry 20-1.jpg
|
||||
Mock Entry 20-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-1
|
||||
year: 2020
|
||||
Mock Entry 20-1.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-1
|
||||
Mock Entry 20-2.info.json
|
||||
Mock Entry 20-2.jpg
|
||||
Mock Entry 20-2.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-2
|
||||
year: 2020
|
||||
Mock Entry 20-2.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-2
|
||||
Mock Entry 20-3.info.json
|
||||
Mock Entry 20-3.jpg
|
||||
Mock Entry 20-3.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-07
|
||||
title: Mock Entry 20-3
|
||||
year: 2020
|
||||
Mock Entry 20-3.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-07
|
||||
title: Mock Entry 20-3
|
||||
Mock Entry 21-1.info.json
|
||||
Mock Entry 21-1.jpg
|
||||
Mock Entry 21-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
year: 2021
|
||||
Mock Entry 21-1.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Custom Title.info.json
|
||||
Custom Title.jpg
|
||||
Custom Title.mp4
|
||||
Video Tags:
|
||||
album: Concerts
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Custom Title
|
||||
year: 2021
|
||||
Custom Title.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Concerts
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Custom Title
|
||||
Mock Entry 20-4.info.json
|
||||
Mock Entry 20-4.jpg
|
||||
Mock Entry 20-4.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-06
|
||||
title: Mock Entry 20-4
|
||||
year: 2020
|
||||
Mock Entry 20-4.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-06
|
||||
title: Mock Entry 20-4
|
||||
Mock Entry 20-5.info.json
|
||||
Mock Entry 20-5.jpg
|
||||
Mock Entry 20-5.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-5
|
||||
year: 2020
|
||||
Mock Entry 20-5.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-5
|
||||
Mock Entry 20-6.info.json
|
||||
Mock Entry 20-6.jpg
|
||||
Mock Entry 20-6.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-6
|
||||
year: 2020
|
||||
Mock Entry 20-6.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-6
|
||||
Mock Entry 20-7.info.json
|
||||
Mock Entry 20-7.jpg
|
||||
Mock Entry 20-7.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-06-06
|
||||
title: Mock Entry 20-7
|
||||
year: 2020
|
||||
Mock Entry 20-7.nfo
|
||||
NFO tags:
|
||||
musicvideo:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-06-06
|
||||
title: Mock Entry 20-7
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Mock Entry 20-1.info.json
|
||||
Mock Entry 20-1.jpg
|
||||
Mock Entry 20-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-1
|
||||
year: 2020
|
||||
Mock Entry 20-2.info.json
|
||||
Mock Entry 20-2.jpg
|
||||
Mock Entry 20-2.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-08
|
||||
title: Mock Entry 20-2
|
||||
year: 2020
|
||||
Mock Entry 20-3.info.json
|
||||
Mock Entry 20-3.jpg
|
||||
Mock Entry 20-3.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-07
|
||||
title: Mock Entry 20-3
|
||||
year: 2020
|
||||
Mock Entry 21-1.info.json
|
||||
Mock Entry 21-1.jpg
|
||||
Mock Entry 21-1.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Mock Entry 21-1
|
||||
year: 2021
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-subscription_test-download-archive.json
|
||||
{output_directory}/subscription_test
|
||||
Custom Title.info.json
|
||||
Custom Title.jpg
|
||||
Custom Title.mp4
|
||||
Video Tags:
|
||||
album: Concerts
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2021-08-08
|
||||
title: Custom Title
|
||||
year: 2021
|
||||
Mock Entry 20-4.info.json
|
||||
Mock Entry 20-4.jpg
|
||||
Mock Entry 20-4.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-08-06
|
||||
title: Mock Entry 20-4
|
||||
year: 2020
|
||||
Mock Entry 20-5.info.json
|
||||
Mock Entry 20-5.jpg
|
||||
Mock Entry 20-5.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-5
|
||||
year: 2020
|
||||
Mock Entry 20-6.info.json
|
||||
Mock Entry 20-6.jpg
|
||||
Mock Entry 20-6.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-07-06
|
||||
title: Mock Entry 20-6
|
||||
year: 2020
|
||||
Mock Entry 20-7.info.json
|
||||
Mock Entry 20-7.jpg
|
||||
Mock Entry 20-7.mp4
|
||||
Video Tags:
|
||||
album: Music Videos
|
||||
artist: subscription_test
|
||||
genre: ytdl-sub
|
||||
premiered: 2020-06-06
|
||||
title: Mock Entry 20-7
|
||||
year: 2020
|
||||
|
|
@ -34,7 +34,7 @@ def test_subscription_logs_write_to_file(
|
|||
keep_successful_logs: bool,
|
||||
match: List[str],
|
||||
):
|
||||
subscription_names = ["Rick Astley", "Michael Jackson", "Eric Clapton"]
|
||||
subscription_names = ["Rick Astley", "Michael Jackson", "Eric Clapton", "Guns N' Roses"]
|
||||
if match:
|
||||
subscription_names = ["Rick Astley", "Michael Jackson"]
|
||||
num_runs = 2
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import json
|
||||
import re
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
|
@ -470,6 +471,15 @@ def test_advanced_tv_show_subscriptions(
|
|||
== "https://www.youtube.com/playlist?list=PLi8V8UemxeG6lo5if5H5g5EbsteELcb0_"
|
||||
)
|
||||
|
||||
assert overrides.apply_formatter(overrides.dict["subscription_array"]) == json.dumps(
|
||||
[
|
||||
"https://www.youtube.com/@gardeningwithciscoe4430",
|
||||
"https://www.youtube.com/playlist?list=PLi8V8UemxeG6lo5if5H5g5EbsteELcb0_",
|
||||
"https://www.youtube.com/playlist?list=PLsJlQSR-KjmaQqqJ9jq18cF6XXXAR4kyn",
|
||||
"https://www.youtube.com/watch?v=2vq-vPubS5I",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_music_subscriptions(default_config: ConfigFile, music_subscriptions_path: Path):
|
||||
subs = Subscription.from_file_path(
|
||||
|
|
@ -493,16 +503,31 @@ def test_music_video_subscriptions(default_config: ConfigFile, music_video_subsc
|
|||
config=default_config, subscription_path=music_video_subscription_path
|
||||
)
|
||||
|
||||
assert len(subs) == 3
|
||||
assert len(subs) == 4
|
||||
assert subs[1].name == "Michael Jackson"
|
||||
monk = subs[1].overrides.script
|
||||
jackson = subs[1].overrides.script
|
||||
|
||||
assert monk.get("subscription_name").native == "Michael Jackson"
|
||||
assert jackson.get("subscription_name").native == "Michael Jackson"
|
||||
assert (
|
||||
monk.get("subscription_value").native
|
||||
jackson.get("subscription_value").native
|
||||
== "https://www.youtube.com/playlist?list=OLAK5uy_mnY03zP6abNWH929q2XhGzWD_2uKJ_n8E"
|
||||
)
|
||||
assert monk.get("subscription_indent_1").native == "Pop"
|
||||
assert jackson.get("subscription_indent_1").native == "Pop"
|
||||
assert (
|
||||
jackson.get("url").native
|
||||
== "https://www.youtube.com/playlist?list=OLAK5uy_mnY03zP6abNWH929q2XhGzWD_2uKJ_n8E"
|
||||
)
|
||||
|
||||
assert subs[3].name == "Guns N' Roses"
|
||||
gnr = subs[3].overrides.script
|
||||
|
||||
assert gnr.get("subscription_name").native == "Guns N' Roses"
|
||||
assert (
|
||||
gnr.get("url").native
|
||||
== "https://www.youtube.com/playlist?list=PLOTK54q5K4INNXaHKtmXYr6J7CajWjqeJ"
|
||||
)
|
||||
assert gnr.get("subscription_indent_1").native == "Rock"
|
||||
assert gnr.get("url2").native == "https://www.youtube.com/watch?v=OldpIhHPsbs"
|
||||
|
||||
|
||||
def test_default_docker_config_and_subscriptions():
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import copy
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
|
@ -9,6 +10,7 @@ from expected_download import assert_expected_downloads
|
|||
from expected_transaction_log import assert_transaction_log_matches
|
||||
|
||||
from ytdl_sub.prebuilt_presets.music import MusicPresets
|
||||
from ytdl_sub.prebuilt_presets.music_videos import MusicVideoExtrasPresets
|
||||
from ytdl_sub.prebuilt_presets.music_videos import MusicVideoPresets
|
||||
from ytdl_sub.prebuilt_presets.tv_show import TvShowByDateEpisodeFormattingPresets
|
||||
from ytdl_sub.prebuilt_presets.tv_show import TvShowByDateOldPresets
|
||||
|
|
@ -16,6 +18,7 @@ from ytdl_sub.prebuilt_presets.tv_show import TvShowCollectionEpisodeFormattingP
|
|||
from ytdl_sub.prebuilt_presets.tv_show import TvShowCollectionPresets
|
||||
from ytdl_sub.prebuilt_presets.tv_show import TvShowCollectionSeasonPresets
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
from ytdl_sub.utils.exceptions import RegexNoMatchException
|
||||
from ytdl_sub.utils.exceptions import ValidationException
|
||||
|
||||
|
||||
|
|
@ -530,3 +533,91 @@ class TestPrebuiltMusicVideoPresets:
|
|||
dry_run=False,
|
||||
expected_download_summary_file_name=f"{expected_summary_name}.json",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("music_video_preset", MusicVideoPresets.preset_names)
|
||||
@pytest.mark.parametrize("multi_url", [True, False])
|
||||
class TestPrebuiltMusicVideoPresetsWithCategories:
|
||||
|
||||
def _preset_dict(
|
||||
self,
|
||||
output_directory: Path,
|
||||
music_video_preset: str,
|
||||
multi_url: bool,
|
||||
) -> Dict:
|
||||
subscription_dict = {"Music Videos": ["https://your.name.here"]}
|
||||
|
||||
if multi_url:
|
||||
subscription_dict["Concerts"] = [
|
||||
{"url": "https://your.name.here2", "title": "Custom Title"}
|
||||
]
|
||||
|
||||
preset_dict = {
|
||||
"preset": [
|
||||
music_video_preset,
|
||||
],
|
||||
"overrides": {
|
||||
"music_video_directory": output_directory,
|
||||
"subscription_map": subscription_dict,
|
||||
},
|
||||
}
|
||||
|
||||
return preset_dict
|
||||
|
||||
def test_compilation(
|
||||
self,
|
||||
config,
|
||||
output_directory: Path,
|
||||
music_video_preset: str,
|
||||
multi_url: bool,
|
||||
):
|
||||
preset_dict = self._preset_dict(
|
||||
output_directory=output_directory,
|
||||
music_video_preset=music_video_preset,
|
||||
multi_url=multi_url,
|
||||
)
|
||||
|
||||
_ = Subscription.from_dict(
|
||||
config=config, preset_name="preset_test", preset_dict=preset_dict
|
||||
)
|
||||
|
||||
def test_presets_run(
|
||||
self,
|
||||
config,
|
||||
subscription_name,
|
||||
output_directory,
|
||||
mock_download_collection_entries,
|
||||
music_video_preset: str,
|
||||
multi_url: bool,
|
||||
):
|
||||
expected_summary_name = (
|
||||
f"unit/music_videos/{music_video_preset} Categorized/multi_url_{multi_url}"
|
||||
)
|
||||
|
||||
preset_dict = self._preset_dict(
|
||||
output_directory=output_directory,
|
||||
music_video_preset=music_video_preset,
|
||||
multi_url=multi_url,
|
||||
)
|
||||
|
||||
subscription = Subscription.from_dict(
|
||||
config=config,
|
||||
preset_name=subscription_name,
|
||||
preset_dict=preset_dict,
|
||||
)
|
||||
|
||||
with mock_download_collection_entries(
|
||||
is_youtube_channel=False, num_urls=2 if multi_url else 1, is_extracted_audio=False
|
||||
):
|
||||
transaction_log = subscription.download(dry_run=False)
|
||||
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name=f"{expected_summary_name}.txt",
|
||||
)
|
||||
assert_expected_downloads(
|
||||
output_directory=output_directory,
|
||||
dry_run=False,
|
||||
expected_download_summary_file_name=f"{expected_summary_name}.json",
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue