diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | README.md | 11 | ||||
| -rwxr-xr-x | youtube-to-xspf.py | 63 | 
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 @@ -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()
 | 
