meeb / tubesync

Syncs YouTube channels and playlists to a locally hosted media server
GNU Affero General Public License v3.0
1.9k stars 121 forks source link

Can't use directories in media/directory paths? {playlist_title} not working #511

Open joestump opened 3 months ago

joestump commented 3 months ago

I've started using TubeSync and am wondering the best way to map the library. I've started with marking it as a Shows library, which results in everything being grouped as a single season. Ideally, I would playlists as seasons, but I can't seem to get that working.

I've tried two things:

{playlist_title}/{yyyymmdd}_{title}_[{key}]_{format}.{ext} as the Media Format, but this resulted in the following error:

common.errors.DownloadFailedException: Failed to download media: 6Aey0YFYjbQ (UUID: 8af9b6dd-aa99-4a82-b0af-1d8bafb78f34) to disk, expected outfile does not exist: /20230825_i-turned-my-steam-deck-into-a-powerful-home-server_[6Aey0YFYjbQ]_1080p-vp9-opus-60fps.mkv

It appears to not like / in the media format.

Next I tried adding {playlist_title} to the Directory - e.g. hardwarehaven/{playlist_title}, but it appears that field doesn't get rendered through a template.

Any pointers on mapping playlists to seasons?

joestump commented 3 months ago

Looks like Media formats the directory_path in a way that this should work: https://github.com/meeb/tubesync/blob/e3b5d63501a0a8e2fffac64ee1a48b9a69421d3e/tubesync/sync/models.py#L1227

But looks like the Source module has slightly different logic? https://github.com/meeb/tubesync/blob/e3b5d63501a0a8e2fffac64ee1a48b9a69421d3e/tubesync/sync/models.py#L478-L481

joestump commented 3 months ago

Okay, I think I see what's going on here. The task uses media.filepath, which returns return self.source.directory_path / self.filename, which is the unformatted Source.directory_path I referenced above.

Should line 1232 in models.py just be self.directory_path instead of self.source.directory_path?

meeb commented 2 months ago

The source directory_path (which is just media_file_storage.location with video or audio as a sub-directory) doesn't support formatting. Currently, there isn't a way to ad-hoc create directories by adding / into the media format. Getting show / season information into Plex can be irritating. There's some plugins that can read the NFO file data, but since Plex removed plugin support this is pretty hacky. Personally, I just browse the library as folders.

joestump commented 2 months ago

@meeb would you accept a PR that added this support to media_format? I tested it out and this does appear (in Jellyfin anyways) that playlists would show up as seasons if they were sub-folders under the videos/$channel folder.

meeb commented 2 months ago

Absolutely, very happy to accept any well formatted PRs. Tests where appropriate and no regressions / full compatibility with current behavior will help it get merged quickly.

Edit: and thanks for the offer!

joestump commented 2 months ago

@meeb I'll take a look. Which route would you prefer I go?

  1. Update media_format so it'll work with /'s in it.
  2. Update directory_path so that it'll work with the same formatting options?
meeb commented 2 months ago

Almost certainly editing media_format would be more sensible and not split logic up. You probably don't need to do a great deal here given pathlib supports strings with / in to mean subdirectories:

>>> from pathlib import Path
>>> p = Path('/some/basepath')
>>> media_format = 'some/example/file.ext'
>>> p / media_format
PosixPath('/some/basepath/some/example/file.ext')

An appropriately placed somepath.mkdir(parents=True, exist_ok=True) and a check it's all working as expected is likely sufficient. I'm assuming the only reason the yt-dlp call to download the media item fails is because the sub-directory doesn't exist so once that's created downloads should generally just work in theory.

joestump commented 2 months ago

@meeb was looking into this today over my morning ☕ and found this test, which does indeed pass:

https://github.com/meeb/tubesync/blob/main/tubesync/sync/tests.py#L591-L594

Not sure why the test passes, but we're getting the error.

meeb commented 2 months ago

Honestly it's entirely possible I added sub-directory support as a feature a year or two ago and forgot about it, sorry!

I've just re-read your original message and I've just noticed the output path. Your issue might be something else. Your {playlist_title} is resolving to '' which means your media path is actually just /{yyyymmdd}_{title}_[{key}]_{format}.{ext} which is confirmed in your error message:

common.errors.DownloadFailedException: Failed to download media: 6Aey0YFYjbQ (UUID: 8af9b6dd-aa99-4a82-b0af-1d8bafb78f34) to disk, expected outfile does not exist: /20230825_i-turned-my-steam-deck-into-a-powerful-home-server_[6Aey0YFYjbQ]_1080p-vp9-opus-60fps.mkv

Sorry I hadn't had my coffee and missed the path. This should be /downloads/video/source-name/20230825_i-turned-my-steam-deck-into-a-powerful-home-server_[6Aey0YFYjbQ]_1080p-vp9-opus-60fps.mkv. With the playlist title being empty pathlib will just assume a root URL and squash the prefix directory:

>>> from pathlib import Path
>>> p = Path('/download/path')
>>> p / 'valid/dir'
PosixPath('/download/path/valid/dir')
>>> p / '/invalid/path/with/root/slash'
PosixPath('/invalid/path/with/root/slash')

Obviously writing to / is going to fail, which is why your download doesn't work.

So, I think the actual issue is {playlist_title} being empty. Also this could do with a check that the formatted media_path doesn't start with a / to catch this most likely.

joestump commented 2 months ago

So, I think the actual issue is {playlist_title} being empty.

I think you're correct. {playlist_title} is empty, even when I explicitly use a playlist for a source. I've tried both with and without the / at the front of the media_path and it's empty regardless:

2024-07-13 18:09:15,006 [tubesync/INFO] Downloading media: -TZ-pzLXFhk (UUID: f35e3284-0d31-4f15-978e-0c09bf93c3df) to: "//2023-01-28_serpadesign-animal-room_the-real-story-behind-my-new-animal-room-its-done_[-TZ-pzLXFhk]_1080p-vp9-opus.mkv"

I've also tried {playlist_title} without any / at all and it fails to populate. What should we look at next?

meeb commented 2 months ago

{playlist_title} is populated from metadata when available from YouTube. This has changed several times over the years, and it appears that {playlist_title} isn't available now. I'll remove it in the next release and check in a few months to see if it's appeared again. Your best bet now is just to set the playlist directory manually:

my-playlist-name/{yyyymmdd}_{title}_[{key}]_{format}.{ext}