danmaku_tools icon indicating copy to clipboard operation
danmaku_tools copied to clipboard

合并多个 .xml 成1个文件时,xml 文件中不包含 <?xml-stylesheet type="text/xsl" href="#s"?> 导致浏览器无法加载样式

Open DoodleBears opened this issue 1 year ago • 0 comments

如题,试图合并多个 .xml 文件时,合并出的 /xml 文件

  1. 注释部分被舍弃(注释没了倒还好)
  2. xml-stylesheet 没了(虽然只是不能在浏览器舒适地浏览弹幕)

尝试使用 lxml 后解决,不知道是不是只有我有这个问题 参考了:https://stackoverflow.com/questions/61252951/how-to-insert-a-processing-instruction-in-xml-file

import argparse
import subprocess
# import xml.etree.ElementTree as ET 生成的文件不包含 <?xml-stylesheet type="text/xsl" href="#s"?>
from lxml import etree as ET
from dateutil.parser import parse

parser = argparse.ArgumentParser(description='Merge BiliLiveReocrder XML')
parser.add_argument('xml_files', type=str, nargs='+', help='path to the danmaku file')
parser.add_argument('--video_time', type=str, default="", help='use video length as the duration of the file')
parser.add_argument('--output', type=str, default=None, help='output path for the output XML', required=True)


def get_root_time(root_xml):
    record_info = root_xml.findall('BililiveRecorderRecordInfo')[0]
    record_start_time_str = record_info.attrib['start_time']
    record_start_time = parse(record_start_time_str)
    return record_start_time


def add_root(orig_root:ET.ElementBase, new_root:ET.ElementBase, new_offset:float):
    for child in new_root:
        if child.tag in ['sc', 'gift', 'guard']:
            orig_time = float(child.attrib['ts'])
            new_time = orig_time + new_offset
            new_time_str = str(new_time)
            child.set('ts', new_time_str)
            orig_root.append(child)
        if child.tag in ['d']:
            orig_parameters_str = child.attrib['p'].split(',')
            orig_time = float(orig_parameters_str[0])
            new_time = orig_time + new_offset
            new_parameters_str = [str(new_time)] + orig_parameters_str[1:]
            child.set('p', ','.join(new_parameters_str))
            orig_root.append(child)


if __name__ == '__main__':
    args = parser.parse_args()

    if len(args.xml_files) == 0:
        print("At least one XML files have to be passed as input.")
        exit(1)
    print(f"Started to combine {args.xml_files} \ninto one file: {args.output}")
    

    tree:ET.ElementTree = ET.parse(args.xml_files[0])
    root:ET.Element = tree.getroot()
    new_root_offset = 0
    all_flv = ""

    for i in range(len(args.xml_files) - 1):
        new_root:ET.Element = ET.parse(args.xml_files[i + 1]).getroot()
        if args.video_time == "":
            root_time = get_root_time(root)
            new_root_offset = (get_root_time(new_root) - root_time).total_seconds()
        else:
            prev_xml_path = args.xml_files[i]
            base_file_path = prev_xml_path.rpartition('.')[0]
            flv_file_path = base_file_path + args.video_time
            total_seconds_str = subprocess.check_output(
                f'ffprobe -v error -show_entries format=duration '
                f'-of default=noprint_wrappers=1:nokey=1 "{flv_file_path}"', shell=True
            )
            all_flv += flv_file_path + "\n"
            new_root_offset += float(total_seconds_str)
        add_root(root, new_root, new_root_offset)
        
    tree.write(args.output, encoding='UTF-8',xml_declaration=True)

DoodleBears avatar May 04 '23 13:05 DoodleBears