#!perl ################################################################################################# ### Erzeugung von HTML-Seiten aus SSA-Untertiteldateien für Silent Möbius The Motion Pictures ### ################################################################################################# # 2007-11-09, Devil Doll # # ============================================================================= use strict; # ============================================================================= ############################ ### Aufbau der SSA-Datei ### ############################ # ============================================================================= # Schablonen für Zeilen des Abschnitts my $title_pattern = "^Title: (.*)\$"; my $script_pattern = "^Original Script: (.*)\$"; my $timing_pattern = "^Original Timing: (.*)\$"; my $translation_pattern = "^Original Translation: (.*)\$"; my $style_pattern = '^Style: (.*)'; my $dialogue_pattern = '^Dialogue: (.*)'; my $comment_pattern_t = '^Comment: (.*)'; my $comment_pattern_c = '^; (.*)'; my $comment_pattern_m = '^;MANGA:(.*)'; # ----------------------------------------------------------------------------- # Markierung von Abschnitten Abschnitts my $style_header = "[V4 Styles]"; # SSA-Version my $event_header = "[Events]"; # ----------------------------------------------------------------------------- # Art der zuletzt analysierten Events-Zeile my $event_state = undef; # ============================================================================= ####################### ### HTML-Schablonen ### ####################### # ============================================================================= # Zu erzeugende Dateien: HTML oder PHP? my $extension = '.html'; # ----------------------------------------------------------------------------- # Dokument-Start my $html_head1 = '' . "\n" . '' . "\n" . '' . "\n" . "\n" . '' . "\n" . "\n" . '%s' . "\n" . '' . "\n" . '' . "\n" . "\n" . '' . "\n" . "\n" . ''; # ----------------------------------------------------------------------------- my $table_on = "\n" . ''; # my $dialogue = "\n" . ''; my $dialogue = "\n" . ''; my $table_off = "\n" . '
%s%s:%s
%s:%s
'; # ----------------------------------------------------------------------------- my $comment_c = "\n" . '

%s

'; my $comment_m = "\n" . '
%s
'; my $comment_t = "\n" . '
%s
'; my $separator = "\n" . '
'; # ----------------------------------------------------------------------------- my $html_tail = "\n" . "\n" . '' . "\n" . ''; # ============================================================================= my $body_open = "\n" . '
' . "\n" . '

%s

'; my $body_close = "" # '

' # . "\n" . '' # . "\n" . 'Valid XHTML 1.1!' # . "\n" . '' # . "\n" . '' # . "\n" . 'Valid CSS!' # . "\n" . '' # . "\n" . '

