Git Product home page Git Product logo

ytdl-sub's Introduction

ytdl-sub

Automate downloading and metadata generation with YoutubeDL.

codecov Code Qaulity Checks License

ytdl-sub is a command-line tool that downloads media via yt-dlp and prepares it for your favorite media player, including Kodi, Jellyfin, Plex, Emby, and modern music players. No additional plugins or external scrapers are needed.

We recognize that everyone stores their media differently. Our approach for file and metadata formatting is to provide maximum flexibility while maintaining simplicity.

YouTube Channels as TV Shows

Plex

unknown

Jellyfin

jellyfin

Music Videos and Concerts

Kodi

kodi

Jellyfin

jelly_mv

SoundCloud Discography

Writes proper music-tags via beets API

sc_mb

Bandcamp Discography

bc_nav

How it Works

ytdl-sub uses YAML files to define subscriptions. Each subscription imports presets that define how to handle and output media files. ytdl-sub comes packaged with many prebuilt presets that do the work of config-building, so you can start downloading immediately.

# subscriptions.yaml:
# Everything in here can be downloaded using the command:
#   ytdl-sub sub subscriptions.yaml

# __preset__ is a place to define global overrides for all subscriptions
__preset__:
  overrides:
    # Root folder of all ytdl-sub TV Shows
    tv_show_directory: "/tv_shows"
    
    # Root folder of all ytdl-sub Music
    music_directory: "/music"
    
    # Root folder of all ytdl-sub Music Videos
    music_video_directory: "/music_videos"
    
    # For 'Only Recent' preset, only keep vids within this range and limit
    only_recent_date_range: "2months"
    only_recent_max_files: 30
    
  # Pass any arg directly to yt-dlp's Python API
  ytdl_options:
    cookiefile: "/config/cookie.txt" 

###################################################################
# TV Show Presets. Can replace Plex with Plex/Jellyfin/Kodi

Plex TV Show by Date:

  # Sets genre tag to "Documentaries"
  = Documentaries:
    "NOVA PBS": "https://www.youtube.com/@novapbs"
    "National Geographic": "https://www.youtube.com/@NatGeo"
    "Cosmos - What If": "https://www.youtube.com/playlist?list=PLZdXRHYAVxTJno6oFF9nLGuwXNGYHmE8U"

  # Sets genre tag to "Kids", "TV-Y" for content rating
  = Kids | = TV-Y:
    "Jake Trains": "https://www.youtube.com/@JakeTrains"
    "Kids Toys Play": "https://www.youtube.com/@KidsToysPlayChannel"

  = Music:
    # TV show subscriptions can support multiple urls and store in the same TV Show
    "Rick Beato":
      - "https://www.youtube.com/@RickBeato"
      - "https://www.youtube.com/@rickbeato240"

  # Set genre tag to "News", use `Only Recent` preset to only store videos uploaded recently
  = News | Only Recent:
    "BBC News": "https://www.youtube.com/@BBCNews"

Plex TV Show Collection:
  = Music:
    # Prefix with ~ to set specific override variables
    "~Beyond the Guitar":
      s01_name: "Videos"
      s01_url: "https://www.youtube.com/c/BeyondTheGuitar"
      s02_name: "Covers"
      s02_url: "https://www.youtube.com/playlist?list=PLE62gWlWZk5NWVAVuf0Lm9jdv_-_KXs0W"

###################################################################
# Music Presets. Can replace Plex with Plex/Jellyfin/Kodi

YouTube Releases:
  = Jazz:  # Sets genre tag to "Jazz"
    "Thelonious Monk": "https://www.youtube.com/@theloniousmonk3870/releases"

YouTube Full Albums:
  = Lofi:
    "Game Chops": "https://www.youtube.com/playlist?list=PLBsm_SagFMmdWnCnrNtLjA9kzfrRkto4i"

SoundCloud Discography:
  = Chill Hop:
    "UKNOWY": "https://soundcloud.com/uknowymunich"
  = Synthwave:
    "Lazerdiscs Records": "https://soundcloud.com/lazerdiscsrecords"
    "Earmake": "https://soundcloud.com/earmake"

Bandcamp:
  = Lofi:
    "Emily Hopkins": "https://emilyharpist.bandcamp.com/"

