aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md11
-rwxr-xr-xyoutube-to-xspf.py63
3 files changed, 75 insertions, 1 deletions
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<track>\n\t\t<location>"+item["link"]+"</location>\n" +
+ "\t\t<title>"+item["title"]+ "</title>\n" +
+ "\t\t<creator>" + item["channel"] + "</creator>\n" +
+ "\t\t<album>" + item["date"] + "</album>\n" +
+ "\t</track>\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 = '</trackList>\n'
+ f.write('''<?xml version="1.0" encoding="UTF-8"?>
+ <playlist xmlns="http://xspf.org/ns/0/" xmlns:vlc="http://www.videolan.org/vlc/playlist/ns/0/" version="1">
+ <title>Subscriptions</title>
+ <trackList>\n''')
+ for item in enumerate(tracks):
+ f.write(get_entry(item[1], item[0]))
+ file_tail += '</playlist>\n'
+ f.write(file_tail)
+ print("Done")
+
+if __name__ == '__main__':
+ main()