diff --git a/README.md b/README.md index 48b58af..19043e5 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ Cookies (in Netscape format) are needed to access membership-only videos as well The example config file `livestream_saver.cfg` is optional and is meant as a convenience to override the default values. -# WARNING: this program is currently broken! - -**Since early 2023/04, Youtube has broken everything and this program does not work anymore.** -**You will get "HTTP 503 Forbidden" errors when attempting to download stream segments.** -**Until this is fixed, use yt-dlp to download live streams.** -**For example (triggers every 5 minutes):** -```shell -while true; do yt-dlp --fragment-retries 50 -o '%(upload_date)s [%(uploader)s] %(title)s [%(height)s][%(id)s].%(ext)s' -ciw -f '133+140/134+140/mp4+m4a/bestvideo+bestaudio' --add-metadata --embed-thumbnail --live-from-start --match-filter 'is_live' https://www.youtube.com/chanel_name_or_id/live; sleep $((5*60)); done -``` +# WARNING + +The download feature is half-broken (see issue [#63](https://github.com/glubsy/livestream_saver/issues/63)) so we rely on yt-dlp for the time being. + +As a result, many native config options (and some hooks) are currently **ignored**. + +The `yt_dlp_conf.py` file holds the default options passed to yt-dlp as defined in their [Readme.md](https://github.com/yt-dlp/yt-dlp#embedding-examples) + +So you might want to edit this file too! # Monitoring a channel diff --git a/livestream_saver.cfg.template b/livestream_saver.cfg.template index 4b4750b..5848d68 100644 --- a/livestream_saver.cfg.template +++ b/livestream_saver.cfg.template @@ -201,10 +201,10 @@ on_merge_done_command_logged = false # These values in the following sections only apply to Monitor mode. -[monitor Meru] +[monitor Meruru] channel_name = Matsuro Meru scan_delay = 20.0 -URL = https://www.youtube.com/channel/UCIJ6TGsTcBlYGUj-zbL60EQ +URL = https://www.youtube.com/@Meruru [monitor Prune] @@ -219,6 +219,18 @@ scan_delay = 20.0 URL = https://www.youtube.com/channel/UCdrQWcX7XLDSUEh9SAxnyBg +[monitor Riro] +channel_name = Riro Ron +scan_delay = 20.0 +URL = https://www.youtube.com/@riroron + + +[monitor Panko] +channel_name = Komachi Panko +scan_delay = 20.0 +URL = https://www.youtube.com/@komachipanko + + [monitor Kana] channel_name = Kamiko Kana scan_delay = 20.0 diff --git a/livestream_saver.py b/livestream_saver.py index 1b2ad98..906042e 100644 --- a/livestream_saver.py +++ b/livestream_saver.py @@ -10,6 +10,9 @@ import re from shlex import split +import yt_dlp +from yt_dlp_conf import ydl_opts + from livestream_saver import extract, util import livestream_saver from livestream_saver.monitor import YoutubeChannel @@ -559,6 +562,17 @@ def monitor_mode(config: ConfigParser, args: Dict[str, Any]): download_wanted = ls.pre_download_checks() if download_wanted: + if "cookiepath" not in ydl_opts and args.get("cookie") is not None: + ydl_opts["cookiepath"] = args.get("cookie") + + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + error_code = ydl.download(ls.url) + if error_code: + log.error(f"yt-dlp error: {error_code}") + + util.wait_block(min_minutes=scan_delay, variance=TIME_VARIANCE) + continue + try: ls.download() except Exception as e: diff --git a/yt_dlp_conf.py b/yt_dlp_conf.py new file mode 100644 index 0000000..4126eb3 --- /dev/null +++ b/yt_dlp_conf.py @@ -0,0 +1,38 @@ +ydl_opts = { + # Stream selection format. + # 360p video + AAC 128kpbs audio, + # otherwise fallback to "best" according to yt-dlp's logic + 'format': '134+140/mp4+m4a/bestvideo+bestaudio', + + # Path to your cookies (this is also deduced from the native --cookie argument) + # 'cookiefile': "", + + # Do not stop on download/postprocessing errors. + # Can be 'only_download' to ignore only download errors. + # Default is 'only_download' for CLI, but False for API + # 'ignoreerrors': 'only_download', + + "outtmpl": '%(upload_date)s [%(uploader)s] %(title)s [%(height)s][%(id)s].%(ext)s', + + # Need to test this one, but it's not needed in our case anyway: + # "match_filter": 'is_live', + + "live_from_start": True, + + # "wait_for_video" = (60, 120), + + 'postprocessors': [ + { + # --embed-thumbnail + 'key': 'EmbedThumbnail', + # already_have_thumbnail = True prevents the file from being deleted after embedding + 'already_have_thumbnail': False + }, + { + 'key': 'FFmpegMetadata', + 'add_chapters': False, + 'add_metadata': True, + 'add_infojson': False, + } + ] +} \ No newline at end of file