From 859fed4650b4c750e24631128c2bc2c0afac6dcb Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Wed, 9 Sep 2020 22:13:31 -0500 Subject: Add main file --- .gitignore | 2 ++ README.md | 11 +++++++++- youtube-to-xspf.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100755 youtube-to-xspf.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b089f27 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +subscription_manager.xml +subscriptions.xspf diff --git a/README.md b/README.md index 98c738c..6c60e84 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ # youtube-subscriptions-xspf -Creates an xspf file to watch youtube videos in your favorite media player. \ No newline at end of file +Creates an xspf file to watch youtube videos in your favorite media player. + +## Dependencies +requests +bs4 (beautiful soup) + +## Usage +Download your youtube subscriptions xml file from [here](https://www.youtube.com/subscription_manager). +Then run youtube-to-xspf.py to generate the playlist file subscriptions.xspf, which can be opened in VLC. +You can sort by Album to arrange by date uploaded. diff --git a/youtube-to-xspf.py b/youtube-to-xspf.py new file mode 100755 index 0000000..a91d935 --- /dev/null +++ b/youtube-to-xspf.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 + +import sys, datetime, re, itertools, multiprocessing, html, threading +import requests +from bs4 import BeautifulSoup + +subscriptions = [] +with open("subscription_manager.xml") as f: + subs = BeautifulSoup(f.read(), "xml") + for sub in subs.find_all("outline"): + if "xmlUrl" in sub.attrs: + subscriptions.append(sub["xmlUrl"]) + +def get_videos(channel): + tracks = [] + print ("=", end="", flush=True) + r = requests.get(channel) + updates = BeautifulSoup(r.text.encode(sys.stdout.encoding, errors='replace'), "xml") + for entry in updates.find_all("entry")[:3]: + if entry.title and entry.link: + item = {} + item["title"] = html.escape(entry.title.string if entry.title.string else "") + item["link"] = entry.link["href"] + item["channel"] = html.escape(entry.author.find("name").string) + date_string = entry.published.string.split("T")[0] + item["date"] = date_string + date = datetime.datetime.strptime(date_string, "%Y-%m-%d") + today = datetime.datetime.today() + margin = datetime.timedelta(days = 7) + if today-margin <= date: + tracks.append(item) + return tracks + +def get_entry(item, index): + string = ("\t\n\t\t"+item["link"]+"\n" + + "\t\t"+item["title"]+ "\n" + + "\t\t" + item["channel"] + "\n" + + "\t\t" + item["date"] + "\n" + + "\t\n") + return re.sub(r'[^\x00-\x7F]+',' ', string) + +def main(): + tracks = [] + with multiprocessing.Pool(4) as p: + print("[ " + " "*len(subscriptions)+ "]",end="\r[=", flush=True) + videos = p.map(get_videos, subscriptions) + tracks = list(itertools.chain.from_iterable(videos)) + print() + + with open("subscriptions.xspf", "w") as f: + file_tail = '\n' + f.write(''' + + Subscriptions + \n''') + for item in enumerate(tracks): + f.write(get_entry(item[1], item[0])) + file_tail += '\n' + f.write(file_tail) + print("Done") + +if __name__ == '__main__': + main() -- cgit v1.2.3