diff options
| author | 2015-10-11 17:54:06 +0200 | |
|---|---|---|
| committer | 2015-10-11 17:54:56 +0200 | |
| commit | a7fe15b99d64904855ba2bd3649b1a3642824a75 (patch) | |
| tree | 35c2da4777ffcbd1b6fb661227af8a6528646030 | |
| parent | f1ddf104809017784aa136ebb8ff7e2cfb96d5f4 (diff) | |
| download | youtube-podcaster-a7fe15b99d64904855ba2bd3649b1a3642824a75.tar.gz youtube-podcaster-a7fe15b99d64904855ba2bd3649b1a3642824a75.tar.bz2 youtube-podcaster-a7fe15b99d64904855ba2bd3649b1a3642824a75.zip | |
Can actually be installed with setup.py now
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | setup.cfg | 2 | ||||
| -rw-r--r-- | youtube_podcaster/__init__.py | 28 | ||||
| -rw-r--r-- | youtube_podcaster/__main__.py | 8 | ||||
| -rw-r--r-- | youtube_podcaster/podcastfeeder.py | 43 | ||||
| -rw-r--r--[-rwxr-xr-x] | youtube_podcaster/podcastupdater.py (renamed from youtube_podcaster/youtube-podcaster) | 81 | ||||
| -rw-r--r-- | youtube_podcaster/youtube/__init__.py | 4 |
7 files changed, 103 insertions, 69 deletions
| @@ -39,3 +39,9 @@ docs/api/* | |||
| 39 | docs/_build/* | 39 | docs/_build/* |
| 40 | cover/* | 40 | cover/* |
| 41 | MANIFEST | 41 | MANIFEST |
| 42 | |||
| 43 | # Outputted files by youtube-podcaster | ||
| 44 | *.xml | ||
| 45 | *.save | ||
| 46 | downloads/ | ||
| 47 | youtube-podcaster.json | ||
| @@ -13,6 +13,8 @@ classifiers = Development Status :: 3 - Alpha, | |||
| 13 | Programming Language :: Python :: 3 :: Only | 13 | Programming Language :: Python :: 3 :: Only |
| 14 | 14 | ||
| 15 | [entry_points] | 15 | [entry_points] |
| 16 | console_scripts = | ||
| 17 | youtube-podcaster = youtube_podcaster:main | ||
| 16 | # Add here console scripts like: | 18 | # Add here console scripts like: |
| 17 | # console_scripts = | 19 | # console_scripts = |
| 18 | # hello_world = youtube_podcaster.module:function | 20 | # hello_world = youtube_podcaster.module:function |
diff --git a/youtube_podcaster/__init__.py b/youtube_podcaster/__init__.py new file mode 100644 index 0000000..32aee7c --- /dev/null +++ b/youtube_podcaster/__init__.py | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | |||
| 3 | import json | ||
| 4 | |||
| 5 | from http.server import ( | ||
| 6 | HTTPServer, | ||
| 7 | ) | ||
| 8 | |||
| 9 | from . import ( | ||
| 10 | youtube, | ||
| 11 | ) | ||
| 12 | |||
| 13 | from .podcastfeeder import ( | ||
| 14 | create_feeder | ||
| 15 | ) | ||
| 16 | |||
| 17 | |||
| 18 | def main(): | ||
| 19 | config = json.load(open("youtube-podcaster.json")) | ||
| 20 | |||
| 21 | try: | ||
| 22 | PodcastFeeder = create_feeder(config["youtube"], config["podcasts"]) | ||
| 23 | server = HTTPServer(("", 8888), PodcastFeeder) | ||
| 24 | server.serve_forever() | ||
| 25 | except KeyboardInterrupt: | ||
| 26 | server.socket.close() | ||
| 27 | |||
| 28 | # vim: set ts=8 sw=4 tw=0 et : | ||
diff --git a/youtube_podcaster/__main__.py b/youtube_podcaster/__main__.py new file mode 100644 index 0000000..941a79a --- /dev/null +++ b/youtube_podcaster/__main__.py | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | |||
| 3 | import youtube_podcaster | ||
| 4 | |||
| 5 | if __name__ == "__main__": | ||
| 6 | youtube_podcaster.main() | ||
| 7 | |||
| 8 | # vim: set ts=8 sw=4 tw=0 et : | ||
diff --git a/youtube_podcaster/podcastfeeder.py b/youtube_podcaster/podcastfeeder.py new file mode 100644 index 0000000..3f752d2 --- /dev/null +++ b/youtube_podcaster/podcastfeeder.py | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | from http.server import BaseHTTPRequestHandler | ||
| 2 | |||
| 3 | from .podcastupdater import ( | ||
| 4 | PodcastUpdater | ||
| 5 | ) | ||
| 6 | |||
| 7 | |||
| 8 | def create_feeder(youtube_config, podcast_config): | ||
| 9 | class PodcastFeeder(BaseHTTPRequestHandler): | ||
| 10 | def __init__(self, request, client_address, server): | ||
| 11 | self.updater = PodcastUpdater(youtube_config, podcast_config) | ||
| 12 | super(PodcastFeeder, self).__init__(request, client_address, server) | ||
| 13 | |||
| 14 | def do_GET(self): | ||
| 15 | path = self.path.split('/') | ||
| 16 | |||
| 17 | if len(path) == 3: | ||
| 18 | channel = path[1] | ||
| 19 | playlist = path[2] | ||
| 20 | else: | ||
| 21 | return self.return_error(404) | ||
| 22 | |||
| 23 | xml = self.updater.get_xml(channel, playlist) | ||
| 24 | |||
| 25 | if not xml: | ||
| 26 | return self.return_error(404) | ||
| 27 | else: | ||
| 28 | self.send_response(200) | ||
| 29 | self.send_header("Content-type", "text/xml") | ||
| 30 | self.end_headers() | ||
| 31 | self.wfile.write(bytes(xml, 'UTF-8')) | ||
| 32 | |||
| 33 | def return_error(self, code): | ||
| 34 | self.send_response(code) | ||
| 35 | self.send_header("Content-type", "text/html") | ||
| 36 | self.end_headers() | ||
| 37 | |||
| 38 | reponse = "<body>Error: %s</body>" % (code) | ||
| 39 | self.wfile.write(bytes(reponse, 'UTF-8')) | ||
| 40 | |||
| 41 | return PodcastFeeder | ||
| 42 | |||
| 43 | # vim: set ts=8 sw=4 tw=0 et : | ||
diff --git a/youtube_podcaster/youtube-podcaster b/youtube_podcaster/podcastupdater.py index bb2db26..4a0a017 100755..100644 --- a/youtube_podcaster/youtube-podcaster +++ b/youtube_podcaster/podcastupdater.py | |||
| @@ -1,29 +1,19 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | import time | ||
| 3 | import os | ||
| 4 | import pickle | 1 | import pickle |
| 5 | import json | 2 | import os |
| 6 | 3 | import time | |
| 7 | from http.server import HTTPServer, BaseHTTPRequestHandler | 4 | import hashlib |
| 8 | from hashlib import sha1 | ||
| 9 | 5 | ||
| 10 | from feedgen.feed import FeedGenerator | 6 | from feedgen.feed import FeedGenerator |
| 11 | 7 | ||
| 12 | import youtube | 8 | from . import ( |
| 9 | youtube, | ||
| 10 | ) | ||
| 13 | 11 | ||
| 14 | 12 | ||
| 15 | class PodcastUpdater: | 13 | class PodcastUpdater: |
| 16 | instance = None | 14 | def __init__(self, youtube_config, podcast_config): |
| 17 | 15 | self.podcasts = podcast_config | |
| 18 | def get_instance(): | 16 | self.youtube = youtube.Youtube(youtube_config["api-key"]) |
| 19 | if PodcastUpdater.instance: | ||
| 20 | return PodcastUpdater.instance | ||
| 21 | else: | ||
| 22 | PodcastUpdater.instance = PodcastUpdater() | ||
| 23 | return PodcastUpdater.instance | ||
| 24 | |||
| 25 | def __init__(self): | ||
| 26 | self.podcasts = config["podcasts"] | ||
| 27 | 17 | ||
| 28 | self.feeds_file = "feeds.save" | 18 | self.feeds_file = "feeds.save" |
| 29 | if os.path.isfile(self.feeds_file): | 19 | if os.path.isfile(self.feeds_file): |
| @@ -51,9 +41,9 @@ class PodcastUpdater: | |||
| 51 | return open(xml).read() | 41 | return open(xml).read() |
| 52 | 42 | ||
| 53 | def update_podcast(self, channel, playlist): | 43 | def update_podcast(self, channel, playlist): |
| 54 | feed_id = sha1(bytes("%s %s" % (channel, playlist), "UTF-8")).hexdigest() | 44 | feed_id = hashlib.sha1(bytes("%s %s" % (channel, playlist), "UTF-8")).hexdigest() |
| 55 | yt_channel = yt.get_channel(channel)[0] | 45 | yt_channel = self.youtube.get_channel(channel)[0] |
| 56 | yt_playlists = yt.get_playlists(yt_channel, 50) | 46 | yt_playlists = self.youtube.get_playlists(yt_channel, 50) |
| 57 | 47 | ||
| 58 | for yt_playlist in yt_playlists: | 48 | for yt_playlist in yt_playlists: |
| 59 | if yt_playlist["snippet"]["title"] == playlist: | 49 | if yt_playlist["snippet"]["title"] == playlist: |
| @@ -92,12 +82,12 @@ class PodcastUpdater: | |||
| 92 | return feed | 82 | return feed |
| 93 | 83 | ||
| 94 | def populate_feed(self, feed, feed_id, yt_playlist, max_results=5): | 84 | def populate_feed(self, feed, feed_id, yt_playlist, max_results=5): |
| 95 | videos = yt.get_playlist_items(yt_playlist, max_results) | 85 | videos = self.youtube.get_playlist_items(yt_playlist, max_results) |
| 96 | downloader = youtube.Downloader.get_instance("vorbis", "downloads", "192.168.178.100") | 86 | downloader = youtube.Downloader.get_instance("vorbis", "downloads", "192.168.178.100") |
| 97 | 87 | ||
| 98 | entries = feed.entry() | 88 | entries = feed.entry() |
| 99 | for video in videos: | 89 | for video in videos: |
| 100 | video_id = sha1(bytes(video["id"], "UTF-8")).hexdigest() | 90 | video_id = hashlib.sha1(bytes(video["id"], "UTF-8")).hexdigest() |
| 101 | for entry in entries: | 91 | for entry in entries: |
| 102 | if entry.id() == video_id: | 92 | if entry.id() == video_id: |
| 103 | break | 93 | break |
| @@ -113,47 +103,4 @@ class PodcastUpdater: | |||
| 113 | 103 | ||
| 114 | feed.last_updated = time.time() | 104 | feed.last_updated = time.time() |
| 115 | 105 | ||
| 116 | |||
| 117 | class PodcastFeeder(BaseHTTPRequestHandler): | ||
| 118 | def do_GET(self): | ||
| 119 | updater = PodcastUpdater.get_instance() | ||
| 120 | path = self.path.split('/') | ||
| 121 | |||
| 122 | if len(path) == 3: | ||
| 123 | channel = path[1] | ||
| 124 | playlist = path[2] | ||
| 125 | else: | ||
| 126 | return self.return_error(404) | ||
| 127 | |||
| 128 | xml = updater.get_xml(channel, playlist) | ||
| 129 | |||
| 130 | if not xml: | ||
| 131 | return self.return_error(404) | ||
| 132 | else: | ||
| 133 | self.send_response(200) | ||
| 134 | self.send_header("Content-type", "text/xml") | ||
| 135 | self.end_headers() | ||
| 136 | self.wfile.write(bytes(xml, 'UTF-8')) | ||
| 137 | |||
| 138 | def return_error(self, code): | ||
| 139 | self.send_response(code) | ||
| 140 | self.send_header("Content-type", "text/html") | ||
| 141 | self.end_headers() | ||
| 142 | |||
| 143 | reponse = "<body>Error: %s</body>" % (code) | ||
