Da ich mir nicht sicher war ob das mit tv_augment aus dem XMLTV Projekt zu machen ist, habe ich mal ein Skript zum Testen geschrieben.
#!/usr/bin/perl
use strict;
use warnings;
my $rytec = shift;
my $XMLTV;
my $subtitle = "";
my $desc = "";
my $director = "";
my @actors = ();
my $year = "";
my @categories = ();
my $season = "";
my $episode = "";
my $fsk = "";
#
# The categories recognized by tvheadend (see epg.c)
#
my $MOVIE = "Movie / Drama";
my $THRILLER = "Detective / Thriller";
my $ADVENTURE = "Adventure / Western / War";
my $SF = "Science fiction / Fantasy / Horror";
my $COMEDY = "Comedy";
my $SOAP = "Soap / Melodrama / Folkloric";
my $ROMANCE = "Romance";
my $HISTORICAL = "Serious / Classical / Religious / Historical movie / Drama";
my $XXX = "Adult movie / Drama";
my $NEWS = "News / Current affairs";
my $WEATHER = "News / Weather report";
my $NEWS_MAGAZINE = "News magazine";
my $DOCUMENTARY = "Documentary";
my $DEBATE = "Discussion / Interview / Debate";
my $INTERVIEW = $DEBATE ;
my $SHOW = "Show / Game show";
my $GAME = "Game show / Quiz / Contest";
my $VARIETY = "Variety show";
my $TALKSHOW = "Talk show";
my $SPORT = "Sports";
my $SPORT_SPECIAL = "Special events (Olympic Games; World Cup; etc.)";
my $SPORT_MAGAZINE = "Sports magazines";
my $FOOTBALL = "Football / Soccer";
my $TENNIS = "Tennis / Squash";
my $SPORT_TEAM = "Team sports (excluding football)";
my $ATHLETICS = "Athletics";
my $SPORT_MOTOR = "Motor sport";
my $SPORT_WATER = "Water sport";
my $KIDS = "Children's / Youth programmes";
my $KIDS_0_5 = "Pre-school children's programmes";
my $KIDS_6_14 = "Entertainment programmes for 6 to 14";
my $KIDS_10_16 = "Entertainment programmes for 10 to 16";
my $EDUCATIONAL = "Informational / Educational / School programmes";
my $CARTOON = "Cartoons / Puppets";
my $MUSIC = "Music / Ballet / Dance";
my $ROCK_POP = "Rock / Pop";
my $CLASSICAL = "Serious music / Classical music";
my $FOLK = "Folk / Traditional music";
my $JAZZ = "Jazz";
my $OPERA = "Musical / Opera";
my $CULTURE = "Arts / Culture (without music)";
my $PERFORMING = "Performing arts";
my $FINE_ARTS = "Fine arts";
my $RELIGION = "Religion";
my $POPULAR_ART = "Popular culture / Traditional arts";
my $LITERATURE = "Literature";
my $FILM = "Film / Cinema";
my $EXPERIMENTAL_FILM = "Experimental film / Video";
my $BROADCASTING = "Broadcasting / Press";
my $SOCIAL = "Social / Political issues / Economics";
my $MAGAZINE = "Magazines / Reports / Documentary";
my $ECONOMIC = "Economics / Social advisory";
my $VIP = "Remarkable people";
my $SCIENCE = "Education / Science / Factual topics";
my $NATURE = "Nature / Animals / Environment";
my $TECHNOLOGY = "Technology / Natural sciences";
my $DIOLOGY = $TECHNOLOGY;
my $MEDECINE = "Medicine / Physiology / Psychology";
my $FOREIGN = "Foreign countries / Expeditions";
my $SPIRITUAL = "Social / Spiritual sciences";
my $FURTHER_EDUCATION = "Further education";
my $LANGUAGES = "Languages";
my $NOCLASS = "Unpublished";
my $HOBBIES = "Leisure hobbies";
my $TRAVEL = "Tourism / Travel";
my $HANDICRAF = "Handicraft";
my $MOTORING = "Motoring";
my $FITNESS = "Fitness and health";
my $COOKING = "Cooking";
my $SHOPPING = "Advertisement / Shopping";
my $GARDENING = "Gardening";
my %REPLACE=(
"Actionkrimi" => $THRILLER,
"Dailysoap" => $SOAP,
"Daily Soap" => $SOAP,
"Dauerwerbesendung" => $SHOPPING,
"Dekosoap" => $SOAP,
"Dokusoap" => $SOAP,
"Doku-Soap" => $SOAP,
"E-Sport" => $SPORT,
"Extremsport" => $SPORT,
"Extremsport-Reihe" => $SPORT,
"Freizeit. Kochen" => $COOKING,
"Historiensoap" => $SOAP,
"Horror-Krimi" => $THRILLER,
"Kampfsport" => $SPORT,
"Kinderabenteuerserie" => $KIDS,
"Kinder-Abenteuerserie" => $KIDS,
"Kinder" => $KIDS,
"Kinder-Fantasyserie" => $KIDS,
"Kinderkrimiserie" => $KIDS,
"Kindermagazin" => $KIDS,
"Kindernachrichten" => $KIDS,
"Kinderquiz" => $KIDS,
"Kinderreihe" => $KIDS,
"Kinderreportage" => $KIDS,
"Kinderserie" => $KIDS,
"Kindershow" => $KIDS,
"Kinderspielshow" => $KIDS,
"Kinder-Tierserie" => $KIDS,
"Knast-Soap" => $SOAP,
"Koch-Dokusoap" => $SOAP,
"Koch-Doku-Soap" => $SOAP,
"Kochduell" => $COOKING,
"Kochsendung" => $COOKING,
"Kochserie" => $COOKING,
"Kochshow" => $COOKING,
"Krimi" => $THRILLER,
"Krimidrama" => $THRILLER,
"Krimikomödie" => $THRILLER,
"Krimireihe" => $THRILLER,
"Krimiserie" => $THRILLER,
"Motorradsport" => $SPORT,
"Motorsport" => $SPORT,
"Motorsportmagazin" => $SPORT,
"Mysterykrimi" => $THRILLER,
"Nachrichten" => $NEWS,
"Nachrichten. Dokumentation" => $NEWS,
"Nachrichtenmagazin" => $NEWS_MAGAZINE,
"Nachrichtenrückblick" => $NEWS,
"Nachrichtensatire" => $NEWS,
"Pseudo-Doku-Soap" => $SOAP,
"Radsport" => $SPORT,
"Realitysoap" => $SOAP,
"Reality-Soap" => $SOAP,
"Regionalnachrichten" => $NEWS,
"Science-Fiction-Abenteuer" => $SF,
"Science-Fiction" => $SF,
"Science-Fiction-Horror" => $SF,
"Science-Fiction-Serie" => $SF,
"Science-fiction series" => $SF,
"Science-Fiction-Thriller" => $SF,
"SciFi-Actionfilm" => $SF,
"SciFi-Drama" => $SF,
"Sci-Fi-Film" => $SF,
"Sci-Fi-Horror" => $SF,
"SciFi-Horror" => $SF,
"SciFi-Komödie" => $SF,
"Sci-Fi-Serie" => $SF,
"SciFi-Serie" => $SF,
"Soap" => $SOAP,
"Sport" => $SPORT,
"Sportdoku" => $SPORT,
"Sporthighlights" => $SPORT,
"Sportlerdrama" => $SPORT,
"Sportmagazin" => $SPORT,
"Sportnachrichten" => $SPORT,
"Sportquiz" => $SPORT,
"Sportreportage" => $SPORT,
"US-Sport" => $SPORT,
"Wassersport" => $SPORT,
"Werbesendung" => $SHOPPING,
"Werbung" => $SHOPPING,
"Wetterbericht" => $WEATHER,
"Wintersport" => $SPORT,
"Zeichentrick" => $CARTOON,
"Zeichentrickfilm" => $CARTOON,
"Zeichentrickserie" => $CARTOON,
);
sub parse_subtitle()
{
# Extract year
if ($subtitle =~ m/\((\d{4})\)/) {
$year = $1;
$subtitle =~ s/\(\d{4}\)//;
# Remove leading and trailing whitespace
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
}
# Extract season and episode number
if ($subtitle =~ m/\(Staffel (\d+), Episode (\d+)\)/) {
$season = $1;
$episode = $2;
$subtitle =~ s/\(Staffel \d+, Episode \d+\)//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/\(Staffel (\d+), Folge (\d+)\)/) {
$season = $1;
$episode = $2;
$subtitle =~ s/\(Staffel \d+, Folge \d+\)//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/\(Staffel (\d+), Folge (\d+)<\)/) {
$season = $1;
$episode = $2;
$subtitle =~ s/\(Staffel \d+, Folge \d+<\)//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/\((\d+) (\d+)\)/) {
$season = $1;
$episode = $2;
$subtitle =~ s/\(\d+ \d+\)//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
}
# Extract episode number
elsif ($subtitle =~ m/\(Episode (\d+)\)/) {
$season = "";
$episode = $1;
$subtitle =~ s/\(Episode \d+\)//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/Episode (\d+)/) {
$season = "";
$episode = $1;
$subtitle =~ s/Episode \d+//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/\(Folge (\d+)\)/) {
$season = "";
$episode = $1;
$subtitle =~ s/\(Folge \d+\)//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/\(Folge (\d+)<\)/) {
$season = "";
$episode = $1;
$subtitle =~ s/\(Folge \d+<\)//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
}
# Extract multiple categories with content rating
if ($subtitle =~ m/\[([^\]]+\[\d+\][^\]]+)\]/) {
#TODO push @categories, $1;
$subtitle =~ s/\[[^\]]+\[\d+\][^\]]+\]//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
}
# Extrate content rating
if ($subtitle =~ m/\[0\+\]/) {
$fsk = "FSK 0";
$subtitle =~ s/\[0\+\]//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/\[(\d+)\]/) {
$fsk = "FSK " . $1;
$subtitle =~ s/\[\d+\]//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
} elsif ($subtitle =~ m/\[(\d+)\+\]/) {
$fsk = "FSK " . $1;
$subtitle =~ s/\[\d+\+\]//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
}
# Extract categories
while ($subtitle =~ m/\[([^\]]+)\]/) {
my $text = $1;
while ($text =~ m/([^\,]+)/) {
push @categories, $1;
$text =~ s/[^\,]+//;
$text =~ s/^\, //;
}
$subtitle =~ s/\[[^\]]+\]//;
$subtitle =~ s/^\s+//;
$subtitle =~ s/\s+$//;
}
$subtitle = "" if "." eq $subtitle;
}
sub parse_desc()
{
# Remove ()
$desc =~ s/\(\)//;
$desc =~ s/^\s+//;
$desc =~ s/\s+$//;
if ($desc =~ m/([^-]*) - (.*)/) {
$subtitle = $1;
$desc = $2;
}
}
open $XMLTV, "<$rytec" or die "\e[1;31m$!\e[0m: »$rytec«\n";
while (<$XMLTV>) {
chomp;
# Remove wrong and so useless »lang="??"« attributes
$_ =~ s/ lang="\w\w"//;
# Handle <programme>
if (m/^\W+<programme/) {
# TODO convert timestamps to UTC
printf "%s\n", $_;
next;
}
# Handle <title>
if (m/^\W+<title>/) {
printf "%s\n", $_;
next;
}
# Handle <sub-title>
if (m/^\W+<sub-title>(.*)<\/sub-title>/) {
$subtitle = $1;
parse_subtitle();
next;
}
# Handle <desc>
if (m/^\W+<desc>(.*)/) {
$desc = $1;
# Remove </desc>
$desc =~ s/<\/desc>//;
parse_desc();
next;
}
# Handle </programme>
if (m/^\W+<\/programme>/) {
printf " <sub-title>%s</sub-title>\n", $subtitle unless "" eq $subtitle;
printf " <desc>%s</desc>\n", $desc unless "" eq $desc;
if ("" ne $director) {
printf " <credits>\n <director>%s</director>\n", $director;
for my $actor (@actors) {
printf " <actor>%s</actor>\n", $actor;;
}
printf " </credits>\n";
}
printf " <date>%s</date>\n", $year unless "" eq $year;
for my $category (@categories) {
if (exists $REPLACE{$category}) {
printf " <category>%s</category>\n", $REPLACE{$category};
} else {
printf " <category>»%s«</category>\n", $category;
}
}
printf " <episode-num system=\"xmltv_ns\">%s.%s.</episode-num>\n", $season, $episode unless "" eq $episode;
printf " <rating system=\"FSK\">\n <value>%s</value>\n </rating>\n", $fsk unless "" eq $fsk;
printf "%s\n", $_;
$subtitle = "";
$desc = "";
$director = "";
@actors = ();
$year = "";
@categories = ();
$season = "";
$episode = "";
$fsk = "";
next;
}
# Write channel part
if (m/\W+<channel/) {
printf "%s\n", $_;
next;
}
if (m/\W+<display-name>/) {
# TODO Set lang attribute depending on channel id
printf "%s\n", $_;
next;
}
if (m/\W+<\/channel>/) {
printf "%s\n", $_;
next;
}
# Catch all for <?xml>, <!DOCTYPE>, <tv> and </tv>
if (m/^<.*/) {
printf "%s\n", $_;
next;
}
# Remove </desc>
$_ =~ s/<\/desc>//;
# Handle remaining
my @words_on_this_line = split(" ", $_);
if ("" ne $director) {
push @actors, $_;
} elsif (10 > scalar(@words_on_this_line)) {
$director = $_;
} else {
$desc = $desc . " - " . $_;
parse_desc();
}
}
close ($XMLTV);
Alles anzeigen
Das Kodi EPG wird schon mal eingefärbt, aber das schreiben der Kategorien muss ich noch mal überdenken. Als Parameter wird das EPG XML erwartet und das neue auf die Standardausgabe geschrieben.