aboutsummaryrefslogtreecommitdiffstats
path: root/youtube_podcaster
diff options
context:
space:
mode:
Diffstat (limited to 'youtube_podcaster')
-rw-r--r--youtube_podcaster/__init__.py44
-rw-r--r--youtube_podcaster/__main__.py8
-rw-r--r--youtube_podcaster/config.py64
-rw-r--r--youtube_podcaster/podcastfeeder.py4
-rw-r--r--youtube_podcaster/podcastupdater.py34
-rw-r--r--youtube_podcaster/youtube-podcaster.json.sample10
-rw-r--r--youtube_podcaster/youtube/downloader.py23
7 files changed, 135 insertions, 52 deletions
diff --git a/youtube_podcaster/__init__.py b/youtube_podcaster/__init__.py
index 32aee7c..77ab9cc 100644
--- a/youtube_podcaster/__init__.py
+++ b/youtube_podcaster/__init__.py
@@ -1,27 +1,47 @@
1#!/usr/bin/env python3 1#!/usr/bin/env python3
2 2
3import json 3import argparse
4 4
5from http.server import ( 5from http.server import HTTPServer
6 HTTPServer,
7)
8 6
9from . import ( 7from .podcastfeeder import create_feeder
10 youtube, 8from .config import (
9 Config,
10 ConfigException
11) 11)
12 12
13from .podcastfeeder import ( 13"""
14 create_feeder 14Start the program
15) 15"""
16 16
17 17
18def main(): 18def main():
19 config = json.load(open("youtube-podcaster.json")) 19 arg_parser = argparse.ArgumentParser(prog="youtube-podcaster",
20 description="Converts youtube \
21 playlists to RSS-feeds")
22 arg_parser.add_argument("-c", "--config",
23 dest="config",
24 help="Use CONFIG as the config file")
25 arg_parser.add_argument("-i", "--interface",
26 dest="interface",
27 help="The interface the http server will listen on")
28 arg_parser.add_argument("-p", "--port",
29 dest="port",
30 help="The port the http server will listen on")
31 arg_parser.add_argument("--api-key",
32 dest="apikey",
33 help="The YouTube API v3 key")
34 args = arg_parser.parse_args()
20 35
21 try: 36 try:
22 PodcastFeeder = create_feeder(config["youtube"], config["podcasts"]) 37 config = Config.parse_config(args)
23 server = HTTPServer(("", 8888), PodcastFeeder) 38
39 PodcastFeeder = create_feeder(config)
40
41 server = HTTPServer(config.get_server_address(), PodcastFeeder)
24 server.serve_forever() 42 server.serve_forever()
43 except ConfigException as e:
44 print(e)
25 except KeyboardInterrupt: 45 except KeyboardInterrupt:
26 server.socket.close() 46 server.socket.close()
27 47
diff --git a/youtube_podcaster/__main__.py b/youtube_podcaster/__main__.py
deleted file mode 100644
index 941a79a..0000000
--- a/youtube_podcaster/__main__.py
+++ /dev/null
@@ -1,8 +0,0 @@
1#!/usr/bin/env python3
2
3import youtube_podcaster
4
5if __name__ == "__main__":
6 youtube_podcaster.main()
7
8# vim: set ts=8 sw=4 tw=0 et :
diff --git a/youtube_podcaster/config.py b/youtube_podcaster/config.py
new file mode 100644
index 0000000..bfce902
--- /dev/null
+++ b/youtube_podcaster/config.py
@@ -0,0 +1,64 @@
1import sys
2import os
3import json
4
5
6class ConfigException(Exception):
7 def __init__(self, msg):
8 super(ConfigException, self).__init__("Config exception: %s" % (msg))
9
10
11class Config:
12 instance = None
13
14 def parse_config(config_file=None):
15 if not Config.instance:
16 Config.instance = Config(config_file)
17
18 return Config.instance
19
20 def __init__(self, args):
21 if args.config:
22 config = args.config
23 else:
24 config_file = "youtube-podcaster.json"
25
26 if sys.platform == "linux" and not hasattr(sys, "real_prefix"):
27 config = "/etc/%s" % (config_file)
28 else:
29 config = "%s/etc/%s" % (sys.prefix, config_file)
30
31 if not os.path.isfile(config):
32 raise ConfigException("%s not found" % (config))
33
34 try:
35 config = json.load(open(config))
36 except json.decoder.JSONDecodeError as e:
37 raise ConfigException("%s is not valid json: %s" % (
38 config, str(e)))
39
40 try:
41 self.server = config["server"]
42 self.youtube = config["youtube"]
43 self.podcasts = config["podcasts"]
44 except KeyError as e:
45 raise ConfigException("Missing %s-section in %s" % (
46 str(e), config))
47
48 for arg, value in vars(args).items():
49 if not value:
50 continue
51
52 if arg == "interface":
53 self.server["interface"] = value
54 elif arg == "port":
55 self.server["port"] = value
56 elif arg == "apikey":
57 self.youtube["api-key"] = value
58
59 def get_server_address(self):
60 interface = str(self.server["interface"])
61 port = int(self.server["port"])
62 return interface, port
63
64# vim: set ts=8 sw=4 tw=0 et :
diff --git a/youtube_podcaster/podcastfeeder.py b/youtube_podcaster/podcastfeeder.py
index 3f752d2..4181d6c 100644
--- a/youtube_podcaster/podcastfeeder.py
+++ b/youtube_podcaster/podcastfeeder.py
@@ -5,10 +5,10 @@ from .podcastupdater import (
5) 5)
6 6
7 7
8def create_feeder(youtube_config, podcast_config): 8def create_feeder(config):
9 class PodcastFeeder(BaseHTTPRequestHandler): 9 class PodcastFeeder(BaseHTTPRequestHandler):
10 def __init__(self, request, client_address, server): 10 def __init__(self, request, client_address, server):
11 self.updater = PodcastUpdater(youtube_config, podcast_config) 11 self.updater = PodcastUpdater(config)
12 super(PodcastFeeder, self).__init__(request, client_address, server) 12 super(PodcastFeeder, self).__init__(request, client_address, server)
13 13
14 def do_GET(self): 14 def do_GET(self):
diff --git a/youtube_podcaster/podcastupdater.py b/youtube_podcaster/podcastupdater.py
index 4a0a017..75b8b10 100644
--- a/youtube_podcaster/podcastupdater.py
+++ b/youtube_podcaster/podcastupdater.py
@@ -2,6 +2,7 @@ import pickle
2import os 2import os
3import time 3import time
4import hashlib 4import hashlib
5import sys
5 6
6from feedgen.feed import FeedGenerator 7from feedgen.feed import FeedGenerator
7 8
@@ -11,11 +12,19 @@ from . import (
11 12
12 13
13class PodcastUpdater: 14class PodcastUpdater:
14 def __init__(self, youtube_config, podcast_config): 15 def __init__(self, config):
15 self.podcasts = podcast_config 16 self.podcasts = config.podcasts
16 self.youtube = youtube.Youtube(youtube_config["api-key"]) 17 self.youtube = youtube.Youtube(config.youtube["api-key"])
18
19 if sys.platform == "linux" and not hasattr(sys, "real_prefix"):
20 self.data_dir = "/var/lib/youtube-podcaster"
21 else:
22 self.data_dir = "%s/var/lib/youtube-podcaster" % (sys.prefix)
23
24 os.makedirs(self.data_dir, 0o755, True)
25
26 self.feeds_file = "%s/feeds.dump" % (self.data_dir)
17 27
18 self.feeds_file = "feeds.save"
19 if os.path.isfile(self.feeds_file): 28 if os.path.isfile(self.feeds_file):
20 with open(self.feeds_file, "rb") as feeds: 29 with open(self.feeds_file, "rb") as feeds:
21 self.feeds = pickle.load(feeds) 30 self.feeds = pickle.load(feeds)
@@ -42,6 +51,8 @@ class PodcastUpdater:
42 51
43 def update_podcast(self, channel, playlist): 52 def update_podcast(self, channel, playlist):
44 feed_id = hashlib.sha1(bytes("%s %s" % (channel, playlist), "UTF-8")).hexdigest() 53 feed_id = hashlib.sha1(bytes("%s %s" % (channel, playlist), "UTF-8")).hexdigest()
54 feed_file = "%s/%s.xml" % (self.data_dir, feed_id)
55
45 yt_channel = self.youtube.get_channel(channel)[0] 56 yt_channel = self.youtube.get_channel(channel)[0]
46 yt_playlists = self.youtube.get_playlists(yt_channel, 50) 57 yt_playlists = self.youtube.get_playlists(yt_channel, 50)
47 58
@@ -58,17 +69,16 @@ class PodcastUpdater:
58 69
59 if feed.last_updated < time.time() - 600: 70 if feed.last_updated < time.time() - 600:
60 self.populate_feed(feed, feed_id, yt_playlist) 71 self.populate_feed(feed, feed_id, yt_playlist)
72 feed.rss_file(feed_file)
61 73
62 feed_file = "%s.xml" % (feed_id) 74 with open(self.feeds_file, "wb") as feeds:
63 self.feeds[feed_id].rss_file(feed_file) 75 pickle.dump(self.feeds, feeds)
64