星期日, 10月 30, 2011

ann2srt v0.3

出乎意料之外的,ann2srt v0.2 的英文發布網誌得到了不少使用者回應。反觀中文版的對應發布文章反而靜悄悄...

言歸正傳,感謝在英文網誌上回應並協助測試的讀者 L,ann2srt script 修正了在某些英文註解中會遇到的特殊狀況(例如註解中有換行字元和半形逗號),以及在 Cygwin 環境下因為混用 DOS 與 UNIX 格式的換行字元造成程式執行錯誤的問題,因此釋放出 0.3 版。雖然這些修正其實在上週就完成了,且在上週末經過測試確認可以在 Linux 和 Cygwin 下執行無誤,不過實在是太懶惰了,所以一直沒有正式釋放出來...


廢話不多說,因為也想不出有啥廢話可以繼續扯下去,所以以下就是 v0.3 的原始碼:


#!/bin/bash
#
# Convert the youtube annotation into SRT subtitle
#
# By Shang-Feng Yang
# Version: 0.3
# License: GPL v3
#
# Changelog:
# * v0.3 (Oct/19/2011):
# - Fix the parsing errors caused by comma and newline characters in
# some English annotations
# - Adding transparent dos2unix conversion for compatibility under Cygwin
# * v0.2 (Jan/19/2011):
# - Sort the annotations using the "begin" time as key
# - Minor bugs fixing
# * v0.1 (Dec/7/2010):
# - Initial release


ANN=$1
SRT=$(basename ${ANN} .xml).srt
IFS=$'\n'
I=0

function usage() {
echo -e "Usage:\n"
echo -e "\t$(basename $0) ANNOTATION_FILE\n"
}

function parseXML() {
cat ${ANN} | tr -d '\r' |tr '\n' ' ' | xmlstarlet sel -t -m 'document/annotations/annotation' -v 'TEXT' -o '|' -m 'segment/movingRegion/rectRegion' -v '@t' -o '|' -b -n | tr -d '\r'
}

function reformatTime() {
local H=$(echo $1 |cut -d ':' -f 1)
local M=$(echo $1 |cut -d ':' -f 2)
local S=$(echo $1 |cut -d ':' -f 3)
printf '%02d:%02d:%06.3f' ${H} ${M} ${S} |tr '.' ','
}

function time2sod() {
# Convert time in HH:MM:SS.SSS format into second-of-the-day value
local SOD=$(echo $1 | awk -F ":" '{printf("%f\n", $1*3600+$2*60+$3);}')

echo ${SOD}
}

[ "x${ANN}" = "x" ] && { usage; exit 1; }
[ -f ${ANN} ] || { usage; exit 1; }
[ -f ${SRT} ] && rm ${SRT}
[ -f ${SRT}.tmp ] && rm ${SRT}.tmp

for LINE in $(parseXML); do
C=$(echo ${LINE} |cut -d '|' -f 1)
B=$(echo ${LINE} |cut -d '|' -f 2)
E=$(echo ${LINE} |cut -d '|' -f 3)
echo "$(time2sod ${B})#${B}#${E}#${C}" >> ${SRT}.tmp
done

grep "###" ${SRT}.tmp && {
echo "\"${ANN}\" has no valid annotation!" >&2
rm ${SRT}.tmp
exit 1
}

for LINE in $(cat ${SRT}.tmp|sort -n -t '#'); do
(( I++ ))
C=$(echo ${LINE} |cut -d '#' -f 4)
B=$(reformatTime $(echo ${LINE} |cut -d '#' -f 2))
E=$(reformatTime $(echo ${LINE} |cut -d '#' -f 3))
echo -e "${I}\n${B} --> ${E}\n${C}\n" >> ${SRT}
done

rm ${SRT}.tmp


為了避免因為複製貼上造成的錯誤,所以以上程式也可以從這邊下載:
http://dl.dropbox.com/u/1382119/tmp/ann2srt

基本上 v0.3 和 v0.2 比起來,並沒有太多的改變,只有為了避開註解中出現半形逗號的狀況,所以把本來當作中介格式的 CSV 格式的分隔符號,由逗號改成了 "|" 符號,並且使用 tr 移除沒必要的換行字元和把 DOS 的換行字元轉換成 UNIX 格式。由於 DOS 轉 UNIX 格式實際上只是摻除 carrier return 字元 ("\r" 字元),所以這樣的修改並不會影響在 Linux 下的執行。

13 則留言:

Adam 提到...

我就是想找個把註解轉換成srt字幕的工具而已。
可以幫忙編成輸入youtube視頻地址就能生成註解的srt字幕的傻瓜程式嗎,我看不懂代碼,不知道如何運用。

Unknown 提到...

我在Cygwin執行ann2srt Version: 0.3.1
後只出現下列文字
Usage:

anno.sh ANNOTATION_FILE

敬請版主幫忙釋疑how to correctly run the program? Thanks

Shang-Feng Yang 提到...

@WelFor Tsai:

請給我你的完整執行指令,否則我實在不知道你無法成功執行這個 script 的原因。

Unknown 提到...

指令和結果如下:
asus@asus-PC ~
$ sh anno.sh
Usage:

anno.sh ANNOTATION_FILE

我已將檔案改名為anno.sh。
我另以E-mail詳細報告整個過程。Thanks

Shang-Feng Yang 提到...

@WelFor Tsai:

我實在不知道該怎麼回應才好。

