[BACKEND] Bandcamp e2e test, update music example (#393)
* [BUGFIX] Fix missing contains function when checking entries * remove children func * [BACKEND] Bandcamp e2e test, update music example * WIP * combine soundcloud and all music into music_audio config * sc fixtures * updated tests and examples * bandcamp e2e test * regen off * remove url validators * use bandcamp artist url for more parent coverage * lint
This commit is contained in:
parent
c828ca5978
commit
e5b5c5e638
30 changed files with 852 additions and 636 deletions
35
.github/workflows/ci.yaml
vendored
35
.github/workflows/ci.yaml
vendored
|
|
@ -102,11 +102,33 @@ jobs:
|
|||
source /opt/env/bin/activate
|
||||
coverage run -m pytest tests/e2e/soundcloud && coverage xml -o /opt/coverage/soundcloud/coverage.xml
|
||||
|
||||
test-bandcamp:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: test-build
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Restore Python build cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /opt/env
|
||||
key: ${{github.sha}}-env
|
||||
|
||||
- name: Run e2e soundcloud tests with coverage
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ffmpeg
|
||||
source /opt/env/bin/activate
|
||||
coverage run -m pytest tests/e2e/bandcamp && coverage xml -o /opt/coverage/bandcamp/coverage.xml
|
||||
|
||||
- name: Save coverage
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /opt/coverage/soundcloud
|
||||
key: ${{github.sha}}-coverage-soundcloud
|
||||
path: /opt/coverage/bandcamp
|
||||
key: ${{github.sha}}-coverage-bandcamp
|
||||
|
||||
test-youtube:
|
||||
runs-on: ubuntu-22.04
|
||||
|
|
@ -169,6 +191,7 @@ jobs:
|
|||
needs: [
|
||||
test-unit,
|
||||
test-soundcloud,
|
||||
test-bandcamp,
|
||||
test-youtube,
|
||||
test-plugins
|
||||
]
|
||||
|
|
@ -188,6 +211,12 @@ jobs:
|
|||
path: /opt/coverage/soundcloud
|
||||
key: ${{github.sha}}-coverage-soundcloud
|
||||
|
||||
- name: Restore bandcamp test coverage
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /opt/coverage/bandcamp
|
||||
key: ${{github.sha}}-coverage-bandcamp
|
||||
|
||||
- name: Restore youtube test coverage
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
@ -204,4 +233,4 @@ jobs:
|
|||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: /opt/coverage/unit/coverage.xml,/opt/coverage/soundcloud/coverage.xml,/opt/coverage/youtube/coverage.xml,/opt/coverage/plugins/coverage.xml
|
||||
files: /opt/coverage/unit/coverage.xml,/opt/coverage/soundcloud/coverage.xml,/opt/coverage/bandcamp/coverage.xml,/opt/coverage/youtube/coverage.xml,/opt/coverage/plugins/coverage.xml
|
||||
195
examples/music_audio_config.yaml
Normal file
195
examples/music_audio_config.yaml
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# This config builds presets to download and format the following use-cases:
|
||||
# - YouTube
|
||||
# - Songs
|
||||
# - From a single video
|
||||
# - Albums
|
||||
# - From a video, where each song is represented by chapters
|
||||
# - From a playlist where each video is a song on the album
|
||||
# - Discographies
|
||||
# - From a channel or a channel's set of playlists
|
||||
# - Bandcamp
|
||||
# - Track, Album, Artist URL as a Discography
|
||||
# - Soundcloud
|
||||
# - Track, Album, Artist URL as a Discography
|
||||
#
|
||||
# All files will look like:
|
||||
#
|
||||
# music_directory/
|
||||
# Artist/
|
||||
# [2022] Some Single/
|
||||
# 01 - Some Single.mp3
|
||||
# folder.jpg
|
||||
# [2023] Latest Album/
|
||||
# 01 - Track Title.mp3
|
||||
# 02 - Another Track.mp3
|
||||
# folder.jpg
|
||||
#
|
||||
# The idea is to format files under music_directory as `Artist/Album/Song`. Singles that do not
|
||||
# belong to an album will be represented like albums with a single track.
|
||||
#
|
||||
# Each file will be properly tagged regardless of file extension (suppers flac, ogg, mp3, etc)
|
||||
# and should show up nicely in music players that take advantage of tags.
|
||||
configuration:
|
||||
working_directory: '.ytdl-sub-downloads'
|
||||
umask: "002"
|
||||
|
||||
presets:
|
||||
|
||||
# The `base` preset that represents how all files will be structured after downloading.
|
||||
# Every other preset afterwards will inherit this preset.
|
||||
base:
|
||||
# Store all music under our music_directory (to be set as an override variable).
|
||||
# Store each resulting file with its full track path, and treat thumbnails as the album covers.
|
||||
#
|
||||
# Maintain a download archive. This will produce a hidden file in your music directory
|
||||
# containing an archive of all audio previously downloaded. This makes it so we do not
|
||||
# re-download files we already have.
|
||||
output_options:
|
||||
output_directory: "{music_directory}"
|
||||
file_name: "{track_full_path}"
|
||||
thumbnail_name: "{album_cover_path}"
|
||||
maintain_download_archive: True
|
||||
|
||||
# Set break_on_existing to True. This will stop fetching any more metadata once we
|
||||
# hit a video/audio that we already have downloaded.
|
||||
ytdl_options:
|
||||
break_on_existing: True
|
||||
|
||||
# Extract any audio from files using this codec and quality.
|
||||
audio_extract:
|
||||
codec: "mp3"
|
||||
quality: 320
|
||||
|
||||
# Set these music tags on every resulting audio file.
|
||||
# It is recommended to keep most of this as-is, and use override
|
||||
# variables to set them to be what you want.
|
||||
music_tags:
|
||||
tags:
|
||||
artist: "{track_artist}"
|
||||
artists: "{track_artist}"
|
||||
albumartist: "{track_artist}"
|
||||
albumartists: "{track_artist}"
|
||||
title: "{track_title}"
|
||||
album: "{track_album}"
|
||||
track: "{track_number}"
|
||||
tracktotal: "{track_total}"
|
||||
year: "{track_year}"
|
||||
genre: "{track_genre}"
|
||||
|
||||
# For every configurable field, make it an override variable,
|
||||
# so we can carefully tune different use-cases by only modifying override variables.
|
||||
overrides:
|
||||
# Track Overrides. By default, set overrides to make each song its own album
|
||||
track_title: "{title}"
|
||||
track_album: "{title}"
|
||||
track_artist: "{channel}"
|
||||
track_number: "1"
|
||||
track_number_padded: "01"
|
||||
track_total: "1"
|
||||
track_year: "{upload_year}"
|
||||
track_genre: "Unset"
|
||||
# Filename Overrides
|
||||
track_file_name: "{track_number_padded} - {track_title_sanitized}.{ext}"
|
||||
album_file_name: "folder.{thumbnail_ext}"
|
||||
# Directory Name Overrides
|
||||
music_directory: "OVERRIDE THIS WITH YOUR MUSIC DIRECTORY"
|
||||
artist_dir: "{track_artist_sanitized}"
|
||||
album_dir: "[{track_year}] {track_album_sanitized}"
|
||||
# Full Filepath Overrides
|
||||
track_full_path: "{artist_dir}/{album_dir}/{track_file_name}"
|
||||
album_cover_path: "{artist_dir}/{album_dir}/{album_file_name}"
|
||||
|
||||
####################################################################################################
|
||||
|
||||
# Make the 'single` preset accept a single URL using the override variable 'url'
|
||||
# Each audio file will reside in its own album.
|
||||
single:
|
||||
# Inherit from `base`
|
||||
preset: "base"
|
||||
|
||||
download:
|
||||
download_strategy: "url"
|
||||
url: "{url}"
|
||||
|
||||
####################################################################################################
|
||||
|
||||
# Make the 'albums_from_playlists' preset format audio files to reside under albums, where
|
||||
# each album is a playlist. If a file downloaded using this preset is not part of a playlist,
|
||||
# it will default to how it'd look as a `single`.
|
||||
albums_from_playlists:
|
||||
# Inherit from single
|
||||
preset: "single"
|
||||
|
||||
# Override various track properties using playlist variables.
|
||||
overrides:
|
||||
track_album: "{playlist_title}"
|
||||
track_number: "{playlist_index}"
|
||||
track_number_padded: "{playlist_index_padded}"
|
||||
track_total: "{playlist_count}"
|
||||
track_year: "{playlist_max_upload_year}"
|
||||
|
||||
####################################################################################################
|
||||
|
||||
# Make the 'albums_from_chapters' preset format audio files to reside under an album, where the
|
||||
# video itself is an album containing all the songs in it represented by chapters.
|
||||
albums_from_chapters:
|
||||
# Inherit from single
|
||||
preset: "single"
|
||||
|
||||
# Embed chapters if present. If no chapters are present, allow parsing comments that contain
|
||||
# timestamps to each song, and use those as chapters.
|
||||
chapters:
|
||||
embed_chapters: True
|
||||
allow_chapters_from_comments: True
|
||||
|
||||
# Split each file by its chapters. If a file does not have chapters, simply 'pass' on it and
|
||||
# process the next audio/video file.
|
||||
split_by_chapters:
|
||||
when_no_chapters: "pass"
|
||||
|
||||
# Override various track properties using chapter variables.
|
||||
overrides:
|
||||
track_title: "{chapter_title}" # Chapter title is the track title
|
||||
track_album: "{title}" # Video's title is the album title
|
||||
track_number: "{chapter_index}"
|
||||
track_number_padded: "{chapter_index_padded}"
|
||||
track_total: "{chapter_count}"
|
||||
|
||||
####################################################################################################
|
||||
|
||||
# Make the 'soundcloud_discography' preset specially made for ripping SoundCloud artists.
|
||||
# We will use the 'multi_url' approach to download both albums and non-album tracks
|
||||
soundcloud_discography:
|
||||
preset: "base"
|
||||
|
||||
# Download using the multi_url strategy
|
||||
download:
|
||||
download_strategy: "multi_url"
|
||||
urls:
|
||||
# The first URL will be all the artist's tracks.
|
||||
# Treat these as singles - an album with a single track
|
||||
- url: "{sc_artist_url}/tracks"
|
||||
variables:
|
||||
sc_track_album: "{title}"
|
||||
sc_track_number: "1"
|
||||
sc_track_number_padded: "01"
|
||||
sc_track_total: "1"
|
||||
sc_track_year: "{upload_year}"
|
||||
# Set the second URL to the artist's albums. If a track belongs to both
|
||||
# to an album and tracks (in the URL above), it will resolve to this
|
||||
# URL and include the album metadata we set below.
|
||||
- url: "{sc_artist_url}/albums"
|
||||
variables:
|
||||
sc_track_album: "{playlist_title}"
|
||||
sc_track_number: "{playlist_index}"
|
||||
sc_track_number_padded: "{playlist_index_padded}"
|
||||
sc_track_total: "{playlist_count}"
|
||||
sc_track_year: "{playlist_max_upload_year}"
|
||||
|
||||
# Override various track properties using playlist variables.
|
||||
overrides:
|
||||
track_album: "{sc_track_album}"
|
||||
track_number: "{sc_track_number}"
|
||||
track_number_padded: "{sc_track_number_padded}"
|
||||
track_total: "{sc_track_total}"
|
||||
track_year: "{sc_track_year}"
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
# Extracts audio from YouTube videos, converts it to mp3, and adds audio tags to it.
|
||||
configuration:
|
||||
working_directory: '.ytdl-sub-downloads'
|
||||
|
||||
presets:
|
||||
song:
|
||||
download:
|
||||
download_strategy: "url"
|
||||
url: "{url}"
|
||||
|
||||
output_options:
|
||||
output_directory: "{music_directory}"
|
||||
file_name: "{custom_track_name_sanitized}.{ext}"
|
||||
|
||||
audio_extract:
|
||||
codec: "mp3"
|
||||
quality: 128
|
||||
|
||||
music_tags:
|
||||
embed_thumbnail: False # Set to True to embed album art
|
||||
tags:
|
||||
artist: "{custom_artist_name}"
|
||||
artists: "{custom_artist_name}"
|
||||
albumartist: "{custom_artist_name}"
|
||||
albumartists: "{custom_artist_name}"
|
||||
title: "{custom_track_name}"
|
||||
album: "{custom_album_name}"
|
||||
track: "{custom_track_number}"
|
||||
year: "{upload_year}"
|
||||
genre: "Unset"
|
||||
|
||||
overrides:
|
||||
music_directory: "/path/to/music"
|
||||
custom_track_name: "{title}"
|
||||
custom_album_name: "Singles"
|
||||
custom_artist_name: "{channel}"
|
||||
custom_track_number: "1"
|
||||
|
||||
# TODO: make a playlist of individual songs into an album. Need playlist_title
|
||||
song_playlist:
|
||||
preset: "song"
|
||||
overrides:
|
||||
custom_track_number: "{playlist_index}"
|
||||
|
||||
album_from_chapters:
|
||||
preset: "song"
|
||||
output_options:
|
||||
file_name: "{custom_album_name_sanitized}/{chapter_index_padded} - {custom_track_name_sanitized}.{ext}"
|
||||
thumbnail_name: "{custom_album_name_sanitized}/folder.{thumbnail_ext}"
|
||||
|
||||
chapters:
|
||||
embed_chapters: True
|
||||
|
||||
split_by_chapters:
|
||||
when_no_chapters: "pass"
|
||||
|
||||
overrides:
|
||||
custom_track_name: "{chapter_title}"
|
||||
custom_album_name: "{title}" # Have the video name be the album
|
||||
custom_track_number: "{chapter_index}"
|
||||
138
examples/music_audio_subscriptions.yaml
Normal file
138
examples/music_audio_subscriptions.yaml
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# Define any number of subscriptions in a single file, or use multiple
|
||||
# files to organize (i.e by use-case, website, genre, etc)
|
||||
#
|
||||
# Each example show-cases every use case:
|
||||
# - YouTube
|
||||
# - Songs
|
||||
# - From a single video
|
||||
# - Albums
|
||||
# - From a video, where each song is represented by chapters
|
||||
# - From a playlist where each video is a song on the album
|
||||
# - Discographies
|
||||
# - From a channel or a channel's set of playlists
|
||||
# - Bandcamp
|
||||
# - Track, Album, Artist URL as a Discography
|
||||
# - Soundcloud
|
||||
# - Track, Album, Artist URL as a Discography
|
||||
#
|
||||
####################################################################################################
|
||||
# YOUTUBE - PLAYLIST OF ALBUMS
|
||||
# See https://www.youtube.com/playlist?list=PLBsm_SagFMmdWnCnrNtLjA9kzfrRkto4i
|
||||
#
|
||||
# Downloads the GameChops Albums' playlist. Each video in the playlist is an album with
|
||||
# chapters representing songs.
|
||||
game_chops:
|
||||
preset: "albums_from_chapters"
|
||||
|
||||
# Perform regex to extract title from the chapter's title to not include the track number.
|
||||
# Configuring this hard is a bit overkill, but I'm a perfectionist :-)
|
||||
regex:
|
||||
from:
|
||||
chapter_title:
|
||||
match:
|
||||
- "^\\d+\\.\\.(.*)" # Captures 'title' from '1..title'
|
||||
capture_group_names:
|
||||
- "captured_track_title"
|
||||
capture_group_defaults:
|
||||
- "{chapter_title}"
|
||||
|
||||
# Explicitly set the URL, track artist, and genre.
|
||||
# Override various track properties using the regex variables we extracted.
|
||||
overrides:
|
||||
url: "https://www.youtube.com/playlist?list=PLBsm_SagFMmdWnCnrNtLjA9kzfrRkto4i"
|
||||
track_artist: "GameChops"
|
||||
track_genre: "Lofi"
|
||||
track_title: "{captured_track_title}"
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# YOUTUBE - MANY ALBUMS FROM MANY ARTISTS UPLOADED BY A CHANNEL
|
||||
# See https://www.youtube.com/@heavymetalofeasternbloc
|
||||
#
|
||||
# Downloads the entire 'Heavy Metal from the Eastern Bloc' channel. Each video they upload
|
||||
# is an album from Eastern Europe with chapters representing songs.
|
||||
eastern_bloc:
|
||||
# Inherit albums from chapters
|
||||
preset: "albums_from_chapters"
|
||||
|
||||
# Perform regex on many fields (title, description, chapter title) to extract as much
|
||||
# metadata as possible
|
||||
regex:
|
||||
skip_if_match_fails: False # Error if regex match fails
|
||||
from:
|
||||
title:
|
||||
match:
|
||||
- "^(.*) - (.*) \\|\\|.*" # Captures artist, album from 'artist - album ||...'
|
||||
- "^(.*) - (.*) \\[.*" # Captures artist, ablum from 'artist - album [...'
|
||||
- "^(.*) - (.*)" # Captures artist, ablum from 'artist - album'
|
||||
capture_group_names:
|
||||
- "captured_track_artist"
|
||||
- "captured_track_album"
|
||||
description:
|
||||
match:
|
||||
- "Genre:\\s*(.*)\\s*\n(?:Rec.+|Year):\\s*.*(\\d{4})\\s*\\n" # Captures genre and recorded year
|
||||
capture_group_names:
|
||||
- "captured_track_genre"
|
||||
- "captured_track_year"
|
||||
chapter_title:
|
||||
match:
|
||||
- "^(?:\\d+\\.\\s*|)(.*)" # Captures title from '1. title'
|
||||
capture_group_names:
|
||||
- "captured_track_title"
|
||||
capture_group_defaults:
|
||||
- "{chapter_title}"
|
||||
|
||||
# Explicitly set the URL.
|
||||
# Override various track properties using the regex variables we extracted.
|
||||
overrides:
|
||||
url: "https://www.youtube.com/@heavymetalofeasternbloc"
|
||||
track_artist: "{captured_track_artist}"
|
||||
track_album: "{captured_track_album}"
|
||||
track_title: "{captured_track_title}"
|
||||
track_year: "{captured_track_year}"
|
||||
track_genre: "Eastern Bloc {captured_track_genre}"
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# BANDCAMP - DISCOGRAPHY
|
||||
# See https://emilyharpist.bandcamp.com/
|
||||
#
|
||||
# Downloads the GameChops Albums' playlist. Each video in the playlist is an album with
|
||||
# chapters representing songs.
|
||||
emily_hopkins:
|
||||
preset: "albums_from_playlists"
|
||||
regex:
|
||||
from:
|
||||
title:
|
||||
match:
|
||||
- "^Emily Hopkins - (.*)" # Captures 'title' from 'Emily Hopkins - title'
|
||||
capture_group_names:
|
||||
- "captured_track_title"
|
||||
capture_group_defaults:
|
||||
- "{title}"
|
||||
|
||||
# Explicitly set the URL, track artist, and genre.
|
||||
# Override various track properties using the regex variables we extracted.
|
||||
overrides:
|
||||
url: "https://emilyharpist.bandcamp.com/"
|
||||
track_artist: "Emily Hopkins"
|
||||
track_genre: "Lofi"
|
||||
track_title: "{captured_track_title}"
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# SOUNDCLOUD - DISCOGRAPHY
|
||||
# See https://soundcloud.com/jessebannon
|
||||
#
|
||||
# Downloads my acoustic 'album' and various tracks from SoundCloud using the soundcloud
|
||||
# discography preset. I'm not very good so keep your expectations low :-)
|
||||
jmbannon:
|
||||
# Inherit soundcloud_discography preset
|
||||
preset: "soundcloud_discography"
|
||||
|
||||
# Explicitly set the SoundCloud artist url, track artist, and genre.
|
||||
overrides:
|
||||
sc_artist_url: "sc_artist_url"
|
||||
track_artist: "jmbannon"
|
||||
track_genre: "Acoustic"
|
||||
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
# This example shows how to download and format a Soundcloud artist's
|
||||
# discography with tags and album art. We will configure this to make
|
||||
# the output directory formatted as:
|
||||
#
|
||||
# /path/to/music
|
||||
# /The Be Sharps
|
||||
# /[2020] My first upload
|
||||
# 01 - My first upload.mp3
|
||||
# folder.jpg
|
||||
# /[2021] My first album
|
||||
# 01 - Track one.mp3
|
||||
# 02 - Track two.mp3
|
||||
# folder.jpg
|
||||
# /Another artist
|
||||
# ...
|
||||
#
|
||||
configuration:
|
||||
working_directory: '.ytdl-sub-downloads'
|
||||
|
||||
presets:
|
||||
soundcloud_discography:
|
||||
# Download using the multi_url strategy
|
||||
download:
|
||||
download_strategy: "multi_url"
|
||||
urls:
|
||||
# The first URL will be all the artist's tracks.
|
||||
# Treat these as singles - an album with a single track
|
||||
- url: "{artist_url}/tracks"
|
||||
variables:
|
||||
track_number: "1"
|
||||
track_number_padded: "01"
|
||||
track_count: "1"
|
||||
album: "{title}"
|
||||
album_sanitized: "{title_sanitized}"
|
||||
album_year: "{upload_year}"
|
||||
# Set the second URL to the artist's albums. If a track belongs both
|
||||
# to an album and tracks (in the URL above), it will resolve to this
|
||||
# URL and include the album metadata we set below.
|
||||
- url: "{artist_url}/albums"
|
||||
variables:
|
||||
track_number: "{playlist_index}"
|
||||
track_number_padded: "{playlist_index_padded}"
|
||||
track_count: "{playlist_count}"
|
||||
album: "{playlist_title}"
|
||||
album_sanitized: "{playlist_title_sanitized}"
|
||||
album_year: "{playlist_max_upload_year}"
|
||||
|
||||
# For advanced YTDL users only; set any YTDL parameter here.
|
||||
# Let us set the format to download the best mp3.
|
||||
ytdl_options:
|
||||
format: 'bestaudio[ext=mp3]'
|
||||
|
||||
# For each song downloaded, set the file and thumbnail name here.
|
||||
# The output directory stores all artists in a shared {music_directory}.
|
||||
# We store the audio file in its respective {album_directory_name} folder
|
||||
# with the track number and title. The (thumbnail) album art is stored
|
||||
# in the album folder.
|
||||
#
|
||||
# Set maintain_download_archive=True. This will tell YTDL not to
|
||||
# re-download them on a successive invocation.
|
||||
output_options:
|
||||
output_directory: "{music_directory}"
|
||||
file_name: "{album_path}/{track_file_name}.{ext}"
|
||||
thumbnail_name: "{album_path}/folder.{thumbnail_ext}"
|
||||
maintain_download_archive: True
|
||||
|
||||
# For each song downloaded, populate the audio file with music tags.
|
||||
# Tagging should work with most audio file formats. See
|
||||
# https://ytdl-sub.readthedocs.io/en/latest/config.html#music-tags
|
||||
# for more details.
|
||||
music_tags:
|
||||
tags:
|
||||
artist: "{artist}"
|
||||
albumartist: "{artist}"
|
||||
title: "{title}"
|
||||
album: "{album}"
|
||||
track: "{track_number}"
|
||||
year: "{album_year}"
|
||||
genre: "Unset"
|
||||
|
||||
# Overrides is a section where we can define our own variables, and use them in
|
||||
# any other section. We define our music directory and album directory names here,
|
||||
# which gets reused above for the audio file name and album art path.
|
||||
overrides:
|
||||
album_directory_name: "[{album_year}] {album_sanitized}"
|
||||
track_file_name: "{track_number_padded} - {title_sanitized}"
|
||||
album_path: "{artist_sanitized}/{album_directory_name}"
|
||||
music_directory: "/path/to/music"
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
from typing import Any
|
||||
from typing import Optional
|
||||
from urllib.parse import parse_qs
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from ytdl_sub.validators.validators import StringValidator
|
||||
|
||||
|
||||
class YoutubeVideoUrlValidator(StringValidator):
|
||||
|
||||
_expected_value_type_name = "Youtube video url"
|
||||
|
||||
@classmethod
|
||||
def _get_video_id(cls, url: str) -> Optional[str]:
|
||||
"""
|
||||
Examples:
|
||||
|
||||
https://youtu.be/SA2iWivDJiE
|
||||
https://www.youtube.com/watch?v=_oPAwA_Udwc&feature=feedu
|
||||
https://www.youtube.com/embed/SA2iWivDJiE
|
||||
https://www.youtube.com/v/SA2iWivDJiE?version=3&hl=en_US
|
||||
https://www.youtube.com/shorts/ucYmEqmlhFw
|
||||
|
||||
Returns
|
||||
-------
|
||||
The video id if it is parsed correctly. None if parsing fails
|
||||
"""
|
||||
# If the url doesn't contain youtube or youtu.be, assume it is invalid
|
||||
if "youtube.com" not in url and "youtu.be" not in url:
|
||||
return None
|
||||
|
||||
# If https:// is not present, urlparse will not work
|
||||
if not url.startswith("https://"):
|
||||
url = f"https://{url}"
|
||||
|
||||
query = urlparse(url)
|
||||
if query.hostname in ("youtu.be", "www.youtu.be"):
|
||||
return query.path[1:]
|
||||
if query.hostname in ("youtube.com", "www.youtube.com"):
|
||||
if query.path == "/watch":
|
||||
parsed_q = parse_qs(query.query)
|
||||
if "v" in parsed_q:
|
||||
return parsed_q["v"][0]
|
||||
if query.path.startswith(("/embed/", "/v/", "/shorts/")):
|
||||
return query.path.split("/")[2]
|
||||
|
||||
return None
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
super().__init__(name, value)
|
||||
|
||||
self._video_id = self._get_video_id(value)
|
||||
if not self._video_id:
|
||||
raise self._validation_exception(f"'{value}' is not a valid Youtube video url.")
|
||||
|
||||
@property
|
||||
def video_url(self) -> str:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
Full video URL
|
||||
"""
|
||||
return f"https://youtube.com/watch?v={self._video_id}"
|
||||
|
||||
|
||||
class YoutubePlaylistUrlValidator(StringValidator):
|
||||
|
||||
_expected_value_type_name = "Youtube playlist url"
|
||||
|
||||
@classmethod
|
||||
def _get_playlist_id(cls, url: str) -> Optional[str]:
|
||||
"""
|
||||
Examples:
|
||||
- https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc
|
||||
"""
|
||||
# If the url doesn't contain youtube, assume it is invalid
|
||||
if "youtube.com" not in url:
|
||||
return None
|
||||
|
||||
# If https:// is not present, urlparse will not work
|
||||
if not url.startswith("https://"):
|
||||
url = f"https://{url}"
|
||||
|
||||
query = urlparse(url)
|
||||
if query.hostname in ("youtube.com", "www.youtube.com"):
|
||||
if query.path == "/playlist":
|
||||
parsed_q = parse_qs(query.query)
|
||||
if "list" in parsed_q:
|
||||
return parsed_q["list"][0]
|
||||
|
||||
return None
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
super().__init__(name, value)
|
||||
|
||||
self._playlist_id = self._get_playlist_id(value)
|
||||
if not self._playlist_id:
|
||||
raise self._validation_exception(f"'{value}' is not a valid Youtube playlist url.")
|
||||
|
||||
@property
|
||||
def playlist_url(self) -> str:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
Full playlist URL
|
||||
"""
|
||||
return f"https://youtube.com/playlist?list={self._playlist_id}"
|
||||
|
||||
|
||||
class YoutubeChannelUrlValidator(StringValidator):
|
||||
|
||||
_expected_value_type_name = "Youtube channel url"
|
||||
|
||||
@classmethod
|
||||
def _get_channel_url(cls, url: str) -> Optional[str]:
|
||||
"""
|
||||
Examples:
|
||||
- https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw
|
||||
- https://www.youtube.com/user/username
|
||||
- https://www.youtube.com/c/channel_name
|
||||
- https://youtube.com/channel_name
|
||||
"""
|
||||
# If the url doesn't contain youtube, assume it is invalid
|
||||
if "youtube.com" not in url:
|
||||
return None
|
||||
|
||||
# If https:// is not present, urlparse will not work
|
||||
if not url.startswith("https://"):
|
||||
url = f"https://{url}"
|
||||
|
||||
query = urlparse(url)
|
||||
if query.hostname in ("youtube.com", "www.youtube.com"):
|
||||
query_path_split = query.path.split("/")
|
||||
if any(query.path.startswith(qpath) for qpath in ("/channel/", "/user/", "/c/")):
|
||||
# Ensure there is "/path/id".split('/') = ['', 'path', 'id'] at least three
|
||||
if len(query_path_split) < 3 or len(query_path_split[2]) == 0:
|
||||
return None
|
||||
return f"https://youtube.com{query.path}"
|
||||
if len(query_path_split) == 2 and len(query_path_split[1]) > 0:
|
||||
# For channels that do not feature a 'c' or 'channel'
|
||||
# Ensure length of channel string is at least one
|
||||
return f"https://youtube.com{query.path}"
|
||||
|
||||
return None
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
super().__init__(name, value)
|
||||
|
||||
self._channel_url = self._get_channel_url(value)
|
||||
if not self._channel_url:
|
||||
raise self._validation_exception(f"'{value}' is not a valid Youtube channel url.")
|
||||
|
||||
@property
|
||||
def channel_url(self) -> str:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
Full channel URL
|
||||
"""
|
||||
return self._channel_url
|
||||
|
||||
|
||||
class SoundcloudUsernameUrlValidator(StringValidator):
|
||||
|
||||
_expected_value_type_name = "Soundcloud username url"
|
||||
|
||||
@classmethod
|
||||
def _get_channel_url(cls, url: str) -> Optional[str]:
|
||||
"""
|
||||
Examples:
|
||||
- https://www.soundcloud.com/artist_name
|
||||
"""
|
||||
# If the url doesn't contain soundcloud, assume it is invalid
|
||||
if "soundcloud.com" not in url:
|
||||
return None
|
||||
|
||||
# If https:// is not present, urlparse will not work
|
||||
if not url.startswith("https://"):
|
||||
url = f"https://{url}"
|
||||
|
||||
query = urlparse(url)
|
||||
if query.hostname in ("soundcloud.com", "www.soundcloud.com"):
|
||||
if len(query.path) > 2: # /artist_name
|
||||
username = query.path[1:].split("/")[0] # strip extra paths or slashes
|
||||
username = username.split("?")[0] # strip extra arguments
|
||||
return f"https://soundcloud.com/{username}"
|
||||
|
||||
return None
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
super().__init__(name, value)
|
||||
|
||||
self._username_url = self._get_channel_url(value)
|
||||
if not self._username_url:
|
||||
raise self._validation_exception(f"'{value}' is not a valid Soundcloud username url.")
|
||||
|
||||
@property
|
||||
def username_url(self) -> str:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
Full artist URL
|
||||
"""
|
||||
return self._username_url
|
||||
0
tests/e2e/bandcamp/__init__.py
Normal file
0
tests/e2e/bandcamp/__init__.py
Normal file
61
tests/e2e/bandcamp/test_bandcamp.py
Normal file
61
tests/e2e/bandcamp/test_bandcamp.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import pytest
|
||||
from expected_download import assert_expected_downloads
|
||||
from expected_transaction_log import assert_transaction_log_matches
|
||||
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def subscription_dict(output_directory):
|
||||
return {
|
||||
"preset": "albums_from_playlists",
|
||||
"regex": {
|
||||
"skip_if_match_fails": False, # Error if regex match fails
|
||||
"from": {
|
||||
"title": {
|
||||
"match": ["^(.*) - (.*)"], # Captures 'title' from 'Emily Hopkins - title'
|
||||
"capture_group_names": [
|
||||
"captured_track_artist",
|
||||
"captured_track_title",
|
||||
],
|
||||
}
|
||||
},
|
||||
},
|
||||
"ytdl_options": {
|
||||
"max_downloads": 15,
|
||||
},
|
||||
"date_range": {"before": "20230101"},
|
||||
"overrides": {
|
||||
"url": "https://funkypselicave.bandcamp.com/",
|
||||
"track_title": "{captured_track_title}",
|
||||
"track_artist": "{captured_track_artist}",
|
||||
"music_directory": output_directory,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class TestBandcamp:
|
||||
@pytest.mark.parametrize("dry_run", [True, False])
|
||||
def test_download_artist_url(
|
||||
self,
|
||||
subscription_dict,
|
||||
music_audio_config,
|
||||
output_directory,
|
||||
dry_run,
|
||||
):
|
||||
discography_subscription = Subscription.from_dict(
|
||||
preset_dict=subscription_dict,
|
||||
preset_name="jb",
|
||||
config=music_audio_config,
|
||||
)
|
||||
transaction_log = discography_subscription.download(dry_run=dry_run)
|
||||
assert_transaction_log_matches(
|
||||
output_directory=output_directory,
|
||||
transaction_log=transaction_log,
|
||||
transaction_log_summary_file_name="bandcamp/test_artist_url.txt",
|
||||
)
|
||||
assert_expected_downloads(
|
||||
output_directory=output_directory,
|
||||
dry_run=dry_run,
|
||||
expected_download_summary_file_name="bandcamp/test_artist_url.json",
|
||||
)
|
||||
|
|
@ -79,18 +79,10 @@ def channel_as_tv_show_config(working_directory) -> ConfigFile:
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def soundcloud_discography_config(working_directory) -> ConfigFile:
|
||||
return _load_config(
|
||||
config_path="examples/soundcloud_discography_config.yaml",
|
||||
working_directory=working_directory,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def youtube_audio_config(working_directory) -> ConfigFile:
|
||||
def music_audio_config(working_directory) -> ConfigFile:
|
||||
return _load_config(
|
||||
config_path="examples/music_audio_from_videos.yaml", working_directory=working_directory
|
||||
config_path="examples/music_audio_config.yaml", working_directory=working_directory
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ from ytdl_sub.subscriptions.subscription import Subscription
|
|||
@pytest.fixture
|
||||
def single_song_preset_dict(output_directory):
|
||||
return {
|
||||
"preset": "song",
|
||||
"download": {"url": "https://www.youtube.com/watch?v=2lAe1cqCOXo"},
|
||||
"output_options": {"output_directory": output_directory},
|
||||
"preset": "single",
|
||||
# test multi-tags
|
||||
"music_tags": {"embed_thumbnail": True, "tags": {"genres": ["multi_tag_1", "multi_tag_2"]}},
|
||||
# download the worst format so it is fast
|
||||
|
|
@ -18,21 +16,27 @@ def single_song_preset_dict(output_directory):
|
|||
"format": "worst[ext=mp4]",
|
||||
"postprocessor_args": {"ffmpeg": ["-bitexact"]}, # Must add this for reproducibility
|
||||
},
|
||||
"overrides": {
|
||||
"url": "https://www.youtube.com/watch?v=2lAe1cqCOXo",
|
||||
"music_directory": output_directory,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def multiple_songs_preset_dict(output_directory):
|
||||
return {
|
||||
"preset": "song_playlist",
|
||||
"download": {"url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35"},
|
||||
"output_options": {"output_directory": output_directory},
|
||||
"preset": "albums_from_playlists",
|
||||
"audio_extract": {"codec": "vorbis", "quality": 140},
|
||||
# download the worst format so it is fast
|
||||
"ytdl_options": {
|
||||
"format": "worst[ext=mp4]",
|
||||
"postprocessor_args": {"ffmpeg": ["-bitexact"]}, # Must add this for reproducibility
|
||||
},
|
||||
"overrides": {
|
||||
"url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35",
|
||||
"music_directory": output_directory,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -40,13 +44,13 @@ class TestAudioExtract:
|
|||
@pytest.mark.parametrize("dry_run", [True, False])
|
||||
def test_audio_extract_single_song(
|
||||
self,
|
||||
youtube_audio_config,
|
||||
music_audio_config,
|
||||
single_song_preset_dict,
|
||||
output_directory,
|
||||
dry_run,
|
||||
):
|
||||
subscription = Subscription.from_dict(
|
||||
config=youtube_audio_config,
|
||||
config=music_audio_config,
|
||||
preset_name="single_song_test",
|
||||
preset_dict=single_song_preset_dict,
|
||||
)
|
||||
|
|
@ -66,13 +70,13 @@ class TestAudioExtract:
|
|||
@pytest.mark.parametrize("dry_run", [True, False])
|
||||
def test_audio_extract_multiple_songs(
|
||||
self,
|
||||
youtube_audio_config,
|
||||
music_audio_config,
|
||||
multiple_songs_preset_dict,
|
||||
output_directory,
|
||||
dry_run,
|
||||
):
|
||||
subscription = Subscription.from_dict(
|
||||
config=youtube_audio_config,
|
||||
config=music_audio_config,
|
||||
preset_name="multiple_songs_test",
|
||||
preset_dict=multiple_songs_preset_dict,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ def single_song_video_dict(output_directory):
|
|||
class TestMusicTags:
|
||||
def test_music_tags_errors_on_video(
|
||||
self,
|
||||
youtube_audio_config,
|
||||
music_audio_config,
|
||||
single_song_video_dict,
|
||||
output_directory,
|
||||
):
|
||||
subscription = Subscription.from_dict(
|
||||
config=youtube_audio_config,
|
||||
config=music_audio_config,
|
||||
preset_name="single_song_test",
|
||||
preset_dict=single_song_video_dict,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,15 +12,16 @@ from ytdl_sub.utils.exceptions import ValidationException
|
|||
@pytest.fixture
|
||||
def yt_album_as_chapters_preset_dict(output_directory):
|
||||
return {
|
||||
"preset": "album_from_chapters",
|
||||
"download": {"url": "https://www.youtube.com/watch?v=zeR2_YjlXWA"},
|
||||
# override the output directory with our fixture-generated dir
|
||||
"output_options": {"output_directory": output_directory, "maintain_download_archive": True},
|
||||
"preset": "albums_from_chapters",
|
||||
# download the worst format so it is fast
|
||||
"ytdl_options": {
|
||||
"format": "worst[ext=mp4]",
|
||||
"postprocessor_args": {"ffmpeg": ["-bitexact"]}, # Must add this for reproducibility
|
||||
},
|
||||
"overrides": {
|
||||
"url": "https://www.youtube.com/watch?v=zeR2_YjlXWA",
|
||||
"music_directory": output_directory,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ def yt_album_as_chapters_with_regex_preset_dict(yt_album_as_chapters_preset_dict
|
|||
"from": {
|
||||
"chapter_title": {
|
||||
"match": r"\d+\. (.+)",
|
||||
"capture_group_names": "captured_chapter_title",
|
||||
"capture_group_names": "captured_track_title",
|
||||
"capture_group_defaults": "{chapter_title}",
|
||||
},
|
||||
"title": {
|
||||
|
|
@ -42,8 +43,8 @@ def yt_album_as_chapters_with_regex_preset_dict(yt_album_as_chapters_preset_dict
|
|||
"(.+) - (.+)",
|
||||
],
|
||||
"capture_group_names": [
|
||||
"captured_artist",
|
||||
"captured_album",
|
||||
"captured_track_artist",
|
||||
"captured_track_album",
|
||||
],
|
||||
"capture_group_defaults": [
|
||||
"{channel}",
|
||||
|
|
@ -53,9 +54,9 @@ def yt_album_as_chapters_with_regex_preset_dict(yt_album_as_chapters_preset_dict
|
|||
}
|
||||
},
|
||||
"overrides": {
|
||||
"custom_track_name": "{captured_chapter_title}",
|
||||
"custom_album_name": "{captured_album}",
|
||||
"custom_artist_name": "{captured_artist}",
|
||||
"track_title": "{captured_track_title}",
|
||||
"track_album": "{captured_track_album}",
|
||||
"track_artist": "{captured_track_artist}",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -66,13 +67,13 @@ class TestSplitByChapters:
|
|||
@pytest.mark.parametrize("dry_run", [True, False])
|
||||
def test_video_with_chapters(
|
||||
self,
|
||||
youtube_audio_config,
|
||||
music_audio_config,
|
||||
yt_album_as_chapters_preset_dict,
|
||||
output_directory,
|
||||
dry_run,
|
||||
):
|
||||
subscription = Subscription.from_dict(
|
||||
config=youtube_audio_config,
|
||||
config=music_audio_config,
|
||||
preset_name="split_by_chapters_video",
|
||||
preset_dict=yt_album_as_chapters_preset_dict,
|
||||
)
|
||||
|
|
@ -96,13 +97,13 @@ class TestSplitByChapters:
|
|||
@pytest.mark.parametrize("dry_run", [True, False])
|
||||
def test_video_with_chapters_and_regex(
|
||||
self,
|
||||
youtube_audio_config,
|
||||
music_audio_config,
|
||||
yt_album_as_chapters_with_regex_preset_dict,
|
||||
output_directory,
|
||||
dry_run,
|
||||
):
|
||||
subscription = Subscription.from_dict(
|
||||
config=youtube_audio_config,
|
||||
config=music_audio_config,
|
||||
preset_name="split_by_chapters_with_regex_video",
|
||||
preset_dict=yt_album_as_chapters_with_regex_preset_dict,
|
||||
)
|
||||
|
|
@ -123,7 +124,7 @@ class TestSplitByChapters:
|
|||
@pytest.mark.parametrize("when_no_chapters", ["pass", "drop", "error"])
|
||||
def test_video_with_no_chapters_and_regex(
|
||||
self,
|
||||
youtube_audio_config,
|
||||
music_audio_config,
|
||||
yt_album_as_chapters_with_regex_preset_dict,
|
||||
output_directory,
|
||||
dry_run,
|
||||
|
|
@ -138,7 +139,7 @@ class TestSplitByChapters:
|
|||
)
|
||||
|
||||
subscription = Subscription.from_dict(
|
||||
config=youtube_audio_config,
|
||||
config=music_audio_config,
|
||||
preset_name="split_by_chapters_with_regex_video",
|
||||
preset_dict=yt_album_as_chapters_with_regex_preset_dict,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ def subscription_dict(output_directory):
|
|||
"format": "worst[ext=mp3]",
|
||||
},
|
||||
"overrides": {
|
||||
"artist": "j_b",
|
||||
"artist_url": "https://soundcloud.com/jessebannon",
|
||||
"track_artist": "j_b",
|
||||
"sc_artist_url": "https://soundcloud.com/jessebannon",
|
||||
"music_directory": output_directory,
|
||||
},
|
||||
}
|
||||
|
|
@ -31,14 +31,14 @@ class TestSoundcloudDiscography:
|
|||
def test_discography_download(
|
||||
self,
|
||||
subscription_dict,
|
||||
soundcloud_discography_config,
|
||||
music_audio_config,
|
||||
output_directory,
|
||||
dry_run,
|
||||
):
|
||||
discography_subscription = Subscription.from_dict(
|
||||
preset_dict=subscription_dict,
|
||||
preset_name="jb",
|
||||
config=soundcloud_discography_config,
|
||||
config=music_audio_config,
|
||||
)
|
||||
transaction_log = discography_subscription.download(dry_run=dry_run)
|
||||
assert_transaction_log_matches(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
".ytdl-sub-jb-download-archive.json": "9f5ca17dc0d842ac4c296054c0011ace",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/01 - Spark it.mp3": "6f21b6f977609382fa9b9fa9817b28cc",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/02 - Astronomikal Funk.mp3": "870199f5e75ea170051122f7220e2f42",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/03 - Impulse.mp3": "3a14e5e034016ad131186caf94be00da",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/04 - September.mp3": "c58520ef3f7f8944151ee0fb95fb0ac5",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/05 - Interlune.mp3": "5a7365a253ac4a5af54e550508a40b66",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/06 - Ninjutsu Techniques.mp3": "07b3f74ef78cb0c869c86dded054b1e9",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/07 - Space Funk Flow.mp3": "fef74e222258c4845e8b51e05acd240f",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/08 - Cellar Groove.mp3": "743927c47df60e811d367f5ef969faaf",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/09 - Solar Wind.mp3": "dd97643e3dc5decefb543da3a6e31356",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/10 - Interlune II.mp3": "37717cbd8f837657047616743937595b",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/11 - Ghetto Anthem.mp3": "54089f39836d469f391f6850926a392d",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/12 - Street Degree.mp3": "ddd3dc74d9bc07b988e4e4da363624dd",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/13 - Trouble World.mp3": "90dacf561b52852312f9e3f06084bfca",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/14 - Relaxation.mp3": "12dc503e0f758ae0b962e941727f272b",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/15 - Journey From Within.mp3": "c593e610ac6853b3795781b6650fc59e",
|
||||
"El Jazzy Chavo/[2022] S950 Funk/folder.jpg": "62e51365dd309e76a6323f927f6fcc94"
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
".ytdl-sub-split_by_chapters_video-download-archive.json": "7001417f7a398959f3296ece81575a77",
|
||||
"Alfa Mist - Nocturne [Full Album]/01 - 01. Intro (Feat. Racheal Ofori & Barney Artist).mp3": "87d036987c4903e62e4f5001ea38a49a",
|
||||
"Alfa Mist - Nocturne [Full Album]/02 - 02. Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3": "96975f139dcc87a05dec03ab4f839d94",
|
||||
"Alfa Mist - Nocturne [Full Album]/03 - 03. Blaze (Feat. Kaya Thomas - Dyke).mp3": "58df7bb835d05e3cb0e28abb4c784a5e",
|
||||
"Alfa Mist - Nocturne [Full Album]/04 - 04. What If (Interlude).mp3": "d8313eb888dc3c8109623c84139280e7",
|
||||
"Alfa Mist - Nocturne [Full Album]/05 - 05. No Peace (Feat. Tom Misch).mp3": "4c6ee32b371e6e5374c722f4c854a965",
|
||||
"Alfa Mist - Nocturne [Full Album]/06 - 06. Closer (Feat. Lester Duval).mp3": "d54280bca884ddc1a0614b00c2d70ea3",
|
||||
"Alfa Mist - Nocturne [Full Album]/07 - 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3": "61943dfb29ca40069969790773bf3cd9",
|
||||
"Alfa Mist - Nocturne [Full Album]/08 - 08. Dreams (Feat. Carmody).mp3": "c37001fb9f3c0cca1bffdf3b2ae4a0fc",
|
||||
"Alfa Mist - Nocturne [Full Album]/09 - 09. Dreaming (Interlude) (Feat. Racheal Ofori).mp3": "5334aa0af6ce2ec1283806cf7d9a15c1",
|
||||
"Alfa Mist - Nocturne [Full Album]/10 - 10. Hopeful (Feat. Jordan Rakei).mp3": "526d70f88ab03b972c06243f164d4b0e",
|
||||
"Alfa Mist - Nocturne [Full Album]/11 - 11. Sunrise (Pillows) (Feat. Emmavie).mp3": "8376927e5cecf6bed63f016649b77354",
|
||||
"Alfa Mist - Nocturne [Full Album]/folder.jpg": "bd3685acc53072e591bae2505ecb0648"
|
||||
".ytdl-sub-split_by_chapters_video-download-archive.json": "5e7a31ec4a73e71696f8f3ba9eab9303",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/01 - 01. Intro (Feat. Racheal Ofori & Barney Artist).mp3": "29d09da874133ce5c5f7459c2fa6cd85",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/02 - 02. Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3": "d5432e6a4f7af9810b0e7c8eebe4898a",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/03 - 03. Blaze (Feat. Kaya Thomas - Dyke).mp3": "cf03da6688a73373f9295dc595156e11",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/04 - 04. What If (Interlude).mp3": "b7b943b6f3395c05433b8532364d63d6",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/05 - 05. No Peace (Feat. Tom Misch).mp3": "0d9719268900d4abcd8c0f51ad3af92c",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/06 - 06. Closer (Feat. Lester Duval).mp3": "bbd9ec616a0f7d3c5d13c04bb118681e",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/07 - 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3": "2e59ecdc0f8050bcf190a7898d7ae968",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/08 - 08. Dreams (Feat. Carmody).mp3": "e58966f3326b876f0ab97459b681f76f",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/09 - 09. Dreaming (Interlude) (Feat. Racheal Ofori).mp3": "d6939215b73457fce4e026f8c9b57ecc",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/10 - 10. Hopeful (Feat. Jordan Rakei).mp3": "82d0e7d8070fd15d71c2e11c0285d426",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/11 - 11. Sunrise (Pillows) (Feat. Emmavie).mp3": "3edb11e8cd5f270dd42ee62d9a9aa4ff",
|
||||
"Proved Records/[2017] Alfa Mist - Nocturne [Full Album]/folder.jpg": "bd3685acc53072e591bae2505ecb0648"
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
".ytdl-sub-split_by_chapters_with_regex_video-download-archive.json": "11367ac13068646e35a53d25deeba834",
|
||||
"Oblivion Mod "Falcor" p.1/01 - Oblivion Mod "Falcor" p.1.mp3": "dfcf5aed1742bd55e562a0d93e555f01",
|
||||
"Oblivion Mod "Falcor" p.1/folder.jpg": "fb95b510681676e81c321171fc23143e"
|
||||
".ytdl-sub-split_by_chapters_with_regex_video-download-archive.json": "ed212171889707bf65462878248fc0b8",
|
||||
"Project Zombie/[2010] Oblivion Mod \"Falcor\" p.1/01 - Oblivion Mod \"Falcor\" p.1.mp3": "a3c01f164eeca4541aeed49264d2fc8c",
|
||||
"Project Zombie/[2010] Oblivion Mod \"Falcor\" p.1/folder.jpg": "fb95b510681676e81c321171fc23143e"
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
".ytdl-sub-split_by_chapters_with_regex_video-download-archive.json": "5f281991d441f406b0d721b250e74b79",
|
||||
"Nocturne/01 - Intro (Feat. Racheal Ofori & Barney Artist).mp3": "1f51d6809509904b51ad8930d9bb49b0",
|
||||
"Nocturne/02 - Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3": "16ba92db30c7199373855d0ed6d2cdde",
|
||||
"Nocturne/03 - Blaze (Feat. Kaya Thomas - Dyke).mp3": "21af1894554dc61f437b191a6702c274",
|
||||
"Nocturne/04 - What If (Interlude).mp3": "b6cab2cfcbcb3807eb8176281960e9be",
|
||||
"Nocturne/05 - No Peace (Feat. Tom Misch).mp3": "56ae7656dc6edca4e55e0afc9422002a",
|
||||
"Nocturne/06 - Closer (Feat. Lester Duval).mp3": "93e7025813924670595032c3a2038d94",
|
||||
"Nocturne/07 - Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3": "b757d50d7ad154fe36d13ae72a05a744",
|
||||
"Nocturne/08 - Dreams (Feat. Carmody).mp3": "de1e9313623368a9c7e63a08d77ca54b",
|
||||
"Nocturne/09 - Dreaming (Interlude) (Feat. Racheal Ofori).mp3": "264e0a6c3e572e05daffc38bf8178226",
|
||||
"Nocturne/10 - Hopeful (Feat. Jordan Rakei).mp3": "e72408d03604ff928acf6ce4b383895c",
|
||||
"Nocturne/11 - Sunrise (Pillows) (Feat. Emmavie).mp3": "146d981480be3bf28726a27443c1695a",
|
||||
"Nocturne/folder.jpg": "bd3685acc53072e591bae2505ecb0648"
|
||||
".ytdl-sub-split_by_chapters_with_regex_video-download-archive.json": "cb82ae5ed9d7a41aea15446254c93738",
|
||||
"Alfa Mist/[2017] Nocturne/01 - Intro (Feat. Racheal Ofori & Barney Artist).mp3": "7be57c4dde9ba2c3fa72e9cc65b0f586",
|
||||
"Alfa Mist/[2017] Nocturne/02 - Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3": "5ee032da9965c51913fcfa0319d061bd",
|
||||
"Alfa Mist/[2017] Nocturne/03 - Blaze (Feat. Kaya Thomas - Dyke).mp3": "82c1f35bdccfb4ec146f33661ac94d6b",
|
||||
"Alfa Mist/[2017] Nocturne/04 - What If (Interlude).mp3": "040b38c249e478d8832dcea8bfeca17f",
|
||||
"Alfa Mist/[2017] Nocturne/05 - No Peace (Feat. Tom Misch).mp3": "06f7e57fecdc7b4d2e37c7652791ce19",
|
||||
"Alfa Mist/[2017] Nocturne/06 - Closer (Feat. Lester Duval).mp3": "91a03449c33bf9dcff5a9654a8525626",
|
||||
"Alfa Mist/[2017] Nocturne/07 - Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3": "54c26621b8d4e74f37217c836479a077",
|
||||
"Alfa Mist/[2017] Nocturne/08 - Dreams (Feat. Carmody).mp3": "2704327ac5998086e77a77da164e2afd",
|
||||
"Alfa Mist/[2017] Nocturne/09 - Dreaming (Interlude) (Feat. Racheal Ofori).mp3": "75b8a26d3099aa2d9ba488b33c4eb1e7",
|
||||
"Alfa Mist/[2017] Nocturne/10 - Hopeful (Feat. Jordan Rakei).mp3": "0bf0979c99c55ef986efaba55c0dc858",
|
||||
"Alfa Mist/[2017] Nocturne/11 - Sunrise (Pillows) (Feat. Emmavie).mp3": "78950fbfe459de8e9aa951ab6fa153bf",
|
||||
"Alfa Mist/[2017] Nocturne/folder.jpg": "bd3685acc53072e591bae2505ecb0648"
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"Jesse's Minecraft Server [Trailer - Feb.1].ogg": "e0ab90ea97f26738195111de2fbf0f5f",
|
||||
"Jesse's Minecraft Server [Trailer - Feb.27].ogg": "814bdd627fbd4b55017341ffdec9da9d",
|
||||
"Jesse's Minecraft Server [Trailer - Mar.21].ogg": "90303a47a312c27cf8eed56bf09aa526"
|
||||
".ytdl-sub-multiple_songs_test-download-archive.json": "54237df5e00d1598dfd39f341ee03d75",
|
||||
"Project Zombie/[2011] Jesse's Minecraft Server/01 - Jesse's Minecraft Server [Trailer - Mar.21].ogg": "5657c5b92f8980b20d8bbee0fdc7e5d8",
|
||||
"Project Zombie/[2011] Jesse's Minecraft Server/02 - Jesse's Minecraft Server [Trailer - Feb.27].ogg": "a2a3a34e02e26a6c0265530d4499473b",
|
||||
"Project Zombie/[2011] Jesse's Minecraft Server/03 - Jesse's Minecraft Server [Trailer - Feb.1].ogg": "b2d6388b4ddf8e3fbca042cb123672c3",
|
||||
"Project Zombie/[2011] Jesse's Minecraft Server/folder.jpg": "e7830aa8a64b0cde65ba3f7e5fc56530"
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
{
|
||||
"YouTube Rewind 2019: For the Record | #YouTubeRewind.mp3": "05bd1d218f5a0c942ddb1448d939a1dc"
|
||||
".ytdl-sub-single_song_test-download-archive.json": "22c1431e35033d777a674c4802bcc786",
|
||||
"YouTube/[2019] YouTube Rewind 2019: For the Record | #YouTubeRewind/01 - YouTube Rewind 2019: For the Record | #YouTubeRewind.mp3": "7affc0ecf01f36de9cee1a7aafd776eb",
|
||||
"YouTube/[2019] YouTube Rewind 2019: For the Record | #YouTubeRewind/folder.jpg": "50ee47c80f679029f5d3503bb91b045a"
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
".ytdl-sub-jb-download-archive.json": "1a99156e9ece62539fb2608416a07200",
|
||||
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3": "bffbd558e12c6a9e029dc136a88342c4",
|
||||
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3": "a8955bccae34c39e64d70a021c95e6d4",
|
||||
"j_b/[2021] Baby Santana's Dorian Groove/folder.jpg": "967892be44b8c47e1be73f055a7c6f08",
|
||||
"j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3": "038db58aebe2ba875b733932b42a94d6",
|
||||
"j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3": "ec1d40fee597da35f5dc0126438efe54",
|
||||
"j_b/[2021] Purple Clouds/folder.jpg": "967892be44b8c47e1be73f055a7c6f08",
|
||||
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3": "e145f0a2f6012768280c38655ca58065",
|
||||
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3": "60c8b8817a197a13e4bb90903af612c5",
|
||||
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3": "8265b7e4f79878af877bc6ecd9757efe",
|
||||
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3": "accf46b76891d2954b893d0f91d82816",
|
||||
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3": "e1f584f523336160d5c1104a61de77f3",
|
||||
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3": "f6885b25901177f0357649afe97328cc",
|
||||
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3": "fa057f221cbe4cf2442cd2fdb960743e",
|
||||
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3": "7794ae812c64580e2ac8fc457d5cc85f",
|
||||
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3": "adbf02eddb2090c008eb497d13ff84b9",
|
||||
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3": "65bb10c84366c71498161734f953e93d",
|
||||
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3": "6904b2918e5dc38d9a9f72d967eb74bf",
|
||||
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3": "768e148a2b24ed2de299ca4899d8e533",
|
||||
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3": "a9cd2d2176f94fdad8965c1fbbc3396a",
|
||||
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3": "f3c74e7e8595505d15a384226d0c906e",
|
||||
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3": "d13a3008d9a39da3e5fdcd0c279718e8",
|
||||
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3": "3a40d1108c4f6a0d004eea2151001d66",
|
||||
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3": "8224406bb95e100f4ebcdf7fec3db1c0",
|
||||
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3": "1ea96a8581eb81e45564617f75bd467e",
|
||||
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3": "df14e3b41386cf408b4d1549428a17a5",
|
||||
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3": "f52df647e1f5cf15df720d62b5ad64b1",
|
||||
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3": "429ac1c752822230803c1a452987e492",
|
||||
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3": "9322445a6a7cdd506038b8714cb1731f",
|
||||
"j_b/[2022] Acoustic Treats/folder.jpg": "967892be44b8c47e1be73f055a7c6f08"
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-jb-download-archive.json
|
||||
{output_directory}/El Jazzy Chavo/[2022] S950 Funk
|
||||
01 - Spark it.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Spark it
|
||||
track: 1
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
02 - Astronomikal Funk.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Astronomikal Funk
|
||||
track: 2
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
03 - Impulse.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Impulse
|
||||
track: 3
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
04 - September.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: September
|
||||
track: 4
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
05 - Interlune.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Interlune
|
||||
track: 5
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
06 - Ninjutsu Techniques.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Ninjutsu Techniques
|
||||
track: 6
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
07 - Space Funk Flow.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Space Funk Flow
|
||||
track: 7
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
08 - Cellar Groove.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Cellar Groove
|
||||
track: 8
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
09 - Solar Wind.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Solar Wind
|
||||
track: 9
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
10 - Interlune II.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Interlune II
|
||||
track: 10
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
11 - Ghetto Anthem.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Ghetto Anthem
|
||||
track: 11
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
12 - Street Degree.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Street Degree
|
||||
track: 12
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
13 - Trouble World.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Trouble World
|
||||
track: 13
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
14 - Relaxation.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Relaxation
|
||||
track: 14
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
15 - Journey From Within.mp3
|
||||
Music Tags:
|
||||
album: S950 Funk
|
||||
albumartist: El Jazzy Chavo
|
||||
albumartists: El Jazzy Chavo
|
||||
artist: El Jazzy Chavo
|
||||
artists: El Jazzy Chavo
|
||||
genre: Unset
|
||||
title: Journey From Within
|
||||
track: 15
|
||||
tracktotal: 15
|
||||
year: 2022
|
||||
folder.jpg
|
||||
|
|
@ -2,7 +2,7 @@ Files created:
|
|||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-split_by_chapters_video-download-archive.json
|
||||
{output_directory}/Alfa Mist - Nocturne [Full Album]
|
||||
{output_directory}/Proved Records/[2017] Alfa Mist - Nocturne [Full Album]
|
||||
01 - 01. Intro (Feat. Racheal Ofori & Barney Artist).mp3
|
||||
From Chapter Split:
|
||||
Warning: Dry-run assumes embedded chapters with no modifications
|
||||
|
|
@ -17,6 +17,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 01. Intro (Feat. Racheal Ofori & Barney Artist)
|
||||
track: 1
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
02 - 02. Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -32,6 +33,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 02. Answers (Feat. Rick David & Kaya Thomas - Dyke)
|
||||
track: 2
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
03 - 03. Blaze (Feat. Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -47,6 +49,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 03. Blaze (Feat. Kaya Thomas - Dyke)
|
||||
track: 3
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
04 - 04. What If (Interlude).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -62,6 +65,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 04. What If (Interlude)
|
||||
track: 4
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
05 - 05. No Peace (Feat. Tom Misch).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -77,6 +81,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 05. No Peace (Feat. Tom Misch)
|
||||
track: 5
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
06 - 06. Closer (Feat. Lester Duval).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -92,8 +97,9 @@ Files created:
|
|||
genre: Unset
|
||||
title: 06. Closer (Feat. Lester Duval)
|
||||
track: 6
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
07 - 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
07 - 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
Warning: Dry-run assumes embedded chapters with no modifications
|
||||
Source Title: Alfa Mist - Nocturne [Full Album]
|
||||
|
|
@ -107,6 +113,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori)
|
||||
track: 7
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
08 - 08. Dreams (Feat. Carmody).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -122,6 +129,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 08. Dreams (Feat. Carmody)
|
||||
track: 8
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
09 - 09. Dreaming (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -137,6 +145,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 09. Dreaming (Interlude) (Feat. Racheal Ofori)
|
||||
track: 9
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
10 - 10. Hopeful (Feat. Jordan Rakei).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -152,6 +161,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 10. Hopeful (Feat. Jordan Rakei)
|
||||
track: 10
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
11 - 11. Sunrise (Pillows) (Feat. Emmavie).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -167,5 +177,6 @@ Files created:
|
|||
genre: Unset
|
||||
title: 11. Sunrise (Pillows) (Feat. Emmavie)
|
||||
track: 11
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
folder.jpg
|
||||
|
|
@ -2,7 +2,7 @@ Files created:
|
|||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-split_by_chapters_video-download-archive.json
|
||||
{output_directory}/Alfa Mist - Nocturne [Full Album]
|
||||
{output_directory}/Proved Records/[2017] Alfa Mist - Nocturne [Full Album]
|
||||
01 - 01. Intro (Feat. Racheal Ofori & Barney Artist).mp3
|
||||
From Chapter Split:
|
||||
Source Title: Alfa Mist - Nocturne [Full Album]
|
||||
|
|
@ -16,6 +16,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 01. Intro (Feat. Racheal Ofori & Barney Artist)
|
||||
track: 1
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
02 - 02. Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -30,6 +31,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 02. Answers (Feat. Rick David & Kaya Thomas - Dyke)
|
||||
track: 2
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
03 - 03. Blaze (Feat. Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -44,6 +46,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 03. Blaze (Feat. Kaya Thomas - Dyke)
|
||||
track: 3
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
04 - 04. What If (Interlude).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -58,6 +61,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 04. What If (Interlude)
|
||||
track: 4
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
05 - 05. No Peace (Feat. Tom Misch).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -72,6 +76,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 05. No Peace (Feat. Tom Misch)
|
||||
track: 5
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
06 - 06. Closer (Feat. Lester Duval).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -86,8 +91,9 @@ Files created:
|
|||
genre: Unset
|
||||
title: 06. Closer (Feat. Lester Duval)
|
||||
track: 6
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
07 - 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
07 - 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
Source Title: Alfa Mist - Nocturne [Full Album]
|
||||
Segment: 17:57 - 20:05
|
||||
|
|
@ -100,6 +106,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 07. Delusions: Rumination (Interlude) (Feat. Racheal Ofori)
|
||||
track: 7
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
08 - 08. Dreams (Feat. Carmody).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -114,6 +121,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 08. Dreams (Feat. Carmody)
|
||||
track: 8
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
09 - 09. Dreaming (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -128,6 +136,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 09. Dreaming (Interlude) (Feat. Racheal Ofori)
|
||||
track: 9
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
10 - 10. Hopeful (Feat. Jordan Rakei).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -142,6 +151,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: 10. Hopeful (Feat. Jordan Rakei)
|
||||
track: 10
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
11 - 11. Sunrise (Pillows) (Feat. Emmavie).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -156,5 +166,6 @@ Files created:
|
|||
genre: Unset
|
||||
title: 11. Sunrise (Pillows) (Feat. Emmavie)
|
||||
track: 11
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
folder.jpg
|
||||
|
|
@ -2,8 +2,8 @@ Files created:
|
|||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-split_by_chapters_with_regex_video-download-archive.json
|
||||
{output_directory}/Oblivion Mod "Falcor" p.1
|
||||
01 - Oblivion Mod "Falcor" p.1.mp3
|
||||
{output_directory}/Project Zombie/[2010] Oblivion Mod "Falcor" p.1
|
||||
01 - Oblivion Mod "Falcor" p.1.mp3
|
||||
Music Tags:
|
||||
album: Oblivion Mod "Falcor" p.1
|
||||
albumartist: Project Zombie
|
||||
|
|
@ -13,5 +13,6 @@ Files created:
|
|||
genre: Unset
|
||||
title: Oblivion Mod "Falcor" p.1
|
||||
track: 1
|
||||
tracktotal: 1
|
||||
year: 2010
|
||||
folder.jpg
|
||||
|
|
@ -2,7 +2,7 @@ Files created:
|
|||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-split_by_chapters_with_regex_video-download-archive.json
|
||||
{output_directory}/Nocturne
|
||||
{output_directory}/Alfa Mist/[2017] Nocturne
|
||||
01 - Intro (Feat. Racheal Ofori & Barney Artist).mp3
|
||||
From Chapter Split:
|
||||
Warning: Dry-run assumes embedded chapters with no modifications
|
||||
|
|
@ -17,6 +17,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Intro (Feat. Racheal Ofori & Barney Artist)
|
||||
track: 1
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
02 - Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -32,6 +33,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Answers (Feat. Rick David & Kaya Thomas - Dyke)
|
||||
track: 2
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
03 - Blaze (Feat. Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -47,6 +49,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Blaze (Feat. Kaya Thomas - Dyke)
|
||||
track: 3
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
04 - What If (Interlude).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -62,6 +65,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: What If (Interlude)
|
||||
track: 4
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
05 - No Peace (Feat. Tom Misch).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -77,6 +81,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: No Peace (Feat. Tom Misch)
|
||||
track: 5
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
06 - Closer (Feat. Lester Duval).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -92,8 +97,9 @@ Files created:
|
|||
genre: Unset
|
||||
title: Closer (Feat. Lester Duval)
|
||||
track: 6
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
07 - Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
07 - Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
Warning: Dry-run assumes embedded chapters with no modifications
|
||||
Source Title: Alfa Mist - Nocturne [Full Album]
|
||||
|
|
@ -107,6 +113,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Delusions: Rumination (Interlude) (Feat. Racheal Ofori)
|
||||
track: 7
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
08 - Dreams (Feat. Carmody).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -122,6 +129,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Dreams (Feat. Carmody)
|
||||
track: 8
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
09 - Dreaming (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -137,6 +145,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Dreaming (Interlude) (Feat. Racheal Ofori)
|
||||
track: 9
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
10 - Hopeful (Feat. Jordan Rakei).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -152,6 +161,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Hopeful (Feat. Jordan Rakei)
|
||||
track: 10
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
11 - Sunrise (Pillows) (Feat. Emmavie).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -167,5 +177,6 @@ Files created:
|
|||
genre: Unset
|
||||
title: Sunrise (Pillows) (Feat. Emmavie)
|
||||
track: 11
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
folder.jpg
|
||||
|
|
@ -2,7 +2,7 @@ Files created:
|
|||
----------------------------------------
|
||||
{output_directory}
|
||||
.ytdl-sub-split_by_chapters_with_regex_video-download-archive.json
|
||||
{output_directory}/Nocturne
|
||||
{output_directory}/Alfa Mist/[2017] Nocturne
|
||||
01 - Intro (Feat. Racheal Ofori & Barney Artist).mp3
|
||||
From Chapter Split:
|
||||
Source Title: Alfa Mist - Nocturne [Full Album]
|
||||
|
|
@ -16,6 +16,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Intro (Feat. Racheal Ofori & Barney Artist)
|
||||
track: 1
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
02 - Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -30,6 +31,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Answers (Feat. Rick David & Kaya Thomas - Dyke)
|
||||
track: 2
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
03 - Blaze (Feat. Kaya Thomas - Dyke).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -44,6 +46,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Blaze (Feat. Kaya Thomas - Dyke)
|
||||
track: 3
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
04 - What If (Interlude).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -58,6 +61,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: What If (Interlude)
|
||||
track: 4
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
05 - No Peace (Feat. Tom Misch).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -72,6 +76,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: No Peace (Feat. Tom Misch)
|
||||
track: 5
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
06 - Closer (Feat. Lester Duval).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -86,8 +91,9 @@ Files created:
|
|||
genre: Unset
|
||||
title: Closer (Feat. Lester Duval)
|
||||
track: 6
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
07 - Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
07 - Delusions: Rumination (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
Source Title: Alfa Mist - Nocturne [Full Album]
|
||||
Segment: 17:57 - 20:05
|
||||
|
|
@ -100,6 +106,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Delusions: Rumination (Interlude) (Feat. Racheal Ofori)
|
||||
track: 7
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
08 - Dreams (Feat. Carmody).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -114,6 +121,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Dreams (Feat. Carmody)
|
||||
track: 8
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
09 - Dreaming (Interlude) (Feat. Racheal Ofori).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -128,6 +136,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Dreaming (Interlude) (Feat. Racheal Ofori)
|
||||
track: 9
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
10 - Hopeful (Feat. Jordan Rakei).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -142,6 +151,7 @@ Files created:
|
|||
genre: Unset
|
||||
title: Hopeful (Feat. Jordan Rakei)
|
||||
track: 10
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
11 - Sunrise (Pillows) (Feat. Emmavie).mp3
|
||||
From Chapter Split:
|
||||
|
|
@ -156,5 +166,6 @@ Files created:
|
|||
genre: Unset
|
||||
title: Sunrise (Pillows) (Feat. Emmavie)
|
||||
track: 11
|
||||
tracktotal: 11
|
||||
year: 2017
|
||||
folder.jpg
|
||||
|
|
@ -1,31 +1,11 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
Jesse's Minecraft Server [Trailer - Feb.1].ogg
|
||||
.ytdl-sub-multiple_songs_test-download-archive.json
|
||||
{output_directory}/Project Zombie/[2011] Jesse's Minecraft Server
|
||||
01 - Jesse's Minecraft Server [Trailer - Mar.21].ogg
|
||||
Music Tags:
|
||||
album: Singles
|
||||
albumartist: Project Zombie
|
||||
albumartists: Project Zombie
|
||||
artist: Project Zombie
|
||||
artists: Project Zombie
|
||||
genre: Unset
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.1]
|
||||
track: 3
|
||||
year: 2011
|
||||
Jesse's Minecraft Server [Trailer - Feb.27].ogg
|
||||
Music Tags:
|
||||
album: Singles
|
||||
albumartist: Project Zombie
|
||||
albumartists: Project Zombie
|
||||
artist: Project Zombie
|
||||
artists: Project Zombie
|
||||
genre: Unset
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.27]
|
||||
track: 2
|
||||
year: 2011
|
||||
Jesse's Minecraft Server [Trailer - Mar.21].ogg
|
||||
Music Tags:
|
||||
album: Singles
|
||||
album: Jesse's Minecraft Server
|
||||
albumartist: Project Zombie
|
||||
albumartists: Project Zombie
|
||||
artist: Project Zombie
|
||||
|
|
@ -33,4 +13,30 @@ Files created:
|
|||
genre: Unset
|
||||
title: Jesse's Minecraft Server [Trailer - Mar.21]
|
||||
track: 1
|
||||
year: 2011
|
||||
tracktotal: 3
|
||||
year: 2011
|
||||
02 - Jesse's Minecraft Server [Trailer - Feb.27].ogg
|
||||
Music Tags:
|
||||
album: Jesse's Minecraft Server
|
||||
albumartist: Project Zombie
|
||||
albumartists: Project Zombie
|
||||
artist: Project Zombie
|
||||
artists: Project Zombie
|
||||
genre: Unset
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.27]
|
||||
track: 2
|
||||
tracktotal: 3
|
||||
year: 2011
|
||||
03 - Jesse's Minecraft Server [Trailer - Feb.1].ogg
|
||||
Music Tags:
|
||||
album: Jesse's Minecraft Server
|
||||
albumartist: Project Zombie
|
||||
albumartists: Project Zombie
|
||||
artist: Project Zombie
|
||||
artists: Project Zombie
|
||||
genre: Unset
|
||||
title: Jesse's Minecraft Server [Trailer - Feb.1]
|
||||
track: 3
|
||||
tracktotal: 3
|
||||
year: 2011
|
||||
folder.jpg
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
Files created:
|
||||
----------------------------------------
|
||||
{output_directory}
|
||||
YouTube Rewind 2019: For the Record | #YouTubeRewind.mp3
|
||||
.ytdl-sub-single_song_test-download-archive.json
|
||||
{output_directory}/YouTube/[2019] YouTube Rewind 2019: For the Record | #YouTubeRewind
|
||||
01 - YouTube Rewind 2019: For the Record | #YouTubeRewind.mp3
|
||||
Embedded Thumbnail, Music Tags:
|
||||
album: Singles
|
||||
album: YouTube Rewind 2019: For the Record | #YouTubeRewind
|
||||
albumartist: YouTube
|
||||
albumartists: YouTube
|
||||
artist: YouTube
|
||||
|
|
@ -14,4 +16,6 @@ Files created:
|
|||
- multi_tag_2
|
||||
title: YouTube Rewind 2019: For the Record | #YouTubeRewind
|
||||
track: 1
|
||||
year: 2019
|
||||
tracktotal: 1
|
||||
year: 2019
|
||||
folder.jpg
|
||||
|
|
@ -7,10 +7,13 @@ Files created:
|
|||
Music Tags:
|
||||
album: Baby Santana's Dorian Groove
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: Baby Santana's Dorian Groove
|
||||
track: 1
|
||||
tracktotal: 1
|
||||
year: 2021
|
||||
folder.jpg
|
||||
{output_directory}/j_b/[2021] Purple Clouds
|
||||
|
|
@ -18,10 +21,13 @@ Files created:
|
|||
Music Tags:
|
||||
album: Purple Clouds
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: Purple Clouds
|
||||
track: 1
|
||||
tracktotal: 1
|
||||
year: 2021
|
||||
folder.jpg
|
||||
{output_directory}/j_b/[2022] Acoustic Treats
|
||||
|
|
@ -29,99 +35,132 @@ Files created:
|
|||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20160426 184214
|
||||
track: 1
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
02 - 20160502 123150.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20160502 123150
|
||||
track: 2
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
03 - 20160504 143832.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20160504 143832
|
||||
track: 3
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
04 - 20160601 221234.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20160601 221234
|
||||
track: 4
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
05 - 20160601 222440.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20160601 222440
|
||||
track: 5
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
06 - 20170604 190236.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20170604 190236
|
||||
track: 6
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
07 - 20170612 193646.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20170612 193646
|
||||
track: 7
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
08 - 20170628 215206.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: 20170628 215206
|
||||
track: 8
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
09 - Finding Home.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: Finding Home
|
||||
track: 9
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
10 - Shallow Water WIP.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: Shallow Water WIP
|
||||
track: 10
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
11 - Untold History.mp3
|
||||
Music Tags:
|
||||
album: Acoustic Treats
|
||||
albumartist: j_b
|
||||
albumartists: j_b
|
||||
artist: j_b
|
||||
artists: j_b
|
||||
genre: Unset
|
||||
title: Untold History
|
||||
track: 11
|
||||
tracktotal: 11
|
||||
year: 2022
|
||||
folder.jpg
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from ytdl_sub.utils.exceptions import ValidationException
|
||||
from ytdl_sub.validators.url_validator import SoundcloudUsernameUrlValidator
|
||||
from ytdl_sub.validators.url_validator import YoutubeChannelUrlValidator
|
||||
from ytdl_sub.validators.url_validator import YoutubePlaylistUrlValidator
|
||||
from ytdl_sub.validators.url_validator import YoutubeVideoUrlValidator
|
||||
|
||||
|
||||
class TestYoutubeVideoUrlValidator:
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"youtu.be/dQw4w9WgXcQ",
|
||||
"www.youtu.be/dQw4w9WgXcQ",
|
||||
"https://youtu.be/dQw4w9WgXcQ",
|
||||
"https://www.youtu.be/dQw4w9WgXcQ",
|
||||
"https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=feedu",
|
||||
"https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
"https://www.youtube.com/v/dQw4w9WgXcQ?version=3&hl=en_US",
|
||||
"https://www.youtube.com/shorts/dQw4w9WgXcQ",
|
||||
],
|
||||
)
|
||||
def test_youtube_video_url_validator_success(self, url):
|
||||
video_url = YoutubeVideoUrlValidator(name="unit test", value=url).video_url
|
||||
assert video_url == "https://youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"bad_url",
|
||||
[
|
||||
"utube.com/watch?v=sdfsadf",
|
||||
"youtube.com/nope?v=sdfsadf",
|
||||
"youtube.com",
|
||||
"youtube.com/watch",
|
||||
"youtube.com/watch?v=",
|
||||
"youtu.be/",
|
||||
"youtu.be",
|
||||
"youtube.com/shorts",
|
||||
],
|
||||
)
|
||||
def test_youtube_video_url_validator_fail(self, bad_url):
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube video url."
|
||||
with pytest.raises(ValidationException, match=re.escape(expected_error_msg)):
|
||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
||||
|
||||
|
||||
class TestYoutubePlaylistUrlValidator:
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
"www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
"https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
"https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
],
|
||||
)
|
||||
def test_youtube_playlist_url_validator_success(self, url):
|
||||
playlist_url = YoutubePlaylistUrlValidator(name="unit test", value=url).playlist_url
|
||||
assert (
|
||||
playlist_url == "https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"bad_url",
|
||||
[
|
||||
"youpoop.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
"youtube.com/playlistlist=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
"youtube.com",
|
||||
"youtube.com/playlist/asdfsdfsdf",
|
||||
"youtube.com/playlist?list=",
|
||||
"youtube.com/playlist",
|
||||
],
|
||||
)
|
||||
def test_youtube_playlist_url_validator_fail(self, bad_url):
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube playlist url."
|
||||
with pytest.raises(ValidationException, match=re.escape(expected_error_msg)):
|
||||
YoutubePlaylistUrlValidator(name="unit test", value=bad_url)
|
||||
|
||||
|
||||
class TestYoutubeChannelUrlValidator:
|
||||
@pytest.mark.parametrize(
|
||||
"url, expected_url",
|
||||
[
|
||||
(
|
||||
"https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
),
|
||||
(
|
||||
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
),
|
||||
(
|
||||
"youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
),
|
||||
(
|
||||
"www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
"https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
),
|
||||
(
|
||||
"https://www.youtube.com/c/RickastleyCoUkOfficial",
|
||||
"https://youtube.com/c/RickastleyCoUkOfficial",
|
||||
),
|
||||
(
|
||||
"https://www.youtube.com/user/videogamedunkey",
|
||||
"https://youtube.com/user/videogamedunkey",
|
||||
),
|
||||
(
|
||||
"https://youtube.com/extracredits",
|
||||
"https://youtube.com/extracredits",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_youtube_channel_url_validator_success(self, url, expected_url):
|
||||
channel_url = YoutubeChannelUrlValidator(name="unit test", value=url).channel_url
|
||||
assert channel_url == expected_url
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"bad_url",
|
||||
[
|
||||
"www.youtube.com/cha/UCuAXFkgsw1L7xaCfnd5JJOw",
|
||||
"www.nopetube.com/channel/asdfdsf",
|
||||
"www.youtube.com/channel/",
|
||||
"www.youtube.com/channell/asdfasdf",
|
||||
],
|
||||
)
|
||||
def test_youtube_channel_url_validator_fail(self, bad_url):
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube channel url."
|
||||
with pytest.raises(ValidationException, match=re.escape(expected_error_msg)):
|
||||
YoutubeChannelUrlValidator(name="unit test", value=bad_url)
|
||||
|
||||
|
||||
class TestSoundcloudUsernameUrlValidator:
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"soundcloud.com/poop",
|
||||
"www.soundcloud.com/poop",
|
||||
"https://soundcloud.com/poop",
|
||||
"https://www.soundcloud.com/poop",
|
||||
"https://www.soundcloud.com/poop/albums",
|
||||
"https://www.soundcloud.com/poop?link=clipboard_share",
|
||||
],
|
||||
)
|
||||
def test_soundcloud_artist_url_validator_success(self, url):
|
||||
username_url = SoundcloudUsernameUrlValidator(name="unit test", value=url).username_url
|
||||
assert username_url == "https://soundcloud.com/poop"
|
||||
|
||||
@pytest.mark.parametrize("bad_url", ["soundcloud.com", "soundnope.lol", "soundcloud.comm/"])
|
||||
def test_youtube_playlist_url_validator_fail(self, bad_url):
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Soundcloud username url."
|
||||
with pytest.raises(ValidationException, match=re.escape(expected_error_msg)):
|
||||
SoundcloudUsernameUrlValidator(name="unit test", value=bad_url)
|
||||
Loading…
Reference in a new issue