diff options
| -rw-r--r-- | youtube_podcaster/config.py | 1 | ||||
| -rw-r--r-- | youtube_podcaster/podcastupdater.py | 40 | ||||
| -rw-r--r-- | youtube_podcaster/youtube/downloader.py | 40 |
3 files changed, 64 insertions, 17 deletions
diff --git a/youtube_podcaster/config.py b/youtube_podcaster/config.py index bfce902..e535dcf 100644 --- a/youtube_podcaster/config.py +++ b/youtube_podcaster/config.py | |||
| @@ -41,6 +41,7 @@ class Config: | |||
| 41 | self.server = config["server"] | 41 | self.server = config["server"] |
| 42 | self.youtube = config["youtube"] | 42 | self.youtube = config["youtube"] |
| 43 | self.podcasts = config["podcasts"] | 43 | self.podcasts = config["podcasts"] |
| 44 | self.downloads = config["downloads"] | ||
| 44 | except KeyError as e: | 45 | except KeyError as e: |
| 45 | raise ConfigException("Missing %s-section in %s" % ( | 46 | raise ConfigException("Missing %s-section in %s" % ( |
| 46 | str(e), config)) | 47 | str(e), config)) |
diff --git a/youtube_podcaster/podcastupdater.py b/youtube_podcaster/podcastupdater.py index 75b8b10..8afebfa 100644 --- a/youtube_podcaster/podcastupdater.py +++ b/youtube_podcaster/podcastupdater.py | |||
| @@ -10,11 +10,14 @@ from . import ( | |||
| 10 | youtube, | 10 | youtube, |
| 11 | ) | 11 | ) |
| 12 | 12 | ||
| 13 | from threading import Thread | ||
| 14 | |||
| 13 | 15 | ||
| 14 | class PodcastUpdater: | 16 | class PodcastUpdater: |
| 15 | def __init__(self, config): | 17 | def __init__(self, config): |
| 16 | self.podcasts = config.podcasts | 18 | self.podcasts = config.podcasts |
| 17 | self.youtube = youtube.Youtube(config.youtube["api-key"]) | 19 | self.youtube = youtube.Youtube(config.youtube["api-key"]) |
| 20 | self.downloads = config.downloads | ||
| 18 | 21 | ||
| 19 | if sys.platform == "linux" and not hasattr(sys, "real_prefix"): | 22 | if sys.platform == "linux" and not hasattr(sys, "real_prefix"): |
| 20 | self.data_dir = "/var/lib/youtube-podcaster" | 23 | self.data_dir = "/var/lib/youtube-podcaster" |
| @@ -95,7 +98,14 @@ class PodcastUpdater: | |||
| 95 | 98 | ||
| 96 | def populate_feed(self, feed, feed_id, yt_playlist, max_results=5): | 99 | def populate_feed(self, feed, feed_id, yt_playlist, max_results=5): |
| 97 | videos = self.youtube.get_playlist_items(yt_playlist, max_results) | 100 | videos = self.youtube.get_playlist_items(yt_playlist, max_results) |
| 98 | downloader = youtube.Downloader.get_instance("vorbis", "downloads", "192.168.178.100") | 101 | |
| 102 | file_format = self.downloads["format"] | ||
| 103 | download_path = self.downloads["path"] | ||
| 104 | download_url = self.downloads["url"] | ||
| 105 | |||
| 106 | downloader = youtube.Downloader.get_instance(file_format, download_path, download_url) | ||
| 107 | |||
| 108 | threads = [] | ||
| 99 | 109 | ||
| 100 | entries = feed.entry() | 110 | entries = feed.entry() |
| 101 | for video in videos: | 111 | for video in videos: |
| @@ -104,17 +114,27 @@ class PodcastUpdater: | |||
| 104 | if entry.id() == video_id: | 114 | if entry.id() == video_id: |
| 105 | break | 115 | break |
| 106 | else: | 116 | else: |
| 107 | url, size, mime = downloader.download(video, video_id, feed_id) | 117 | t = Thread(target=self.process_video, args=(downloader, video, video_id, feed_id)) |
| 108 | 118 | threads.append(t) | |
| 109 | feed_entry = feed.add_entry() | 119 | t.start() |
| 110 | 120 | ||
| 111 | feed_entry.id(video_id) | 121 | for t in threads: |
| 112 | feed_entry.guid(video_id) | 122 | t.join() |
| 113 | feed_entry.title(video["snippet"]["title"]) | ||
| 114 | feed_entry.description(video["snippet"]["description"]) | ||
| 115 | feed_entry.published(video["snippet"]["publishedAt"]) | ||
| 116 | feed_entry.enclosure(url, size, mime) | ||
| 117 | 123 | ||
| 118 | feed.last_updated = time.time() | 124 | feed.last_updated = time.time() |
| 119 | 125 | ||
| 126 | def process_video(self, downloader, video, video_id, feed_id): | ||
| 127 | url, size, mime = downloader.download(video, video_id, feed_id) | ||
| 128 | |||
| 129 | feed = self.feeds[feed_id] | ||
| 130 | feed_entry = feed.add_entry() | ||
| 131 | |||
| 132 | feed_entry.id(video_id) | ||
| 133 | feed_entry.guid(video_id) | ||
| 134 | feed_entry.title(video["snippet"]["title"]) | ||
| 135 | feed_entry.description(video["snippet"]["description"]) | ||
| 136 | feed_entry.published(video["snippet"]["publishedAt"]) | ||
| 137 | feed_entry.enclosure(url, size, mime) | ||
| 138 | |||
| 139 | |||
| 120 | # vim: set ts=8 sw=4 tw=0 et : | 140 | # vim: set ts=8 sw=4 tw=0 et : |
diff --git a/youtube_podcaster/youtube/downloader.py b/youtube_podcaster/youtube/downloader.py index 529902a..24fa1b0 100644 --- a/youtube_podcaster/youtube/downloader.py +++ b/youtube_podcaster/youtube/downloader.py | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #!/usr/bin/env python3 | 1 | #!/usr/bin/env python3 |
| 2 | 2 | ||
| 3 | import os | 3 | import os |
| 4 | import sys | ||
| 4 | import mimetypes | 5 | import mimetypes |
| 5 | 6 | ||
| 6 | import youtube_dl | 7 | import youtube_dl |
| @@ -19,26 +20,51 @@ class Downloader: | |||
| 19 | self.location = location | 20 | self.location = location |
| 20 | self.base_url = base_url | 21 | self.base_url = base_url |
| 21 | 22 | ||
| 23 | self.downloaded = [] | ||
| 24 | |||
| 22 | if file_format == "vorbis": | 25 | if file_format == "vorbis": |
| 23 | self.extension = "ogg" | 26 | self.extension = "ogg" |
| 27 | elif file_format == "opus": | ||
| 28 | self.extension = "opus" | ||
| 29 | |||
| 30 | if sys.platform == "linux" and not hasattr(sys, "real_prefix"): | ||
| 31 | self.tmp_dir = "/tmp/youtube-podcaster" | ||
| 32 | else: | ||
| 33 | self.tmp_dir= "%s/tmp/youtube-podcaster" % (sys.prefix) | ||
| 34 | |||
| 35 | os.makedirs(self.tmp_dir, 0o755, True) | ||
| 24 | 36 | ||
| 25 | def download(self, video, video_id, feed_id): | 37 | def download(self, video, video_id, feed_id): |
| 26 | output = "%s/%s/%s.%s" % (self.location, feed_id, video_id, self.extension) | 38 | |
| 39 | # Real output | ||
| 40 | filename = "%s.%s" % (video_id, self.extension) | ||
| 41 | output_dir = "%s/%s" % (self.location, feed_id) | ||
| 42 | output = "%s/%s" % (output_dir, filename) | ||
| 43 | |||
| 44 | # Tmp output | ||
| 45 | tmp_filename = "%s.webm" % (video_id) | ||
| 46 | tmp_output = "%s/%s" % (self.tmp_dir, tmp_filename) | ||
| 47 | |||
| 27 | options = {"format": "bestaudio/best", | 48 | options = {"format": "bestaudio/best", |
| 28 | "outtmpl": output, | 49 | "outtmpl": tmp_output, |
| 29 | "postprocessors": [{ | 50 | "postprocessors": [{ |
| 30 | "key": "FFmpegExtractAudio", | 51 | "key": "FFmpegExtractAudio", |
| 31 | "preferredcodec": self.file_format | 52 | "preferredcodec": self.file_format |
| 32 | }], | 53 | }]} |
| 33 | "nooverwrites": True} | ||
| 34 | |||
| 35 | 54 | ||
| 36 | video_url = "https://www.youtube.com/watch?v=%s" % (video["snippet"]["resourceId"]["videoId"]) | 55 | video_url = "https://www.youtube.com/watch?v=%s" % (video["snippet"]["resourceId"]["videoId"]) |
| 37 | youtube_dl.YoutubeDL(options).download([video_url]) | 56 | youtube_dl.YoutubeDL(options).download([video_url]) |
| 38 | 57 | ||
| 58 | tmp_output = "%s/%s" % (self.tmp_dir, filename) | ||
| 59 | |||
| 39 | url = "%s/%s/%s.%s" % (self.base_url, feed_id, video_id, self.extension) | 60 | url = "%s/%s/%s.%s" % (self.base_url, feed_id, video_id, self.extension) |
| 40 | size = str(os.path.getsize(output)) | 61 | size = str(os.path.getsize(tmp_output)) |
| 41 | mime = mimetypes.guess_type(output)[0] | 62 | mime = mimetypes.guess_type(tmp_output)[0] |
| 63 | |||
| 64 | os.makedirs(output_dir, 0o755, True) | ||
| 65 | os.rename(tmp_output, output) | ||
| 66 | |||
| 67 | self.downloaded.append(output) | ||
| 42 | 68 | ||
| 43 | return (url, size, mime) | 69 | return (url, size, mime) |
| 44 | 70 | ||
