def CodeVideo(videolist, outputdir, codetype='.mp4'): if outputdir[-1] != '\\': outputdir += '\\' if codetype[0] != '.': codetype = '.' + codetype for onevideo in videolist: title = onevideo['title'] # 处理弹幕 if 'danmu' in onevideo: try: danmaku2ass.Danmaku2ASS(input_format='Bilibili', input_files=onevideo['danmu'], output_file=outputdir + title + '.ass', stage_width=onevideo['width'], stage_height=onevideo['height'], reserve_blank=480, font_size=fontsize, text_opacity=0.6, duration_marquee=12.0, duration_still=6.0) except Exception as e: return '错误[弹幕转换失败]因为:\n' + str(e) # 处理视频 # ffmpeg -i video2.avi -i audio.mp3 -vcodec copy -acodec copy output.avi cmd = r'.\"%s" -i "%s" -i "%s" -vcodec copy -acodec copy "%s"' % ( ffmpeg, onevideo['videofile'], onevideo['audiofile'], outputdir + title + codetype) os.system(cmd) #res = os.popen(cmd) return '编码完成'
def convert_comments(danmaku_url_or_raw, video_size): if isinstance(danmaku_url_or_raw, str): resp_comment = simply_get_url(danmaku_url_or_raw) else: resp_comment = danmaku_url_or_raw comment_in = io.StringIO(resp_comment.decode('utf-8', 'replace')) comment_out = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8-sig', newline='\r\n', prefix='tmp-danmaku2ass-', suffix='.ass', delete=False) logging.info('Invoking Danmaku2ASS, converting to %s' % comment_out.name) d2aflags = {} d2a_args = dict({'stage_width': video_size[0], 'stage_height': video_size[1], 'font_face': 'SimHei', 'font_size': math.ceil(video_size[1] / 21.6), 'text_opacity': 0.8, 'duration_marquee': min(max(6.75 * video_size[0] / video_size[1] - 4, 3.0), 8.0), 'duration_still': 5.0, 'reserve_blank': video_size[1] // 10}, **d2aflags) for i, j in ((('stage_width', 'stage_height', 'reserve_blank'), int), (('font_size', 'text_opacity', 'comment_duration', 'duration_still', 'duration_marquee'), float)): for k in i: if k in d2aflags: d2a_args[k] = j(d2aflags[k]) try: danmaku2ass.Danmaku2ASS([comment_in], comment_out, **d2a_args) except Exception as e: logging.error('Danmaku2ASS failed, comments are disabled. {}'.format(e)) comment_out.flush() comment_out.close() # Close the temporary file early to fix an issue related to Windows NT file sharing return comment_out
def convert_to_ass(input_file, output_file): print( f'convert {input_file} -> {output_file} in {os.path.abspath(os.curdir)}' ) danmaku2ass.Danmaku2ASS( input_file, 'autodetect', output_file, 1920, 1080, text_opacity=0.25, duration_marquee=25, duration_still=25, )
def get_comment_ass(video_size, comment_in, input_format, d2aflags={}): '''Warpper for danmaku2ass.Danmaku2ASS to get comment in .ass format comment_in must be an valid xml comment. It can be either filename or file content ''' comment_out = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8-sig', newline='\r\n', prefix='tmp-danmaku2ass-', suffix='.ass', delete=False) logging.info('Invoking Danmaku2ASS, converting to %s' % comment_out.name) d2a_args = dict( { 'stage_width': video_size[0], 'stage_height': video_size[1], 'font_face': 'SimHei', 'font_size': math.ceil(video_size[1] / 21.6), 'text_opacity': 0.8, 'duration_marquee': min(max(6.75 * video_size[0] / video_size[1] - 4, 3.0), 8.0), 'duration_still': 5.0 }, **d2aflags) for i, j in ((('stage_width', 'stage_height', 'reserve_blank'), int), (('font_size', 'text_opacity', 'comment_duration', 'duration_still', 'duration_marquee'), float)): for k in i: if k in d2aflags: d2a_args[k] = j(d2aflags[k]) try: danmaku2ass.Danmaku2ASS(input_files=[comment_in], input_format=input_format, output_file=comment_out, **d2a_args) except Exception as e: log_or_raise(e, debug=debug) logging.error('Danmaku2ASS failed, comments are disabled.') comment_out.flush() comment_out.close( ) # Close the temporary file early to fix an issue related to Windows NT file sharing return comment_out
if os.path.splitext(file)[1] == '.flv': # 拼接成完整路径 filePath = os.path.join(root_dir, file) # 载入视频 video = VideoFileClip(filePath) # 添加到数组 L.append(video) # 拼接视频 final_clip = concatenate_videoclips(L) # 生成目标视频文件 final_clip.to_videofile(os.path.join(root_dir,r'{}.mp4'.format(title)), fps=24, remove_temp=False) print('[视频合并完成]') else: #视频只有一段则直接打印下载完成 print('[下载完成]:' + title) print("[获取弹幕]:"+title) xmlurl='https://comment.bilibili.com/'+cid+'.xml' x = requests.get(xmlurl) with open(xmlpath+'xml',"wb")as code: code.write(x.content) #urllib.request.urlretrieve(url=xmlurl,filename=os.path.join(currentVideoPath,r'{}.xml'.format(cid))) #py=sys.path[5]+"\\python" print("[弹幕转码]:调用danmaku2ass") danmaku2ass.Danmaku2ASS(xmlpath+'xml',"autodetect",xmlpath+'ass',1920,1080,0,'MS PGothic',48,0.8,5,5,None,False) #os.system(py+' .\\danmaku2ass.py -o ".\\'+title+'-'+str(num)+'.ass" -s 1920x1080 -fn MS PGothic -fs 48 -a 0.8 -dm 5 -ds 5 ".\\'+title+'-'+str(num)+'.xml"') #拓展:分P视频:url相同,只是cid不同,通过url?p=1,2..分别找出每个分P的cid,带入请求得到下载地址 #如果是windows系统,下载完成后打开下载目录 if(sys.platform.startswith('win')): os.startfile(currentVideoPath)
def extracVideo(partPath, outputPath): partPath = Path(partPath) outputPath = Path(outputPath) if not os.path.exists(partPath / "entry.json"): return with open(partPath / "entry.json", 'r', encoding='utf-8') as file: retDic = json.load(file) print("retDic:" + str(retDic)) print("partPath:" + str(partPath)) if ("page_data" not in retDic) or ("type_tag" not in retDic) or \ ("title" not in retDic): return pageData = retDic['page_data'] typeTag = retDic['type_tag'] videoTitle = retDic['title'] partTitle = pageData['part'] width = pageData['width'] height = pageData['height'] formatPartTitle = formatTitle(partTitle) # https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.with_suffix # PurePath.with_suffix(suffix) # Return a new path with the suffix changed. If the original path doesn’t have a suffix, the new suffix is appended instead. If the suffix is an empty string, the original suffix is removed: outPutVideoName = Path(formatPartTitle).with_suffix(".mp4") outputVideoPath = outputPath / outPutVideoName #extract danmu file if os.path.exists(partPath / "danmaku.xml"): outAssName = (outputPath / formatPartTitle).with_suffix(".ass") print(str(outAssName)) if os.path.exists(outAssName): print(str(outAssName) + "extract down.") else: import danmaku2ass # reuse code in danmaku2ass.py # when high resolution, make font larger fontSize = 23.0 if width >= 1920: fontSize = 36.0 danmaku2ass.Danmaku2ASS(str(partPath / "danmaku.xml"), "Bilibili" , str(outAssName), width, height,\ reserve_blank=480,font_size=fontSize, text_opacity=1, duration_marquee=12.0, duration_still=6.0) # to tune argus fileRealPath = partPath / typeTag oldAudioPath = fileRealPath / "audio.m4s" oldVideoPath = fileRealPath / "video.m4s" newAudioPath = fileRealPath / "audio.mp3" newVideoPath = fileRealPath / "video.mp4" if os.path.exists(oldAudioPath): os.rename(oldAudioPath, newAudioPath) if os.path.exists(oldVideoPath): os.rename(oldVideoPath, newVideoPath) if os.path.exists(outputVideoPath): print(str(outputVideoPath) + " extract done!") return print(outputVideoPath) # https://docs.python.org/3/library/subprocess.html # https://stackoverflow.com/questions/25655173/does-pythons-subprocess-popen-accept-spaces-in-paths # A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument. subprocess.call( 'ffmpeg -i "%s" -i "%s" -codec copy "%s"' % (str(newVideoPath), str(newAudioPath), str(outputVideoPath)), shell=True)