' . "\n" . "\n" . '
'; # ============================================================================= my $nav_open = "\n" . '' . "\n"; # ============================================================================= ################################################################## ### Episoden-Namen (als Titel-Texte auf den Navigations-Links) ### ################################################################## # ============================================================================= my %episode_name = ( 1 => 'Silent Möbius - The Motion Picture 1', 2 => 'Silent Möbius - The Motion Picture 2', ); # ============================================================================= #################################################### ### CSS-Farbcode aus einem SSA-Farbcode erzeugen ### #################################################### # CSS verwendet #rrggbb; SSA verwendet &Hbbggrr. # ============================================================================= sub css_color_code ($) { # =========================================================================== # Parameterwerte übernehmen my ($ssa_color_code) = @_; # =========================================================================== # Auftrennen in einzelne Zeichen my @digits = split (//, $ssa_color_code); # --------------------------------------------------------------------------- # Reihenfolge der Farb-Komponenten umsortieren return $digits[6] . $digits[7] . $digits[4] . $digits[5] . $digits[2] . $digits[3]; # =========================================================================== } # ============================================================================= ###################################################################### ### CSS-Klassen-Definition aus einer SSA-Style-Definition erzeugen ### ###################################################################### # Format: 0=Name, 1=Fontname, 2=Fontsize, 3=PrimaryColour, 4=SecondaryColour, # 5=TertiaryColour, 6=BackColour, 7=BoldFlag, 8=ItalicFlag, 9=BorderStyle, # 10=Outline, 11=Shadow, 12=Alignment, 13=MarginL, 14=MarginR, 15=MarginV, # 16=AlphaLevel, 17=Encoding # ============================================================================= sub print_css_class ($) { # =========================================================================== # Parameterwerte übernehmen my ($style_parameters) = @_; # =========================================================================== # Komma-separierte Parameterliste auftrennen my @parameters = split /,/, $style_parameters; # --------------------------------------------------------------------------- # CSS-Style-Definition generieren print FILE_OUT sprintf ($css_style, $parameters[0], $parameters[0], # $parameters[1], sprintf ("%d", $parameters[2] * 0.7), # Font auf 70% skalieren! ($parameters[7] ? 'bold' : 'normal'), # aus Schablone ausgelagert ($parameters[8] ? 'italic' : 'normal'), css_color_code ($parameters[6]), css_color_code ($parameters[3]), ); # =========================================================================== } # ============================================================================= #################################### ### "Säubern" einer Dialog-Zeile ### #################################### # ============================================================================= sub cleanup_content ($$) { # =========================================================================== # Parameterwerte übernehmen my ($string, $html_flag) = @_; my $italic_on_replacement = ($html_flag ? '' : ''); my $italic_off_replacement = ($html_flag ? '' : ''); # =========================================================================== # Harte Zeilenumbrüche entfernen $string =~ s/\\N/ /g; # --------------------------------------------------------------------------- # Inline-Kursiv-Markierungen ersetzen my $italic_on = q({.i1}); $string =~ s/$italic_on/$italic_on_replacement/g; my $italic_off= q({.i0}); $string =~ s/$italic_off/$italic_off_replacement/g; # --------------------------------------------------------------------------- # Sonstige Meta-Markierungen "{...}" ersatzlos löschen $string =~ s/{[^}]+}//g; # --------------------------------------------------------------------------- # HTML-Sonderzeichen ersetzen if ($html_flag) { $string =~ s/ä/ä/g; $string =~ s/ö/ö/g; $string =~ s/ü/ü/g; $string =~ s/Ä/Ä/g; $string =~ s/Ö/Ö/g; $string =~ s/Ü/Ü/g; $string =~ s/ß/ß/g; $string =~ s/"/"/g; $string =~ s/é/é/g; $string =~ s/°/°/g; $string =~ s/à/à/g; $string =~ s/²/²/g; } # --------------------------------------------------------------------------- # Ergebnis der Behandlung zurückliefern return $string; # =========================================================================== } # ============================================================================= ################################################# ### Ausgabe einer inhaltlichen Kommentarzeile ### ################################################# # ============================================================================= sub print_comment_content ($) { # =========================================================================== # Parameterwerte übernehmen my ($string) = @_; # =========================================================================== # Hatten wir direkt davor eine Dialog-Zeile? if ($event_state eq 'dialogue') { # -------------------------------------------------------------------- # Dialog-Block abschließen print FILE_OUT $table_off; # -------------------------------------------------------------------- } # --------------------------------------------------------------------------- # Kommentarzeile ausgeben print FILE_TXT sprintf ("%s\n", cleanup_content ($string, 0)); print FILE_OUT sprintf ($comment_c, cleanup_content ($string, 1)); $event_state = 'comment'; # =========================================================================== } # ============================================================================= ########################################## ### Ausgabe einer Manga-Referenz-Zeile ### ########################################## # ============================================================================= sub print_comment_manga ($) { # =========================================================================== # Parameterwerte übernehmen my ($string) = @_; # =========================================================================== # Hatten wir direkt davor eine Dialog-Zeile? if ($event_state eq 'dialogue') { # -------------------------------------------------------------------- # Dialog-Block abschließen print FILE_OUT $table_off; # -------------------------------------------------------------------- } # --------------------------------------------------------------------------- # Kommentarzeile ausgeben print FILE_TXT sprintf ("%s\n", cleanup_content ($string, 0)); print FILE_OUT sprintf ($comment_m, cleanup_content ($string, 1)); $event_state = 'manga'; # =========================================================================== } # ============================================================================= ############################################################ ### Ausgabe einer übersetzungstechnischen Kommentarzeile ### ############################################################ # ============================================================================= sub print_comment_translation ($) { # =========================================================================== # Parameterwerte übernehmen my ($string) = @_; # =========================================================================== # Hatten wir direkt davor eine Dialog-Zeile? if ($event_state eq 'dialogue') { # -------------------------------------------------------------------- # Dialog-Block abschließen print FILE_OUT $table_off; # -------------------------------------------------------------------- } # --------------------------------------------------------------------------- # Kommentarzeile ausgeben print FILE_OUT sprintf ($comment_t, cleanup_content ($string, 1)); $event_state = 'comment'; # =========================================================================== } # ============================================================================= ################################ ### Ausgabe einer Trennzeile ### ################################ # ============================================================================= sub print_separator () { # =========================================================================== # Hatten wir direkt davor eine Dialog-Zeile? if ($event_state eq 'dialogue') { # -------------------------------------------------------------------- # Dialog-Block abschließen print FILE_OUT $table_off; # -------------------------------------------------------------------- } # --------------------------------------------------------------------------- # Separatorzeile ausgeben print FILE_TXT "\n"; print FILE_OUT $separator; $event_state = 'comment'; # =========================================================================== } # ============================================================================= ################################# ### Ausgabe einer Dialogzeile ### ################################# # ============================================================================= sub print_dialogue ($) { # =========================================================================== # Parameterwerte übernehmen my ($string) = @_; # =========================================================================== # Komma-separierte Dialogzeile in Spalten aufbrechen my @fields = split (/,/, $string, 10); # 0, 0:02:12.00, 0:02:14.90, Dai, , 0000, 0000, 0000, , Reki, warum kommst du nicht in die Schule? # 0, 0:20:50.03, 0:20:51.13, Mainfont, , 0000, 0000, 0000, ,{\be1}Ich... # --------------------------------------------------------------------------- # Enthält diese Zeile "echten Inhalt"? if (! $fields[4]) { # -------------------------------------------------------------------- # Hatten wir direkt davor auch eine Dialog-Zeile? if ($event_state ne 'dialogue') { # ------------------------------------------------------------- # Dialog-Block einleiten print FILE_OUT $table_on; # ------------------------------------------------------------- } # -------------------------------------------------------------------- # Dialogzeile ausgeben # print FILE_OUT sprintf ($dialogue, $fields[3], $fields[2], $fields[3], cleanup_content ($fields[9], 1)); print FILE_OUT sprintf ($dialogue, $fields[3], $fields[3], cleanup_content ($fields[9], 1)); $event_state = 'dialogue'; # -------------------------------------------------------------------- # Textversion ausgeben print FILE_TXT sprintf ("===> %s: %s\n", $fields[3], cleanup_content ($fields[9], 0)); # -------------------------------------------------------------------- } # (Erklärende Einblendungen etc. wollen wir hier ignorieren.) # =========================================================================== } # ============================================================================= #@@@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@ Hauptprogramm @@@@@ #@@@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@@@@@@@@@@@@@@@@@@@@@ # ============================================================================= # Kommandozeilen-Parameter lesen my $input_filename = $ARGV[0]; my $output_filename = $ARGV[1]; my $txt_filename = $ARGV[2]; print "Eingabe: '$input_filename'\n"; print "Ausgabe: '$output_filename'\n"; print "Textversion: '$txt_filename'\n"; my $episode_number = substr ($input_filename, 2, 2); my $previous_episode = sprintf ("%02d", ($episode_number + 2) % 2 + 1); my $next_episode = sprintf ("%02d", ($episode_number + 0) % 2 + 1); # ============================================================================= # "make: Ist die Ausgabedatei neuer als die Eingabedatei? my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat ($input_filename); my $lastmod_in = $mtime; my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat ($output_filename); my $lastmod_out = $mtime; # if ($lastmod_out >= $lastmod_in) {exit 2;} # ============================================================================= # Dateien öffnen open (FILE_IN, "<$input_filename") or die "cannot open[read] file $input_filename: $!"; open (FILE_OUT, ">$output_filename") or die "cannot open[write] file $output_filename: $!"; open (FILE_TXT, ">$txt_filename") or die "cannot open[write] file $txt_filename: $!"; # ============================================================================= # Alle Zeilen bis zum Beginn des Style-Abschnitts lesen my $title_content = "unknown"; my $script_content = "unknown"; my $timing_content = "unknown"; my $translation_content = "unknown"; SCRIPTINFO: while () { # ------------------------------------------------------- # Zeileninhalt adressieren my $this_line = $_; chomp $this_line; last SCRIPTINFO if ($this_line eq $style_header); # ------------------------------------------------------- # Ist das eine der bekannten Kopfzeilen? if ($this_line =~/$title_pattern/) {$title_content = $1;} if ($this_line =~/$script_pattern/) {$script_content = $1;} if ($this_line =~/$timing_pattern/) {$timing_content = $1;} if ($this_line =~/$translation_pattern/) {$translation_content = $1;} # ------------------------------------------------------- } # ----------------------------------------------------------------------------- # Schablone mit eingesetzten Werten ausgeben print FILE_OUT sprintf ($html_head1, cleanup_content ($title_content, 1), $previous_episode, $next_episode); # ============================================================================= # Zuerst die allgemeinen Attribute aller CSS-Klassen festlegen: print FILE_OUT sprintf ($css_common); # ----------------------------------------------------------------------------- # Alle Zeilen bis zum Beginn des Event-Abschnitts lesen STYLES: while () { # ------------------------------------------------------- # Zeileninhalt adressieren my $this_line = $_; chomp $this_line; last STYLES if ($this_line eq $event_header); # ------------------------------------------------------- # Ist das eine Style-Definition? if (/$style_pattern/) { # ------------------------------------------------ # dann generiere daraus eine CSS-Klasse für Tabellenzeilen print_css_class ($1); # ------------------------------------------------ } # ------------------------------------------------------- } # ----------------------------------------------------------------------------- # Schablone mit eingesetzten Werten ausgeben print FILE_OUT $html_head2; # ============================================================================= # Navigation ausgeben print FILE_OUT $nav_open; for (my $episode = 1; $episode <= 2; $episode++) { my $episode_printable = sprintf ("%d", $episode); if ($episode_printable eq $episode_number) { print FILE_OUT sprintf ($nav_line, $episode_printable); } else { print FILE_OUT sprintf ($nav_link, $episode_printable, $episode_name {$episode}, $episode_printable, $episode_printable); } } print FILE_OUT $nav_close; # ============================================================================= # Dokument-Body öffnen print FILE_OUT sprintf ($body_open, cleanup_content ($title_content, 1)); # ============================================================================= # Alle restlichen Zeilen der Datei lesen EVENTS: while () { # ----------------------------------------------------------- # Zeileninhalt adressieren my $this_line = $_; chomp $this_line; # ----------------------------------------------------------- if (/$dialogue_pattern/) { print_dialogue ($1); next EVENTS; } if (/$comment_pattern_c/) { print_comment_content ($1); next EVENTS; } if (/$comment_pattern_m/) { print_comment_manga ($1); next EVENTS; } if (/$comment_pattern_t/) { print_comment_translation ($1); next EVENTS; } if (/^$/) { print_separator (); next EVENTS; } # ----------------------------------------------------------- } # ----------------------------------------------------------------------------- # Hatten wir zuletzt eine Dialog-Zeile? if ($event_state eq 'dialogue') { print FILE_OUT $table_off; } # ============================================================================= # Dateien schließen print FILE_OUT $body_close; print FILE_OUT $html_tail; close (FILE_IN) or die "cannot close[read] file $input_filename: $!"; close (FILE_OUT) or die "cannot close[write] file $output_filename: $!"; close (FILE_TXT) or die "cannot close[write] file $txt_filename: $!"; # =============================================================================