Ejemplo n.º 1
0
 def _downloadSmallFile(self, url, filename):
     debug('begin _downloadSmallFile')
     try:
         if not os.path.exists(os.path.dirname(filename)):
             os.makedirs(os.path.dirname(filename))
         for proto in ['http', 'https']:
             if re.match(r'http', url):
                 tempUrl = url
             else:
                 if re.match(r'://', url):
                     tempUrl = '%s%s' % (proto, url)
                 elif re.match(r'//', url):
                     tempUrl = '%s:%s' % (proto, url)
                 else:
                     tempUrl = '%s://%s' % (proto, url)
             try:
                 webpage = self._ydl.urlopen(tempUrl).read()
                 f = open(filename, 'wb')
                 f.write(webpage)
                 f.close()
                 debug('end _downloadSmallFile Sucess')
                 break
             except Exception as e:
                 if re.match(r'http', url):  #原来就有http头的就不要重试了
                     raise e
                 else:
                     debug(e)
     except Exception as e:
         debug('end _downloadSmallFile fail Exception:')
         debug(e)
Ejemplo n.º 2
0
    def get_mediainfo(self, msg):
        filename = msg['destFile']
        if not os.path.exists(filename):
            return

        try:
            ffpp = FFmpegPostProcessor(downloader=self._ydl)
            args = [ffpp.executable]
            args += ['-i', filename]
            p = subprocess.Popen(args,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE,
                                 startupinfo=get_startinfo())
            stdout, stderr = p.communicate()
            # 获取成功
            if p.returncode != 0:
                stderr = stderr.decode('utf-8', 'replace')
                # 时长
                m = re.search(r'Duration\:\s*((?:\d\d[.:]){3}\d\d)', stderr)
                if m:
                    duration = m.group(1)
                    h, m, s = duration.strip().split(':')
                    msg['duration'] = int(h) * 3600 + int(m) * 60 + float(s)
                # 分辨率
                m = re.search(r'\d{2,}x\d{2,}', stderr)
                if m:
                    msg['resolution'] = m.group()

                # 缩略图
                thumb = msg.get('thumbnail', '')
                if thumb != '' and not os.path.exists(thumb):
                    msg['thumbnail'] = thumb
                    start_pos = random.uniform(5, 20)
                    if msg.get('duration', 0) < start_pos:
                        start_pos = 0
                    start_pos = str(start_pos)
                    try:
                        args = [ffpp.executable]
                        args += ['-ss', start_pos]
                        args += ['-i', filename]
                        args += ['-f', 'image2']
                        args += ['-y', thumb]
                        p = subprocess.Popen(args,
                                             stdout=subprocess.PIPE,
                                             stderr=subprocess.PIPE,
                                             startupinfo=get_startinfo())
                        p.communicate()
                    except:
                        msg.pop('thumbnail')

            self._GA.send('event', 'get_mediainfo', 'success', '')
        except Exception as e:
            self._GA.send('event', 'get_mediainfo', 'fail',
                          traceback.format_exc())
            debug(traceback.format_exc())
Ejemplo n.º 3
0
 def fixup_m3u8(self):
     try:
         converter = FFmpegFixupM3u8PPForToggle(self._ydl)
         info_dict = {}
         # 源文件
         info_dict['filepath'] = self._infos['downloadingFiles'].keys()[0]
         # 目标文件
         dest_filename = '%s\m3u8_fix%s' % (
             self._downloadtempPath,
             os.path.splitext(self._infos['destFileName'])[1])
         info_dict['destpath'] = dest_filename
         converter.run(info_dict)
         self.move_to_dest(dest_filename)
         self._GA.send('event', 'fixup_m3u8', 'success', '')
     except Exception as e:
         self._GA.send('event', 'fixup_m3u8', 'fail',
                       traceback.format_exc())
         debug(traceback.format_exc())
