Czasami (może nawet trochę częściej) jeśli ściąga się filmy i napisy osobno występuje problem synchronizacją. Strasznie upierdliwa sprawa. Oczywiście zwykle jest to proste przesunięcie, w całym filmie, lub na przykład po każdej przerwie na reklamy, więc wystarczy trzymać paluchy na z i x (oczywiście, o ile używa się mplayera). Jest to oczywiście półśrodek, zwłaszcza jeśli owe filmy archiwizujemy i/lub dzielimy się nimi z innymi. Dlatego też napisałem prosty plugin dla vima, który pozwala bardzo łatwo i przyjemnie (najlepiej w połączeniu z mplayerem, w którym można łatwo kontrolować numer odtwarzanej w danym momencie klatki) poradzić sobie z problemem napisów pojawiających się za wcześnie lub za późno.
" Submaker -- video subtitle editor ver 20090611 - early one
" (c) by Bartosz Pastudzki 2009
" I wrote this file. As long as you retain this notice you can do whatever you
" want with this stuff. If we meet some day, and you think this stuff is worth
" it, you can buy me a beer in return.
" Split subtitle line into list of content : [start,end,text]
function SplitLine (line)
let cline = getline (a:line)
let start = match (cline, "{")
if (start == -1)
throw "start1"
endif
let end = match (cline, "}", start)
if (end == -1)
throw "end1"
endif
let subStart = str2nr (cline[start+1 : end-1])
if (start == -1)
throw "start2"
endif
let start = match (cline, "{", end)
let end = match (cline, "}", start)
if (end == -1)
throw "end2"
endif
let subEnd = str2nr (cline[start+1 : end-1])
let content = match (cline, '\S', end+1)
return [subStart, subEnd, cline[content :] ]
endfunction
" Function opposite to SplitLine -- create valid subtitle line from content list
function JoinContent (content)
return "{". a:content[0] . "}{" . a:content[1] . "}" . a:content[2]
endfunction
" Function to find out if subtitle file is valid
function Validate ()
for lineNum in range (1,line ("$"))
try
call SplitLine (lineNum)
catch /.+/
return lineNum
endtry
endfor
return -1
endfunction
" Low level version of Delay. It takes numbers of lines too. It's not intended
" to be called directly by user.
function DelayLL (delay, start, end)
for line in range (a:start,a:end)
let content = SplitLine (line)
let content[0] += a:delay
let content[1] += a:delay
let nline = JoinContent (content)
call setline (line, nline)
endfor
endfunction
" Delay selected part of text
function DelayS (delay)
call DelayLL (a:delay, a:firstline, a:lastline)
endfunction
" Standard delay, from current line to the end
function Delay (delay)
call DelayLL (a:delay, line ("."), line ("$"))
endfunction
function GoToFrame (frame)
let linenum = 0
while 1
let linenum += 1
let last = SplitLine (linenum)
if (last[1] >= a:frame)
break
elseif (linenum == line ("$"))
break
endif
endwhile
call setpos (".", [0,linenum,1])
endfunction
Aby móc używać go w dowolnym momencie, należy zapisać go na dysku, w odzielnym pliku i do pliku .vimrc dodać linijkę "source ". Funkcjami, które służą do używania z zewnątrz są Delay, DelayS i GoToFrame.
Funkcja Delay opóźnia wszystkie napisy od linii w której znajduje się kursor do końca. Na przykład wywołanie ":call Delay (-5)" przesunie je o 5 klatek w tył.
Funkcja DelayS działa tak samo jak Delay, z tą różnicą przesuwa tylko te zaznaczone.
Funkcja GoToFrame przesuwa kursor do linijki, w której znajduje się napis, który się wyświetli się w klatce podanej w parametrze bądź następnego, jeśli w tej klatce nie ma żadnego napisu.
Należy zaznaczyć, że program działa tylko dla napisów w formacie "{start}{koniec} napis" i nie zadziała poprawnie jeśli liczba klatek przekroczy zakres 32-bitowej liczby ze znakiem (231).
Mam nadzieję, że komuś się przyda, będę wdzięczny za wszelkie uwagi i sugestie, ewentualnie łatki.
> Standart
-d.
> oposite
opposite
Minus za obsługę tylko jednego formatu napisów.
Nie potrafię powiedzieć jak to osiągnąć, bo skrypczeniem vim-a nigdy się nie zajmowałem, ale jestem przekonany że potrafi on wyróżnić czy pracuje na zaznaczeniu, i w takim przypadku podjąć jakąś akcję tylko na nim; w przeciwnym zaś przypadku zrobić coś na jakimś domyślnym zakresie, czyli całym pliku lub od kursora do końca/początku.
Bo aktualnie, z tego co rozumiem, dla całego pliku trzeba wywołać jedną funkcję, zaś dla zaznaczenia jakąś inną. Ale powiedzmy że mam pełne prawo źle rozumieć ;) .
Pdbr: Jak przyjdzie mi modyfikować napisy w innym formacie, pewnie rozszerzę.
Minio: Dobrze zrozumiałeś. Prawdopodobnie można, ale moja aktualna wiedza nie jest wystarczająca. Z resztą funkcja do używania z zaznaczeniem i tak jest raczej mało przydatna. Stworzyłem ją bardziej dla treningu. :)
Livio: Dzięki. :)
Wiem, że prawdziwi twardziele nie używają gotowców, ale mimo to polecę subtitleeditora (http://home.gna.org/subtitleeditor/) ;)
Radek: To nie kwestia bycia twardzielem. To kwestia lenistwa (tyle wysiłku żeby poszukać w guglach) i poczucia, że wykorzystuję mój edytor tekstu w tak znikomym stopniu. Chciałem sobie pisanie skryptów poćwiczyć głównie, a że coś z tego wyszło, to czemu nie puścić w świat, może się przyda.
No jak tak, to rozumiem ;) Myślałem, że chcesz poprostu wygodnie poprawiać napisy, a subtitleeditor jest naprawdę świetny i nie sądzę, żebyś go łatwo zastąpił ;) Mi się na przykład bardzo podoba opcja robienia "waveform" do filmu - wykres natężenia dźwięku w czasie na którym można sobie mychą przesuwać napisy. Dzięki temu można łatwo (chociaż ręcznie) zsynchronizować nawet totalnie niedopasowane napisy.
...wrzystkie? Oo"