From 63b1f54515c3880fdb627b66fc5258ad1ad39c80 Mon Sep 17 00:00:00 2001 From: pta Date: Wed, 17 Apr 2024 13:37:00 -0400 Subject: [PATCH] Get video ids from youtube with yt-dlp For two reasons: 1. Youtube is the primary source. Apparently staff manually copies the video id youtube gives them, since they sometimes forget to update their json. With this commit, I'm practically implementing the automation they should have implemented themselves. 2. Make links available ahead of time for convenience. Currently on our site, links aren't available until the moment the program starts. So in practice, I have to open youtube to copy the next stream's url for playing in mpv, lest I miss the first several seconds of the show. (I know staff puts the next stream's link in chat, but since it's manual, occasionally they forget, and the url is usually in "/live/" rather than "/watch?v=" format: the latter makes clearer screenshot filenames, imo. yt-dlp becomes a required dependency. The same information could be sourced with Julia code to scrape an invidious instance, but that would incur more code to produce the same array of per-video dictionaries, which could be desireable later as exercise in Julia. --- src/WeatherNews.jl | 51 +++++++++++++++++++++++++++++++++++++--------- src/api.jl | 11 +++++++++- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/WeatherNews.jl b/src/WeatherNews.jl index 18d2f58..2ca4856 100644 --- a/src/WeatherNews.jl +++ b/src/WeatherNews.jl @@ -24,6 +24,15 @@ TITLES = Dict( "ウェザーニュースLiVE" => "_", ) +HOURS = Dict( + "モーニング" => 5, + "サンシャイン" => 8, + "コーヒータイム" => 11, + "アフタヌーン" => 14, + "イブニング" => 17, + "ムーン" => 20 +) + function massage_fn(zone, leading_zero; t=now()) zn = ZonedDateTime(t, localzone()) td = Date(astimezone(zn, tz"Asia/Tokyo")) @@ -78,6 +87,26 @@ function get_schedule() get_schedule(localzone()) end +"Derive full jst from stream title's date string and WNL segment title" +function wnl_title_to_jst(title) + date_re = r"(?[1-9][0-9]{3})[年.](?[0-1]?[0-9])[月.](?[0-3]?[0-9])日?" + d = match(date_re, title) + segment_re = r"モーニング|サンシャイン|コーヒータイム|アフタヌーン|イブニング|ムーン" + s = match(segment_re, title) + h = isnothing(s) ? 23 : HOURS[s.match] + return ZonedDateTime(DateTime(parse(Int64, d[:year]), + parse(Int64, d[:month]), + parse(Int64, d[:day]), + h), + tz"Asia/Tokyo") +end + +"Assume titles with ウェザーニュースLiVE and a full date string belong to regular WNL streams" +function iswnl(title) + return occursin(r"ウェザーニュース[Ll][Ii][Vv][Ee]", title) && + occursin(r"[1-9][0-9]{3}[年.][0-1]?[0-9][月.][0-3]?[0-9]日?", title) +end + """ Find the current live video's id and update the schedule table if a corresponding row can be found. @@ -87,16 +116,18 @@ julia> WeatherNews.update_schedule_with_live_video(db) ``` """ function update_schedule_with_live_video(db) - v = WeatherNews.API.video_ids() - zn = ZonedDateTime(now(), localzone()) - jn = astimezone(zn, tz"Asia/Tokyo") - jst_1h = floor(jn, Dates.Hour) - @debug jst_1h, v[:live][:id] - return DB.update_schedule_with_video( - db, - jst_1h |> string, - v[:live][:id] - ) + vids = WeatherNews.API.video_ids() + for v in vids + if iswnl(v[:title]) + jst = wnl_title_to_jst(v[:title]) + DB.update_schedule_with_video(db, string(jst), v[:id]) + if hour(jst) == 23 + DB.update_schedule_with_video(db, string(jst + Hour(1)), v[:id]) + end + else + continue + end + end end """ diff --git a/src/api.jl b/src/api.jl index d94b06d..c5e2e2f 100644 --- a/src/api.jl +++ b/src/api.jl @@ -28,5 +28,14 @@ function mscale() end function video_ids() - return get_json(urls[:video_ids] |> nocache) + # depends on external program, yt-dlp + # get first 25 items because sometimes staff spams live cams + 地震 streams + cmd = `yt-dlp --flat-playlist + --extractor-args "youtube:player-client=web" + --ignore-no-formats-error + --dump-single-json + --playlist-items 1:25 + https://www.youtube.com/weathernews/streams` + playlist = readchomp(cmd) |> JSON3.read + return playlist[:"entries"] end