Ejemplo n.º 4
0
 def convert_to_mp3(self):
     try:
         converter = FFmpegExtractMp3(
             self._ydl, preferredquality=self._infos['quality'])
         info_dict = {}
         # 源文件
         info_dict['filepath'] = self._infos['downloadingFiles'].keys()[0]
         # 目标文件
         dest_filename = '%s\youtube_audio%s' % (
             self._downloadtempPath,
             os.path.splitext(self._infos['destFileName'])[1])
         info_dict['destpath'] = dest_filename
         info_dict['filetime'] = self._infos.get('last-modified', None)
         converter.run(info_dict)
         self.move_to_dest(dest_filename)
         self._GA.send('event', 'convert_to_mp3', 'success', '')
     except Exception as e:
         self._GA.send('event', 'convert_to_mp3', 'fail',
                       traceback.format_exc())
         debug(traceback.format_exc())
Ejemplo n.º 5
0
 def _beforeDownload(self, filename, info):
     debug('_download begin %s' % filename)
     debug('......info......')
     debug(info)
     debug('......info......')
     if type(filename) != compat_str:
         try:
             filename = unicode(filename)
         except:
             filename = filename.decode('utf-8')
     if not os.path.exists(os.path.dirname(filename)):
         os.makedirs(os.path.dirname(filename))
     return filename
Ejemplo n.º 6
0
 def dash_merge_WEBM(self):
     try:
         from youtube_dl.postprocessor import FFmpegMergerPP
         merger = FFmpegMergerPP(self._ydl)
         info_dict = {}
         for item in self._infos['downloadingFiles'].keys():
             if re.search(r'opus|vorbis|m4a', item):
                 audio = item
             else:
                 video = item
         dest_filename = '%s\youtube_meger%s' % (os.path.dirname(video),
                                                 os.path.splitext(video)[1])
         info_dict['__files_to_merge'] = [video, audio]
         info_dict['filepath'] = dest_filename
         merger.run(info_dict)
         self.move_to_dest(dest_filename)
         self._GA.send('event', 'dash_merge_WEBM', 'success', '')
     except Exception as e:
         self._GA.send('event', 'dash_merge_WEBM', 'fail',
                       traceback.format_exc())
         debug(traceback.format_exc())
Ejemplo n.º 7
0
 def multi_video_concat(self):
     try:
         concater = FFmpegConcatMultiVideo(self._ydl,
                                           self._infos['quality'])
         info_dict = {}
         # 源文件
         dt = sorted(self._infos['downloadingFiles'].iteritems(),
                     key=lambda item: item[1]['order'])
         src_files = [item[0] for item in dt]
         info_dict['__files_to_concat'] = src_files
         # 目标文件
         dest_filename = '%s\youtube_concat%s' % (
             self._downloadtempPath,
             os.path.splitext(self._infos['destFileName'])[1])
         info_dict['destpath'] = dest_filename
         concater.run(info_dict)
         self.move_to_dest(dest_filename)
         self._GA.send('event', 'multi_video_merge', 'success', '')
     except Exception as e:
         self._GA.send('event', 'multi_video_merge', 'fail',
                       traceback.format_exc())
         debug(traceback.format_exc())
Ejemplo n.º 8
0
 def move_to_dest(self, source):
     debug('Copy file to dest dir!')
     try:
         self.fix_dest_filename()
         os.chdir(os.path.dirname(source))
         dest = self._infos['destFileName']
         os.rename(source, dest)
         # 拷贝字幕
         if os.path.exists(self._subtitleFile):
             debug('Move Subtitle to Dest Begin...')
             subtitle_ext = os.path.splitext(self._subtitleFile)[1]
             dst_subtitle = os.path.splitext(
                 self._infos['destFileName'])[0] + subtitle_ext
             os.rename(self._subtitleFile, dst_subtitle)
             debug('Move Subtitle to Dest End')
     except Exception as e:
         debug(e)
     try:
         shutil.rmtree(self._infos.get('downloadTempPath'))
     except:
         pass
