0x00前言

因为笔者现在获得了大把的教学视频。而日常整理视频需要极多的时间成本,所以笔者选择使用脚本处理一些简单的递归操作。

阅读本文,您可能需要掌握的知识:

技能熟练度
Python语言熟悉

0x10 需求

首先,笔者的文件夹结构为主文件夹-子文件夹-具体的视频其中,子文件夹的名称也是当前视频的系列名称。笔者暂时需要处理对于当前的视频列表下的视频总时间与视频的名称,并将其存储在excel表格中。

而笔者的需求主要为输入主文件夹,输出excel表格,并将其保存在主文件夹下。

因为是脚本,笔者选择了python作为源,这里也是因为python包多而且好维护。

0x20 代码

0x21读取子文件夹列表

首先,选择读取当前文件的列表

def getAllfolder(folder):
    """
    获取当前所有的文件夹的列表,但是不会检索第二层
    :param folder: 获取的文件夹
    :return: 回复当前的文件夹的子文件夹,子文件夹不检索
    """
    assert os.path.exists(folder)
    assert os.path.isdir(folder)
    result = []
    list = os.listdir(folder)
    for subfolder in list:
        result.append(os.path.join(folder, subfolder))
    return result

这里因为笔者前方介绍的目录架构,这个函数(方法)刚刚好。

0x22读取单个视频列表

获取当前的文件列表之后,笔者就可以查看单个文件夹的内部视频文件了。

def getAllImages(folder):
    """
    获取当前文件夹内部的所有的视频文件。并且筛出MP4的文件格式、以列表的形式返回。其中,子目录不搜索。且当前的输入为需要搜索的目录
    :param folder: 需要截取的文件夹
    :return: 返回获取MP4的文件列表,子文件夹不检索
    """
    result = []
    if os.path.isdir(folder) is False:
        return result
    for maindir, subdir, file_name_list in os.walk(folder):

        for filename in file_name_list:
            # 排除当前的除了mp4以外的文件
            if filename.split(".")[-1] != "mp4":
                continue
            # 解决提取这个文件
            apath = os.path.join(maindir, filename)
            result.append(apath)
    return result

这里因为笔者存下的都是mp4的文件,所以直接选择筛选后缀的方式进行处理。

0x23读取单个视频轨道信息

随后就可以处理当前的单个视频文件。

def getOnceMediaInfo(folder):
    """
    获取当前一个media的参数
    :param folder: 当前的一个mp4的文件
    :return: 返回当前的文件时长,错误返回文件没有属性的回复
    """
    assert os.path.exists(folder)
    media_info = MediaInfo.parse(folder)
    for track in media_info.tracks:
        if track in media_info.tracks:
            if track.track_type == "Video" or track.track_type == "General" or track.track_type == "Audio":
                video_info = track.other_duration
    if video_info is None:
        print(folder + 'is no long param')
        return '00:00:00.000'
    return video_info[3]

因为某些视频文件的轨道不完善,所以笔者只能选择读取最常用和有用的三个轨道。现在看起来完全够用。

0x24处理时间获取全部时间轴

有了这些函数,就可以完成对于当前视频列表的简单架构。随后就可以实现整体文件夹的处理。笔者实现了两个列表,分别对应存储当前的视频文件夹名称列表与视频时长的对应。

