起因

使用弹弹Play看番时字幕过大,大概长这样:

于是我便开始寻找解决办法

解决之路

首先,查看是不是弹弹Play的问题。 使用PotPlayer观看是这样:

显然是弹弹Play的问题,在尝试更换播放器内核等一系列操作后,仍然没有解决。于是,我打算更换字幕试试。

然鹅,虽然找到了字体正常的字幕,但是时间轴却和这个视频不对应...看来得尝试其他方法。

终于,在字幕设置的右下角发现了这个:

一查证,果然如此!但是用手一个一个地修改太浪费时间了,我立马想到python可以帮我。

使用python批量修改这些文件

  • 需求:在每个字幕(.ass)文件开头一行加上[Script Info]
  • 额外需求:以后遇到相似问题,小改代码还能接着用

所以,基本思路是:

  1. 获取文件路径
  2. 打开并修改文件

在此过程中,我遇到了一些问题和困难:

  1. 每个字幕文件名尽管遵循一定规则,但是不仅仅有数字(集数)上的差异,还有几个我找不出规律的字母。 其中的"E43C438E"

我打算使用正则表达式来解决这个问题,但是一搜,还是比较麻烦。最后还是在这篇文章的引导下,获取了所有符合要求的文件名。

from os import listdir
path0 = "你要搜的文件夹"

flist = listdir(path0) #使用listdir()函数获取所有的文件名,保存到名为flist的list变量里
flist_need = [] #存放所需的名字

for i in range(0, len(flist)):  #遍历flist里面的所有项
    extension = flist[i].split(".")[-1] #使用split()分割字符串,获取尾缀([-1])
    if extension == "ass":  #符合条件的尾缀
        flist_need.append(flist[i]) #将符合条件的名称存入list

  1. 如何在开头添加字符串,而不是结尾

经过搜索,众多文章都提到了seek(0,0),这是让指针移动到指定位置的函数。前面的0代表位移量,后面的0代表从文件开头开始(1代表当前位置,2代表末尾位置)。

with open(path0 + flist_need[i], 'r+', encoding='utf-8') as f:  #注意此处encoding,而且必须是'r+'
    content = f.read()
    f.seek(0,0) #必须得有,不然还是在尾巴那里加
    f.write(insert_str + '\n' + content)    #按照这个保存原本的内容->存入新内容的逻辑,应该不需要seek啊。但是去掉seek后会导致插在最后一行
  1. 编码问题

首先是报错,然后改成utf-8后,只有前两个文件成功了,但是后面的文件全乱码了...

用notepad++查看了一下编码格式,发现前两个文件格式是utf-8,后面两个就变成utf-16了。要解决这个问题,需要分开处理。

最终代码

from os import listdir
import os   

insert_str = "[Script Info]"    #要插入的内容
path0 = "你的文件夹路径"    

flist = listdir(path0)  #获取所有文件名称
flist_need = [] #存放所需的名字

for i in range(0, len(flist)):
    extension = flist[i].split(".")[-1] #获取尾缀
    if extension == "ass":
        flist_need.append(flist[i]) #获取所有字幕名

#print(flist_need) #测试

for i in range(2):
    with open(path0 + flist_need[i], 'r+', encoding='utf-8') as f:  #如果是'a+'之类的,文件会只剩[Script Info]
        content = f.read()
        f.seek(0,0) #必须得有,不然还是在尾巴那里加
        f.write(insert_str + '\n' + content)

for i in range(2,24):
    with open(path0 + flist_need[i], 'r+', encoding='utf-16') as f:
        content = f.read()
        f.seek(0,0) #必须得有,不然还是在尾巴那里加
        f.write(insert_str + '\n' + content)

总结

  • from os import listdir里,listdir(文件夹路径)可以获取该文件夹里面所有文件名(但是子文件夹里面的名字无法访问)。
  • seek()函数可以帮我们指定指针指向的文件的位置。seek(位移数, [起始位置]),起始位置默认为0,即开头;1为当前位置;2为末尾。
  • 只要打开文件就要注意编码问题!

SUFE大二在读