5 from .common
import InfoExtractor
13 class FptplayIE(InfoExtractor
):
14 _VALID_URL
= r
'https?://fptplay\.vn/xem-video/[^/]+\-(?P<id>\w+)(?:/tap-(?P<episode>\d+)?/?(?:[?#]|$)|)'
15 _GEO_COUNTRIES
= ['VN']
17 IE_DESC
= 'fptplay.vn'
19 'url': 'https://fptplay.vn/xem-video/nhan-duyen-dai-nhan-xin-dung-buoc-621a123016f369ebbde55945',
20 'md5': 'ca0ee9bc63446c0c3e9a90186f7d6b33',
22 'id': '621a123016f369ebbde55945',
24 'title': 'Nhân Duyên Đại Nhân Xin Dừng Bước - Tập 1A',
25 'description': 'md5:23cf7d1ce0ade8e21e76ae482e6a8c6c',
28 'url': 'https://fptplay.vn/xem-video/ma-toi-la-dai-gia-61f3aa8a6b3b1d2e73c60eb5/tap-3',
29 'md5': 'b35be968c909b3e4e1e20ca45dd261b1',
31 'id': '61f3aa8a6b3b1d2e73c60eb5',
33 'title': 'Má Tôi Là Đại Gia - Tập 3',
34 'description': 'md5:ff8ba62fb6e98ef8875c42edff641d1c',
37 'url': 'https://fptplay.vn/xem-video/lap-toi-do-giam-under-the-skin-6222d9684ec7230fa6e627a2/tap-4',
38 'md5': 'bcb06c55ec14786d7d4eda07fa1ccbb9',
40 'id': '6222d9684ec7230fa6e627a2',
42 'title': 'Lạp Tội Đồ Giám - Tập 2B',
43 'description': 'md5:e5a47e9d35fbf7e9479ca8a77204908b',
46 'url': 'https://fptplay.vn/xem-video/nha-co-chuyen-hi-alls-well-ends-well-1997-6218995f6af792ee370459f0',
47 'only_matching': True,
50 def _real_extract(self
, url
):
51 video_id
, slug_episode
= self
._match
_valid
_url
(url
).group('id', 'episode')
52 webpage
= self
._download
_webpage
(url
, video_id
=video_id
, fatal
=False) or ''
53 title
= self
._search
_regex
(
54 r
'(?s)<h4\s+class="mb-1 text-2xl text-white"[^>]*>(.+)</h4>', webpage
, 'title', fatal
=False)
55 real_episode
= slug_episode
if not title
else self
._search
_regex
(
56 r
'<p.+title="(?P<episode>[^">]+)"\s+class="epi-title active"', webpage
, 'episode', fatal
=False)
57 title
= strip_or_none(title
) or self
._html
_search
_meta
(('og:title', 'twitter:title'), webpage
)
59 info
= self
._download
_json
(
60 self
.get_api_with_st_token(video_id
, int(slug_episode
) - 1 if slug_episode
else 0), video_id
)
61 formats
, subtitles
= self
._extract
_m
3u8_formats
_and
_subtitles
(info
['data']['url'], video_id
, 'mp4')
64 'title': join_nonempty(title
, real_episode
, delim
=' - '),
66 clean_html(self
._search
_regex
(r
'<p\s+class="overflow-hidden"[^>]*>(.+)</p>', webpage
, 'description'))
67 or self
._html
_search
_meta
(('og:description', 'twitter:description'), webpage
)),
69 'subtitles': subtitles
,
72 def get_api_with_st_token(self
, video_id
, episode
):
73 path
= f
'/api/v6.2_w/stream/vod/{video_id}/{episode}/auto_vip'
74 timestamp
= int(time
.time()) + 10800
76 t
= hashlib
.md5(f
'WEBv6Dkdsad90dasdjlALDDDS{timestamp}{path}'.encode()).hexdigest().upper()
77 r
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
78 n
= [int(f
'0x{t[2 * o: 2 * o + 2]}', 16) for o
in range(len(t
) // 2)]
87 for _
in range(s
, 0, -1):
93 a
[0] = (252 & i
[0]) >> 2
94 a
[1] = ((3 & i
[0]) << 4) + ((240 & i
[1]) >> 4)
95 a
[2] = ((15 & i
[1]) << 2) + ((192 & i
[2]) >> 6)
101 for o
in range(n
, 3):
104 for o
in range(n
+ 1):
105 a
[0] = (252 & i
[0]) >> 2
106 a
[1] = ((3 & i
[0]) << 4) + ((240 & i
[1]) >> 4)
107 a
[2] = ((15 & i
[1]) << 2) + ((192 & i
[2]) >> 6)
116 st_token
= convert(n
).replace('+', '-').replace('/', '_').replace('=', '')
117 return f
'https://api.fptplay.net{path}?{urllib.parse.urlencode({"st": st_token, "e": timestamp})}'