2022-03-08 17:52:51 +01:00
import hashlib
import time
import urllib . parse
2024-09-12 10:34:38 +02:00
2024-09-10 08:01:16 +02:00
from . common import InfoExtractor
2022-03-08 17:52:51 +01:00
from . . utils import (
2024-09-10 05:24:16 +02:00
ExtractorError ,
int_or_none ,
2022-03-08 17:52:51 +01:00
)
2024-09-12 10:34:38 +02:00
2024-09-12 10:39:06 +02:00
2022-03-08 17:52:51 +01:00
class FptplayIE ( InfoExtractor ) :
2024-09-10 05:24:16 +02:00
_VALID_URL = r ' https?://fptplay \ .vn/xem-video/[^/]+ \ -(?P<id>[a-f0-9]+) '
2022-03-08 17:52:51 +01:00
_GEO_COUNTRIES = [ ' VN ' ]
IE_NAME = ' fptplay '
IE_DESC = ' fptplay.vn '
_TESTS = [ {
2024-09-10 05:24:16 +02:00
' url ' : ' https://fptplay.vn/xem-video/jumanji-tro-choi-ky-ao-615c9b232089bd0509bfbf42 ' ,
2022-03-08 17:52:51 +01:00
' info_dict ' : {
2024-09-10 05:24:16 +02:00
' id ' : ' 615c9b232089bd0509bfbf42 ' ,
2022-03-08 17:52:51 +01:00
' ext ' : ' mp4 ' ,
2024-09-10 05:24:16 +02:00
' 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 ' ,
2022-03-08 17:52:51 +01:00
} ,
} , {
2024-09-10 05:24:16 +02:00
' url ' : ' https://fptplay.vn/xem-video/sang-nhu-trang-trong-may-6156d8292089bd2184e26238 ' ,
2022-03-08 17:52:51 +01:00
' info_dict ' : {
2024-09-10 05:24:16 +02:00
' id ' : ' 346034 ' ,
2022-03-08 17:52:51 +01:00
' ext ' : ' mp4 ' ,
2024-09-10 05:24:16 +02:00
' title ' : ' Bright As The Moon ' ,
' description ' : ' ' ,
' release_year ' : ' 2021 ' ,
' season_number ' : ' 1 ' ,
' episode ' : ' Tập 1 ' ,
' episode_number ' : ' 1 ' ,
2024-09-10 08:01:39 +02:00
' duration ' : ' 2665 ' ,
2022-03-08 17:52:51 +01:00
} ,
2024-09-10 08:01:45 +02:00
} ]
2024-09-12 13:02:58 +02:00
2022-03-08 17:52:51 +01:00
def _real_extract ( self , url ) :
2024-09-10 05:24:16 +02:00
contentId = self . _match_id ( url )
# Need valid cookie with Bearer token, else it won't work
2024-09-10 08:01:53 +02:00
token = self . _get_cookies ( url ) . get ( ' token ' )
2024-09-10 05:24:16 +02:00
res = self . _download_json ( self . get_api_with_st_token ( contentId ) , contentId , expected_status = 406 )
2024-09-10 08:02:00 +02:00
if res [ ' result ' ] [ ' episode_type ' ] == 0 :
2024-09-10 05:24:16 +02:00
# 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 )
2024-09-10 08:00:54 +02:00
if manifest . get ( ' msg ' ) != ' success ' :
2024-09-12 10:20:53 +02:00
raise ExtractorError ( f " - Got an error, response: { manifest . get ( ' msg ' ) } " , expected = True )
formats , subtitles = self . _extract_m3u8_formats_and_subtitles ( manifest [ ' data ' ] [ ' url ' ] , contentId )
2024-09-10 05:24:16 +02:00
return {
' id ' : contentId ,
2024-09-12 10:20:53 +02:00
' 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 ' ] ) ,
2024-09-10 05:24:16 +02:00
' formats ' : formats ,
2024-09-12 10:20:53 +02:00
' subtitles ' : subtitles ,
2024-09-10 05:24:16 +02:00
}
else :
# playlist
entries = [ ]
2024-09-12 10:34:38 +02:00
for episode in res [ ' result ' ] [ ' episodes ' ] :
2024-09-12 10:20:53 +02:00
if episode [ ' is_trailer ' ] == 1 :
2024-09-10 05:24:16 +02:00
continue
2024-09-12 10:20:53 +02:00
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 ' ] )
2024-09-10 05:24:16 +02:00
entry = {
2024-09-12 10:20:53 +02:00
' 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 ' ] ) ,
2024-09-10 05:24:16 +02:00
' season_number ' : 1 , # Assuming season 1 for simplicity
2024-09-12 10:20:53 +02:00
' episode ' : episode [ ' title ' ] ,
' episode_number ' : episode [ ' _id ' ] + 1 ,
' duration ' : int_or_none ( episode [ ' duration ' ] ) ,
2024-09-10 05:24:16 +02:00
' formats ' : formats ,
2024-09-12 10:20:53 +02:00
' subtitles ' : subtitles ,
2024-09-10 05:24:16 +02:00
}
entries . append ( entry )
return {
' _type ' : ' playlist ' ,
' id ' : contentId ,
2024-09-12 10:20:53 +02:00
' title ' : res [ ' result ' ] [ ' title_origin ' ] if res [ ' result ' ] [ ' title_origin ' ] else res [ ' result ' ] [ ' title_vie ' ] ,
' entries ' : entries ,
2024-09-10 05:24:16 +02:00
}
2024-09-12 13:02:58 +02:00
2024-09-10 05:24:16 +02:00
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 ' 6ea6d2a4e2d3a4bd5e275401aa086d { timestamp } { path } ' . encode ( ) ) . hexdigest ( ) . upper ( )
2022-03-08 17:52:51 +01:00
r = ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ '
n = [ int ( f ' 0x { t [ 2 * o : 2 * o + 2 ] } ' , 16 ) for o in range ( len ( t ) / / 2 ) ]
2024-09-12 13:02:58 +02:00
2022-03-08 17:52:51 +01:00
def convert ( e ) :
t = ' '
n = 0
i = [ 0 , 0 , 0 ]
a = [ 0 , 0 , 0 , 0 ]
s = len ( e )
c = 0
2024-06-12 01:09:58 +02:00
for _ in range ( s , 0 , - 1 ) :
2022-03-08 17:52:51 +01:00
if n < = 3 :
i [ n ] = e [ c ]
n + = 1
c + = 1
2024-09-10 05:24:16 +02:00
if n == 3 :
2022-03-08 17:52:51 +01:00
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 ] )
for v in range ( 4 ) :
t + = r [ a [ v ] ]
n = 0
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 ] ]
2024-09-10 05:24:16 +02:00
n + = 1
2022-03-08 17:52:51 +01:00
while n < 3 :
t + = ' '
n + = 1
return t
st_token = convert ( n ) . replace ( ' + ' , ' - ' ) . replace ( ' / ' , ' _ ' ) . replace ( ' = ' , ' ' )
2024-09-12 10:22:35 +02:00
return f " https://api.fptplay.net { path } ? { urllib . parse . urlencode ( { ' st ' : st_token , ' e ' : timestamp } ) } "