(Python)BiliBili(手机端缓存视频转换)
目錄
需求
功能實(shí)現(xiàn)分析
需要進(jìn)行的操作
使用到的技術(shù):Python基礎(chǔ)和ffepeg
需求分析(一個(gè)簡(jiǎn)單的思維導(dǎo)圖)
源代碼
總結(jié)反思:
需求
?這一個(gè)將b站手機(jī)端緩存直接轉(zhuǎn)換為可以直接打開(kāi)的視頻的軟件。 用戶在Config里面設(shè)置好之后,運(yùn)行程序即可實(shí)現(xiàn)自動(dòng)轉(zhuǎn)換。(這里我將Config里的設(shè)置直接復(fù)制到了代碼最上方)
功能實(shí)現(xiàn)分析
轉(zhuǎn)換規(guī)則:
1.總視頻文件夾 外面的純數(shù)字是普通視頻 純數(shù)字代表視頻的av號(hào) s_開(kāi)頭的是番劇類型的視頻2.劇集文件夾 點(diǎn)開(kāi)av號(hào)的文件夾,里面的c_開(kāi)頭的是視頻的cid3.視頻信息文件夾 點(diǎn)開(kāi)cid的文件夾,entry.json里面是視頻的json信息,里面有視頻標(biāo)題,av號(hào)(avid)bv號(hào)(bvid)還有分p信息(page_data,里面有視頻的cid和分p的名字)還有視頻的清晰度代號(hào)(比如80代表1080P) danmaku.xml是視頻的xml彈幕。4.視頻文件夾 點(diǎn)開(kāi)清晰度代號(hào)文件夾,里面有audio.m4s和video.m4s,這種情況用ffmpeg進(jìn)行合并: ffmpeg -i "audio.m4s" -i "video.m4s" "output.mp4" 這樣就能直接合并為MP4文件。對(duì)于blv文件,也是使用ffmpeg直接封裝為MP4: ffmpeg -i "0.blv" -acodec copy -vcodec copy "output.mp4" 要注意,ffmpeg對(duì)中文支持不是很好,盡量不要在命令行直接使用中文命名,而是完成操作之后軟件重命名。 ? ?需要進(jìn)行的操作
1.打開(kāi)總文件夾,通過(guò)命名將視頻進(jìn)行分類(3類,番劇類,普通視頻分P類,普通單P視頻)
2.將每一個(gè)視頻進(jìn)行解析。進(jìn)入視頻json文件中解析視頻信息,從中找到命名信息。
3.將每一個(gè)視頻中的視頻文件轉(zhuǎn)化為MP4文件,bilibili里的視頻文件分為兩種(一種為音頻和視頻分開(kāi)的兩個(gè)m4s文件,一種為blv文件,均不能直接播放)
使用到的技術(shù):Python基礎(chǔ)和ffepeg
需求分析(一個(gè)簡(jiǎn)單的思維導(dǎo)圖)
?
源代碼
import json import os ? # bilibili緩存視頻地址 input_path = "C:/Users/Promise/Desktop/download" # 保存視頻文件夾 out_path = 'C:/Users/Promise/Desktop/bili_video' # 是否轉(zhuǎn)換普通視頻類文件 c_video = True # 是否轉(zhuǎn)換番劇類文件 c_anime = True # 番劇轉(zhuǎn)換是否放在同一個(gè)文件夾(類似唧唧的批量下載) anime_folder = True # 多個(gè)分P的視頻是否放在同一個(gè)文件夾 video_folder = True # 是否輸出xml彈幕 c_xml = True # 是否把xml彈幕轉(zhuǎn)換為ass彈幕 xml2ass=True # 是否使用唧唧Down的命名規(guī)則,如果為False則使用視頻的cid命名 enable_JJDown_rename = True # 轉(zhuǎn)換完成后是否刪除源文件 delete_input_file = False ? # 打開(kāi)總文件夾 def open_download(): ?# 所有緩存視頻all_video = os.listdir(input_path)# 補(bǔ)全路徑list = []for video in all_video:video = input_path + '/' +videolist.append(video)return list ? # 判斷大類型 def judge_huge_type(video):# 根據(jù)文件命名判斷類型if 's_' in video:type = 's'return typeelse:type = 'c'return type ? # 判斷普通視頻是否分P def c_judge_p(video_path):# 根據(jù)路徑打開(kāi)文件夾# 根據(jù)文件數(shù)量判斷是否分Psub_video_list = os.listdir(video_path) ?if len(sub_video_list) > 1:return Trueelse:return False ? def sub_file(video_path):# 根據(jù)路徑打開(kāi)劇集文件夾# 根據(jù)文件數(shù)量判斷是否分Psub_video_list = os.listdir(video_path)sub_list = []for sub_video in sub_video_list:sub_video = video_path+ '/' +sub_videosub_list.append(sub_video)return sub_list ? def subsub_file(sub_video_path):# 根據(jù)劇集路徑進(jìn)入每一集信息文件夾subsub_video_info = os.listdir(sub_video_path)video_info = []for fileinfo in subsub_video_info:fileinfo = sub_video_path + '/' +fileinfovideo_info.append(fileinfo)return video_info ? def get_name(video_info):# 獲取名稱for video_file_info in video_info:if str(video_file_info).endswith('json'):with open(video_file_info, 'r', encoding='utf8') as out:json_data = json.load(out)# print(json_data['title'])return json_data['title'] ? def get_anime_index(video_info):# 獲取番劇劇集信息for video_file_info in video_info:if str(video_file_info).endswith('json'):with open(video_file_info, 'r', encoding='utf8') as out:json_data = json.load(out)info = ?json_data['ep']result = info['index']+' '+info['index_title'] ?return result ? def get_pages_index(video_info):# 獲取分P視頻信息for video_file_info in video_info:if str(video_file_info).endswith('json'):with open(video_file_info, 'r', encoding='utf8') as out:json_data = json.load(out)info = json_data['page_data']result = info['part'] ?return result ? def last_file(video_info):# 進(jìn)入最后一個(gè)文件夾last_list = []for video_file_info in video_info:if ?not str(video_file_info).endswith('json') and not str(video_file_info).endswith('xml') :last_file_list = os.listdir(video_file_info)for last_file_info in last_file_list:last_file_info = video_file_info + '/' +last_file_infolast_list.append(last_file_info) ?return last_list ? ? def convert_mp4(last_list,last_file_path):# 將兩個(gè)m4s文件轉(zhuǎn)換為MP4文件m4s_count = 0blv_count = 0m4sfile_list = []blvfile_list = []for last_file in last_list:if str(last_file).endswith('m4s'):m4sfile_list.append(last_file)m4s_count += 1elif str(last_file).endswith('blv'):blvfile_list.append(last_file)blv_count += 1else:passif m4s_count == 2:os.system('ffmpeg -i ' + '"' + m4sfile_list[0] + '" ' + '-i' + ' "' + m4sfile_list[1] + '" -acodec copy -vcodec copy ' + '"' + last_file_path + '"')elif blv_count == 1:os.system('ffmpeg -i ' + '"' + blvfile_list[0] + '"' + ' -acodec copy -vcodec copy ' + '"' + last_file_path + '"')else:passprint(last_file_path , '轉(zhuǎn)換成功!') ? ? ? ? if __name__ == '__main__':# 打開(kāi)視頻文件夾all_video = open_download()# 遍歷視頻文件夾for video in all_video:# 判斷視頻類型(番劇還是普通視頻)type = judge_huge_type(video)if type == 's':print('番劇')# 如果設(shè)置中打開(kāi)轉(zhuǎn)換番劇為Trueif c_anime:# 打開(kāi)劇集文件夾all_sub_video= sub_file(video)# 遍歷劇集文件夾for sub_video in all_sub_video:# 打開(kāi)每一集視頻信息文件夾video_info = subsub_file(sub_video)# 從json文件中取出視頻相關(guān)信息# 視頻名稱name = get_name(video_info)# 劇集名稱index_name = ?get_anime_index(video_info)# 保存位置save_dirpath = out_path# 如果番劇保存需要零開(kāi)一個(gè)文件夾if anime_folder:# 添加一個(gè)由番劇名稱組成的文件夾save_dirpath = out_path + '/' + name# 創(chuàng)建文件夾if not os.path.exists(save_dirpath):os.mkdir(save_dirpath)# 寫最終文件路徑last_file_path = save_dirpath + '/' + index_name + '.mp4'last_list = last_file(video_info)# 轉(zhuǎn)換文件格式convert_mp4(last_list, last_file_path) ? ?else:print('普通')# 同上if c_video:if c_judge_p(video):print('分p')all_sub_video = sub_file(video)for sub_video in all_sub_video:video_info = subsub_file(sub_video) ?name = get_name(video_info)index_name = get_pages_index(video_info)save_dirpath = out_pathif video_folder:save_dirpath = out_path + '/' + nameif not os.path.exists(save_dirpath):os.mkdir(save_dirpath) ?last_file_path = save_dirpath + '/' +index_name +'.mp4'last_list = last_file(video_info)convert_mp4(last_list,last_file_path) ?else:# 同上all_sub_video = sub_file(video)for sub_video in all_sub_video:video_info = subsub_file(sub_video) ?name = get_name(video_info)last_file_path = out_path + '/' + name + '.mp4' ?last_list = last_file(video_info)convert_mp4(last_list, last_file_path) ? ?總結(jié)反思:
1.感覺(jué)這個(gè)代碼還是盡力封裝了許多函數(shù),但是main函數(shù)還是太長(zhǎng)了,封裝的效果也不太好,希望接下來(lái)可以改進(jìn)。
2.代碼長(zhǎng)了容易記不住名字,所以需要更加規(guī)范的命名原則。
3.最后一個(gè)for循環(huán)里的功能有些可以繼續(xù)封裝,但是還是有點(diǎn)懶,最后沒(méi)有改進(jìn)。
4.所有可以進(jìn)行封裝的功能還是要盡量封裝,也讓代碼有更高的可讀性。
滿懷希望就會(huì)所向披靡!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 一位剛在CSDN發(fā)表文章的Python小萌新
總結(jié)
以上是生活随笔為你收集整理的(Python)BiliBili(手机端缓存视频转换)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: session过期后登陆页面跳出ifra
- 下一篇: 图像拼接算法及实现