Ejemplo n.º 9
0
    def downloadThumbnail(self, url, fileName):
        debug('downloadThumbnail begin')
        try:
            # 置位,以便于ffmpeg获取
            self._infos['thumbnail_filename'] = fileName
            if not url or url == '':
                return
            if not os.path.exists(fileName):
                self._downloadSmallFile(url, fileName)

            if os.path.exists(fileName):
                msg = {'event': 'download_thumbnail', 'filePath': fileName}
                if self._callback:
                    self._callback(msg)
        except:
            debug(traceback.format_exc())
            pass
        debug('downloadThumbnail end')
Ejemplo n.º 10
0
 def _download(self, filename, info):
     filename = self._beforeDownload(filename, info)
     if type(info) is not dict:
         info = eval(info)
         #'protocol': 'http_dash_segments',
     url = self._infos.get('url', None)
     host = get_top_host(url) if url else ''
     for i in range(3):
         try:
             debug('downloader.py _download try %d' % i)
             if info.has_key('fragments'):
                 info['protocol'] = 'http_dash_segments'
             fd = self.get_suitable_downloader(filename, info)
             fd.add_progress_hook(self.progress_hook)
             if fd.download(filename, info):
                 try:
                     url = self._infos.get('url', None)
                     url = get_top_host(url) if url else ''
                     self._GA.send('event', 'download_success',
                                   type(fd).__name__, host)
                 except:
                     pass
                 break
             else:
                 raise Exception('downloadFail')
         except:
             if self._cancel:
                 break
             debug(traceback.format_exc())
             if i == 2:
                 try:
                     self._GA.send('event', 'download_fail',
                                   type(fd).__name__, host)
                     self._GA.send('event', 'fail_detail', host,
                                   traceback.format_exc())
                 except:
                     pass
                 raise Exception(traceback.format_exc())
             else:
                 threading._sleep(1)
     debug('_download end')
Ejemplo n.º 11
0
    def downloadWebSiteIcon(self, url, savePath):
        if url == '':
            return

        debug('downloadWebSiteIcon begin')
        try:
            if (not re.search(r'//', url)):
                url = 'http://' + url
            o = urlparse(url)
            fileName = os.path.join(savePath, '%s.ico' % o.netloc)
            if not os.path.exists(fileName):
                webpage = self._ydl.urlopen(url).read()
                mobj = re.search(
                    r'<link rel="shortcut icon"\s*href="([^\"]+)"', webpage)
                faviconURL = ''
                if mobj:
                    faviconURL = mobj.group(1)

                    if (not re.search(r'//', faviconURL)):
                        if faviconURL.find(r'/') == 0:
                            faviconURL = 'http://' + o.netloc + faviconURL
                        else:
                            faviconURL = 'http://' + faviconURL

                if not os.path.exists(fileName) and faviconURL != '':
                    info = {'url': faviconURL}
                    self._downloadSmallFile(fileName, info)

                if not os.path.exists(fileName):
                    faviconURL = '%s://%s/favicon.ico' % (o.scheme, o.netloc)
                    self._downloadSmallFile(faviconURL, fileName)

            if os.path.exists(fileName):
                msg = {'event': 'download_icon', 'filePath': fileName}
                if self._callback:
                    self._callback(msg)
        except:
            debug(traceback.format_exc())
            pass
        debug('downloadWebSiteIcon end')