我想我知道你的問題在哪了,我想你應該是沒有爬文,然後又忽略掉程式列印出來的使用說明。我之前的文章中有一些說明,然後程式印出來的 Usage 訊息雖然短,但是應該還算是簡單明療才對,你要把要處理的註解檔案的檔名當程式的命令列參數傳給他,程式才知道要處理的檔案是哪一個。Usage不是無聊寫好玩的,請不要視而不見。

Unknown 提到...

這也是我的問題所在。
版主能否告知如何將要處理的註解檔案的檔名當程式的命令列參數傳給程式。
我曾嘗試用過好幾種方式,但都沒有成功。
如果我要處理的註解檔案的檔名是Bob.flv,我應如何將此檔名傳給程式。Thanks

Unknown 提到...

It is really hard to understand how to use this program.
用declare先宣告ANNOTATION_FILE=Bob.flv
或者
在執行前先直接宣告ANNOTATION_FILE=Bob.flv (結果如下)
全部都不work

asus@asus-PC ~
$ ANNOTATION_FILE=Bob.flv

asus@asus-PC ~
$ echo $ANNOTATION_FILE
Bob.flv

asus@asus-PC ~
$ sh anno.sh
Usage:

anno.sh ANNOTATION_FILE

It is really beyong my capability to use it.
Would you please kindly advise how to use your program.
Your quick response will be highly appreciated.

Shang-Feng Yang 提到...

@WelFor Tsai:

既然你會用 declare 建立環境變數,那怎麼會不知道什麼叫作『命令列參數』呢?我前一個回應不是告訴你了要把檔名當作命令列參數傳給 script 嗎?怎麼會變成宣告成環境變數了呢?另外你會用 declare 代表對 shell 有基本的認識,我的 script 也是完全公開的,為何不乾脆看一下 script 的內容,不就知道要怎麼傳檔名進去了嗎?

此外,一般來說 .flv 附檔名是 Flash Video 影片檔案用的附檔名,所以除非是命名上的問題,不然你的 Bob.flv 實際上是個影片檔,不是註解檔。你把影片檔的檔名當作參數傳給這個 script 基本上是沒有用的,除了不會產生字幕檔以外,script 大概也不會正確執行。

假設你確定你的註解檔就是 Bob.flv 的話,那正確的命令列指令應該是像這樣:

./anno.sh Bob.flv

或者

bash anno.sh Bob.flv

真的有那麼難嗎?

Unknown 提到...

I have also used the methods that you direct before.
They didn't work.
The results are as below.
asus@asus-PC ~
$ bash anno.sh Bob.flv
anno.sh: line 35: xmlstarlet:命令找不到
grep: Bob.flv.srt.tmp: No such file or directory
cat: Bob.flv.srt.tmp: No such file or directory
rm: 無法移除 ‘Bob.flv.srt.tmp’: No such file or directory

asus@asus-PC ~
$ chmod 755 anno.sh

asus@asus-PC ~
$ ./anno.sh Bob.flv
./anno.sh: line 35: xmlstarlet:命令找不到
grep: Bob.flv.srt.tmp: No such file or directory
cat: Bob.flv.srt.tmp: No such file or directory
rm: 無法移除 ‘Bob.flv.srt.tmp’: No such file or directory

Bob.flv is really a video file.
I thought that your program is written to directly abstract the annotation from the Youtube video.
As I know, the program such as Google2SRT-0.5.3 is used to directly get the caption from the Youtube video.
Now, the question is how to get the annotation file from the Youtube video?
Would you please advise how to do that? Thanks

Shang-Feng Yang 提到...

@WelFor Tsai:

1. Google2SRT 的輸入不是『YouTube Video』,它的『Google subtitles』欄位是用來填 Google Video 或 YouTube 的影片 URL 的,如果你直接填一個影片檔的檔名給它,Google2SRT 鐵定也抓不到 CC 字幕。FLV container format 不像 MKV 那樣可以內嵌文字字幕。既然是不存在於影片檔內的資訊,是要怎麼無中生有?

2. BASH 吐出來的錯誤訊息其實已經很清楚了,所以你顯然依然還是沒看過前幾篇跟這個 script 有關的舊文章,這篇文章中提到的英文版發布網誌的 comment 部分你應該也沒看過。之前的文章以及英文版的 comment 中,都有提到這個 script 用到哪些外部指令。下載註解檔的方法基本上不是我寫這個程式的重點,不過最初的發布文章中有給相關的連結,事實上 Google 搜尋一下應該也可以找到,我當初也是用 Google 搜尋才找到下載註解檔的方法,因此才會想要寫這個 script 做轉換。

既然你有能力用英文張貼意見,代表你的英文毒寫能力應該有一定程度,那相關資訊應該很容易就可以從舊文章或 Google 搜尋中找到。所以你問問題之前,是否該先做好相關的功課?尤其是我之前的回應已經說了你顯然沒有爬文。

Unknown 提到...

I have tried to Google for quite a long time, but until now I still haven't found a solution.
Just as Adam has mentioned, all we need is a program like Google2SRT that only requests to put the the Youtube video URL.
It is really disappointed, but it is my fault to misunderstand that you already help solve the issue.
However, thanks a lot.I have learnt something from this experience.
I never touched Cygwin and Bash Language before. In order to run your program, I spent about 2 weeks to learn about them.
Is it possible for you to write a program like Google2SRT to let us download the annotation direectly from the Youtube video?

山間 提到...

那個,我很想下載 YouTube 註解,看了您的文章後……請問該如何使用那段程式碼?

Shang-Feng Yang 提到...

@山間,

下載的方法可以用 Google 搜尋找到,或者是在 ann2srt v0.1 的發布文章中,也有提到我當初找到下載方法的網址連結。