@ -33,21 +33,21 @@ class AfreecaTVBaseIE(InfoExtractor):
}
response = self . _download_json (
' https://login. afreecatv.com /app/LoginAction.php' , None ,
' https://login. sooplive.co.kr /app/LoginAction.php' , None ,
' Logging in ' , data = urlencode_postdata ( login_form ) )
_ERRORS = {
- 4 : ' Your account has been suspended due to a violation of our terms and policies. ' ,
- 5 : ' https://member. afreecatv.com /app/user_delete_progress.php' ,
- 6 : ' https://login. afreecatv.com /membership/changeMember.php' ,
- 8 : " Hello! AfreecaTV here.\n The username you have entered belongs to \n an account that requires a legal guardian ' s consent. \n If you wish to use our services without restriction, \n please make sure to go through the necessary verification process. " ,
- 9 : ' https://member. afreecatv.com /app/pop_login_block.php' ,
- 11 : ' https://login. afreecatv.com /afreeca/second_login.php' ,
- 12 : ' https://member. afreecatv.com /app/user_security.php' ,
- 5 : ' https://member. sooplive.co.kr /app/user_delete_progress.php' ,
- 6 : ' https://login. sooplive.co.kr /membership/changeMember.php' ,
- 8 : " Hello! Soop here.\n The username you have entered belongs to \n an account that requires a legal guardian ' s consent. \n If you wish to use our services without restriction, \n please make sure to go through the necessary verification process. " ,
- 9 : ' https://member. sooplive.co.kr /app/pop_login_block.php' ,
- 11 : ' https://login. sooplive.co.kr /afreeca/second_login.php' ,
- 12 : ' https://member. sooplive.co.kr /app/user_security.php' ,
0 : ' The username does not exist or you have entered the wrong password. ' ,
- 1 : ' The username does not exist or you have entered the wrong password. ' ,
- 3 : ' You have entered your username/password incorrectly. ' ,
- 7 : ' You cannot use your Global AfreecaTV account to access Korean AfreecaTV .' ,
- 7 : ' You cannot use your Global Soop account to access Korean Soop .' ,
- 10 : ' Sorry for the inconvenience. \n Your account has been blocked due to an unauthorized access. \n Please contact our Help Center for assistance. ' ,
- 32008 : ' You have failed to log in. Please contact our Help Center. ' ,
}
@ -61,76 +61,40 @@ class AfreecaTVBaseIE(InfoExtractor):
def _call_api ( self , endpoint , display_id , data = None , headers = None , query = None ) :
return self . _download_json ( Request (
f ' https://api.m. afreecatv.com /{ endpoint } ' ,
f ' https://api.m. sooplive.co.kr /{ endpoint } ' ,
data = data , headers = headers , query = query ,
extensions = { ' legacy_ssl ' : True } ) , display_id ,
' Downloading API JSON ' , ' Unable to download API JSON ' )
class AfreecaTVIE ( AfreecaTVBaseIE ) :
IE_NAME = ' afreecatv '
IE_DESC = ' afreecatv.com '
_VALID_URL = r ''' (?x)
https ? : / /
( ? :
( ? : ( ? : live | afbbs | www ) \. ) ? afreeca ( ? : tv ) ? \. com ( ? : : \d + ) ?
( ? :
/ app / ( ? : index | read_ucc_bbs ) \. cgi |
/ player / [ Pp ] layer \. ( ? : swf | html )
) \? . * ? \bnTitleNo = |
vod \. afreecatv \. com / ( PLAYER / STATION | player ) /
)
( ? P < id > \d + ) / ? ( ? : $ | [ ? #&])
'''
IE_NAME = ' soop '
IE_DESC = ' sooplive.co.kr '
_VALID_URL = r ' https?://vod \ .(?:sooplive \ .co \ .kr|afreecatv \ .com)/(?:PLAYER/STATION|player)/(?P<id> \ d+)/?(?:$|[?#&]) '
_TESTS = [ {
' url ' : ' http://live.afreecatv.com:8079/app/index.cgi?szType=read_ucc_bbs&szBjId=dailyapril&nStationNo=16711924&nBbsNo=18605867&nTitleNo=36164052&szSkin= ' ,
' md5 ' : ' f72c89fe7ecc14c1b5ce506c4996046e ' ,
' info_dict ' : {
' id ' : ' 36164052 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' 데일리 에이프릴 요정들의 시상식! ' ,
' thumbnail ' : ' re:^https?://(?:video|st)img.afreecatv.com/.*$ ' ,
' uploader ' : ' dailyapril ' ,
' uploader_id ' : ' dailyapril ' ,
' upload_date ' : ' 20160503 ' ,
} ,
' skip ' : ' Video is gone ' ,
} , {
' url ' : ' http://afbbs.afreecatv.com:8080/app/read_ucc_bbs.cgi?nStationNo=16711924&nTitleNo=36153164&szBjId=dailyapril&nBbsNo=18605867 ' ,
' url ' : ' https://vod.sooplive.co.kr/player/96753363 ' ,
' info_dict ' : {
' id ' : ' 36153164 ' ,
' title ' : " BJ유트루와 함께하는 ' 팅커벨 메이크업! ' " ,
' thumbnail ' : ' re:^https?://(?:video|st)img.afreecatv.com/.*$ ' ,
' uploader ' : ' dailyapril ' ,
' uploader_id ' : ' dailyapril ' ,
} ,
' playlist_count ' : 2 ,
' playlist ' : [ {
' md5 ' : ' d8b7c174568da61d774ef0203159bf97 ' ,
' info_dict ' : {
' id ' : ' 36153164_1 ' ,
' id ' : ' 20230108_9FF5BEE1_244432674_1 ' ,
' ext ' : ' mp4 ' ,
' title ' : " BJ유트루와 함께하는 ' 팅커벨 메이크업! ' " ,
' upload_date ' : ' 20160502 ' ,
' uploader_id ' : ' rlantnghks ' ,
' uploader ' : ' 페이즈으 ' ,
' duration ' : 10840 ,
' thumbnail ' : r ' re:https?://videoimg \ .sooplive \ .co/.kr/.+ ' ,
' upload_date ' : ' 20230108 ' ,
' timestamp ' : 1673218805 ,
' title ' : ' 젠지 페이즈 ' ,
} ,
} , {
' md5 ' : ' 58f2ce7f6044e34439ab2d50612ab02b ' ,
' info_dict ' : {
' id ' : ' 36153164_2 ' ,
' ext ' : ' mp4 ' ,
' title ' : " BJ유트루와 함께하는 ' 팅커벨 메이크업! ' " ,
' upload_date ' : ' 20160502 ' ,
' params ' : {
' skip_download ' : True ,
} ,
} ] ,
' skip ' : ' Video is gone ' ,
} , {
# non standard key
' url ' : ' http://vod. afreecatv.com /PLAYER/STATION/20515605' ,
' url ' : ' http://vod.sooplive.co.kr/PLAYER/STATION/20515605 ' ,
' info_dict ' : {
' id ' : ' 20170411_BE689A0E_190960999_1_2_h ' ,
' ext ' : ' mp4 ' ,
' title ' : ' 혼자사는여자집 ' ,
' thumbnail ' : ' re:^https?://(?:video|st)img.afreecatv.com/.*$ ' ,
' thumbnail ' : r' re:https?://(?:video|st)img \ .sooplive \ .co \ .kr/.+ ' ,
' uploader ' : ' ♥이슬이 ' ,
' uploader_id ' : ' dasl8121 ' ,
' upload_date ' : ' 20170411 ' ,
@ -142,12 +106,12 @@ class AfreecaTVIE(AfreecaTVBaseIE):
} ,
} , {
# adult content
' url ' : ' https://vod. afreecatv.com /player/97267690' ,
' url ' : ' https://vod. sooplive.co.kr /player/97267690' ,
' info_dict ' : {
' id ' : ' 20180327_27901457_202289533_1 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' [생]빨개요♥ (part 1) ' ,
' thumbnail ' : ' re:^https?://(?:video|st)img.afreecatv.com/.*$ ' ,
' thumbnail ' : r' re:https?://(?:video|st)img \ .sooplive \ .co \ .kr/.+ ' ,
' uploader ' : ' [SA]서아 ' ,
' uploader_id ' : ' bjdyrksu ' ,
' upload_date ' : ' 20180327 ' ,
@ -157,36 +121,17 @@ class AfreecaTVIE(AfreecaTVBaseIE):
' skip_download ' : True ,
} ,
' skip ' : ' The VOD does not exist ' ,
} , {
' url ' : ' http://www.afreecatv.com/player/Player.swf?szType=szBjId=djleegoon&nStationNo=11273158&nBbsNo=13161095&nTitleNo=36327652 ' ,
' only_matching ' : True ,
} , {
' url ' : ' https://vod.afreecatv.com/player/96753363 ' ,
' info_dict ' : {
' id ' : ' 20230108_9FF5BEE1_244432674_1 ' ,
' ext ' : ' mp4 ' ,
' uploader_id ' : ' rlantnghks ' ,
' uploader ' : ' 페이즈으 ' ,
' duration ' : 10840 ,
' thumbnail ' : r ' re:https?://videoimg \ .afreecatv \ .com/.+ ' ,
' upload_date ' : ' 20230108 ' ,
' timestamp ' : 1673218805 ,
' title ' : ' 젠지 페이즈 ' ,
} ,
' params ' : {
' skip_download ' : True ,
} ,
} , {
# adult content
' url ' : ' https://vod. afreecatv.com /player/70395877' ,
' url ' : ' https://vod.sooplive.co.kr/player/70395877 ' ,
' only_matching ' : True ,
} , {
# subscribers only
' url ' : ' https://vod. afreecatv.com /player/104647403' ,
' url ' : ' https://vod.sooplive.co.kr/player/104647403 ' ,
' only_matching ' : True ,
} , {
# private
' url ' : ' https://vod. afreecatv.com /player/81669846' ,
' url ' : ' https://vod.sooplive.co.kr/player/81669846 ' ,
' only_matching ' : True ,
} ]
@ -262,11 +207,11 @@ class AfreecaTVIE(AfreecaTVBaseIE):
class AfreecaTVCatchStoryIE ( AfreecaTVBaseIE ) :
IE_NAME = ' afreecatv :catchstory'
IE_DESC = ' afreecatv.com catch story'
_VALID_URL = r ' https?://vod \ . afreecatv\ .com /player/(?P<id>\ d+)/catchstory '
IE_NAME = ' soop :catchstory'
IE_DESC = ' sooplive.co.kr catch story'
_VALID_URL = r ' https?://vod \ . (?:sooplive\ .co \ .kr| afreecatv\ .com ) /player/(?P<id>\ d+)/catchstory '
_TESTS = [ {
' url ' : ' https://vod. afreecatv.com /player/103247/catchstory' ,
' url ' : ' https://vod. sooplive.co.kr /player/103247/catchstory' ,
' info_dict ' : {
' id ' : ' 103247 ' ,
} ,
@ -299,11 +244,11 @@ class AfreecaTVCatchStoryIE(AfreecaTVBaseIE):
class AfreecaTVLiveIE ( AfreecaTVBaseIE ) :
IE_NAME = ' afreecatv :live'
IE_DESC = ' afreecatv.com livestreams'
_VALID_URL = r ' https?://play \ . afreeca(?: tv)? \ .com /(?P<id>[^/]+)(?:/(?P<bno>\ d+))? '
IE_NAME = ' soop :live'
IE_DESC = ' sooplive.co.kr livestreams'
_VALID_URL = r ' https?://play \ . (?:sooplive\ .co \ .kr| afreecatv\ .com ) /(?P<id>[^/?# ]+)(?:/(?P<bno>\ d+))? '
_TESTS = [ {
' url ' : ' https://play. afreecatv.com /pyh3646/237852185' ,
' url ' : ' https://play. sooplive.co.kr /pyh3646/237852185' ,
' info_dict ' : {
' id ' : ' 237852185 ' ,
' ext ' : ' mp4 ' ,
@ -315,30 +260,30 @@ class AfreecaTVLiveIE(AfreecaTVBaseIE):
} ,
' skip ' : ' Livestream has ended ' ,
} , {
' url ' : ' https://play. afreecatv.com /pyh3646/237852185' ,
' url ' : ' https://play. sooplive.co.kr /pyh3646/237852185' ,
' only_matching ' : True ,
} , {
' url ' : ' https://play. afreecatv.com /pyh3646' ,
' url ' : ' https://play. sooplive.co.kr /pyh3646' ,
' only_matching ' : True ,
} ]
_LIVE_API_URL = ' https://live. afreecatv.com /afreeca/player_live_api.php'
_LIVE_API_URL = ' https://live. sooplive.co.kr /afreeca/player_live_api.php'
_WORKING_CDNS = [
' gcp_cdn ' , # live-global-cdn-v02. afreecatv.com
' gs_cdn_pc_app ' , # pc-app.stream. afreecatv.com
' gs_cdn_mobile_web ' , # mobile-web.stream. afreecatv.com
' gs_cdn_pc_web ' , # pc-web.stream. afreecatv.com
' gcp_cdn ' , # live-global-cdn-v02. sooplive.co.kr
' gs_cdn_pc_app ' , # pc-app.stream. sooplive.co.kr
' gs_cdn_mobile_web ' , # mobile-web.stream. sooplive.co.kr
' gs_cdn_pc_web ' , # pc-web.stream. sooplive.co.kr
]
_BAD_CDNS = [
' gs_cdn ' , # chromecast.afreeca.gscdn.com (cannot resolve)
' gs_cdn_chromecast ' , # chromecast.stream. afreecatv.com (HTTP Error 400)
' azure_cdn ' , # live-global-cdn-v01. afreecatv.com (cannot resolve)
' aws_cf ' , # live-global-cdn-v03. afreecatv.com (cannot resolve)
' kt_cdn ' , # kt.stream. afreecatv.com (HTTP Error 400)
' gs_cdn_chromecast ' , # chromecast.stream. sooplive.co.kr (HTTP Error 400)
' azure_cdn ' , # live-global-cdn-v01. sooplive.co.kr (cannot resolve)
' aws_cf ' , # live-global-cdn-v03. sooplive.co.kr (cannot resolve)
' kt_cdn ' , # kt.stream. sooplive.co.kr (HTTP Error 400)
]
def _extract_formats ( self , channel_info , broadcast_no , aid ) :
stream_base_url = channel_info . get ( ' RMD ' ) or ' https://livestream-manager. afreecatv.com '
stream_base_url = channel_info . get ( ' RMD ' ) or ' https://livestream-manager. sooplive.co.kr '
# If user has not passed CDN IDs, try API-provided CDN ID followed by other working CDN IDs
default_cdn_ids = orderedSet ( [
@ -358,7 +303,7 @@ class AfreecaTVLiveIE(AfreecaTVBaseIE):
try :
return self . _extract_m3u8_formats (
m3u8_url , broadcast_no , ' mp4 ' , m3u8_id = ' hls ' , query = { ' aid ' : aid } ,
headers = { ' Referer ' : ' https://play. afreecatv.com /' } )
headers = { ' Referer ' : ' https://play. sooplive.co.kr /' } )
except ExtractorError as e :
if attempt == len ( cdn_ids ) :
raise
@ -374,7 +319,13 @@ class AfreecaTVLiveIE(AfreecaTVBaseIE):
broadcaster_id = channel_info . get ( ' BJID ' ) or broadcaster_id
broadcast_no = channel_info . get ( ' BNO ' ) or broadcast_no
if not broadcast_no :
result = channel_info . get ( ' RESULT ' )
if result == 0 :
raise UserNotLive ( video_id = broadcaster_id )
elif result == - 6 :
self . raise_login_required (
' This channel is streaming for subscribers only ' , method = ' password ' )
raise ExtractorError ( ' Unable to extract broadcast number ' )
password = self . get_param ( ' videopassword ' )
if channel_info . get ( ' BPWD ' ) == ' Y ' and password is None :
@ -403,7 +354,7 @@ class AfreecaTVLiveIE(AfreecaTVBaseIE):
formats = self . _extract_formats ( channel_info , broadcast_no , aid )
station_info = traverse_obj ( self . _download_json (
' https://st. afreecatv.com /api/get_station_status.php' , broadcast_no ,
' https://st. sooplive.co.kr /api/get_station_status.php' , broadcast_no ,
' Downloading channel metadata ' , ' Unable to download channel metadata ' ,
query = { ' szBjId ' : broadcaster_id } , fatal = False ) , { dict } ) or { }
@ -419,11 +370,11 @@ class AfreecaTVLiveIE(AfreecaTVBaseIE):
}
class AfreecaTVUserIE ( InfoExtractor ) :
IE_NAME = ' afreecatv :user'
_VALID_URL = r ' https?:// bj\ .afreeca(?:tv)? \ .com/(?P<id>[^/]+)/vods/?(?P<slug_type>[^/ ]+)?'
class AfreecaTVUserIE ( AfreecaTVBaseIE ) :
IE_NAME = ' soop :user'
_VALID_URL = r ' https?:// ch\ .(?:sooplive \ .co \ .kr|afreecatv \ .com)/(?P<id>[^/?#]+)/vods/?(?P<slug_type>[^/?# ]+)?'
_TESTS = [ {
' url ' : ' https:// bj.afreecatv.com /ryuryu24/vods/review' ,
' url ' : ' https:// ch.sooplive.co.kr /ryuryu24/vods/review' ,
' info_dict ' : {
' _type ' : ' playlist ' ,
' id ' : ' ryuryu24 ' ,
@ -431,7 +382,7 @@ class AfreecaTVUserIE(InfoExtractor):
} ,
' playlist_count ' : 218 ,
} , {
' url ' : ' https:// bj.afreecatv.com /parang1995/vods/highlight' ,
' url ' : ' https:// ch.sooplive.co.kr /parang1995/vods/highlight' ,
' info_dict ' : {
' _type ' : ' playlist ' ,
' id ' : ' parang1995 ' ,
@ -439,7 +390,7 @@ class AfreecaTVUserIE(InfoExtractor):
} ,
' playlist_count ' : 997 ,
} , {
' url ' : ' https:// bj.afreecatv.com /ryuryu24/vods' ,
' url ' : ' https:// ch.sooplive.co.kr /ryuryu24/vods' ,
' info_dict ' : {
' _type ' : ' playlist ' ,
' id ' : ' ryuryu24 ' ,
@ -447,7 +398,7 @@ class AfreecaTVUserIE(InfoExtractor):
} ,
' playlist_count ' : 221 ,
} , {
' url ' : ' https:// bj.afreecatv.com /ryuryu24/vods/balloonclip' ,
' url ' : ' https:// ch.sooplive.co.kr /ryuryu24/vods/balloonclip' ,
' info_dict ' : {
' _type ' : ' playlist ' ,
' id ' : ' ryuryu24 ' ,
@ -459,12 +410,12 @@ class AfreecaTVUserIE(InfoExtractor):
def _fetch_page ( self , user_id , user_type , page ) :
page + = 1
info = self . _download_json ( f ' https:// bjapi.afreecatv.com /api/{ user_id } /vods/ { user_type } ' , user_id ,
info = self . _download_json ( f ' https:// chapi.sooplive.co.kr /api/{ user_id } /vods/ { user_type } ' , user_id ,
query = { ' page ' : page , ' per_page ' : self . _PER_PAGE , ' orderby ' : ' reg_date ' } ,
note = f ' Downloading { user_type } video page { page } ' )
for item in info [ ' data ' ] :
yield self . url_result (
f ' https://vod. afreecatv.com /player/{ item [ " title_no " ] } / ' , AfreecaTVIE , item [ ' title_no ' ] )
f ' https://vod. sooplive.co.kr /player/{ item [ " title_no " ] } / ' , AfreecaTVIE , item [ ' title_no ' ] )
def _real_extract ( self , url ) :
user_id , user_type = self . _match_valid_url ( url ) . group ( ' id ' , ' slug_type ' )