async def video(self, url, media_dir, title, playurl): """ :param url: hls 视频流文件 :param media_dir: 下载保存目录 :param title: 视频标题 :param playurl: ts文件地址 :return: """ resp = await self.client.get(url, headers=self.header) media = loads(resp.text) # 拼接ts文件列表 playlist = [ "{playurl}{uri}".format(playurl=playurl, uri=uri) for uri in media.segments.uri ] n = 0 new_segments = [] semaphore = asyncio.BoundedSemaphore(20) tasks = [] # get ts file list # async with self.client.parallel() as parallel: for url in playlist: ts_file = os.path.join(media_dir, title, 'm_{num}.ts'.format(num=n)) ts_path = os.path.join(title, 'm_{num}.ts'.format(num=n)) media.data['segments'][n]['uri'] = ts_path new_segments.append(media.data.get('segments')[n]) tasks.append( asyncio.ensure_future( self.fetch_single_ts_file(url, ts_file, semaphore))) n += 1 results = await asyncio.gather(*tasks) for download_result in results: if not download_result.success: logger.exception("url: {} download failed, reason: {}".format( download_result.data_url, download_result.reason)) # change m3u8 data media.data['segments'] = new_segments # 修改m3u8文件信息 segments = SegmentList([ Segment(base_uri=None, keyobject=find_key(segment.get('key', {}), media.keys), **segment) for segment in media.data.get('segments', []) ]) media.segments = segments # save m3u8 file m3u8_file = os.path.join(media_dir, '{title}.m3u8'.format(title=title)) if not os.path.exists(m3u8_file): with open(m3u8_file, 'w', encoding='utf8') as f: f.write(media.dumps())
def download_video(self, download_dir, resource, nocache=False): resource_dir = os.path.join(download_dir, resource['id']) os.makedirs(resource_dir, exist_ok=True) url = resource['video_hls'].replace('\\', '') self.session.headers.update({ 'Referer': 'https://pc-shop.xiaoe-tech.com/{appid}/video_details?id={resourceid}' .format(appid=self.appid, resourceid=resource['id']) }) media = m3u8.loads(self.session.get(url).text) url_prefix, segments, changed, complete = url.split( 'v.f230')[0], SegmentList(), False, True print('Total: {} part'.format(len(media.data['segments']))) for index, segment in enumerate(media.data['segments']): ts_file = os.path.join(resource_dir, 'v_{}.ts'.format(index)) if not nocache and os.path.exists(ts_file): print('Already Downloaded: {title} {file}'.format( title=resource['title'], file=ts_file)) else: url = url_prefix + segment.get('uri') res = self.session.get(url) if res.status_code == 200: with open(ts_file + '.tmp', 'wb') as ts: ts.write(res.content) os.rename(ts_file + '.tmp', ts_file) changed = True print('Download Successful: {title} {file}'.format( title=resource['title'], file=ts_file)) else: print('Download Failed: {title} {file}'.format( title=resource['title'], file=ts_file)) complete = False segment['uri'] = 'v_{}.ts'.format(index) segments.append( Segment(base_uri=None, keyobject=find_key(segment.get('key', {}), media.keys), **segment)) m3u8_file = os.path.join(resource_dir, 'video.m3u8') if changed or not os.path.exists(m3u8_file): media.segments = segments with open(m3u8_file, 'w', encoding='utf8') as f: f.write(media.dumps()) metadata = {'title': resource['title'], 'complete': complete} with open(os.path.join(download_dir, resource['id'], 'metadata'), 'w') as f: json.dump(metadata, f) return
def video(self, url, media_dir, title, playurl): ''' :param url: hls 视频流文件 :param media_dir: 下载保存目录 :param title: 视频标题 :param playurl: ts文件地址 :return: ''' resp = self.session.get(url, headers=self.header) media = loads(resp.text) # 拼接ts文件列表 playlist = ["{playurl}{uri}".format(playurl=playurl, uri=uri) for uri in media.segments.uri] n = 0 new_segments = [] # get ts file list for url in playlist: ts_file = os.path.join(media_dir, title, 'm_{num}.ts'.format(num=n)) ts_path = os.path.join(title, 'm_{num}.ts'.format(num=n)) media.data['segments'][n]['uri'] = ts_path new_segments.append(media.data.get('segments')[n]) # 下载ts文件 resp = self.session.get(url, headers=self.header, cookies=self.cookie) if resp.status_code != 200: print('Error: {title} {tsfile}'.format(title=title, tsfile=ts_file)) # 如果文件不存在或者本地文件大小于接口返回大小不一致则保存ts文件 if not os.path.exists(ts_file) or os.stat(ts_file).st_size != resp.headers['content-length']: with open(ts_file, 'wb') as ts: ts.write(resp.content) n += 1 # change m3u8 data media.data['segments'] = new_segments # 修改m3u8文件信息 segments = SegmentList( [Segment(base_uri=None, keyobject=find_key(segment.get('key', {}), media.keys), **segment) for segment in media.data.get('segments', [])]) media.segments = segments # save m3u8 file m3u8_file = os.path.join(media_dir, '{title}.m3u8'.format(title=title)) if not os.path.exists(m3u8_file): with open(m3u8_file, 'wb', encoding='utf8') as f: f.write(media.dumps())
def refreshM3U8(): global delayed_playlist, delay_segments try: path = os.path.join(directory, 'stream.m3u8') utility.download(args.url, path) playlist = utility.parseM3U8(path) tmp_delayed_playlist = [d.uri for d in delayed_playlist] listdir = os.listdir(directory) for f in listdir: if f != 'stream.m3u8' and f != 'stream.delay.m3u8' and f[ -6:] != ".aria2" and f[-12:] != ".aria2__temp": if f not in playlist.segments.uri and tmp_delayed_playlist and f not in tmp_delayed_playlist: segments.remove(f) os.remove(os.path.join(directory, f)) print("Old segment deleted:" + str(f)) if not playlist.segments: raise Exception("Invalid playlist") if playlist.target_duration is not None: delay_segments = int(args.delay / playlist.target_duration) + len( playlist.segments) for item in playlist.segments: segments.add(item.uri) if item.uri not in tmp_delayed_playlist: delayed_playlist.append(item) if len(delayed_playlist) > delay_segments: delayed_playlist = delayed_playlist[-1 * delay_segments:] segments_tmp = [] for item in delayed_playlist[:int(len(playlist.segments) / 2) + 1]: segments_tmp.append(item) playlist.segments = SegmentList(segments_tmp) del segments_tmp playlist.media_sequence = int( filter(str.isdigit, delayed_playlist[0].uri)) playlist.dump(os.path.join(directory, 'stream.delay.m3u8')) print("Delayed playlist updated") print("Playlist updated") aria_list = segments._aria.tellWaiting(0, 1000) listdir = os.listdir(directory) tmp_delayed_playlist = [d.uri for d in delayed_playlist] uncomplete_segments = utility.listDiff(tmp_delayed_playlist, listdir) waiting_list = [] for item in aria_list: waiting_list.append( os.path.basename(item['files'][0]['uris'][0]['uri'])) failed_segments = utility.listDiff(uncomplete_segments, waiting_list) for item in failed_segments: segments.add(item) if failed_segments: print(str(len(failed_segments)) + " failed segments added to aria") del tmp_delayed_playlist, aria_list, waiting_list except HTTPError as e: print("Error while refreshing M3U8: " + str(e)) except Exception as e: print("Error while processing M3U8: " + str(e)) exc_info = None try: exc_info = sys.exc_info() finally: traceback.print_exception(*exc_info) del exc_info