Ejemplo n.º 12
0
    def run(self, information):
        destpath = information['destpath']
        if os.path.exists(destpath):
            os.remove(destpath)
        input_paths = information['__files_to_concat']
        oldest_mtime = min(os.stat(path).st_mtime for path in input_paths)

        # 构建文件列表文件
        input_txtfile = os.path.join(tempfile.gettempdir(), 'input_list.txt')
        if os.path.exists(input_txtfile):
            os.remove(input_txtfile)
        inputf = open(input_txtfile, 'w')
        for i, file in enumerate(input_paths):
            line = 'file \'%s\'' % file
            if i < len(input_paths) - 1:
                line += '\n'
            inputf.writelines(line)
        inputf.close()

        # 构建参数
        args = [self.executable]
        args += ['-f', 'concat']
        #Unsafe file name '/tmp/temp/Watch Naruto Shippuden Season 17
        args += ['-safe', '-1']
        args += ['-i', input_txtfile]
        args += ['-c', 'copy']
        # 置同一磁盘中,rename会很快,如同盘剪切...若是mp3,则需要再转换
        filename, ext = os.path.splitext(destpath)
        is_audio = True if 'mp3' in ext.lower() else False
        if is_audio:
            ext = '.mp4'
        # 若是音频,则置为mp4然后再转
        destpath_new = filename + ext
        args += [destpath_new]

        try:
            p = subprocess.Popen(args,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE,
                                 stdin=subprocess.PIPE,
                                 startupinfo=get_startinfo())
            stdout, stderr = p.communicate()
            if p.returncode != 0:
                stderr = stderr.decode('utf-8', 'replace')
                msg = stderr.strip().split('\n')[-1]
                raise FFmpegPostProcessorError(msg)

            # 若是mp3,需要再次转换
            if is_audio:
                converter = FFmpegExtractMp3(self._downloader,
                                             preferredquality=self._quality)
                info_dict = {}
                # 源文件
                info_dict['filepath'] = destpath_new
                # 目标文件
                info_dict['destpath'] = destpath
                converter.run(info_dict)
                os.remove(destpath_new)

            self.try_utime(destpath, oldest_mtime, oldest_mtime)
        except Exception as ex:
            debug('multi_video_concat error:')
            debug(ex)
            if is_audio:
                os.remove(destpath_new)
            raise ex
        finally:
            os.remove(input_txtfile)
