Beispiel #1
0
    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())
Beispiel #2
0
    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
Beispiel #3
0
    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