###################################################################
# Music Video Presets
"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"

All of this can be downloaded and ready to import to your favorite player using the command

ytdl-sub sub subscriptions.yaml

See our example subscriptions for more detailed examples and use-cases.

Output

After ytdl-sub runs, the end result will download and format the files into something ready to be consumed by your favorite media player/server.

tv_shows/
  Jake Trains/
    Season 2021/
      s2021.e031701 - Pattys Day Video-thumb.jpg
      s2021.e031701 - Pattys Day Video.mp4
      s2021.e031701 - Pattys Day Video.nfo
      s2021.e031702 - Second Pattys Day Video-thumb.jpg
      s2021.e031702 - Second Pattys Day Video.mp4
      s2021.e031702 - Second Pattys Day Video.nfo
    Season 2022/
      s2022.e122501 - Merry Christmas-thumb.jpg
      s2022.e122501 - Merry Christmas.mp4
      s2022.e122501 - Merry Christmas.nfo
    poster.jpg
    fanart.jpg
    tvshow.nfo

music/
  Artist/
    [2022] Some Single/
      01 - Some Single.mp3
      folder.jpg
    [2023] Latest Album/
      01 - Track Title.mp3
      02 - Another Track.mp3
      folder.jpg

music_videos/
  Elton John/
    Elton John - Rocketman.jpg
    Elton John - Rocketman.mp4

Custom Configs

Any part of this process is modifiable by using custom configs. See our walk-through guide on how to build your first config from scratch. Ready-to-use example configurations can be found here alongside our readthedocs for detailed information on all config fields.

Installation

ytdl-sub can be installed on the following platforms.

Docker Installation

Docker installs can be either headless or use the Web-GUI image, which comprises LSIO's code-server Docker image with ytdl-sub preinstalled. This is the recommended way to use ytdl-sub.

image

Contributing

There are many ways to contribute, even without coding. Please take a look in our GitHub Issues to submit a feature request, or pick up a bug.

Support

We are pretty active in our Discord channel if you have any questions. Also see our FAQ for commonly asked questions.

ytdl-sub's People

Contributors

alxjsn avatar baumandm avatar catduckgnaf avatar costaht avatar frankiebinns avatar jmbannon avatar joshuaboniface avatar maka0 avatar mariamozgunova avatar michaelborn avatar myztillx avatar omarahmadyar avatar p-rintz avatar svagtlys avatar tanookiben avatar xontik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ytdl-sub's Issues

Add --verbose and --quiet CLI args to show/hide logging

Suppress/verbose flags for yt-dlp CLI logs

--debug
  Print all ytdl-sub debug and info messages, and yt-dlp messages

--verbose
  Print all ytdl-sub info messages and yt-dlp messages
  
--quiet
  Hide all ytdl-sub and yt-dlp messages
  
<default>
  Only show ytdl-sub info messages, not yt-dlp

"Tried to use download mapping before it was loaded"

ytdl-sub dl --preset "yt_music_video" --youtube.video_id "nZXRV4MezEw" --overrides.artist "Cher"