Ejemplo n.º 13
0
    def run(self):
        try:
            self.prepareData()
            debug('downloadSubtitle')
            self.downloadSubtitle()
            debug('downloadThumbnailAndIcon')
            self.downloadThumbnailAndIcon(self._infos['fileNameWithoutExt'])
            # YouTube视频下载快于音频10倍,若先下载音频,用户感觉慢,因此给视频提前,感觉上下载快些
            src_medias = sorted(self._infos['downloadingFiles'].iteritems(),
                                key=lambda item: item[1]['order'])
            for key, value in src_medias:
                if self._cancel:
                    raise

                self._downloadingFile = key
                self._download(key, value['format'])
            if self._cancel:
                raise

            # 传与界面,需要原始顺序
            src_files = [item[0] for item in src_medias]
            msg = {
                'event':
                'download_complete',
                'sourceFiles':
                src_files,  #文件名
                'destFile':
                self._infos['destFileName'],
                'nextAction':
                self._infos.get(
                    'action', 'none'
                ),  # 应用层在下载完成之后需要响应的行为包括:"dash_merge(音视频合并), multi_video_merge(多段合并), convert_to_mp3(转换成mp3), none(不需要其他附加行为)"
                'thumbnail':
                self._infos['thumbnail_filename']
                if os.path.exists(self._infos['thumbnail_filename']) else ''
            }

            if os.path.exists(self._subtitleFile):
                msg['subtitle'] = self._subtitleFile,
            debug('------------------download complete-------------------')
            debug(msg)
            debug('------------------download complete-------------------')

            # mac系统,沿用旧逻辑
            if sys.platform != 'win32':
                # 正常结束,不需要额外工作
                if self._infos.get('action', 'none') == 'none':
                    self.move_to_dest(
                        self._infos['downloadingFiles'].keys()[0])
                    msg['destFile'] = self._infos['destFileName']
                elif self._infos.get('action', 'none') in ['dash_convert']:
                    debug(
                        '------------------download dash_convert Begin-------------------'
                    )
                    self.dash_merge_WEBM()
                    msg['destFile'] = self._infos['destFileName']
                    msg['nextAction'] = 'none'
                    debug(
                        '------------------download dash_convert End-------------------'
                    )
                elif self._infos.get('action', 'none') in ['fixM3u8']:
                    # 先发消息给产品,以更新其界面显示
                    if self._callback:
                        msg['nextAction'] = 'convert_progress'
                        self._callback(msg)
                    debug(
                        '------------------FFmpeg fixup m3u8 start-------------------'
                    )
                    self.fixup_m3u8()
                    msg['destFile'] = self._infos['destFileName']
                    msg['nextAction'] = 'none'
                    debug(
                        '------------------FFmpeg fixup m3u8 end-------------------'
                    )
            # windows系统,底层处理界面逻辑
            else:
                # 正常结束,不需要额外工作
                if self._infos.get('action', 'none') == 'none':
                    self.move_to_dest(
                        self._infos['downloadingFiles'].keys()[0])
                    msg['destFile'] = self._infos['destFileName']
                elif self._infos.get('action',
                                     'none') in ['dash_convert', 'dash_merge']:
                    # 先发消息给产品,以更新其界面显示
                    if self._callback:
                        msg['nextAction'] = 'merge_progress' if msg[
                            'nextAction'] == 'dash_merge' else 'convert_progress'
                        self._callback(msg)
                    debug(
                        '------------------download dash_convert Begin-------------------'
                    )
                    self.dash_merge_WEBM()
                    msg['destFile'] = self._infos['destFileName']
                    msg['nextAction'] = 'none'
                    debug(
                        '------------------download dash_convert End-------------------'
                    )
                # 多段视频连接
                elif self._infos.get('action',
                                     'none') in ['multi_video_merge']:
                    # 先发消息给产品,以更新其界面显示
                    if self._callback:
                        msg['nextAction'] = 'merge_progress'
                        self._callback(msg)
                    debug(
                        '------------------multi video merge start-------------------'
                    )
                    self.multi_video_concat()
                    msg['destFile'] = self._infos['destFileName']
                    msg['nextAction'] = 'none'
                    debug(
                        '------------------multi video merge end-------------------'
                    )
                elif self._infos.get('action', 'none') in ['convert2Mp3']:
                    # 先发消息给产品,以更新其界面显示
                    if self._callback:
                        msg['nextAction'] = 'convert_progress'
                        self._callback(msg)
                    debug(
                        '------------------convert to mp3 start-------------------'
                    )
                    self.convert_to_mp3()
                    msg['destFile'] = self._infos['destFileName']
                    msg['nextAction'] = 'none'
                    debug(
                        '------------------convert to mp3 end-------------------'
                    )
                elif self._infos.get('action', 'none') in ['fixM3u8']:
                    # 先发消息给产品,以更新其界面显示
                    if self._callback:
                        msg['nextAction'] = 'convert_progress'
                        self._callback(msg)
                    debug(
                        '------------------FFmpeg fixup m3u8 start-------------------'
                    )
                    self.fixup_m3u8()
                    msg['destFile'] = self._infos['destFileName']
                    msg['nextAction'] = 'none'
                    debug(
                        '------------------FFmpeg fixup m3u8 end-------------------'
                    )

                # 如果正常结束,即'event'为'None',windows这一支获取媒体文件信息
                if msg.get('nextAction', 'none') == 'none':
                    debug(
                        '------------------get_mediainfo start-------------------'
                    )
                    self.get_mediainfo(msg)
                    debug(
                        '------------------get_mediainfo end-------------------'
                    )

        except:
            if self._cancel:
                msg = {
                    'event': 'download_cancel',
                    'quality': self._infos.get('quality'),
                    'data': self._infos
                }
            else:
                error = traceback.format_exc()
                debug(error)
                msg = {
                    'event': 'download_error',
                    'error': error,
                }
                debug('downloader error!')

        if self._callback:
            self._callback(msg)
