#!/usr/bin/perl # # This perl script is intended to perform TV Show data lookups based on # the popular www.tvrage.com website # # # Author: Steve Adeff (adeffs dot mythtv At gmail com) # Based on Source by: Tim Harvey, Andrei Rjeousski and Jesse Anderson # With code contributed by: Mark Spieth, Christoph Holzbaur, Peter Kornhuld # v0.1 # - Using old tvgrabber script, transfered to grabbing information from TVRage.com # Due to my not knowing what was going on... the following features need to be checked # to make sure they still work!! # - Allow mysql.txt to be used. (Originally by Mark Spieth!) # - Allow multple file name input. (Originally by Mark Spieth!) # - Allow "SSxEE - NAME.avi". (Originally by Christoph Holzbaur!) # - Double episode (ie S02E13-14) support. (Originally by Peter Kornhuld!) # - Fix letter S in filename after "S"eason. (Originally by Christoph Holzbaur!) # - Use hostname instead of MythBox. (Originally by Mark Spieth!) # - Replace if Insert fails. May need to make an option to turn # this off. (Originally by Mark Spieth!) # - Option to create a symlink to to the recording. (Originally by Mark Spieth!) # - Four digit series/episode number support. (Originally by Mark Spieth!) # # v0.2 # - fixes for TVRage HTML changes # - Support multiple Writers # # v0.3 # - add random channel generator (Thanks Shane Boulter) # - fix inputfile not making it to the addrecord routine (Thanks Shane Boulter) # # v0.4b1 # - fix plot insert error (Thanks Paul Novotny) # - fix user hostname quotation error (Thanks Paul Novotny) # - KNOWN BUG: The random channel generator causes problems when inserting the same show twice. # I hope to have a decent fix for this soon. # # v0.4b2 # - Attempt a fix for the random channel generator bug... # # v0.4 # - fix plot insert error (Thanks Paul Novotny) # - fix user hostname quotation error (Thanks Paul Novotny) # - fix no date/not found error (Thanks Mark Spieth) # - fix no summary (Thanks Mark Spieth) # - fix replace old instead of add new (Thanks Mark Spieth) # - fix channel can't be 0 (Thanks Mark Spieth) # # # # v0.5 # - Fix for new TVRage page formating # - add channel option to specify the channel number to use. # Following updates by Mark Spieth # - now converts all spaces and - to . in the filename for compatibility # - -nr turns this off # - -nf stops 4 digit numbers from being parsed as ep info. mainly for "the 4400" :-) # - -latest uses the latest ep number for those files that dont have ep info in # them and cant figure it out. # # v0.6 # - Fix for files that use a date instead of season and episode information. # (Thanks Tim Christie) # - update showname parsing which changed # # v0.7 # (Thanks to Matthew Rushton for initial work on all the 0.7 stuff) # - Enhancements # -mythvideo add to mythvideo rather than recordings # -coverfile adds in a cover file when used with -mythvideo # if no cover file is given it will search for the input file name # with .jpg or gif ammended, or cover.jpg or cover.gif in the same # folder as the input file. # -url takes the url from tvrage to get episode details. # -shownum used with epnum to set the shownumber from tvrage.com for shownumber # -epnum used with shownum to set the episode number from tvrage.com for episode number # -year set a hint for the year for searching tvrage.com # - Fix for episode parsing for S\d\dE\d\d <Episode Name> where episode name starts with S # - Fix for two part episodes in one file i.e. S01E01E02. # - Update showname parsing which changed on tvrage # - Better file checking. Will obtain full path when needed from current working # folder or from path given by user. # use DBI; use LWP::Simple; # libwww-perl providing simple HTML get actions use LWP::UserAgent; # libwww-perl providing simple HTML get actions use HTML::Entities; use URI::Escape; use XML::Simple; use Getopt::Long qw(:config permute ); use Sys::Hostname; use File::Spec; use POSIX; use Date::Manip; use IO::Socket::INET; use File::Basename; use Cwd; # User settings my $recgroup = "Seasons"; my $playgroup = "Default"; my $host = `hostname`; my $dbhost = "localhost"; my $database = "mythconverg"; my $user = "mythtv"; my $pass = "mythtv"; my $RecordFilePrefix = "/video/recordings"; my $MasterServerIP = "localhost"; my $MasterServerPort = 6543; chomp $host; # Script Info $title = "TVRage.com Show Info Grabber"; $version = "v0.7"; $author = "Steven Adeff"; my $hflag = ''; my $vflag = ''; my $dflag = ''; my $rflag = ''; my $mflag = ''; my $opt_v = -1; my $opt_d = 0; my $opt_l = 0; my $opt_m = 0; my $opt_t = 0; my $opt_i = -1; my $opt_ep = ''; my $opt_nf = 0; my $opt_nr = 0; my $opt_latest = 0; my $opt_channel = 0; my $coverfile = 'No Cover'; my $opt_coverfile = 0; my $opt_mythvideo = 0; my $cfg_file = "$ENV{'HOME'}/.tvgrabber"; my $argc = @ARGV; if ($argc == 0) { help(); } GetOptions( "help"=> sub { help(); }, "debug"=>\$opt_d, "verbose:i"=>\$opt_v, "manual"=>\$opt_m, "test"=>\$opt_t, "import!"=>\$opt_i, "recgroup=s"=>\$recgroup, "playgroup=s"=>\$playgroup, "file=s"=>\$inputfile, "coverfile=s"=>\$coverfile, "config=s"=>\$cfg_file, "symlink"=>\$opt_l, "mythvideo"=>\$opt_mythvideo, "ep=s"=>\$opt_ep, "latest"=>\$opt_latest, "channel=s"=>\$opt_channel, "year=s"=>\$year, "shownum=s"=>\$shownum, "epnum=s"=>\$epnum, "url=s"=>\$url, "nf"=>\$opt_nf, # ep number format simple exclude "nr"=>\$opt_nr, # no replace fillers to dots #'<>' => \&main ); if ($shownum && (!$epnum)){ print "ERROR: you need to set both -shownum and -epnum\n"; exit (-1); } if ($epnum && (!$shownum)){ print "ERROR: you need to set both -shownum and -epnum\n"; exit (-1); } if ($inputfile) { main($inputfile); } else { main(@ARGV); } exit(0); sub main { open F, "</etc/mythtv/mysql.txt" and do { while (<F>) { /DBHostName=(\S+)/ and do { $dbhost = $1; }; /DBUserName=(\S+)/ and do { $user = $1; }; /DBName=(\S+)/ and do { $database = $1; }; /DBPassword=(\S+)/ and do { $pass = $1; }; } close F; }; #my ( $inputfile ) = @_; my @inputfiles = @_; $opt_v = $opt_v + 1; getsettings(); if ( $opt_v > 2 ) { $opt_v = 0; } if ( $opt_v == 1 ) { print "(V1) Verbose Level 1\n"; } if ( $opt_v == 2 ) { print "(V2) Verbose Level 2\n"; $opt_d = 1; } if ( $opt_d == 1 ) { print "(DD) Debugging On\n"; } if ( $opt_t == 1 ) { print "(TT) Test Mode On\n"; } if ( $opt_l == 1 ) { print "(V1) SymLink Mode On\n" if $opt_v; } if ( $opt_v ) { print "(V1) Input filename: $inputfile\n"; } if ( $coverfile eq "No Cover" ) { $opt_coverfind = 1; } my $laststate = -1; my $addedstuff = 0; while ($#inputfiles>=0) { my $inputfile = shift @inputfiles; my $filename; my $foldername = ""; #Determine if file name exists and get the full path information #See if filename was given with path and if path exists if ( $inputfile =~ m/\//) { $strPos1 = rindex( $inputfile, "/" ); $foldernamegiven = substr($inputfile, 0, $strPos1 + 1); $filename = $inputfile; $filename =~ s/.*\///; if ($opt_d) { print "(V1) FolderGiven: $foldernamegiven\n"; } } else { $filename = $inputfile; } if ($opt_v) { print "(V1) Filename: $filename\n"; } if ( -d$foldernamegiven ) { print "FolderGiven exists!\n"; $foldername = $foldernamegiven; $foldername = $foldername; } #obtain path from current working folder, sometimes users do it like this else { if ($opt_v) { print "No folder given or doesn't exist\n"; } my $foldernameobtained = getcwd; if ($opt_v) { print "(V1) FolderObtained: $foldernameobtained\n"; } $foldername = $foldernameobtained; $foldername = $foldername . "/"; if ($opt_v) { print "(V1) FullPathObtained: $fullpath\n"; } } $fullpath = $foldername . $filename; chdir $foldername; if ( -e $filename ) { if ($opt_v) { print "(V1) File Exists at: $fullpath\n"; } } else { print "\n\nERROR!! Can't find file \n\t$inputfile !\n"; print "ERROR!! Make sure file is in current working directory\n"; print "ERROR!! or the correct full path is given.\n"; exit; } #Take care of cover files and absolute paths as well.... my $coverfoldername = 0; if ( $opt_coverfind ) { $coverfoldername = $foldername; @coveroptions=($filename . ".jpg",$filename . ".gif","cover.jpg","cover.gif"); if ( -e $coveroptions[0]) {$coverfile = $coverfoldername . $coveroptions[0];} if ( -e $coveroptions[1]) {$coverfile = $coverfoldername . $coveroptions[1];} if ( -e $coveroptions[2]) {$coverfile = $coverfoldername . $coveroptions[2];} if ( -e $coveroptions[3]) {$coverfile = $coverfoldername . $coveroptions[3];} if ($opt_v) { print "(V1) Cover Filename: $coverfile\n"; } } else { if ( $coverfile =~ m/\//) { $strPos1 = rindex( $coverfile, "/" ); $coverfoldernamegiven = substr($coverfile, 0, $strPos1 + 1); $coverfilename = $coverfile; $coverfilename =~ s/.*\///; if ($opt_d) { print "(V1) CoverFolderGiven: $coverfoldernamegiven\n"; } } else { $coverfilename = $coverfile; } if ($opt_v) { print "(V1) Cover Filename: $coverfilename\n"; } if ( -d$coverfoldernamegiven ) { print "Cover FolderGiven exists!\n"; $coverfoldername = $coverfoldernamegiven; $coverfoldername = $coverfoldername; } #obtain path from current working folder, sometimes users do it like this else { if ($opt_v) { print "No cover folder given or doesn't exist\n"; } my $coverfoldernameobtained = getcwd; if ($opt_v) { print "(V1) CoverFolderObtained: $coverfoldernameobtained\n"; } $coverfoldername = $coverfoldernameobtained; $coverfoldername = $coverfoldername . "/"; if ($opt_v) { print "(V1) CoverFullPathObtained: $coverfullpath\n"; } } $coverfile = $coverfoldername . $coverfilename; } if ($opt_v) { print "(V1) CoverFullPath: $coverfile\n"; } chdir $coverfoldername; if ( -e $coverfile ) { if ($opt_v) { print "(V1) Cover File Exists at: $coverfile\n"; } } else { print "\n\n!! Can't find cover file \n\t$coverfile !\n"; print "!! Make sure cover file is in current working directory\n"; print "!! or the correct full path is given.\n"; $coverfile = 'No Cover'; } #Symlinking if ($opt_l) { #link file into recorded directory my $rfile = $RecordFilePrefix . "/" . $filename; #print "checking for existing link $rfile\n"; if (-l $rfile) { #print "unlinking $rfile\n"; unlink($rfile); } symlink $fullpath, $rfile; if ($opt_v) { print "(V1) Symlink in : $inputfile, $fullpath, $rfile\n"; } $inputfile = $filename; } @showinfo = search($filename); if ( $opt_i == -1 ) { print "Showinfo = @showinfo\n"; print "Do you want to add this to the Myth Database? (y/n)\n"; chomp(my $answer = <STDIN>); # $answer = <STDIN>; if ($answer eq "y") { if ($opt_v) { print "(V1) Inserting: $fullpath\n"; } if ($opt_mythvideo){ addmythvideo(@showinfo, $inputfile,$fullpath); }else{ addrecord(@showinfo, $inputfile,$fullpath); #exit (-1); $laststate = -1; $addedstuff = 1; next; } } #exit (-1); $laststate = -1; next; } if ($opt_i == 0 ) { #exit (0); $laststate = 0; next; } if ($opt_i == 1 ) { if ($opt_v) { print "(V1) Inserting: $fullpath\n"; } if ($opt_mythvideo){ addmythvideo(@showinfo, $inputfile, $fullpath); }else{ addrecord(@showinfo, $inputfile, $fullpath); $addedstuff = 1; $laststate = -1; #exit (-1); next; } } } send_recordinglistchanged() if (($addedstuff != 0) && (!$mythvideo)); exit ($addedstuff); } sub search { my ($filename, $inputfile) = @_; if ( $opt_v ) { print "(V1) Parseing input filename: $filename\n"; } #get the show title, season, episode from filename @tempFileInfoArray = getShowDataFromName($filename); my $showname=$tempFileInfoArray[0]; my $season=$tempFileInfoArray[1]; my $episode=$tempFileInfoArray[2]; if ($opt_ep ne '') { ($season,$episode) = $opt_ep =~/(\d+)x(\d+)/; } if ($showname eq "") { $filename =~ /([^\.]*)\./ and do { $showname = $1; }; } if ($opt_v) { printf("(V1) Show Name: %s, Season: %s Episode: %s,\n", $showname, $season, $episode);} my $seasonep; if ($season >= 0) { $seasonep = $season . "x" . $episode; } else { $seasonep = $episode; } if ($opt_v) { print "(V1) Searching for '$showname $seasonep'\n"; } #get the episode URL from the TVrage.com search my @tvrage_info = get_show($showname,"0",$seasonep); if (($tvrage_info[6] eq "") and $opt_latest) { $seasonep = $tvrage_info[3]; $seasonep =~ s/,.*$//; ($season,$episode) = $seasonep =~/(\d+)x(\d+)/; @tvrage_info = get_show($showname,"0",$seasonep); } if ($url){ $tvrage_info[6] = $url; if ($url =~ /shows/){ ($tvrage_info[1]) = $url =~ /(http:\/\/www.tvrage.com\/shows\/id-\d+)\/episodes/; }else{ ($tvrage_info[1]) = $url =~ /(http:\/\/www.tvrage.com\/.*)\/episodes/; } } if ($shownum) { $shownum =~ s/id-//i; $tvrage_info[6] = "http://www.tvrage.com/shows/id-$shownum/episodes/$epnum"; $tvrage_info[1] = "http://www.tvrage.com/shows/id-$shownum"; } print "TVRage URL= $tvrage_info[6]\n"; # if ($opt_v) { print "(V1) TVRage URL= $tvrage_info[6]\n"; } if (!($tvrage_info[6])){ print "ERROR: Couldn't find any data for show $filename, not updating\n"; exit (-1); } my @showinfo; @showinfo = getTVRageData($tvrage_info[6], $tvrage_info[1]); $showinfo[3] = "s${season}E${episode}" if ($showinfo[3] eq "") and (${season} >= 0); $showinfo[3] = "${episode}" if ($showinfo[3] eq ""); $showinfo[4] = "Episode $episode" if $showinfo[4] eq ""; return @showinfo; } sub version { print "$title ($version) by $author\n" } sub info { print "Query's www.tvrage.com for show information.\n"; } sub usage { print "usage: $0 -hdvF filename\n"; print "\tfilename format must be in:\n"; print "\tepisode.title.format.s01e01.blah.avi\t\n\tor\n"; print "\tepisode.title.format.101.blah.avi\n"; print "\n\t-h\tthis help screen\n"; print "\t-d\tturn on debugging\n"; print "\t-v\tturn on verbose\n"; print "\n"; # print "\t-m\tManually choose show from query list\n"; print "\t-F\tinput_filename\n"; print "\t-s\tcreate a symlink in the recordings directory first\n"; print "\t\tRequires absolute path or file in current working folder!\n"; print "\t-nr\tDo not convert all spaces and - to . in the filename.\n"; print "\t\t(currently the default for compatibility.)\n"; print "\t-nf\tStop 4 digit numbers from being parsed as ep info,\n"; print "\t\tas for \"The 4400\".\n"; print "\t-l\tUses the latest episode number for files that\n"; print "\t\tdon\'t have episode information.\n"; print "\t-channel\tSpecify the channel number to use\n"; print "\t-year\t\tgive tvrage a hint for the year\n"; print "\t-url\t\tuse the given URL to obtain show information\n"; print "\t-shownum\tset the tvrage shows/id-(ddddd) if known\n"; print "\t-epnum\t\tset the tvrage episodes/(dddddd) if known\n"; print "\n\tMythTV integration options\n\n"; print "\t-import/-noimport\tforce to import or not\n"; print "\t\t\t\tdefault is to ask\n"; print "\t-t\tturn on test mode, won't touch database\n"; print "\n\tMythVideo integration options\n"; print "\t(Requires absolute path or file in current working directory!)\n\n"; print "\t-mythvideo\tadd the entry to the mythvideo db\n"; print "\t-coverfile\tadd a cover for the entries\n"; exit (1); } sub help { version(); info(); usage(); } sub getShowDataFromName { my ($filename) = @_; if ($opt_d) { printf("(DD) Show Name: '%s'\n", $filename);} # if there are more than one Episode in one file (Serie.S02E13-14 or Serie.02x13-14) take the first one if ( $filename =~ /[0-9][0-9]-[0-9][0-9]/) { if ($opt_v) { print "(V1) File seems to have more than one show\n"; } $filename =~ s/(\d\d)-(\d\d)/\1/g; if ($opt_v) { print "(V1) New show name: $filename\n"; } } if (!$opt_nr) { $filename =~ s/[- _]/\./g; } # Convert " - " to "." as Delimiter if ( $filename =~ / - /) { if ($opt_v) { print "(V1) Show name has \" - \" as delimiter\n"; } $filename =~ s/ - /\./g; if ($opt_v) { print "(V1) New show name: $filename\n"; } } #Ignore 720p and 1080p and 1080i in file name if ( $filename =~/720p/) { $filename =~ s/720p\.//g; } if ( $filename =~/1080p/) { $filename =~ s/720p\.//g; } if ( $filename =~/1080p/) { $filename =~ s/720p\.//g; } if ($opt_nf == 0) { # Convert 4 number format to S00E00 format if ( $filename =~ /\.[0-9][0-9][0-9][0-9]\./) { if ($opt_v) { print "(V1) Show name is four-number format\n"; } $filename =~ s/\.(\d\d)(\d\d)\./\.S\1E\2\./g; if ($opt_v) { print "(V1) New show name: $filename\n"; } } else { # Convert 3 number format to S00E00 format if ( $filename =~ /\.[0-9][0-9][0-9]\./) { if ($opt_v) { print "(V1) Show name is three-number format\n"; } $filename =~ s/\.(\d)(\d\d)\./\.S0\1E\2\./g; if ($opt_v) { print "(V1) New show name: $filename\n"; } } } } # Convert 0x00 format to S00E00. format if ( $filename =~ /\.[0-9][xX][0-9][0-9]\./) { if ($opt_v) { print "(V1) Show name is 00x00 format\n"; } $filename =~ s/\.(\d)([xX])(\d\d)\./\.S0\1E\3\./g; if ($opt_v) { print "(V1) New show name: $filename\n"; } } # Convert 00x00 format to S00E00. format if ( $filename =~ /\.[0-9][0-9][xX][0-9][0-9]\./) { if ($opt_v) { print "(V1) Show name is 00x00 format\n"; } $filename =~ s/\.(\d\d)([xX])(\d\d)\./\.S\1E\3\./g; if ($opt_v) { print "(V1) New show name: $filename\n"; } } if ( $filename =~ /\.[sS][0-9][0-9][eE][0-9][0-9]\./ ) { if ($opt_v) { print "(V1) Show name is S00E00 format\n"; } $fileNameType=1 } if ( $filename =~ /s\d\de\d\de\d\d/i ) { if ($opt_v) { print "(V1) Show name is S00E00E00 format\n"; } $fileNameType=1 } # Read date format if ( $filename =~ /\.[0-9][0-9].[0-9][0-9].[0-9][0-9]\./) { if ($opt_v) { print "(V1) Show name is in date format\n"; } $fileNameType = 1; if ($opt_v) { print "(V1) New show name: $filename\n"; } } if ($opt_d) { printf("(DD) File name is type: '%s'\n", $fileNameType);} my @returnData; if ( $fileNameType == 1 ) { #Show.Name.S01E01.Episode Name.avi # $filename =~ s/[sS]([0-9]+)[eE]([0-9]+)/\.S\1E\2/g; #uppercase # my $strPos1 = rindex( $filename, "..S" ); # #my $strPos1 = index( $filename, "..S" ); # my $strPos2 = index( $filename, "E", $strPos1 + 1 ); # my $strPos3 = index( $filename, ".", $strPos2 + 1 ); # if ($opt_d) { print "(DD) Pos1 : $strPos1 pos2: $strPos2 pos3: $strPos3\n"; } ## if ($filename =~ m/the.o.c./) {$filename =~ s/o.c./oc./; } # The OC check # $filename =~ tr/./\ /; # my ($ffilename, $fseason, $fepisode) = $filename =~ /^(.*)S(\d+)E(\d+)/i; # $ffilename =~ s/ $//g; # $ffilename =~ s/-$//g; # $ffilename =~ s/\.$//g; # # #Show Name # $returnData[0] = substr( $filename, 0, $strPos1); # #Season # #$returnData[1] = substr( $filename, $strPos1 + 3, $strPos2 - $strPos1 - 3 ); # $returnData[1] = $fseason; # #Episode # #$returnData[2] = substr( $filename, $strPos2 + 1, $strPos3 - $strPos2 - 1 ); # $returnData[2] = $fepisode; # my ( $file, $path, $suffix ) = fileparse( $filename, qr/\.[^.]*/ ); if ($file =~ /.*?S\d\dE\d\d.*/i){ ($series, $season, $episode, $episodename) = $file =~ /(.*?)S(\d\d)E(\d\d)(.*)/i; }elsif ($filename =~ /S\d\dE\d\d/i){ ($series, $season, $episode) = $file =~ /(.*?)S(\d\d)E(\d\d)/i; } #Show Name $returnData[0] = $series; #Season $returnData[1] = $season; #Episode $returnData[2] = $episode; } else { # # example line in config file # '(Bold and the beautiful) (.*)\.' '"the ".$1' '-1' '$2' # matches "Bold and the beautiful April 13th 2006.avi" # print "reading tvgrabber config\n" if $opt_v; open CF, "< $cfg_file" and do { CFREAD: while (<CF>) { chomp; next if /^\#/; print "got line $_\n" if $opt_v>1; /\'([^\']*)\'\s+\'([^\']*)\'\s+\'([^\']*)\'\s+\'([^\']*)\'/ and do { my $re = $1; my $nameexp = $2; my $seasonexp = $3; my $episodeexp = $4; print "got line $re $nameexp $seasonexp $episodeexp\n" if $opt_v>1; $filename =~ /$re/ and do { $returnData[0] = eval($nameexp); $returnData[1] = eval($seasonexp); $returnData[2] = eval($episodeexp); print "params are $returnData[0], $returnData[1], $returnData[2]\n" if $opt_v>1; last CFREAD; }; }; } } } $returnData[0] =~ s/\./ /g; if ($opt_d) { printf("(DD) Show Name: '%s', Season: '%s' Episode: '%s',\n", $returnData[0], $returnData[1], $returnData[2]);} return @returnData; } sub get_show { my ($show) = $_[0]; my ($exact ) = $_[1]; my ($episode) = $_[2]; my @ret = ""; my $premiered; if ( $show ne "" ){ if ($year){ $show = "$show $year"; } if ($opt_d) { print "Search URL= http://www.tvrage.com/quickinfo.php?show=$show&ep=$episode&exact=$exact\n"; } my $site = get "http://www.tvrage.com/quickinfo.php?show=".$show."&ep=".$episode."&exact=".$exact; foreach $line (split("\n",$site) ) { my ($sec,$val) = split('\@',$line,2); if ($sec eq "Show Name" ) { $ret[0] = $val; my $showname = $val; } elsif ( $sec eq "Show URL" ) { $ret[1] = $val; } elsif ( $sec eq "Premiered" ) { $ret[2] = $val; } elsif ($sec eq "Country" ) { $ret[7] = $val; } elsif ( $sec eq "Status" ) { $ret[8] = $val; } elsif ( $sec eq "Classification" ) { $ret[9] = $val; } elsif ( $sec eq "Latest Episode" ) { my($ep,$title,$airdate) = split('\^',$val); $ret[3] = $ep.", \"".$title."\" aired on ".$airdate; } elsif ( $sec eq "Next Episode" ) { my($ep,$title,$airdate) = split('\^',$val); $ret[4] = $ep.", \"".$title."\" airs on ".$airdate; } elsif ( $sec eq "Episode Info" ) { my($ep,$title,$airdate) = split('\^',$val); $ret[5] = $ep.", \"".$title."\" aired on ".$airdate; print "Searched Episode= Ep: $ep Title: $title Airdate: $airdate\n"; } elsif ( $sec eq "Episode URL" ) { $ret[6] = $val; } } if ( $ret[0] ) { return @ret; } else { print ("Episode URL Not Found!"); exit (1); } } } sub getTVRageData { my ($episodeURL) = $_[0]; my ($showURL) = $_[1]; if ($opt_d) { print "(DD) Episode URL: $episodeURL\n"; } if ($opt_d) { print "(DD) Show URL: $showURL\n"; } my $episodeHTML = get $episodeURL; my $showHTML = get $showURL; if ($opt_v == 2) { print "(V2) Episodes Stripped:\n$episodeHTML\n"; } #parse show name #my $showname = parseBetween( $showHTML, "<h3 align='center' class='nospace'>","</h3><hr>"); #my ($showname) = $showHTML =~ /\<td align='center'[^\>]*\>\<h5 class='nospace'\>"([^"]*)" Summary\<\/h5\>\<\/td\>/; my ($showname) = $showHTML =~ /\<h5 class='nospace'\>\<a\ name='summary'\>\ \;\<\/a\>"([^"]*)" Summary\<\/h5\>\<\/td\>/; # parse title my $title = parseBetween( $episodeHTML, "Title: </b></td><td class='b2'>", "</td>"); $title = trim( $title ); #parse season my $season = parseBetween( $episodeHTML, "Season: </b></td><td class='b2'>", "</td>"); #parse episode number my $episode_number = parseBetween( $episodeHTML, "Episode Number: </b></td><td class='b2'>", "</td>"); #parse season episode number my $s_episode = parseBetween( $episodeHTML, "Season Episode #.: </b></td><td class='b2'>", "</td>"); #parse network my $network = parseBetween($showHTML, "<b>Network: </b></td><td>", "("); $network =~ s/<.+?>//g;~ s/<.+?>//g; #parse production number my $production_number = parseBetween( $episodeHTML, "Production Number: </b></td><td class='b2'>", "</td>"); #parse original airdate my $firstaired = parseBetween( $episodeHTML, "Original Airdate: </b></td><td class='b2'>", "/td>"); $firstaired=parseBetween( $firstaired," ","<"); $strPoint2 = rindex( $firstaired, ", " ); $strPoint1 = index( $firstaired, " " ); # parse year my $firstyear = substr( $firstaired, $strPoint2 + 1 ); # parse month my $monthtemp = substr( $firstaired, 0, $strPoint1 ); my $firstmonth = "00"; use Switch; switch ($monthtemp) { case "January" {$firstmonth = "01"} case "February" {$firstmonth = "02"} case "March" {$firstmonth = "03"} case "April" {$firstmonth = "04"} case "May" {$firstmonth = "05"} case "June" {$firstmonth = "06"} case "July" {$firstmonth = "07"} case "August" {$firstmonth = "08"} case "September" {$firstmonth = "09"} case "October" {$firstmonth = "10"} case "November" {$firstmonth = "11"} case "December" {$firstmonth = "12"} } # parse day my $firstday = substr( $firstaired, $strPoint1 + 1, $strPoint2 - $strPoint1 - 1 ); $firstday =~ s/\D+//; #parse director my $director = parseBetween( $episodeHTML, "Director: </b></td><td class='b2'><i><a href='", "/a></i><br></td></tr>"); $director = stripParensFromName( parseBetween($director, ">", "<") ); #parse writer my $writer = parseBetween( $episodeHTML, "Writer: </b></td><td class='b2'><i>", "</td>"); $writer =~ s/<br><i>/,\ /; $writer =~ s/<.+?>//g;~ s/<.+?>//g; $writer = stripParensFromName( $writer ); #parse summary my $summary = parseBetween( $episodeHTML, "<td><table width='100%'><tr><td valign='top'><table width='100%'><tr><td>", "<br> " ); chomp($summary); if ($summary =~ /There is no summary added for this episode/) { $summary = "There is no summary added for this episode"; } #parse category/genre my $category = parseBetween( $showHTML, "<b>Genre: </b></td><td>", "</td>"); while ($category =~ m/ \| / ) { $category =~ s/\ \|/,/; } #parse airtime my $runtime = parseBetween( $showHTML, "<b>Runtime: </b></td><td>", " Minutes</td>"); my $airtime = parseBetween( $showHTML, "<b>Airs: </b></td><td>", "</td>"); $airtime = parseBetween( $airtime, "at ", "m"); $strPoint1 = index ($airtime, ":" ); $hour = substr($airtime, 0, $strPoint1 ); $minute = substr($airtime, $strPoint1 + 1, 2 ); if ($airtime =~ m/p/) { $hour = $hour + 12 }; if (($airtime =~ m/a/) & ($hour == 12)) { $hour = 00 }; $airtime = $hour . ":" . $minute . ":00"; $endminute = $minute + $runtime; $endhour = $hour; while ($endminute >= 60) { $endminute = $endminute - 60; $endhour = $endhour + 1; } if ($endhour >= 24 ) { $endhour = $endhour - 24; } if ($endminute <10 ) { $endminute = "0" . $endminute; } $endtime = $endhour . ":" . $endminute . ":00"; print "Show: $showname\n"; print "Network: $network\n"; print "Season: $season\n"; print "Episode: $s_episode\n"; print "FakeEp: $episode_number\n"; print "Production Number: $production_number\n"; print "Title: $title\n"; print "First Aired: $firstyear / $firstmonth / $firstday\n"; print "Director: $director\n"; print "Plot:\n$summary\n"; print "Runtime: $runtime\n"; print "Airtime: $airtime\n"; print "Endtime: $endtime\n"; print "Writers: $writer\n"; print "Category: $category\n"; @showinfo = ($showname, $network, $season, $s_episode, $episode_number, $production_number, $title, $firstyear, $firstmonth, $firstday, $director, $summary, $runtime, $airtime, $endtime, $writer, $category ); return @showinfo; } # # # MythTV integration Functions # # sub commercialflag { my ($inputfile) = @_; print("Building a seek table should improve FF/RW and JUMP functions when watching this video\n"); print("Do you want to build a seek table for this file? (y/n): "); chomp(my $do_commflag = <STDIN>); if ($do_commflag eq "y") { if (!$test_mode) { exec("mythcommflag --file $inputfile --rebuild"); } else { print("Test mode: exec would have done\n"); print(" Exec: 'mythcommflag --file $inputfile --rebuild'\n"); } } else { print("Skipping illegal file format: $show\n"); } } sub getsetting { my ($dbh, $ref, $val, $host ) = @_; my $sql = qq{ SELECT data FROM settings WHERE value = '$val' }; $sql .= " AND hostname = '$host'" if defined $host; my $sth = $dbh->prepare($sql); my $rv = $sth->execute(); my $data; if ($rv) { my @row = $sth->fetchrow_array; print "num rows $rv,$#row, $row[0], $row[1], $row[2]\n" if $opt_v; $$ref = $row[0] if ($#row >= 0); } undef $sth; } sub getsettings { my $dbh = DBI->connect("dbi:mysql:database=$database:host=$dbhost","$user","$pass") or die "(EE) Cannot connect to database ($!)\n" . exit(-1); $dbh->{PrintError} = 0; #$dbh->{PrintWarn} = 1; #$dbh->{RaiseError} = 0; getsetting($dbh, \$RecordFilePrefix, "RecordFilePrefix", $host); getsetting($dbh, \$MasterServerIP, "MasterServerIP"); getsetting($dbh, \$MasterServerPort, "MasterServerPort"); $dbh->disconnect; } sub sendcmd { my ($sock, $cmd) = @_; my $l = length($cmd); $cmd = sprintf("%-8d",$l) . $cmd; #print "sending $cmd\n"; print $sock "$cmd"; $sock->flush(); $sock->recv($response,8,0); my $l = int $response; $sock->recv($response,$l,0); return $response; } sub send_recordinglistchanged { print "notifying server of update\n" if $opt_d; my $sock = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => $MasterServerIP, PeerPort => $MasterServerPort) or return 0; $sock->autoflush(1); binmode($sock,":utf8"); my $s = "MESSAGE[]:[]RECORDING_LIST_CHANGE"; my $response = sendcmd($sock, "ANN Playback tvgrabber 0"); #my $response = sendcmd($sock, "ANN SlaveBackend tvgrabber localhost"); print "ANN resp was '$response'\n" if $opt_d; $response = sendcmd($sock, $s); print "response was '$response'\n" if $opt_d; $response = sendcmd($sock, "DONE"); print "DONE resp was '$response'\n" if $opt_d; undef $sock; } ## add records to db sub addrecord { my @showdata = @_; my ($showname, $network, $season, $s_episode, $episode_number, $production_number, $title, $firstyear, $firstmonth, $firstday, $director, $summary, $runtime, $airtime, $endtime, $writer, $category, $inputfile, $fullpath ) = @showdata; my $prevstarttime = ""; print "(V1) Going to add '$showname - $title' to database!\n" if $opt_v; my $chanid = int( rand(900))+1; if ( $opt_channel > 0 ) { $chanid = $opt_channel; print "Channel: $chanid\n"; } # else { $chanid = int( rand(900))+1; } my $fiddledtime = 0; if (($firstyear+0 == 0) or ($firstmonth+0 == 0) or ($firstday+0 == 0)) { my @st = stat($fullpath); my @loctime = localtime($st[9]); # mtime $firstyear = $loctime[5]+1900; $firstmonth = $loctime[4]+1; $firstday = $loctime[3]; print "(V1) time for $fullpath is $firstyear-$firstmonth-$firstday\n" if $opt_v; $fiddledtime = 1; } my $starttime = $firstyear . "-" . $firstmonth . "-" . $firstday . " " . $airtime; my $endtime = $firstyear . "-" . $firstmonth . "-" . $firstday . " " . $endtime; my $originalairdate = $firstyear . "-" . $firstmonth . "-" . $firstday; my $autoexpire = 0; my $programid; print "(V2) season '$season' ep '$s_episode' $episode_number\n" if ($opt_v>1); if ($season ne "") { if ($season < 10 ) { $season = "0" . $season; } if ($s_episode < 10 ) { $s_episode = "0" . $s_episode; } $programid = "S" . $season . "E" . $s_episode; $title = "s" . $season . "e" . $s_episode . " " . $title } else { $title = $s_episode . " " . $title; $programid = $s_episode; } if ($opt_t == 0) { print "Inserting \'$showname - $title\' into MythTV Database\n"; my $dbh = DBI->connect("dbi:mysql:database=$database:host=$dbhost","$user","$pass") or die "(EE) Cannot connect to database ($!)\n" . exit(-1); $dbh->{PrintError} = 0; #$dbh->{PrintWarn} = 1; #$dbh->{RaiseError} = 0; my $sth; # Check for recording my $exists = 0; my $check = "SELECT * FROM recorded WHERE basename = (?)"; my $sths = $dbh->prepare($check); my $rv = $sths->execute($inputfile); print "$rv\n" if $opt_d; if (!$rv) { $exists = 0; print "Show does not exist in database!\n" if $opt_v; } else { my $x = $sths->fetchrow_hashref; if (exists $x->{'chanid'}) { $exists = 1; if ($opt_v) {print "Show exists in database!\n";} $chanid = $x->{'chanid'}; $prevstarttime = $x->{'starttime'}; } else { $exists = 0; print "Show does not exist in Database!\n" if $opt_v; } $sths->finish; } if ($exists == 0) { print "INSERTing show into database!\n" if $opt_v; my $insert = "INSERT INTO recorded (chanid, starttime, endtime, title, subtitle, description, category, hostname, autoexpire, recgroup, playgroup, programid, originalairdate, basename, progstart, progend) VALUES ((?), (?), (?), (?), (?), (?), (?), (?), (?), (?), (?), (?), (?), (?), (?), (?))"; $sth = $dbh->prepare($insert); my $rv = $sth->execute($chanid, $starttime, $endtime, $showname, $title, $summary, $category, $host, $autoexpire, $recgroup, $playgroup, $programid, $originalairdate, $inputfile, $starttime, $endtime); } if ($exists == 1) { print "Show found, REPLACEing instead!\n"; my $replace = "UPDATE recorded SET chanid = (?), starttime = (?), endtime = (?), title = (?), subtitle = (?), description = (?), category = (?), hostname = (?), autoexpire = (?), recgroup = (?), playgroup = (?), programid = (?), originalairdate = (?), basename = (?), progstart = (?), progend = (?) WHERE chanid = (?) AND starttime = (?)"; $sth = $dbh->prepare($replace); $rv = $sth->execute($chanid, $starttime, $endtime, $showname, $title, $summary, $category, $host, $autoexpire, $recgroup, $playgroup, $programid, $originalairdate, $inputfile, $starttime, $endtime, $chanid, $prevstarttime); } print "$rv\n" if $opt_d; if (!$rv) { print "Could not execute ($rv) ",$sth->errstr,"\n"; $sth->finish; $dbh->disconnect; print "chanid: $chanid\n"; print "starttime: $starttime\n"; print "endtime: $endtime\n"; print "title: $showname\n"; print "subtitle: $title\n"; print "description: $summary\n"; print "catagory: $category\n"; print "hostname: $host\n"; print "autoexpire: $autoexpire\n"; print "recgroup: $recgroup\n"; print "playgroup: $playgroup\n"; print "programid: $programid\n"; print "originalairdate: $originalairdate\n"; print "basename: $inputfile\n"; print "progstart: $starttime\n"; print "progend: $endtime\n"; print "prevstarttime: $prevstarttime\n"; return 0; }; $sth->finish; $dbh->disconnect; print "Database updated!\n"; return 1; } else { print("Test mode: insert would have been done\n"); print(" Query: '$i'\n"); print(" Query params: $plot, $inputfile\n"); return 1; } } # # # Generic Functions # # sub parseBetween { my ($data, $beg, $end)=@_; # grab parameters my $ldata = lc($data); my $start = index($ldata, lc($beg)) + length($beg); my $finish = index($ldata, lc($end), $start); if ($start != (length($beg) -1) && $finish != -1) { my $result = substr($data, $start, $finish - $start); # return w/ decoded numeric character references # (see http://www.w3.org/TR/html4/charset.html#h-5.3.1) decode_entities($result); return $result; } return ""; } sub trim { my $string = shift; for ($string) { s/^\s+//; s/\s+$//; } return $string; } sub stripParensFromName { my ($parensName) = @_; # grab parameters if ( rindex( $parensName, "(" ) != -1 ) { return trim( substr( $parensName, 0, rindex( $parensName, "(" ) ) ); } else { return trim( $parensName ); } } # vim: ts=1 sw=1 ai expandtab ## add records to db sub addmythvideo { my @showdata = @_; my ($showname, $network, $season, $s_episode, $episode_number, $production_number, $title, $firstyear, $firstmonth, $firstday, $director, $summary, $runtime, $airtime, $endtime, $writer, $category, $inputfile, $fullpath ) = @showdata; my $prevstarttime = ""; my $inetref = "99999999"; my $tvset = "100"; print "(V3) Going to add '$showname - $title' to database!\n" if $opt_v; my $originalairdate = $firstyear . "-" . $firstmonth . "-" . $firstday; my $programid; print "(V2) season '$season' ep '$s_episode' $episode_number\n" if ($opt_v>1); if ($season ne "") { if ($season < 10 ) { $season = "0" . $season; } if ($s_episode < 10 ) { $s_episode = "0" . $s_episode; } $programid = "S" . $season . "E" . $s_episode; $title = "s" . $season . "e" . $s_episode . " " . $title } else { $title = $s_episode . " " . $title; $programid = $s_episode; } if ($opt_t == 0) { print "Inserting \'$showname - $title\' into MythTV Database\n"; my $dbh = DBI->connect("dbi:mysql:database=$database:host=$dbhost","$user","$pass") or die "(EE) Cannot connect to database ($!)\n" . exit(-1); $dbh->{PrintError} = 0; #$dbh->{PrintWarn} = 1; #$dbh->{RaiseError} = 0; my $sth; # Check for recording my $exists = 0; my $check = "SELECT * FROM videometadata WHERE filename = (?)"; my $sths = $dbh->prepare($check); my $rv = $sths->execute($fullpath); print "$rv\n" if $opt_d; if (!$rv) { $exists = 0; print "Show does not exist in database !\n" if $opt_v; } else { my $x = $sths->fetchrow_hashref; if (exists $x->{'intid'}) { $exists = 1; if ($opt_v) {print "Show exists in database!\n";} $intid = $x->{'intid'}; $prevstarttime = $x->{'starttime'}; } else { $exists = 0; print "(V1) Show does not exist in Database!\n" if $opt_v; } $sths->finish; } if ($exists == 0) { print "INSERTing show into database!\n" if $opt_v; my $insert = "INSERT INTO videometadata (title, director, plot, year, length, filename, inetref, category, browse, showlevel, coverfile ) VALUES ((?), (?), (?), (?), (?), (?), (?), (?), (?), (?), (?))"; $sth = $dbh->prepare($insert); $rv = $sth->execute("$showname $title", $director, $summary, $firstyear, $runtime, $fullpath, $inetref, $tvset, 1, 1, $coverfile ); } if ($exists == 1) { print "Show found, REPLACEing instead!\n"; my $replace = "UPDATE videometadata SET title = (?), plot = (?), director = (?) , year = (?), length = (?), inetref = (?), category = (?), browse = (?), showlevel = (?), coverfile = (?) WHERE filename = (?)"; $sth = $dbh->prepare($replace); $rv = $sth->execute("$showname $title", $summary, $director, $firstyear, $runtime, $inetref, $tvset, "1", "1", $coverfile, $fullpath); } # update the genre from the catagory... # get the intid for the file my $selectint = "SELECT * FROM videometadata WHERE filename = (?)"; my $sths = $dbh->prepare($selectint); my $rv = $sths->execute($inputfile); print "$rv\n" if $opt_d; my $y = $sths->fetchrow_hashref; if (exists $y->{'intid'}) { my $intid = $y->{'intid'}; # delete the existing links if they are there my $delete = "DELETE FROM videometadatagenre WHERE idvideo = (?)"; $sth = $dbh->prepare($delete); $rv = $sth->execute("$intid"); # loop through the categories and link to the entry foreach my $cat ( split(/,/, $category)){ $cat =~ s/^\s//g; $cat =~ s/\s$//g; if ($opt_v) {print "Adding intid $intid to genre $cat\n";} # check to see if the catagory exists in the db. my $genreselect = "SELECT * FROM videogenre where genre like (?)"; my $sths = $dbh->prepare($genreselect); my $srv = $sths->execute($cat); if (!($srv)) { print "INSERTing genre into database!\n" if $opt_v; my $insert = "INSERT INTO videogenre (genre) VALUES (?)"; $sth = $dbh->prepare($insert); $irv = $sth->execute($cat ); $genreselect = "SELECT * FROM videogenre where genre like (?)"; $sth = $dbh->prepare($genreselect); $srv = $sths->execute($cat); } my $z = $sths->fetchrow_hashref; if (exists $z->{'intid'}) { my $genreid = $z->{'intid'}; if ($opt_v) {print "Inserting $intid, $genreid into videometadatagenre\n";} my $insert = "INSERT INTO videometadatagenre (idvideo, idgenre) VALUES ((?), (?))"; my $sth = $dbh->prepare($insert); $irv = $sth->execute($intid, $genreid); } } } print "$rv\n" if $opt_d; if (!$rv) { print "Could not execute ($rv) ",$sth->errstr,"\n"; $sth->finish; $dbh->disconnect; print "intid: $intid\n"; print "title: $showname $title\n"; print "plot: $summary\n"; print "catagory: $category\n"; print "originalairdate: $originalairdate\n"; print "filename: $inputfile\n"; print "coverfile: $coverfile\n"; return 0; }; $sth->finish; $sths->finish; $dbh->disconnect; print "Database updated!\n"; return 1; } else { print("Test mode: insert would have been done\n"); print(" Query: '$i'\n"); print(" Query params: $plot, $inputfile\n"); return 1; } }