produced:

  File "/usr/bin/ytdl-sub", line 8, in <module>
    sys.exit(main())
  File "/usr/lib/python3.10/site-packages/ytdl_sub/main.py", line 78, in main
    _download_subscription_from_cli(config=config, extra_args=extra_args)
  File "/usr/lib/python3.10/site-packages/ytdl_sub/main.py", line 58, in _download_subscription_from_cli
    subscription.download()
  File "/usr/lib/python3.10/site-packages/ytdl_sub/subscriptions/subscription.py", line 247, in download
    plugin.post_process_entry(entry)
  File "/usr/lib/python3.10/site-packages/ytdl_sub/plugins/nfo_tags.py", line 118, in post_process_entry
    self.archive_entry_file_name(entry=entry, relative_file_path=nfo_file_name)
  File "/usr/lib/python3.10/site-packages/ytdl_sub/plugins/plugin.py", line 57, in archive_entry_file_name
    self.__enhanced_download_archive.mapping.add_entry(
  File "/usr/lib/python3.10/site-packages/ytdl_sub/ytdl_additions/enhanced_download_archive.py", line 391, in mapping
    raise ValueError("Tried to use download mapping before it was loaded")
ValueError: Tried to use download mapping before it was loaded

(plz dont laugh, my wife likes this song)

Remove Pillow dependency, use ffmpeg to convert image formats

Here's where all the thumbnail/pillow logic exists:
https://github.com/jmbannon/ytdl-sub/blob/master/src/ytdl_sub/utils/thumbnail.py

There's a bug with yt-dlp that reports it downloading a jpg but actually downloads webp. Not sure if it's fixed yet.
For a first pass though I think we can just replace the PIL functions with an FFMPEG call using this helper class:
https://github.com/jmbannon/ytdl-sub/blob/master/src/ytdl_sub/utils/ffmpeg.py

All of the e2e test md5 hashes for jpgs will probably need to get updated when changing this:
https://github.com/jmbannon/ytdl-sub/blob/master/tests/e2e/youtube/test_channel_as_kodi_tv_show.py#L79

Make sure the image still looks good

Setting to set raw yt-dlp options

Hi there,

thanks for the great software.

I want to set sponsorblock settings that yt-dlp has and was wondering if being able to set raw yt-dlp options to use during download might be a good feature for ytdl-sub, since it might also be used for other preferences people might have.

Might also be used for setting video/audio codecs to download for example.

Thanks again.

Convert all images to jpg

Media players universally accept jpg/jpeg images. We should just cast all image types (looking at you, webp) to jpg. We already do for youtube profile/banner pics

Add plugin for filtering media via regex

Be able to specify regex to include or exclude media by matching title name to regex

Should look like

my_preset:
  regex_filter:
    title:
      include:  # If one of these matches, include it
      - ".*Official Video.*"
      exclude:  # If one of these matches, exclude it
      - "sadfasdfdf"

Add youtube.download_strategy: "split_video"

my_preset:
  youtube:
    download_strategy: "split_video"
    video_id: <id of video>
    split_file: "path/to/split_file.txt"

For a video like this https://www.youtube.com/watch?v=Tf1DEI2lEe0 , it would be great to download the audio, and split it up into separate songs based on the description's timestamps:

0:00 DOOM Eternal
4:48 Hell on Earth
9:29 Deag Nilox - First Priest Death
10:14 Barging In
12:32 Demonic Corruption
16:23 Prayer of the Diminished
17:51 King Novik
...

Probably cannot always rely on videos having chapters, or descriptions having these timestamps (often found in comments). Copy-pasting it to a file one-time with an expected format like above would suffice as an MVP

Create Dockerfile for ytdl-sub

Ideally, we want this app to be hosted by linuxserver at some point. For now though, we should have our own Dockerfile.

The base image should be linuxserver's base image found here:
https://github.com/linuxserver/docker-baseimage-alpine

This image includes S6 overlay which is very convenient for cron jobs, as well as PUID/PGID/TZ env variables.

The Dockerfile will probably look somewhat similar to the linuxserver beets docker image, found here:
https://github.com/linuxserver/docker-beets/blob/master/Dockerfile

Clean up source variable docs

Source variables are information from the media downloaded from ytdlp that can be used to set file names or metadata. They are documented here:
https://ytdl-sub.readthedocs.io/en/latest/config.html#source-variables

If you notice, a few variables' formatting looks weird. Like this one:
https://ytdl-sub.readthedocs.io/en/latest/config.html#ytdl_sub.entries.variables.youtube_variables.YoutubeVideoVariables.artist

There are random asterisks, and it seems like the NOTE changes formatting in some way.

The documentation for these should get cleaned up. They are generated from the docstrings in here:
https://github.com/jmbannon/ytdl-sub/tree/master/src/ytdl_sub/entries/variables

The docs are created using reStructuredText (https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) and the autodocs extension (https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html)

To build the docs locally, run make docs

`ytdl-sub sub` errors

Traceback (most recent call last):
  File "/usr/bin/ytdl-sub", line 8, in <module>
    sys.exit(main())
  File "/usr/lib/python3.10/site-packages/ytdl_sub/main.py", line 73, in main
    _download_subscriptions_from_yaml_files(config=config, args=args)
  File "/usr/lib/python3.10/site-packages/ytdl_sub/main.py", line 27, in _download_subscriptions_from_yaml_files
    presets += Preset.from_file_path(config=config, subscription_path=preset_path)
  File "/usr/lib/python3.10/site-packages/ytdl_sub/config/preset.py", line 284, in from_file_path
    with open(subscription_path, "r", encoding="utf-8") as file:
FileNotFoundError: [Errno 2] No such file or directory: 's'

Should use 'subscriptions.yaml' by default

Support for adding video metadata to be consumed by Plex

For adding personal video media to plex:

Some video filetypes (e.g. MP4, M4V, MOV) allow you to embed metadata within the file. If your files have embedded metadata, that information can be used. To do so, ensure that the Local Media Assets source is enabled and ordered correctly.

(source: https://support.plex.tv/articles/200265246-personal-media-movies/)

I do not use Plex and am not familiar with this process whatsoever. If anyone has done this before and could provide some insight, that would be great.

Add batch download support for youtube channel and playlist

For massive downloads of videos from channels or playlists, we should support batch downloading out of the box.

For playlists, batch by index. For channels, batch by date interval (day, week, month).
For each batch, process all the files end-to-end. This can be done by invoking download multiple times using different yt-dlp args for rejecting videos that are not in the range.

Add youtube.download_strategy "multi_channels"

example_preset:
  youtube:
    download_strategy: "multi_channels"
    multi:
      "First playlist": https://youtube.com/...
      "Second playlist": https://.....
  ...
  output_options:
    file_name: "s{multi_idx_padded}e{upload_year}{upload_month_padded}{upload_day_padded}.{ext}"
  output_nfo_directory:
    include_named_seasons: True

Add youtube.download_strategy "multi_channels_from_playlist"

example_preset:
  youtube:
    download_strategy: "multi_channels"
    multi:
      "First channel": https://youtube.com/...
      "Second channel": https://.....
  ...

should be equivalent to

example_preset:
  youtube:
    download_strategy: "multi_channels_from_playlist"
    playlist: https://youtube.com/...
  ...

where each unique channel in the playlist is an additional channel entry

Add youtube.download strategy "multi_playlists"

example_preset:
  youtube:
    download_strategy: "multi_playlists"
    multi:
      "First playlist": https://youtube.com/...
      "Second playlist": https://.....
  ...
  output_options:
    file_name: "s{multi_idx_padded}e{playlist_idx}.{ext}"
  output_nfo_directory:
    include_named_seasons: True

Add proper logger

Currently all logging is done with prints and with # TODO comments above them. We should instead use a proper logger, but also make sure it prints pretty. It should look similar to YTDL's logger:

[post-process] Moving file to ...
[plugin:music_tags] Tag 'track_number' not supported. Available tags: ....

Create aliases for the `dl` command within the configuration

It would be nice for the config to offer something like

configuration:
  dl_aliases:
    mv: "--preset yt_music_video"
    v: "--youtube.video_url"
    p: "--youtube.playlist_url"
    artist: "--overrides.artist"

to convert this long command

ytdl-sub dl --preset yt_music_video --youtube.video_id https://youtube.com/... --overrides.artist "Tom Petty"

to this

ytdl-sub dl --mv --v https://youtube.com/... --artist 'Tom Petty'

Windows support

Would need to update all path logic for windows-compatible file paths and make ytdl-sub an executable. Hoping a windows scripting god could drive and own this.

The current workaround is use WSL.

Error with Youtube archive when no videos are within the requested timeframe

I've let ytdl-sub run for some channels but it errors out when a specific channel does not have a video within the requested timerange. In config.yaml the default 2 weeks were configured:

configuration:
  working_directory: '/media/youtube/.cache'

presets:
  yt_channel_as_tv:
    # YouTube channels are our source/download strategy
    # Use the channel avatar and banner images for Kodi
    youtube:
      download_strategy: "channel"
      channel_avatar_path: "poster.jpg"
      channel_banner_path: "fanart.jpg"
      after: "today-2weeks"

Normally the archive file is created when processing a channel.

Log output:

[ytdl-sub:yt-dlp] [download] 2022-04-06 upload date is not in range 2022-06-16 - 9999-12-31
[ytdl-sub:downloader] RejectedVideoReached, stopping additional downloads
[ytdl-sub] An uncaught error occurred:
Traceback (most recent call last):
  File "/ytdl-sub/src/ytdl_sub/main.py", line 95, in main
    _main()
  File "/ytdl-sub/src/ytdl_sub/main.py", line 78, in _main
    _download_subscriptions_from_yaml_files(config=config, args=args)
  File "/ytdl-sub/src/ytdl_sub/main.py", line 33, in _download_subscriptions_from_yaml_files
    subscription.download()
  File "/ytdl-sub/src/ytdl_sub/subscriptions/subscription.py", line 262, in download
    with self._prepare_working_directory(), self._maintain_archive_file():
  File "/usr/lib/python3.10/contextlib.py", line 142, in __exit__
    next(self.gen)
  File "/ytdl-sub/src/ytdl_sub/subscriptions/subscription.py", line 234, in _maintain_archive_file
    self._enhanced_download_archive.save_download_mappings()
  File "/ytdl-sub/src/ytdl_sub/ytdl_additions/enhanced_download_archive.py", line 489, in save_download_mappings
    self._download_archive = DownloadArchive.from_file(self._archive_working_file_path)
  File "/ytdl-sub/src/ytdl_sub/ytdl_additions/enhanced_download_archive.py", line 100, in from_file
    with open(file_path, "r", encoding="utf8") as file:
FileNotFoundError: [Errno 2] No such file or directory: '/media/youtube/.cache/yt_tokyolensexplore/.ytdl-subscribe-yt_tokyolensexplore-download-archive.txt'

Add e2e tests using the examples folder as configs

Anything shown as an example should be tested. Hit two birds with one stone by having ytdl-sub e2e tests use each one as its config.yaml, perform a download, then check file md5 hashes to see if they match the expected hash.

REST server to invoke ytdl-sub downloads

The dream will be to create mobile apps or browser extensions to invoke downloads from the couch. Once the server and API is written, the short-term plan could be to self-host a swaggerhub io instance and invoke the rest api from the browser.

Create a flask server that is able to handle requests in a format like this:

curl -X POST -H "Content-type: application/json"                \
    -d '{                                                       \
        "soundcloud.username": "alis_on",                       \
        "overrides.artist": "A.L.I.S.O.N.",                     \
        "overrides.genre": "Synthwave;Electronic;Instrumental"  \
    }'                                                          \
    'localhost:8080/soundcloud_discography'

The endpoint being the preset, and the payload including any overrides as a single-level dict

Add Github hooks for CI/CD

This one is on me to do. Add hooks for

  1. Building the package
  2. Running the linter
  3. Running unit tests
  4. Running e2e tests
  5. (stretch) Building the docker image

Add default `ytdl_options` and `output_options` for certain download_strategy

Youtube channel + playlist should include

ytdl_options:
  breakonexisting: True 
  breakonreject: True
output_options:
  maintain_download_archive: True  # global default False

Soundcloud discography should include

output_options:
  maintain_download_archive: True 

by default, and have this documented in the download strategy section.

This should help reduce YAML redundancy for fields that will most likely always be enabled for particular download strategies.

Support for arm64/raspberry

Can you build the container for arm64 as well? Then it can directly run on raspberry pi using docker.
I've tried building the container locally and needed some more packages (zlib-dev jpeg-dev python3-dev libwebp-dev) in order to install the Pillow requirements, but otherwise it seems to be running without issues.

You should be able to use docker buildx to create both amd64 and arm64 builds in a single step and push the manifest to the repo.

Support links for source fields

All download strategy source fields (youtube.channel_id, youtube.video_id, etc) should support partial and full URL links,
i.e.

# only youtube
youtube.com/channel/tHe_ID

# https youtube
https://youtube.com/channel/tHe_ID

# www youtube
www.youtube.com/channel/tHe_ID

# https + www youtube
https://www.youtube.com/channel/tHe_ID

# only the ID
tHe_ID

A unit test should be written to support each case

Add plugin to capture string from the title via regex

my_preset:
  regex_capture:
    title:
      fail_if_not_captured: True  # or False, if all captures fail, fallback to original value of title
      capture:  # List of regex captures to try
      - "(.+) - (.+) [\[\(].*"
      - "(.+) - (.+)"

This would regex capture "Artist" and "Cool Song" from "Artist - Cool Song (Official Video)" into new source variables title_capture_1 and title_capture_2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.