From 3aaab0cec71534c1c2099a5289942acdddba7eaa Mon Sep 17 00:00:00 2001 From: garret Date: Mon, 5 Aug 2024 08:53:55 +0100 Subject: add support for https://radiko.jp/persons/ URLs those urls give a bio and pic of the person, and recently they've started giving a list of all the programmes that person's appeared in as well. the API is a bit annoying, you have to specify a start and end time to search between, so i had to work out the logic for "everything currently on timefree" also, the site doesn't use the "end_at_lt" parameter, only start_at_lt i tried it in the url on the offchance it would work and save a bit of logic it did so i will keep it, but it probably stands out a quite a bit, idk if the mobile apps use this, or with the end_at_lt parameter the only playlist details I can provide are the ID. There is an API for the actual details, but that's an extra request, and it's protobuf. --- yt_dlp_plugins/extractor/radiko.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/yt_dlp_plugins/extractor/radiko.py b/yt_dlp_plugins/extractor/radiko.py index 024d9a6..a9f53f5 100644 --- a/yt_dlp_plugins/extractor/radiko.py +++ b/yt_dlp_plugins/extractor/radiko.py @@ -681,3 +681,41 @@ class RadikoStationButtonIE(InfoExtractor): station = traverse_obj(queries, ("station_id", 0)) return self.url_result(f"https://radiko.jp/#!/live/{station}", RadikoLiveIE) + + +class RadikoPersonIE(InfoExtractor): + _VALID_URL = r"https?://(?:www\.)?radiko\.jp/persons/(?P\d+)" + + def _real_extract(self, url): + person_id = self._match_id(url) + + now = rtime.RadikoTime.now(tz=rtime.JST) + + min_start = (now - datetime.timedelta(days=7)).broadcast_day_start() + # we set the earliest time as the earliest we can get, + # so, the start of the broadcast day 1 week ago + # that way we can get everything we can actually download, including stuff that aired at eg "26:00" + + person_api_url = update_url_query("https://api.radiko.jp/program/api/v1/programs", { + "person_id": person_id, + "start_at_gte": min_start.isoformat(), + "end_at_lt": now.isoformat(), + }) + person_api = self._download_json(person_api_url, person_id) + + def entries(): + for episode in person_api.get("data"): + + share_url = traverse_obj(episode, ("radiko_url", ("pc", "sp", "android", "ios", "app"), + {url_or_none}), get_all=False) + # they're all identical share links at the moment (5th aug 2024) but they might not be in the future + + # predictions: + # pc will probably stay the same + # don't know what sp is, possibly "SmartPhone"?, anyway seems reasonably generic + # android is easier for me to reverse-engineer than ios (no ithing) + # i assume "app" would be some internal tell-it-to-do-something link, not a regular web link + + yield self.url_result(share_url, ie=RadikoShareIE, video_title=episode.get("title")) + + return self.playlist_result(entries(), playlist_id=join_nonempty("person", person_id)) -- cgit v1.2.3-70-g09d2