From 308e713d9ea22c4fa4676f145cc145864e516ebb Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 08:54:16 +0530 Subject: [PATCH 01/16] Fix extractor --- yt_dlp/extractor/fptplay.py | 143 ++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 54 deletions(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index db9b2e1535..8fabc5ec89 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -2,78 +2,114 @@ import time import urllib.parse -from .common import InfoExtractor from ..utils import ( - clean_html, - join_nonempty, - strip_or_none, + ExtractorError, + int_or_none, ) +from .common import InfoExtractor + class FptplayIE(InfoExtractor): - _VALID_URL = r'https?://fptplay\.vn/xem-video/[^/]+\-(?P\w+)(?:/tap-(?P\d+)?/?(?:[?#]|$)|)' + _VALID_URL = r'https?://fptplay\.vn/xem-video/[^/]+\-(?P[a-f0-9]+)' _GEO_COUNTRIES = ['VN'] IE_NAME = 'fptplay' IE_DESC = 'fptplay.vn' _TESTS = [{ - 'url': 'https://fptplay.vn/xem-video/nhan-duyen-dai-nhan-xin-dung-buoc-621a123016f369ebbde55945', - 'md5': 'ca0ee9bc63446c0c3e9a90186f7d6b33', + 'url': 'https://fptplay.vn/xem-video/jumanji-tro-choi-ky-ao-615c9b232089bd0509bfbf42', 'info_dict': { - 'id': '621a123016f369ebbde55945', + 'id': '615c9b232089bd0509bfbf42', 'ext': 'mp4', - 'title': 'Nhân Duyên Đại Nhân Xin Dừng Bước - Tập 1A', - 'description': 'md5:23cf7d1ce0ade8e21e76ae482e6a8c6c', + 'title': 'Jumanji: Welcome To The Jungle', + 'description': 'Phim theo chân một nhóm bốn học sinh phổ thông bị phạt dọn dẹp tầng hầm trường học. Tại đó, họ phát hiện ra trò chơi cổ mang tên Jumanji.', + 'thumbnail': 'https://images.fptplay.net/media/OTT/VOD/2023/03/13/jumanji-tro-choi-ky-ao-fpt-play-1678685776013_Background_1920x1080_over.jpg', + 'release_year': '2017', }, }, { - 'url': 'https://fptplay.vn/xem-video/ma-toi-la-dai-gia-61f3aa8a6b3b1d2e73c60eb5/tap-3', - 'md5': 'b35be968c909b3e4e1e20ca45dd261b1', + 'url': 'https://fptplay.vn/xem-video/sang-nhu-trang-trong-may-6156d8292089bd2184e26238', 'info_dict': { - 'id': '61f3aa8a6b3b1d2e73c60eb5', + 'id': '346034', 'ext': 'mp4', - 'title': 'Má Tôi Là Đại Gia - Tập 3', - 'description': 'md5:ff8ba62fb6e98ef8875c42edff641d1c', + 'title': 'Bright As The Moon', + 'description': '', + 'release_year': '2021', + 'season_number': '1', + 'episode': 'Tập 1', + 'episode_number': '1', + 'duration': '2665' }, - }, { - 'url': 'https://fptplay.vn/xem-video/lap-toi-do-giam-under-the-skin-6222d9684ec7230fa6e627a2/tap-4', - 'md5': 'bcb06c55ec14786d7d4eda07fa1ccbb9', - 'info_dict': { - 'id': '6222d9684ec7230fa6e627a2', - 'ext': 'mp4', - 'title': 'Lạp Tội Đồ Giám - Tập 2B', - 'description': 'md5:e5a47e9d35fbf7e9479ca8a77204908b', - }, - }, { - 'url': 'https://fptplay.vn/xem-video/nha-co-chuyen-hi-alls-well-ends-well-1997-6218995f6af792ee370459f0', - 'only_matching': True, - }] + }, ] + def _real_extract(self, url): - video_id, slug_episode = self._match_valid_url(url).group('id', 'episode') - webpage = self._download_webpage(url, video_id=video_id, fatal=False) or '' - title = self._search_regex( - r'(?s)]*>(.+)', webpage, 'title', fatal=False) - real_episode = slug_episode if not title else self._search_regex( - r'[^">]+)"\s+class="epi-title active"', webpage, 'episode', fatal=False) - title = strip_or_none(title) or self._html_search_meta(('og:title', 'twitter:title'), webpage) + contentId = self._match_id(url) - info = self._download_json( - self.get_api_with_st_token(video_id, int(slug_episode) - 1 if slug_episode else 0), video_id) - formats, subtitles = self._extract_m3u8_formats_and_subtitles(info['data']['url'], video_id, 'mp4') - return { - 'id': video_id, - 'title': join_nonempty(title, real_episode, delim=' - '), - 'description': ( - clean_html(self._search_regex(r']*>(.+)

', webpage, 'description')) - or self._html_search_meta(('og:description', 'twitter:description'), webpage)), - 'formats': formats, - 'subtitles': subtitles, - } + # Need valid cookie with Bearer token, else it won't work + token = self._get_cookies(url).get("token") + + res = self._download_json(self.get_api_with_st_token(contentId), contentId, expected_status=406) - def get_api_with_st_token(self, video_id, episode): - path = f'/api/v6.2_w/stream/vod/{video_id}/{episode}/auto_vip' + if res["result"]["episode_type"] == 0: + # movie or single video + manifest = self._download_json(self.get_api_with_st_token(contentId, 0), contentId, headers={'authorization': f'Bearer {token.value}'}, expected_status=406) + + if manifest.get("msg") != "success": + raise ExtractorError(f' - Got an error, response: {manifest.get("msg")}', expected=True) + + formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest["data"]["url"], contentId) + return { + 'id': contentId, + 'title': res["result"]["title_origin"] if res["result"]["title_origin"] else res["result"]["title_vie"], + 'description': res["result"]["description"], + 'thumbnail': res["result"]["thumb"], + 'release_year': int_or_none(res["result"]["movie_release_date"]), + 'duration': int_or_none(res["result"]["duration"]), + 'formats': formats, + 'subtitles': subtitles + } + else: + # playlist + entries = [] + for episode in res["result"]["episodes"]: + + if episode["is_trailer"] == 1: + continue + + manifest = self._download_json(self.get_api_with_st_token(contentId, episode["_id"]), episode["_id"], headers={'authorization': f'Bearer {token.value}'}, expected_status=406) + if manifest.get("msg") != "success": + raise ExtractorError(f' - Got an error, response: {manifest.get("msg")}', expected=True) + + formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest["data"]["url"], episode["_id"]) + + entry = { + 'id': episode["ref_episode_id"], + 'title': res["result"]["title_origin"] if res["result"]["title_origin"] else res["result"]["title_vie"], + 'description': episode["description"], + 'thumbnail': episode["thumb"], + 'release_year': int_or_none(res["result"]["movie_release_date"]), + 'season_number': 1, # Assuming season 1 for simplicity + 'episode': episode["title"], + 'episode_number': episode["_id"] + 1, + 'duration': int_or_none(episode["duration"]), + 'formats': formats, + 'subtitles': subtitles + } + entries.append(entry) + + return { + '_type': 'playlist', + 'id': contentId, + 'title': res["result"]["title_origin"] if res["result"]["title_origin"] else res["result"]["title_vie"], + 'entries': entries + } + + def get_api_with_st_token(self, video_id, episode=None): + if episode is not None: + path = f'/api/v7.1_w/stream/vod/{video_id}/{0 if episode is None else episode}/adaptive_bitrate' + else: + path = f'/api/v7.1_w/vod/detail/{video_id}' timestamp = int(time.time()) + 10800 - - t = hashlib.md5(f'WEBv6Dkdsad90dasdjlALDDDS{timestamp}{path}'.encode()).hexdigest().upper() + t = hashlib.md5(f'6ea6d2a4e2d3a4bd5e275401aa086d{timestamp}{path}'.encode()).hexdigest().upper() r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' n = [int(f'0x{t[2 * o: 2 * o + 2]}', 16) for o in range(len(t) // 2)] @@ -89,7 +125,7 @@ def convert(e): i[n] = e[c] n += 1 c += 1 - if 3 == n: + if n == 3: a[0] = (252 & i[0]) >> 2 a[1] = ((3 & i[0]) << 4) + ((240 & i[1]) >> 4) a[2] = ((15 & i[1]) << 2) + ((192 & i[2]) >> 6) @@ -100,14 +136,13 @@ def convert(e): if n: for o in range(n, 3): i[o] = 0 - for o in range(n + 1): a[0] = (252 & i[0]) >> 2 a[1] = ((3 & i[0]) << 4) + ((240 & i[1]) >> 4) a[2] = ((15 & i[1]) << 2) + ((192 & i[2]) >> 6) a[3] = (63 & i[2]) t += r[a[o]] - n += 1 + n += 1 while n < 3: t += '' n += 1 From b1892db0154aaa9372228e7742c5e4b37c90687c Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:30:54 +0530 Subject: [PATCH 02/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index 8fabc5ec89..59005aceb0 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -53,7 +53,7 @@ def _real_extract(self, url): # movie or single video manifest = self._download_json(self.get_api_with_st_token(contentId, 0), contentId, headers={'authorization': f'Bearer {token.value}'}, expected_status=406) - if manifest.get("msg") != "success": + if manifest.get('msg') != 'success': raise ExtractorError(f' - Got an error, response: {manifest.get("msg")}', expected=True) formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest["data"]["url"], contentId) From 1c34d99ab1b1076d834ae48f292c546d63d276b4 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:31:16 +0530 Subject: [PATCH 03/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index 59005aceb0..566719b826 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -2,6 +2,7 @@ import time import urllib.parse +from .common import InfoExtractor from ..utils import ( ExtractorError, int_or_none, From b9c7f716bace3eaa433c30257db50647ba411ba3 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:31:26 +0530 Subject: [PATCH 04/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index 566719b826..b36041d793 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -8,7 +8,6 @@ int_or_none, ) -from .common import InfoExtractor class FptplayIE(InfoExtractor): From 21e451ea5afbbdf00b42ef0f9670f42a5385b4a8 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:31:32 +0530 Subject: [PATCH 05/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index b36041d793..f3e4896171 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -9,7 +9,6 @@ ) - class FptplayIE(InfoExtractor): _VALID_URL = r'https?://fptplay\.vn/xem-video/[^/]+\-(?P[a-f0-9]+)' _GEO_COUNTRIES = ['VN'] From 0ace89202f2eead074fd1dae6beb556afd5bd2b0 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:31:39 +0530 Subject: [PATCH 06/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index f3e4896171..a75630cbec 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -35,7 +35,7 @@ class FptplayIE(InfoExtractor): 'season_number': '1', 'episode': 'Tập 1', 'episode_number': '1', - 'duration': '2665' + 'duration': '2665', }, }, ] From 9aee1ace28ce165278896361c6165ea92c2d30fe Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:31:45 +0530 Subject: [PATCH 07/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index a75630cbec..985d7b0e5d 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -37,7 +37,7 @@ class FptplayIE(InfoExtractor): 'episode_number': '1', 'duration': '2665', }, - }, ] + }] def _real_extract(self, url): From 1a735dc0d83d8ddc351be7738ad88f08a5a50f15 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:31:53 +0530 Subject: [PATCH 08/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index 985d7b0e5d..367771028e 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -44,7 +44,7 @@ def _real_extract(self, url): contentId = self._match_id(url) # Need valid cookie with Bearer token, else it won't work - token = self._get_cookies(url).get("token") + token = self._get_cookies(url).get('token') res = self._download_json(self.get_api_with_st_token(contentId), contentId, expected_status=406) From 46e494d8d268fe4aeae8e8b6d18bcf6206a0fd2c Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:32:00 +0530 Subject: [PATCH 09/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index 367771028e..a393450801 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -48,7 +48,7 @@ def _real_extract(self, url): res = self._download_json(self.get_api_with_st_token(contentId), contentId, expected_status=406) - if res["result"]["episode_type"] == 0: + if res['result']['episode_type'] == 0: # movie or single video manifest = self._download_json(self.get_api_with_st_token(contentId, 0), contentId, headers={'authorization': f'Bearer {token.value}'}, expected_status=406) From e2aafefd2327570a62d108e864c3e20345ff0f1e Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:32:06 +0530 Subject: [PATCH 10/16] Update yt_dlp/extractor/fptplay.py Co-authored-by: N/Ame <173015200+grqz@users.noreply.github.com> --- yt_dlp/extractor/fptplay.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index a393450801..e4a50d4740 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -51,7 +51,6 @@ def _real_extract(self, url): if res['result']['episode_type'] == 0: # movie or single video manifest = self._download_json(self.get_api_with_st_token(contentId, 0), contentId, headers={'authorization': f'Bearer {token.value}'}, expected_status=406) - if manifest.get('msg') != 'success': raise ExtractorError(f' - Got an error, response: {manifest.get("msg")}', expected=True) From 44d1b925ae79bcdf84174197b6594f674dd94523 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:50:53 +0530 Subject: [PATCH 11/16] Update fptplay.py --- yt_dlp/extractor/fptplay.py | 58 +++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index e4a50d4740..a311aeab53 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -7,8 +7,7 @@ ExtractorError, int_or_none, ) - - + class FptplayIE(InfoExtractor): _VALID_URL = r'https?://fptplay\.vn/xem-video/[^/]+\-(?P[a-f0-9]+)' _GEO_COUNTRIES = ['VN'] @@ -39,66 +38,63 @@ class FptplayIE(InfoExtractor): }, }] - def _real_extract(self, url): contentId = self._match_id(url) # Need valid cookie with Bearer token, else it won't work token = self._get_cookies(url).get('token') - res = self._download_json(self.get_api_with_st_token(contentId), contentId, expected_status=406) if res['result']['episode_type'] == 0: # movie or single video manifest = self._download_json(self.get_api_with_st_token(contentId, 0), contentId, headers={'authorization': f'Bearer {token.value}'}, expected_status=406) if manifest.get('msg') != 'success': - raise ExtractorError(f' - Got an error, response: {manifest.get("msg")}', expected=True) - - formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest["data"]["url"], contentId) + raise ExtractorError(f" - Got an error, response: {manifest.get('msg')}", expected=True) + formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest['data']['url'], contentId) return { 'id': contentId, - 'title': res["result"]["title_origin"] if res["result"]["title_origin"] else res["result"]["title_vie"], - 'description': res["result"]["description"], - 'thumbnail': res["result"]["thumb"], - 'release_year': int_or_none(res["result"]["movie_release_date"]), - 'duration': int_or_none(res["result"]["duration"]), + 'title': res['result']['title_origin'] if res['result']['title_origin'] else res['result']['title_vie'], + 'description': res['result']['description'], + 'thumbnail': res['result']['thumb'], + 'release_year': int_or_none(res['result']['movie_release_date']), + 'duration': int_or_none(res['result']['duration']), 'formats': formats, - 'subtitles': subtitles + 'subtitles': subtitles, } else: # playlist entries = [] - for episode in res["result"]["episodes"]: + for episode in res['result']['episodes']: - if episode["is_trailer"] == 1: + if episode['is_trailer'] == 1: continue - manifest = self._download_json(self.get_api_with_st_token(contentId, episode["_id"]), episode["_id"], headers={'authorization': f'Bearer {token.value}'}, expected_status=406) - if manifest.get("msg") != "success": - raise ExtractorError(f' - Got an error, response: {manifest.get("msg")}', expected=True) + manifest = self._download_json(self.get_api_with_st_token(contentId, episode['_id']), episode['_id'], headers={'authorization': f'Bearer {token.value}'}, expected_status=406) + if manifest.get('msg') != 'success': + raise ExtractorError(f" - Got an error, response: {manifest.get('msg')}", expected=True) - formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest["data"]["url"], episode["_id"]) + formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest['data']['url'], episode['_id']) entry = { - 'id': episode["ref_episode_id"], - 'title': res["result"]["title_origin"] if res["result"]["title_origin"] else res["result"]["title_vie"], - 'description': episode["description"], - 'thumbnail': episode["thumb"], - 'release_year': int_or_none(res["result"]["movie_release_date"]), + 'id': episode['ref_episode_id'], + 'title': res['result']['title_origin'] if res['result']['title_origin'] else res['result']['title_vie'], + 'description': episode['description'], + 'thumbnail': episode['thumb'], + 'release_year': int_or_none(res['result']['movie_release_date']), 'season_number': 1, # Assuming season 1 for simplicity - 'episode': episode["title"], - 'episode_number': episode["_id"] + 1, - 'duration': int_or_none(episode["duration"]), + 'episode': episode['title'], + 'episode_number': episode['_id'] + 1, + 'duration': int_or_none(episode['duration']), 'formats': formats, - 'subtitles': subtitles + 'subtitles': subtitles, } entries.append(entry) return { '_type': 'playlist', 'id': contentId, - 'title': res["result"]["title_origin"] if res["result"]["title_origin"] else res["result"]["title_vie"], - 'entries': entries + 'title': res['result']['title_origin'] if res['result']['title_origin'] else res['result']['title_vie'], + 'entries': entries, } def get_api_with_st_token(self, video_id, episode=None): @@ -147,4 +143,4 @@ def convert(e): return t st_token = convert(n).replace('+', '-').replace('/', '_').replace('=', '') - return f'https://api.fptplay.net{path}?{urllib.parse.urlencode({"st": st_token, "e": timestamp})}' + return f'https://api.fptplay.net{path}?{urllib.parse.urlencode({'st': st_token, 'e': timestamp})}' From b36acfe97761798dee48e7abed261d7af1e4b31f Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:52:35 +0530 Subject: [PATCH 12/16] Update fptplay.py --- yt_dlp/extractor/fptplay.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index a311aeab53..bf5d5ba4b4 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -40,11 +40,9 @@ class FptplayIE(InfoExtractor): def _real_extract(self, url): contentId = self._match_id(url) - # Need valid cookie with Bearer token, else it won't work token = self._get_cookies(url).get('token') res = self._download_json(self.get_api_with_st_token(contentId), contentId, expected_status=406) - if res['result']['episode_type'] == 0: # movie or single video manifest = self._download_json(self.get_api_with_st_token(contentId, 0), contentId, headers={'authorization': f'Bearer {token.value}'}, expected_status=406) @@ -143,4 +141,4 @@ def convert(e): return t st_token = convert(n).replace('+', '-').replace('/', '_').replace('=', '') - return f'https://api.fptplay.net{path}?{urllib.parse.urlencode({'st': st_token, 'e': timestamp})}' + return f"https://api.fptplay.net{path}?{urllib.parse.urlencode({'st': st_token, 'e': timestamp})}" From 017bbfe491167f46fd843edc49ab099ab282e9c1 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:58:34 +0530 Subject: [PATCH 13/16] Update fptplay.py --- yt_dlp/extractor/fptplay.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index bf5d5ba4b4..05bffcefa6 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -1,13 +1,11 @@ import hashlib import time import urllib.parse - from .common import InfoExtractor from ..utils import ( ExtractorError, int_or_none, ) - class FptplayIE(InfoExtractor): _VALID_URL = r'https?://fptplay\.vn/xem-video/[^/]+\-(?P[a-f0-9]+)' _GEO_COUNTRIES = ['VN'] @@ -37,7 +35,6 @@ class FptplayIE(InfoExtractor): 'duration': '2665', }, }] - def _real_extract(self, url): contentId = self._match_id(url) # Need valid cookie with Bearer token, else it won't work @@ -62,17 +59,13 @@ def _real_extract(self, url): else: # playlist entries = [] - for episode in res['result']['episodes']: - + for episode in res['result']['episodes']: if episode['is_trailer'] == 1: continue - manifest = self._download_json(self.get_api_with_st_token(contentId, episode['_id']), episode['_id'], headers={'authorization': f'Bearer {token.value}'}, expected_status=406) if manifest.get('msg') != 'success': raise ExtractorError(f" - Got an error, response: {manifest.get('msg')}", expected=True) - formats, subtitles = self._extract_m3u8_formats_and_subtitles(manifest['data']['url'], episode['_id']) - entry = { 'id': episode['ref_episode_id'], 'title': res['result']['title_origin'] if res['result']['title_origin'] else res['result']['title_vie'], @@ -87,14 +80,12 @@ def _real_extract(self, url): 'subtitles': subtitles, } entries.append(entry) - return { '_type': 'playlist', 'id': contentId, 'title': res['result']['title_origin'] if res['result']['title_origin'] else res['result']['title_vie'], 'entries': entries, } - def get_api_with_st_token(self, video_id, episode=None): if episode is not None: path = f'/api/v7.1_w/stream/vod/{video_id}/{0 if episode is None else episode}/adaptive_bitrate' @@ -104,7 +95,6 @@ def get_api_with_st_token(self, video_id, episode=None): t = hashlib.md5(f'6ea6d2a4e2d3a4bd5e275401aa086d{timestamp}{path}'.encode()).hexdigest().upper() r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' n = [int(f'0x{t[2 * o: 2 * o + 2]}', 16) for o in range(len(t) // 2)] - def convert(e): t = '' n = 0 @@ -139,6 +129,5 @@ def convert(e): t += '' n += 1 return t - st_token = convert(n).replace('+', '-').replace('/', '_').replace('=', '') return f"https://api.fptplay.net{path}?{urllib.parse.urlencode({'st': st_token, 'e': timestamp})}" From 74a969dc74c633ab7bd66b402b5babf7038ee3b3 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:04:38 +0530 Subject: [PATCH 14/16] Update fptplay.py --- yt_dlp/extractor/fptplay.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index 05bffcefa6..e6038759be 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -1,11 +1,13 @@ import hashlib import time import urllib.parse + from .common import InfoExtractor from ..utils import ( ExtractorError, int_or_none, ) + class FptplayIE(InfoExtractor): _VALID_URL = r'https?://fptplay\.vn/xem-video/[^/]+\-(?P[a-f0-9]+)' _GEO_COUNTRIES = ['VN'] @@ -59,7 +61,7 @@ def _real_extract(self, url): else: # playlist entries = [] - for episode in res['result']['episodes']: + for episode in res['result']['episodes']: if episode['is_trailer'] == 1: continue manifest = self._download_json(self.get_api_with_st_token(contentId, episode['_id']), episode['_id'], headers={'authorization': f'Bearer {token.value}'}, expected_status=406) From 698680fc3c1837c2c7738843e7011b593bea11a3 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:09:06 +0530 Subject: [PATCH 15/16] Update fptplay.py --- yt_dlp/extractor/fptplay.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index e6038759be..c98b9b0fed 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -8,6 +8,7 @@ int_or_none, ) + class FptplayIE(InfoExtractor): _VALID_URL = r'https?://fptplay\.vn/xem-video/[^/]+\-(?P[a-f0-9]+)' _GEO_COUNTRIES = ['VN'] From 357b639718cabc546413e47c04b81b5f4e022127 Mon Sep 17 00:00:00 2001 From: MrHulk <154370583+MrHulk02@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:32:58 +0530 Subject: [PATCH 16/16] Update fptplay.py --- yt_dlp/extractor/fptplay.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yt_dlp/extractor/fptplay.py b/yt_dlp/extractor/fptplay.py index c98b9b0fed..b1dea9d258 100644 --- a/yt_dlp/extractor/fptplay.py +++ b/yt_dlp/extractor/fptplay.py @@ -38,6 +38,7 @@ class FptplayIE(InfoExtractor): 'duration': '2665', }, }] + def _real_extract(self, url): contentId = self._match_id(url) # Need valid cookie with Bearer token, else it won't work @@ -89,6 +90,7 @@ def _real_extract(self, url): 'title': res['result']['title_origin'] if res['result']['title_origin'] else res['result']['title_vie'], 'entries': entries, } + def get_api_with_st_token(self, video_id, episode=None): if episode is not None: path = f'/api/v7.1_w/stream/vod/{video_id}/{0 if episode is None else episode}/adaptive_bitrate' @@ -98,6 +100,7 @@ def get_api_with_st_token(self, video_id, episode=None): t = hashlib.md5(f'6ea6d2a4e2d3a4bd5e275401aa086d{timestamp}{path}'.encode()).hexdigest().upper() r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' n = [int(f'0x{t[2 * o: 2 * o + 2]}', 16) for o in range(len(t) // 2)] + def convert(e): t = '' n = 0