11import downloader
2- from utils import Soup , Downloader , Session , try_n , format_filename , cut_pair , File , get_print
2+ from utils import Soup , Downloader , Session , try_n , format_filename , cut_pair , File , get_print , print_error , json
33import ree as re
44from io import BytesIO
55from m3u8_tools import playlist2stream , M3u8_stream
66import errors
7- import json
7+ import utils
8+ import os
89
910
1011class LoginRequired (errors .LoginRequired ):
@@ -18,6 +19,7 @@ class Downloader_afreeca(Downloader):
1819 URLS = ['afreecatv.com' ]
1920 single = True
2021 display_name = 'AfreecaTV'
22+ ACCEPT_COOKIES = [r'(.*\.)?afreecatv\.com' ]
2123
2224 def init (self ):
2325 self .session = Session ()
@@ -35,27 +37,40 @@ def read(self):
3537 downloader .download (video ['url_thumb' ], buffer = thumb )
3638 self .setIcon (thumb )
3739
38- self .title = video ['title' ]
40+ self .title = os .path .splitext (video ['name' ])[0 ].replace (':' , ':' )
41+ self .artist = video ['artist' ]
42+
43+ if video ['live' ]:
44+ d = {}
45+ d ['url' ] = self .url
46+ d ['title' ] = self .artist
47+ d ['thumb' ] = thumb .getvalue ()
48+ utils .update_live (d , self .cw )
3949
4050
4151@try_n (4 )
42- def _get_stream (url_m3u8 ):
43- print ('_get_stream' , url_m3u8 )
52+ def _get_stream (url_m3u8 , session , referer , cw = None ):
53+ print_ = get_print (cw )
54+ print_ (f'_get_stream: { url_m3u8 } ' )
4455 try :
45- stream = playlist2stream (url_m3u8 )
56+ stream = playlist2stream (url_m3u8 , referer = referer , session = session )
4657 except Exception as e :
47- print ( e )
48- stream = M3u8_stream (url_m3u8 )
58+ print_ ( print_error ( e ) )
59+ stream = M3u8_stream (url_m3u8 , referer = referer , session = session )
4960 return stream
5061
5162
5263
5364class Video (File ):
5465 type = 'afreeca'
66+ _live_info = None
5567
5668 def get (self ):
5769 print_ = get_print (self .cw )
5870 url , session = self ['referer' ], self .session
71+ if session is None :
72+ session = Session ()
73+ session .purge ('afreeca' )
5974
6075 html = downloader .read_html (url , session = session )
6176 if "document.location.href='https://login." in html :
@@ -69,8 +84,34 @@ def get(self):
6984 url_thumb = soup .find ('meta' , {'property' : 'og:image' }).attrs ['content' ]
7085 print_ ('url_thumb: {}' .format (url_thumb ))
7186
72- vid = re .find ('/player/([0-9]+)' , url , err = 'no vid' )
73- if f'{ vid } /catch' in url : #6215
87+ vid = re .find ('/player/([0-9]+)' , url )
88+ if vid is None : # live
89+ bid = re .find ('afreecatv.com/([^/]+)' , url , err = 'no bid' )
90+
91+ url_api = f'https://st.afreecatv.com/api/get_station_status.php?szBjId={ bid } '
92+ r = session .post (url_api , headers = {'Referer' : url })
93+ d = json .loads (r .text )
94+ artist = d ['DATA' ]['user_nick' ]
95+ if self ._live_info is not None :
96+ self ._live_info ['title' ] = artist
97+
98+ url_api = f'https://live.afreecatv.com/afreeca/player_live_api.php?bjid={ bid } '
99+ #bno = re.find('afreecatv.com/[^/]+/([0-9]+)', url, err='no bno')
100+ bno = re .find (r'nBroadNo\s=\s([0-9]+)' , html , err = 'no bno' ) #6915
101+ r = session .post (url_api , data = {'bid' : bid , 'bno' : bno , 'type' : 'aid' , 'pwd' : '' , 'player_type' : 'html5' , 'stream_type' : 'common' , 'quality' : 'master' , 'mode' : 'landing' , 'from_api' : '0' }, headers = {'Referer' : url })
102+ d = json .loads (r .text )
103+ res = d ['CHANNEL' ].get ('RESULT' )
104+ print_ (f'result: { res } ' )
105+ if res == - 6 :
106+ raise LoginRequired ()
107+ aid = d ['CHANNEL' ]['AID' ]
108+
109+ data = {}
110+ data ['title' ] = soup .find ('meta' , {'property' : 'og:title' })['content' ].strip ()
111+ data ['files' ] = [{'file' : f'https://pc-web.stream.afreecatv.com/live-stm-16/auth_master_playlist.m3u8?aid={ aid } ' }]
112+ data ['writer_nick' ] = artist
113+ data ['live' ] = True
114+ elif f'{ vid } /catch' in url : #6215
74115 url_api = 'https://api.m.afreecatv.com/station/video/a/catchview'
75116 r = session .post (url_api , data = {'nPageNo' : '1' , 'nLimit' : '10' , 'nTitleNo' : vid }, headers = {'Referer' : url })
76117 try :
@@ -92,6 +133,7 @@ def get(self):
92133 data = d ['data' ]
93134
94135 title = data .get ('full_title' ) or data ['title' ]
136+ artist = data .get ('copyright_nickname' ) or data .get ('original_user_nick' ) or data ['writer_nick' ]
95137
96138 if data .get ('adult_status' ) == 'notLogin' :
97139 raise LoginRequired (title )
@@ -105,16 +147,47 @@ def get(self):
105147 urls_m3u8 .append (file )
106148 print_ (f'urls_m3u8: { len (urls_m3u8 )} ' )
107149
108- streams = []
109- for url_m3u8 in urls_m3u8 :
110- try :
111- stream = _get_stream (url_m3u8 )
112- except Exception as e :
113- print (e )
114- continue #2193
115- streams .append (stream )
116- for stream in streams [1 :]:
117- streams [0 ] += stream
118- stream = streams [0 ]
119-
120- return {'url' : stream , 'title' : title , 'name' : format_filename (title , vid , '.mp4' ), 'url_thumb' : url_thumb }
150+ if data .get ('live' ):
151+ hdr = session .headers .copy ()
152+ hdr ['Referer' ] = url
153+ stream = utils .LiveStream (urls_m3u8 [0 ], headers = hdr , cw = self .cw )
154+ else :
155+ streams = []
156+ for url_m3u8 in urls_m3u8 :
157+ try :
158+ stream = _get_stream (url_m3u8 , session , url , cw = self .cw )
159+ except Exception as e :
160+ print_ (print_error (e ))
161+ continue #2193
162+ streams .append (stream )
163+ for stream in streams [1 :]:
164+ streams [0 ] += stream
165+ stream = streams [0 ]
166+
167+ live = data .get ('live' ) or False
168+ return {'url' : stream , 'title' : title , 'name' : format_filename (title , vid , '.mp4' , artist = artist , live = live ), 'url_thumb' : url_thumb , 'artist' : artist , 'live' : live }
169+
170+
171+
172+ class Live_afreeca (utils .Live ):
173+ type = 'afreeca'
174+
175+ @classmethod
176+ def is_live (cls , url ):
177+ return bool (re .match (r'https?://(play|bj).afreecatv.com/([^/?#]+)' , url ))
178+
179+ @classmethod
180+ def fix_url (cls , url ):
181+ bj = re .find (r'https?://(play|bj).afreecatv.com/([^/?#]+)' , url )[1 ]
182+ return f'https://play.afreecatv.com/{ bj } '
183+
184+ @classmethod
185+ def check_live (cls , url , info = None ):
186+ try :
187+ video = Video ({'referer' : url })
188+ video ._live_info = info
189+ video .ready (None )
190+ return True
191+ except Exception as e :
192+ print (e )
193+ return False
0 commit comments