先日動画に字幕を付ける方法をまとめました。
elsammit-beginnerblg.hatenablog.com
ただ私がやりたかったことは英語字幕を日本語字幕にすること!!
そもそも字幕付与を行おうと思った理由が英語音声で公開されているCourseraを日本語字幕で閲覧したかったからなので。
ということで、今回はグーグル翻訳を利用して英語字幕を日本語字幕に変更してみたいと思います!!
■前提条件
タイトルの通り、pythonを用います。
pythonのバージョンですが、
python:3.7.3
を用いました。
さらに、今回は字幕ファイルとしてvttが用意できる場合を前提にします。
※vttファイルの無い(英語字幕付き動画しかない)場合は、、、vttファイルを生成すればよいのだろうけど、、、どうするのだろう??
■pythonでgoogle翻訳
ではまずはpythonでgoogle翻訳する環境を整えていきます。
google翻訳を行うにあたりGoole翻訳APIが無料で公開されているのでこちらを用いれば自動で翻訳が出来そうなのですが、、、
事前にGoogle Apps APIサイトにてプロジェクト作成し、そのパスをpythonコード上に載せて、、、
と少し面倒だったので別の方法がないか調べていました。
※3分で構築と書いてあったのですが、出来れば1分でやりたいw
そこで、"googletrans"というライブラリを発見!!
こちらを利用することにしました。
googletransですが、
pip3 install googletrans
でインストールが行えます。
googletransを用いた翻訳コードですがこちらのようになります。
from googletrans import Translator Translator(service_urls=['translate.googleapis.com']) translated = translator.translate("Hello", dest="ja")
使い方も結構簡単で、
from googletrans import Translator Translator(service_urls=['translate.googleapis.com'])
を定義し、
translated = translator.translate("Hello", dest="ja")
で文字列を日本語翻訳。
以上です。
translateの引数ですが、第1引数に翻訳したい英語文字列、第2引数に翻訳したい言語(今回は日本語)になります。
逆に、日本語⇒英語翻訳したい場合には、
translated = translator.translate("こんにちは", dest="en")
とすればOKです。
■英語字幕ファイルを日本語に翻訳
では、googletrans を用いて英語字幕ファイルから日本語へgoogle翻訳していきます。
vttファイルの構成ですが、こちらの通り
最初の数行がHeaderで、
その後、1行空けて、
表示時間⇒文字列⇒空欄⇒表示時間⇒文字列⇒空欄⇒...
といった構成になっております。
WEBVTT 00:00:00.000 --> 00:00:04.000 position:10%,line-left align:left size:35% Where did he go? 00:00:03.000 --> 00:00:06.500 position:90% align:right size:35% I think he went down this lane. 00:00:04.000 --> 00:00:06.500 position:45%,line-right align:center size:35% What are you waiting for?
そこで、表示時間を検出しその次の行を翻訳する文字列として抽出、translate関数の引数として与えることとしました。
コードはこちら。
import os from googletrans import Translator import time import sys import subprocess def TranslateFunc(FileName): i = 1 j = 0 translator = Translator(service_urls=['translate.googleapis.com']) with open(FileName) as f: sl = f.readlines() ret = sl[0] ret += "\n" data = str(j)+"/"+str(len(sl)-1) while 1: data = str(j)+"/"+str(len(sl)-1) print(data) if j > len(sl)-1: break try: buf = sl[j].split(':') if len(buf) >= 5: ret += sl[j] result = translator.translate(sl[j+1], dest="ja") ret += result.text j+=2 while 1: if len(sl[j]) > 1: result = translator.translate(sl[j], dest="ja") ret += result.text j+=1 else: break else: ret += sl[j] j+=1 except: break f = open('output.vtt','w', encoding='UTF-8') f.write(ret) f.close() if __name__ == '__main__': args = sys.argv if args[2].endswith('.vtt'): TranslateFunc(args[2]) if args[1].endswith('.mp4') and args[2].endswith('.vtt'): cmdline = "ffmpeg -i " + args[1] + " -i output.vtt" + " -map 0:v -map 0:a -map 1 -metadata:s:s:0 language=jpn -c:v copy -c:a copy -c:s srt " + "output2.mkv" res = subprocess.call(cmdline, shell=True)
ちょっと長いですね。。。
if args[1].endswith('.mp4') and args[2].endswith('.vtt'): cmdline = "ffmpeg -i " + args[1] + " -i output.vtt" + " -map 0:v -map 0:a -map 1 -metadata:s:s:0 language=jpn -c:v copy -c:a copy -c:s srt " + "output2.mkv" res = subprocess.call(cmdline, shell=True)
はこちらの記事と同じなので割愛。
elsammit-beginnerblg.hatenablog.com
TranslateFunc関数ですが、
引数として与えたvttを読み出し、
with open(FileName) as f: sl = f.readlines()
while 1: data = str(j)+"/"+str(len(sl)-1) print(data) if j > len(sl)-1: break try: buf = sl[j].split(':') if len(buf) >= 5: ret += sl[j] result = translator.translate(sl[j+1], dest="ja") ret += result.text j+=2 while 1: if len(sl[j]) > 1: result = translator.translate(sl[j], dest="ja") ret += result.text j+=1 else: break else: ret += sl[j] j+=1 except: break
にて先ほど記載した通り、表示時間を検出し次行の文字列を翻訳しています。
表示時間の検知方法ですが、
00:00:03.000 --> 00:00:06.500 position:90% align:right size:35%
となっているので、":"でsplitをかけ、5分割以上出来れば表示時間と判定することにしました。
翻訳する文が2行に分かれている可能性もあります。
そこで、次回の文字列が空欄でない場合には翻訳する文言と判断し、翻訳を実行し次の行に移行させる制御としました。
これらの翻訳データをret変数に格納していっております。
data = str(j)+"/"+str(len(sl)-1) print(data)
ですが、こちらは進捗状況表示用になります。
結構時間がかかり、停止してしまっているのか不安になったので。
■最後に
こちらを用いればCourseraの英語翻訳しかない動画も怖くないですねw
まぁ、Google翻訳にかけているだけなので誤りもあるはずなので英語の理解は必須になりますが。。
Courseraについてはこちらにまとめましたので是非!!
https://elsammit-diarypractice.hatenablog.com/entry/2021/06/30/224351
":"でsplitするのは微妙だったかな??
"-->"が含まれているか判定した方がよかったかな??
まぁ、この辺は使いながらチューニングしていくことにします!!