]>
Commit | Line | Data |
---|---|---|
151f8f1c HTL |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | import hashlib | |
5 | import time | |
6 | import urllib.parse | |
7 | ||
8 | from .common import InfoExtractor | |
9 | from ..utils import ( | |
10 | join_nonempty, | |
11 | ) | |
12 | ||
13 | ||
14 | class FptplayIE(InfoExtractor): | |
15 | _VALID_URL = r'https?://fptplay\.vn/(?P<type>xem-video)/[^/]+\-(?P<id>\w+)(?:/tap-(?P<episode>[^/]+)?/?(?:[?#]|$)|)' | |
16 | _GEO_COUNTRIES = ['VN'] | |
17 | IE_NAME = 'fptplay' | |
18 | IE_DESC = 'fptplay.vn' | |
19 | _TESTS = [{ | |
20 | 'url': 'https://fptplay.vn/xem-video/nhan-duyen-dai-nhan-xin-dung-buoc-621a123016f369ebbde55945', | |
21 | 'md5': 'ca0ee9bc63446c0c3e9a90186f7d6b33', | |
22 | 'info_dict': { | |
23 | 'id': '621a123016f369ebbde55945', | |
24 | 'ext': 'mp4', | |
25 | 'title': 'Nhân Duyên Đại Nhân Xin Dừng Bước - Ms. Cupid In Love', | |
26 | 'description': 'md5:23cf7d1ce0ade8e21e76ae482e6a8c6c', | |
27 | }, | |
28 | }, { | |
29 | 'url': 'https://fptplay.vn/xem-video/ma-toi-la-dai-gia-61f3aa8a6b3b1d2e73c60eb5/tap-3', | |
30 | 'md5': 'b35be968c909b3e4e1e20ca45dd261b1', | |
31 | 'info_dict': { | |
32 | 'id': '61f3aa8a6b3b1d2e73c60eb5', | |
33 | 'ext': 'mp4', | |
34 | 'title': 'Má Tôi Là Đại Gia - 3', | |
35 | 'description': 'md5:ff8ba62fb6e98ef8875c42edff641d1c', | |
36 | }, | |
37 | }, { | |
38 | 'url': 'https://fptplay.vn/xem-video/nha-co-chuyen-hi-alls-well-ends-well-1997-6218995f6af792ee370459f0', | |
39 | 'only_matching': True, | |
40 | }] | |
41 | ||
42 | def _real_extract(self, url): | |
43 | type_url, video_id, episode = self._match_valid_url(url).group('type', 'id', 'episode') | |
44 | webpage = self._download_webpage(url, video_id=video_id, fatal=False) | |
45 | info = self._download_json(self.get_api_with_st_token(video_id, episode or 0), video_id) | |
46 | formats, subtitles = self._extract_m3u8_formats_and_subtitles(info['data']['url'], video_id, 'mp4') | |
47 | self._sort_formats(formats) | |
48 | return { | |
49 | 'id': video_id, | |
50 | 'title': join_nonempty( | |
51 | self._html_search_meta(('og:title', 'twitter:title'), webpage), episode, delim=' - '), | |
52 | 'description': self._html_search_meta(['og:description', 'twitter:description'], webpage), | |
53 | 'formats': formats, | |
54 | 'subtitles': subtitles, | |
55 | } | |
56 | ||
57 | def get_api_with_st_token(self, video_id, episode): | |
58 | path = f'/api/v6.2_w/stream/vod/{video_id}/{episode}/auto_vip' | |
59 | timestamp = int(time.time()) + 10800 | |
60 | ||
61 | t = hashlib.md5(f'WEBv6Dkdsad90dasdjlALDDDS{timestamp}{path}'.encode()).hexdigest().upper() | |
62 | r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' | |
63 | n = [int(f'0x{t[2 * o: 2 * o + 2]}', 16) for o in range(len(t) // 2)] | |
64 | ||
65 | def convert(e): | |
66 | t = '' | |
67 | n = 0 | |
68 | i = [0, 0, 0] | |
69 | a = [0, 0, 0, 0] | |
70 | s = len(e) | |
71 | c = 0 | |
72 | for z in range(s, 0, -1): | |
73 | if n <= 3: | |
74 | i[n] = e[c] | |
75 | n += 1 | |
76 | c += 1 | |
77 | if 3 == n: | |
78 | a[0] = (252 & i[0]) >> 2 | |
79 | a[1] = ((3 & i[0]) << 4) + ((240 & i[1]) >> 4) | |
80 | a[2] = ((15 & i[1]) << 2) + ((192 & i[2]) >> 6) | |
81 | a[3] = (63 & i[2]) | |
82 | for v in range(4): | |
83 | t += r[a[v]] | |
84 | n = 0 | |
85 | if n: | |
86 | for o in range(n, 3): | |
87 | i[o] = 0 | |
88 | ||
89 | for o in range(n + 1): | |
90 | a[0] = (252 & i[0]) >> 2 | |
91 | a[1] = ((3 & i[0]) << 4) + ((240 & i[1]) >> 4) | |
92 | a[2] = ((15 & i[1]) << 2) + ((192 & i[2]) >> 6) | |
93 | a[3] = (63 & i[2]) | |
94 | t += r[a[o]] | |
95 | n += 1 | |
96 | while n < 3: | |
97 | t += '' | |
98 | n += 1 | |
99 | return t | |
100 | ||
101 | st_token = convert(n).replace('+', '-').replace('/', '_').replace('=', '') | |
102 | return f'https://api.fptplay.net{path}?{urllib.parse.urlencode({"st": st_token, "e": timestamp})}' |