"""
处理当前的文件顶层向下一级的文件夹内的视频的总时间的输出
"""
mediamainpath = []  # 总目录下各个分目录的视频采样目录
mediamaintime = []  # 各个分级视频的总时长,对应mediamainpath
"""
这个是检索的文件夹的名字,没有前面的目录
"""
filelist = []
def PraseFolderAllMediaTime(rootFolder):
    """
    解析输入文件的内部子文件的视频的所有时间,将其存储在mediamainpath、mediamaintime、filelist内
    但是第一级的视频文件不收录
    :param rootFolder: 头文件
    :return: 无
    """
    oncetime = []  # 每个目录下的各个视频的单个时长,用于采样所用
    mediapath = []  # 每个目录下的单个视频的列表。
    mediamainpath.clear()
    mediamaintime.clear()
    filelist.clear()
    # 确定当前的操作主目录,这个可以从外部传入
    mediatempmainpath = getAllfolder(rootFolder)
    # 根据主目录搜索内部的视频
    for mainpath in mediatempmainpath:
        # 处理一个目录的所有视频导出
        imageList = getAllImages(mainpath)
        # 如果出现内部什么都没有的情况,就继续下一个目录
        if len(imageList) == 0:
            continue
        # 确认了之后在进行提取
        mediamainpath.append(mainpath)
        filelist.append(mainpath.split(os.sep)[-1])
        # 调试用:输出当前准备转换的文件夹
        # print(mainpath)
        for filepath in imageList:
            # 登记当前目录
            mediapath.append(filepath)
            # 获取当前视频的主要时间
            oncetime.append(getOnceMediaInfo(filepath))
        # 单个目录的全部视频的总时间,临时存储
        tempalltime = datetime.timedelta(hours=0, minutes=0, seconds=0)
        for temponcetime in oncetime:
            # 取得单个的时间差
            temptime = datetime.datetime.strptime(temponcetime, '%H:%M:%S.%f')
            temptime = datetime.timedelta(hours=temptime.hour.real, minutes=temptime.minute.real,
                                          seconds=temptime.second.real)
            # 将当前的时间差累加
            tempalltime = temptime + tempalltime
        # 保存总的时间差
        mediamaintime.append(tempalltime)
        # 输出结果
        print(mainpath + "," + "时间:" + str(tempalltime) + " " + ",现在处理速度:" + str(
            len(mediamaintime) / len(mediatempmainpath) * 100) + "%")
        # 调试用:输出当前转换的百分比
        # print(str(len(mediamaintime) / len(mediatempmainpath)*100) + "%")
        # 处理完成一个目录后清空缓存
        oncetime.clear()
        mediapath.clear()

取得了最后的视频相关资料组成的列表,但是因为笔者选择的视频文件存在本地服务器中,所以需要极长的时间,分析视频音轨需要一个进度的抛出。

image202112212234082871640097255920.png

同样,因为datetime的局限性,timedelta也有很大的局限性,所以笔者只能将就使用timedelta。

0x25存储excel文件

最后,就是将其输出到本地的指定excel文件中。

def saveExcel(path):
    """
    保存当前的检索数据到excel内,当前excel必须要有“时长”的工作表,并且第一第二列会被修改
    :param path: excel文件
    :return: 无
    """
    global workbook
    isInit = False
    try:
        workbook = openpyxl.load_workbook(path)
    except:
        workbook = openpyxl.Workbook()
        isInit = True
    finally:
        #         定位问题点
        if isInit is True:
            workbook.active.title = "时长"
            workbook.active.cell(row=1, column=1).value = "课程名称"
            workbook.active.cell(row=1, column=2).value = "课程总时间"
        sheet = workbook["时长"]
        row = 2
        column = 1
        for y in range(len(filelist)):
            sheet.cell(row=2+y, column=1).value = filelist[y]
            sheet.cell(row=2+y,column=2).value = mediamaintime[y]
        workbook.save(path)

这样就简单的存储在当前的excel文件中。

0x26设定输入参数

最后可以使用cron进行定时执行,只需要输入主目录名称即可。

if __name__ == '__main__':
    # 调试完成(sys.argv[1:])
    if len(sys.argv) == 1:
        exit()
    PraseFolderAllMediaTime(sys.argv[1])
    saveExcel(sys.argv[1] + os.sep + "视频时间总览.xlsx")
    print_hi(sys.argv[1],"Parse Finish")

0x27包括的第三方支持库

import datetime
import os
from pymediainfo import MediaInfo
import sys
import openpyxl

0x30最后的结果

可以看到,最后的执行效果虽然有些冗余,但是看起来还是那个意思的。

image20211221224404998.png

image20211221224549449.png

0x40总结

这个脚本还是一个半吊子脚本,没有用到任何高级的使用方案,完全就是一个简单的面向过程的设计思路,这也是笔者的局限性,后续也许笔者会逐渐对其升级以慢慢的得到更高的执行效率和维护性。


标题:记:一个简单的整理多媒体时长的实现
作者:GreenDream
地址:HTTPS://greendreamer.work/articles/2021/12/22/1640182593748.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!