pinchflat icon indicating copy to clipboard operation
pinchflat copied to clipboard

[FR] Organize folders according to playlists?

Open lightsout opened this issue 1 year ago • 7 comments

Is your feature request related to a problem? Please describe. Dumping a whole channel into one folder can be difficult to navigate for playback with many files.

Describe the solution you'd like I would like to setup pinchflat to organize videos according to playlist in their own folder.

Describe alternatives you've considered I have tried a media profile with this command. Videos/{{ channel }}/{{ playlist_title }}/{{ upload_yyyy_mm_dd }} {{ title }}/{{ upload_yyyy_mm_dd }} {{ title }}.{{ ext }}

I don't get playlist folders but instead everything dumps into a folder titled "NA". So close but not quite there.

Additional context I would rather not have a "source" for every playlist as some channels have many playlists. But I know this could be an option.

lightsout avatar Jul 18 '24 18:07 lightsout

Hey there! Thanks for the report (:

Unfortunately, this isn't possible at current. There's two main reasons for that:

  1. yt-dlp does not (and cannot) return details about what playlist(s) a video belongs to when it's scraping the channel uploads
  2. (related to the above) one video can belong to multiple different channel playlists, so even if yt-dlp could return which playlists a video is in, it wouldn't provide a mechanism to determine which one to use.

For now the only way to do it would be through multiple sources. I have recently improved the workflow for adding multiple sources and I've highlighted it here.


That said, I totally get where you're coming from. I've heard people request this a few times and there might be a way to automatically create sources for each playlist belonging to a channel, but that's a complex feature that would likely not happen any time super soon.

I'll leave this issue open as a reminder-to-self in the meantime!

kieraneglin avatar Jul 18 '24 18:07 kieraneglin

Note to self:

I think I can pull a channel's playlists with something like this:

yt-dlp -ij --flat-playlist "https://www.youtube.com/<channel name>/playlists" | jq -r '.webpage_url'

But I remember there being some weirdness with playlist tabs so I may have to append ?view=1 to the URL

kieraneglin avatar Jul 18 '24 18:07 kieraneglin

Hey there! Thanks for the report (:

Unfortunately, this isn't possible at current. There's two main reasons for that:

1. `yt-dlp` does not (and cannot) return details about what playlist(s) a video belongs to when it's scraping the channel uploads

2. (related to the above) one video can belong to multiple different channel playlists, so even if `yt-dlp` could return which playlists a video is in, it wouldn't provide a mechanism to determine which one to use.

For now the only way to do it would be through multiple sources. I have recently improved the workflow for adding multiple sources and I've highlighted it here.

That said, I totally get where you're coming from. I've heard people request this a few times and there might be a way to automatically create sources for each playlist belonging to a channel, but that's a complex feature that would likely not happen any time super soon.

I'll leave this issue open as a reminder-to-self in the meantime!

Thanks for the quick reply, that template feature is helpful.

I have a .bat file that someone made and gave me on the emby forum. It is made to subscribe to channels and download them in a way that they will show up like TV shows in Emby. It is not perfect, and like you said I am not sure how it handles the problem of videos in multiple playlists, but it does work pretty good. I will share the command here, FYI I have no idea how to write by own .bat and regex type stuff is greek to me. But I'm sure it will make more sense to you.

"!AppFolder!yt-dlp.exe" -S "height:!Resolution!" -o "!ChannelDirLocation!\%%(playlist)s\%%(playlist_index)s - %%(title)s.%%(ext)s" --convert-thumbnails png --write-thumbnail -o "thumbnail:!ChannelDirLocation!\%%(playlist)s\%%(playlist)s.%%(ext)s" --windows-filenames --merge-output-format mkv --remux-video mkv !ChannelName!/playlists --embed-chapters --embed-metadata --ignore-errors --download-archive "!ChannelDirLocation!\!ArchiveName!"

Not sure if that means anything but it seems to work decently.

lightsout avatar Jul 18 '24 19:07 lightsout

Would you all make your own playlists of content you want downloaded and then use this feature to organize folders?

I had similar idea but maybe its too different to be in this thread. My idea was being able to filter a channel - for example - I have a college sports channel and I want just the content that matches the word "football" so that it doesn't download all the basketball games on this channel, as an example.

Austin1 avatar Oct 16 '24 02:10 Austin1

My idea was being able to filter a channel

@Austin1 you can already do that (see here)! Creating a title regex like (?i)football would be the most basic example

kieraneglin avatar Oct 21 '24 17:10 kieraneglin

Ahhhh, I read this but somehow missed that bullet. Sweet!

On Mon, Oct 21, 2024, 12:57 PM Kieran @.***> wrote:

My idea was being able to filter a channel

@Austin1 https://github.com/Austin1 you can already do that (see here https://github.com/kieraneglin/pinchflat/wiki/Frequently-Asked-Questions#i-only-want-certain-videos-from-a-source---how-can-i-only-download-those)! Creating a title regex like (?i)football would be the most basic example

— Reply to this email directly, view it on GitHub https://github.com/kieraneglin/pinchflat/issues/328#issuecomment-2427370693, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACTLIHPCMRF5ZDDSQV43QDZ4U6BXAVCNFSM6AAAAABLDGYUUGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIMRXGM3TANRZGM . You are receiving this because you were mentioned.Message ID: @.***>

Austin1 avatar Oct 21 '24 20:10 Austin1

On my end, for a script I made, I chose to download all the channel videos in a single folder, then I create additional folders for the playlists, and finally I populate those playlist folder with shortcuts (that use relative path) to the videos.

I chosed this way because some video were in multiple playlist and some video were not in any playlist.

Watch out to also double check that the video exist in the "main" folder. Because I also got some occurence (rare) of video not in the /videos of the channel, but in a playlist.

Here some code example (simplified with no error handling), and probably not the best way to do it, it's just an example based on my quick and dirty script ;)

from functools import lru_cache
import yt_dlp

@lru_cache(maxsize=None)
def get_jsons(cookiefile, url):
    ydl_opts = {
        'quiet': True,
        'ignoreerrors': True,
        'cookiefile': cookiefile
    }
    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        data = ydl.extract_info(url, download=False)
    return data

@lru_cache(maxsize=1000)
def get_all_video_info(_format, outtmpl, id):
    ydl = yt_dlp.YoutubeDL(
        {
            'format': _format,
            'outtmpl': outtmpl,
            'quiet': True,
            'ignoreerrors': True
        }
    )
    url = f"https://www.youtube.com/watch?v={id}"
    info = ydl.extract_info(url, download=False)
    return info, ydl

def get_video_info(ydl_opts, _id):
    _format = ydl_opts.get('format')
    try:  # when I skip the download phase, it's a string. Otherwise it's a dict
        outtmpl = ydl_opts.get('outtmpl').get('default')
    except AttributeError:
        outtmpl = ydl_opts.get('outtmpl')
    _, outtmpl_filename = os.path.split(outtmpl)
    video_info, ydl = get_all_video_info(_format, outtmpl_filename, _id)
    filename = ydl.prepare_filename(video_info)
    filename = replace_illegal_chars_from_string(filename)
    return video_info, filename

def replace_illegal_chars_from_string(s, replace_char="-"):
    # Replace Windows & Linux illegal characters (for files and folders)
    s = re.sub(r'[\\/:*?"<>|]', replace_char, s)
    return s

def download_channel_playlists(config, ydl_opts):
    channel_data = get_jsons(ydl_opts.get('cookiefile'), config.playlists_URL)
    for playlist_data in channel_data["entries"]:
        url = playlist_data["webpage_url"]
        if "&sort=" in url or "&shelf_id=" in url:
            raise Exception("Change playlist URL to .../playlists?view=1")
        playlist_name = playlist_data["title"]
        playlist_name = replace_illegal_chars_from_string(playlist_name)  # I use this name to create a folder
        ids = [i["id"] for i in playlist_data["entries"] if i]  # video ids
        # here I do some validation to find out if it's a video that need to downloaded
        ...
        # I also create the shortcut, do to so I get the same filename that yt-dlp use to create the video
        video_info, _filename = get_video_info(ydl_opts, _id)
        filename, _ = os.path.splitext(_filename)

def main():
    ...
    download_channel_playlists(config, ydl_opts)
    ...

benbou8231 avatar Nov 03 '24 00:11 benbou8231