Ejemplo n.º 14
0
    def buildOptions(self, verbose=False):
        ydl_opts = {}
        ydl_opts['debug_printtraffic'] = 1
        ydl_opts['playlistend'] = 1
        #ydl_opts['socket_timeout'] = 600
        #2017.08.10
        ydl_opts['source_address'] = '0.0.0.0'
        ydl_opts['verbose'] = 1
        ydl_opts['continuedl'] = 1
        ydl_opts['nopart'] = True
        ydl_opts['skip_unavailable_fragments'] = False
        ydl_opts['fragment_retries'] = 10
        ffmpeg_name = os.getenv('KVFfmpegPath')
        if ffmpeg_name is None:
            debug('get KVFfmpegPath failed')
            debug(
                'Try Get KVFfmpegPath Begin----------------------------------------------------'
            )
            if sys.platform == 'win32':
                ffmpeg_name = r'DownloadRes\ffmpeg.exe' if os.path.exists(
                    r'DownloadRes\ffmpeg.exe') else 'ffmpeg.exe'
            else:
                ffmpeg_name = 'ffmpeg'
            try:
                # 日文路径,os.path.join(os.path.abspath(os.curdir), ffmpeg_name)会出异常,所以用相对路径置之
                try:
                    ydl_opts['ffmpeg_location'] = os.path.join(
                        os.path.abspath(os.curdir), ffmpeg_name)
                except:
                    ydl_opts['ffmpeg_location'] = ffmpeg_name

                if not os.path.exists(ydl_opts['ffmpeg_location']):
                    debug('_file__Begin')
                    debug(__file__)
                    ydl_opts['ffmpeg_location'] = os.path.join(
                        os.path.abspath(os.path.dirname(__file__)),
                        ffmpeg_name)
                    debug('_file__End')
                debug(ydl_opts['ffmpeg_location'])
            except:
                pass
            debug(
                'Try Get KVFfmpegPath End----------------------------------------------------'
            )
        else:
            debug('get KVFfmpegPath:' + ffmpeg_name)
            ydl_opts['ffmpeg_location'] = ffmpeg_name
        return ydl_opts
Ejemplo n.º 15
0
    def get_suitable_downloader(self, filename, info):
        params = self._ydl.params
        fd = youtube_dl.downloader.get_suitable_downloader(info, {})(self._ydl,
                                                                     params)
        if type(fd) == HttpFD:
            #如果目标路径下存在该文件那么说明使用的是httpFD
            if not os.path.exists(filename):
                debug('-----------------------Test HttpCurl------------------')
                hc = HttpCurl(self._ydl, params)
                self.downloaderTestResult = False
                t = threading.Thread(target=self.testDownloader,
                                     args=(hc.testUrl, info))
                t.start()
                t.join(10)
                if self.downloaderTestResult:
                    fd = hc
                    if self._infos.get('speedUp', 'False') == 'True':
                        fd.openSpeedup()
                debug(
                    '-----------------------Test HttpCurl %s------------------'
                    % ('success' if type(fd) == HttpCurl else 'fail'))
        elif type(fd) in [FFmpegFD, HlsFD]:
            if self._infos.get('url', '').find('youku') > -1 or self._infos.get('url', '').find('tudou') > -1 or \
                            self._infos.get('url', '').find('iview.abc.net.au')>-1:
                return HlsFD(self._ydl, params)

            try:
                if 'http_headers' in info and info[
                        'http_headers'] and 'Accept-Encoding' in info[
                            'http_headers']:
                    info['http_headers'].pop('Accept-Encoding')
            except:
                pass
            debug(
                '-----------------------Select M3u8 Download Begin------------------'
            )
            #目标下存在DS后缀的同名文件,且文件大小大于20K,那么就直接使用WSM3u8FD
            tempFileName = '%s.ds' % filename
            if os.path.exists(tempFileName
                              ) and os.path.getsize(tempFileName) > 1024 * 20:
                debug(
                    '-----------------------Select M3u8 Download Use WSM3u8FD------------------'
                )
                dl = WSM3u8FD(self._ydl, params)

            elif os.path.exists(filename):
                debug(
                    '-----------------------Select M3u8 Download Use FFmpegFDEx------------------'
                )
                #或者如果存在不包含DS的目标文件,那么说明使用了FFMEPG
                dl = FFmpegFDEx(self._ydl, params)
            else:
                debug('-----------------------Test WSM3u8FD------------------')
                dl = WSM3u8FD(self._ydl, params)
                if not dl.testUrl(filename, info):
                    dl = None
                debug(
                    '-----------------------Test WSM3u8FD %s------------------'
                    % ('success' if dl else 'fail'))
                if not dl:
                    dl = FFmpegFDEx(self._ydl, params)

            debug(
                '-----------------------Select M3u8 Download End------------------'
            )
            fd = dl
        debug(fd)
        return fd