(Python) BiliBili (Mobile Cache Video Conversion)

Posted by olko on Sun, 19 Dec 2021 18:28:10 +0100

Catalog

demand

Functional Implementation Analysis

Action required

Techniques used: Python Foundation and ffepeg

Needs Analysis (a simple mind map)

source code

Summary Reflection:

demand

This software converts the mobile cache of station b directly into a video that can be opened directly. After the user has set it up in Config, running the program can achieve automatic conversion. (Here I copy the settings in Config directly to the top of the code)

Functional Implementation Analysis

Conversion rules:

1. Total Video Folder
 Outside pure numbers are normal videos
 av number of pure digital video
 s_ Start with a pantomime-type video
    
2. Episode Folder
 Point open av folder, inside c_ Beginning with cid for video
    
3. Video Information Folder
 Point to open cid's folder, entry.json contains the json information of the video, including the video title, av id bv number (bvid), page_data, CID of the video and the name of the minute p, and the definition code of the video (for example, 80 for 1080P).
danmaku.xml is the xml marquee of the video.
    
4. Video Folders
 Open the definition code folder with audio inside. M4S and video.m4s, in which case ffmpeg is used to merge:
ffmpeg -i "audio.m4s" -i "video.m4s" "output.mp4"
This allows you to merge directly into MP4 files.
    
For blv files, ffmpeg is also used to encapsulate directly into MP4:
ffmpeg -i "0.blv" -acodec copy -vcodec copy "output.mp4"
Note that ffmpeg is not very good at Chinese support, try not to use Chinese naming directly on the command line, but to rename the software after the operation is completed. *

Action required

1. Open the general folder and classify videos by name (3 categories, pantomime category, ordinary video P category, ordinary single P video)

2. Parse each video. Enter the video json file to parse the video information and find the naming information.

3. Convert the video files in each video into MP4 files. The video files in bilibili bili are divided into two types (one is two m4s files separated for audio and video, the other is a blv file, which cannot be played directly)

Techniques used: Python Foundation and ffepeg

Needs Analysis (a simple mind map)

 

source code

import json
import os
​
# bilibili cache video address
input_path = "C:/Users/Promise/Desktop/download"
# Save Video Folder
out_path = 'C:/Users/Promise/Desktop/bili_video'
# Whether to convert normal video class files
c_video = True
# Whether to convert pantomime files
c_anime = True
# Whether the pantomime conversion is placed in the same folder (similar to haggling mass downloads)
anime_folder = True
# Whether videos with multiple points are placed in the same folder
video_folder = True
# Whether to output xml marquees
c_xml = True
# Whether to convert xml to ass
xml2ass=True
# Whether to use the naming rules for Chao Down or cid for False
enable_JJDown_rename = True
# Do you want to delete the source file after the conversion is complete
delete_input_file = False
​
# Open General Folder
def open_download():
​
    # All Cached Videos
    all_video = os.listdir(input_path)
    # path completion
    list = []
    for video in all_video:
        video = input_path + '/' +video
        list.append(video)
    return list
​
# Judging Large Types
def judge_huge_type(video):
    # Determine type by file name
    if 's_' in video:
        type = 's'
        return type
    else:
        type = 'c'
        return type
​
# Determine whether ordinary video is divided into P
def c_judge_p(video_path):
    # Open Folder by Path
    # Determine whether the score is P based on the number of files
    sub_video_list = os.listdir(video_path)
​
    if len(sub_video_list) > 1:
        return True
    else:
        return False
​
def sub_file(video_path):
    # Open episodes folder by path
    # Determine whether the score is P based on the number of files
    sub_video_list = os.listdir(video_path)
    sub_list = []
    for sub_video in sub_video_list:
        sub_video = video_path+ '/' +sub_video
        sub_list.append(sub_video)
    return sub_list
​
def subsub_file(sub_video_path):
    # Enter each episode information folder based on episode path
    subsub_video_info = os.listdir(sub_video_path)
    video_info = []
    for fileinfo in subsub_video_info:
        fileinfo = sub_video_path + '/' +fileinfo
        video_info.append(fileinfo)
    return video_info
​
def get_name(video_info):
    # Get Name
    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):
    # Get episode information
    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):
    # Get Score P Video Information
    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):
    # Enter the last folder
    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_info
                last_list.append(last_file_info)
​
    return last_list
​
​
def convert_mp4(last_list,last_file_path):
    # Convert two m4s files into MP4 files
    m4s_count = 0
    blv_count = 0
    m4sfile_list = []
    blvfile_list = []
    for last_file in last_list:
        if str(last_file).endswith('m4s'):
            m4sfile_list.append(last_file)
            m4s_count += 1
        elif str(last_file).endswith('blv'):
            blvfile_list.append(last_file)
            blv_count += 1
        else:
            pass
    if 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:
        pass
    print(last_file_path , 'Conversion Successful!')
​
​
​
​
if __name__ == '__main__':
    # Open Video Folder
    all_video = open_download()
    # Traverse Video Folders
    for video in all_video:
        # Determine video type (pantomime or regular video)
        type = judge_huge_type(video)
        if type == 's':
            print('Panda')
            #  If the conversion is turned on in the settings to True
            if c_anime:
                # Open the episodes folder
                all_sub_video= sub_file(video)
                # Traverse the episodes folder
                for sub_video in all_sub_video:
                    # Open the video information folder for each episode
                    video_info = subsub_file(sub_video)
                    # Remove video-related information from json file
                    # Video Name
                    name = get_name(video_info)
                    # Episode Name
                    index_name =  get_anime_index(video_info)
                    # Save Location
                    save_dirpath = out_path
                    # If pantomimes need to be saved with a zero-folder
                    if anime_folder:
                        # Add a folder of pantomime titles
                        save_dirpath = out_path + '/' + name
                        # create folder
                        if not os.path.exists(save_dirpath):
                            os.mkdir(save_dirpath)
                    # Write Final File Path
                    last_file_path = save_dirpath + '/' + index_name + '.mp4'
                    last_list = last_file(video_info)
                    # Convert file format
                    convert_mp4(last_list, last_file_path)
​
​
        else:
            print('ordinary')
            # Ditto
            if c_video:
                if c_judge_p(video):
                    print('branch 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_path
                        if video_folder:
                            save_dirpath = out_path + '/' + name
                            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)
                        convert_mp4(last_list,last_file_path)
​
                else:
                    # Ditto
                    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)
​

Summary Reflection:

1. It feels like this code does its best to encapsulate a lot of functions, but the main function is still too long and the encapsulation is not so effective. I hope it can be improved in the future.

2. The code is too long to remember names, so more standard naming principles are needed.

3. Some of the functions in the last for loop can continue to be encapsulated, but they are still a bit lazy and have not been improved in the end.

4. Do you want to encapsulate as much functionality as possible and make your code more readable?

Hope will overwhelm you!

A Python budding post just published on CSDN

Topics: Python