aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsubsense <3291255+subsense@users.noreply.github.com>2025-01-21 00:08:11 +0900
committerGitHub <noreply@github.com>2025-01-20 16:08:11 +0100
commit20c765d02385a105c8ef13b6f7a737491d29c19a (patch)
tree54b8c00219a25b36c54328791cd228b1227d764d
parent3fc46086562857d5493cbcff687f76e4e4ed303f (diff)
[ie/eggs] Add extractors (#11904)
Closes #11843 Authored by: subsense, seproDev Co-authored-by: sepro <sepro@sepr0.com>
-rw-r--r--yt_dlp/extractor/_extractors.py4
-rw-r--r--yt_dlp/extractor/eggs.py155
2 files changed, 159 insertions, 0 deletions
diff --git a/yt_dlp/extractor/_extractors.py b/yt_dlp/extractor/_extractors.py
index d42bce21b..48caf4fb2 100644
--- a/yt_dlp/extractor/_extractors.py
+++ b/yt_dlp/extractor/_extractors.py
@@ -585,6 +585,10 @@ from .egghead import (
EggheadCourseIE,
EggheadLessonIE,
)
+from .eggs import (
+ EggsArtistIE,
+ EggsIE,
+)
from .eighttracks import EightTracksIE
from .eitb import EitbIE
from .elementorembed import ElementorEmbedIE
diff --git a/yt_dlp/extractor/eggs.py b/yt_dlp/extractor/eggs.py
new file mode 100644
index 000000000..6e032441c
--- /dev/null
+++ b/yt_dlp/extractor/eggs.py
@@ -0,0 +1,155 @@
+import secrets
+
+from .common import InfoExtractor
+from .youtube import YoutubeIE
+from ..utils import (
+ int_or_none,
+ parse_iso8601,
+ str_or_none,
+ url_or_none,
+)
+from ..utils.traversal import traverse_obj
+
+
+class EggsBaseIE(InfoExtractor):
+ _API_HEADERS = {
+ 'Accept': '*/*',
+ 'apVersion': '8.2.00',
+ 'deviceName': 'Android',
+ }
+
+ def _real_initialize(self):
+ self._API_HEADERS['deviceId'] = secrets.token_hex(8)
+
+ def _call_api(self, endpoint, video_id):
+ return self._download_json(
+ f'https://app-front-api.eggs.mu/v1/{endpoint}', video_id,
+ headers=self._API_HEADERS)
+
+ def _extract_music_info(self, data):
+ if yt_url := traverse_obj(data, ('youtubeUrl', {url_or_none})):
+ return self.url_result(yt_url, ie=YoutubeIE)
+
+ artist_name = traverse_obj(data, ('artist', 'artistName', {str_or_none}))
+ music_id = traverse_obj(data, ('musicId', {str_or_none}))
+ webpage_url = None
+ if artist_name and music_id:
+ webpage_url = f'https://eggs.mu/artist/{artist_name}/song/{music_id}'
+
+ return {
+ 'id': music_id,
+ 'vcodec': 'none',
+ 'webpage_url': webpage_url,
+ 'extractor_key': EggsIE.ie_key(),
+ 'extractor': EggsIE.IE_NAME,
+ **traverse_obj(data, {
+ 'title': ('musicTitle', {str}),
+ 'url': ('musicDataPath', {url_or_none}),
+ 'uploader': ('artist', 'displayName', {str}),
+ 'uploader_id': ('artist', 'artistId', {str_or_none}),
+ 'thumbnail': ('imageDataPath', {url_or_none}),
+ 'view_count': ('numberOfMusicPlays', {int_or_none}),
+ 'like_count': ('numberOfLikes', {int_or_none}),
+ 'comment_count': ('numberOfComments', {int_or_none}),
+ 'composers': ('composer', {str}, all),
+ 'tags': ('tags', ..., {str}),
+ 'timestamp': ('releaseDate', {parse_iso8601}),
+ 'artist': ('artist', 'displayName', {str}),
+ })}
+
+
+class EggsIE(EggsBaseIE):
+ IE_NAME = 'eggs:single'
+ _VALID_URL = r'https?://eggs\.mu/artist/[^/?#]+/song/(?P<id>[\da-f-]+)'
+
+ _TESTS = [{
+ 'url': 'https://eggs.mu/artist/32_sunny_girl/song/0e95fd1d-4d61-4d5b-8b18-6092c551da90',
+ 'info_dict': {
+ 'id': '0e95fd1d-4d61-4d5b-8b18-6092c551da90',
+ 'ext': 'm4a',
+ 'title': 'シネマと信号',
+ 'uploader': 'Sunny Girl',
+ 'thumbnail': r're:https?://.*\.jpg(?:\?.*)?$',
+ 'uploader_id': '1607',
+ 'like_count': int,
+ 'timestamp': 1731327327,
+ 'composers': ['橘高連太郎'],
+ 'view_count': int,
+ 'comment_count': int,
+ 'artists': ['Sunny Girl'],
+ 'upload_date': '20241111',
+ 'tags': ['SunnyGirl', 'シネマと信号'],
+ },
+ }, {
+ 'url': 'https://eggs.mu/artist/KAMO_3pband/song/1d4bc45f-1af6-47a9-8b30-a70cae350b4f',
+ 'info_dict': {
+ 'id': '80cLKA2wnoA',
+ 'ext': 'mp4',
+ 'title': 'KAMO「いい女だから」Audio',
+ 'uploader': 'KAMO',
+ 'live_status': 'not_live',
+ 'channel_id': 'UCsHLBw2__5Q9y55skXPotOg',
+ 'channel_follower_count': int,
+ 'description': 'md5:d260da711ecbec3e720293dc11401b87',
+ 'availability': 'public',
+ 'uploader_id': '@KAMO_band',
+ 'upload_date': '20240925',
+ 'thumbnail': 'https://i.ytimg.com/vi/80cLKA2wnoA/maxresdefault.jpg',
+ 'comment_count': int,
+ 'channel_url': 'https://www.youtube.com/channel/UCsHLBw2__5Q9y55skXPotOg',
+ 'view_count': int,
+ 'duration': 151,
+ 'like_count': int,
+ 'channel': 'KAMO',
+ 'playable_in_embed': True,
+ 'uploader_url': 'https://www.youtube.com/@KAMO_band',
+ 'tags': [],
+ 'timestamp': 1727271121,
+ 'age_limit': 0,
+ 'categories': ['People & Blogs'],
+ },
+ 'add_ie': ['Youtube'],
+ 'params': {'skip_download': 'Youtube'},
+ }]
+
+ def _real_extract(self, url):
+ song_id = self._match_id(url)
+ json_data = self._call_api(f'musics/{song_id}', song_id)
+ return self._extract_music_info(json_data)
+
+
+class EggsArtistIE(EggsBaseIE):
+ IE_NAME = 'eggs:artist'
+ _VALID_URL = r'https?://eggs\.mu/artist/(?P<id>\w+)/?(?:[?#&]|$)'
+
+ _TESTS = [{
+ 'url': 'https://eggs.mu/artist/32_sunny_girl',
+ 'info_dict': {
+ 'id': '32_sunny_girl',
+ 'thumbnail': 'https://image-pro.eggs.mu/profile/1607.jpeg?updated_at=2024-04-03T20%3A06%3A00%2B09%3A00',
+ 'description': 'Muddy Mine / 東京高田馬場CLUB PHASE / Gt.Vo 橘高 連太郎 / Ba.Cho 小野 ゆうき / Dr 大森 りゅうひこ',
+ 'title': 'Sunny Girl',
+ },
+ 'playlist_mincount': 18,
+ }, {
+ 'url': 'https://eggs.mu/artist/KAMO_3pband',
+ 'info_dict': {
+ 'id': 'KAMO_3pband',
+ 'description': '川崎発3ピースバンド',
+ 'thumbnail': 'https://image-pro.eggs.mu/profile/35217.jpeg?updated_at=2024-11-27T16%3A31%3A50%2B09%3A00',
+ 'title': 'KAMO',
+ },
+ 'playlist_mincount': 2,
+ }]
+
+ def _real_extract(self, url):
+ artist_id = self._match_id(url)
+ artist_data = self._call_api(f'artists/{artist_id}', artist_id)
+ song_data = self._call_api(f'artists/{artist_id}/musics', artist_id)
+ return self.playlist_result(
+ traverse_obj(song_data, ('data', ..., {dict}, {self._extract_music_info})),
+ playlist_id=artist_id, **traverse_obj(artist_data, {
+ 'title': ('displayName', {str}),
+ 'description': ('profile', {str}),
+ 'thumbnail': ('imageDataPath', {url_or_none}),
+ }))