Szybki program do modyfikacji plików z napisami.

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.


Komentarze do notki “Szybki program do modyfikacji plików z napisami.”

  1. Livio 

    > Standart

    -d.

    > oposite

    opposite

  2. Pdbr 

    Minus za obsługę tylko jednego formatu napisów.

  3. Minio 

    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ć ;) .

  4. Bartek 

    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. :)

  5. Radek 

    Wiem, że prawdziwi twardziele nie używają gotowców, ale mimo to polecę subtitleeditora (http://home.gna.org/subtitleeditor/) ;)

  6. Elwis 

    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.

  7. Radek 

    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.

  8. D4rky 

    ...wrzystkie? Oo"

Zostaw odpowiedź