#!/usr/bin/perl -w
#created by Menny Even-Danan (mennyed at the g mail thing)
#additional work by Mark Nolan, Laurie Odgers, cferrier, Lorenzo1985 and paulyche (from Mythbuntu forums).
my $script_version = "1.1.0.6";
#July 31st 2010 - open source with open sources! (almost)
#http://s.evendanan.net/mythvideo
#ideas taken from:
#shabba's script (http://www.skynet.ie/~shabba/tveps.txt). Thread at http://www.gossamer-threads.com/lists/mythtv/users/320471.
#Video length and video thumbs from http://www.perlmonks.org/?node_id=604177. Thanks to MonkE.
# Eli Bendersky's Perl Levenshtein Algorithm implementation - http://eli.thegreenplace.net/programs-and-code/
#This script uses www.thetvdb.com API to retreive information about TV shows.
#This script uses www.themoviedb.org API to retreive information about movies.
#This script uses www.tvsubtitles.net to download tv shows subtitles.
#changelog:
#version 1.1.0.6
# Issue 72 - banners jpg file has no name
# 0.23 support
#version 1.1.0.5
# Issue 71 - File date is taken from the filesystem - by fruitcak.
#version 1.1.0.4
# Issue 70 - Lock file support - by fruitcak.
#version 1.1.0.3
# Issue 67,68 - NFO overriding fix
#version 1.1.0.2
# Issue 67,68 - NFO overriding fix
#version 1.1.0.1
# Issue 66 - posters from tmdb.
#version 1.1.0.0
# Issue 65 - removal of imdb scraping due to 'terms of use' violation.
#version 1.0.9.3
# Issue 60 - Parental Levels - taking data from configuration
#version 1.0.9.2
# Issue 60 - Parental Levels some testing
#version 1.0.9.1
# Issue 61 - quotes in titles and SQL.
#version 1.0.9.0
# General issues with 0.22
#version 1.0.8.8
# Issue 53 - fixing the DVD rip issue.
#version 1.0.8.7
# Much better HTTP caching
#version 1.0.8.6
# Issue 57 - trying to fix the accented characters
#version 1.0.8.5
# Issue 55 - myth-tv version is detected automatically (override is still possible).
#version 1.0.8
# Added TMDB as grabber
# fixed some movies being detected as episodes
#version 1.0.7
#*Issue 47: Taking into account the year of the movie when locating it in IMDB.
#*bug fixes
#version 1.0.6
#*Issue 5: The season folder should show the season's art-work, and not the series. The series folder should show the series art-work
#*bug fixes
#version 1.0.5
#*Issue 45: MythTV 0.22 update for thetvdb.com. Use command arguments:
# -MYTHTV_022 [0/1]
# 0(default)-Disable featching
# 1-Fetch additional Fanart, Banner, and ScreenShot metadata
#*Issue 43: Return rating (G, PG, PG-13, R etc) for movies
#version 1.0.4
#*bug fixes - issue 41
#version 1.0.3 (by cferrier)
#*Motechnet posters retrieval fixed for motechposters.com domain and structure change.
#This includes the neccessary referer spoofing put in to prevent hotlinking.
#*bug fixes
#version 1.0.2
#*Video folder now supports ":" separating.
#*bug fixes
#version 1.0.1
#*Entire folder skip markers - same overriding mechanism for file, has been extended to folder:
#If you wish to override an entire folder, create a file with a name in this format: folder.[folder-name].nfo
#E.g., for folder "MyMovies", create inside this folder a file named "folder.MyMovies.nfo".
#the override options are as file:
# * To skip a folder completely (just ignore, whatever in the database, if any, is OK): The file should contain ''
# * To skip a folder parsing, and just add the file with a snapshot to the database (usefull for private videos): The file should contain ''
#*bug fixes
#version 1.0
#*New IMDB parser. No need for IMDB::Film perl module!
#*New command line arguments:
# -HOST [hostname] : Override the automatic hostname resolving.
# -TV_TITLE_TYPE [0/1/2]
# 0-[Filename]
# 1(default)-[Episode number]: [Episode name]
# 2-[Show] S[Season number]E[Episode number] [Episode name]
# 3-[Show] [Season number]x[Episode number] [Episode name]
# -MOVIE_TITLE_TYPE [0/1/2]
# 0-[Filename]
# 1(default)-[Movie name from IMDB]
# -THUMB_OFFSET [seconds] : take the video snaphost image from the specified time.
#*Can use an external script to retrieve movies posters.
#*Taking hi-res movie posters from posters.motechnet.com
#*Bug fixes
#
#version 0.9.3
#* New command line argument:
# * Override Art-Work folder: -ARTFOLDER [full path to folder]
#* DVD folder fixes.
#* bug fixes.
#version 0.9.2
#* Removed dependency of grep's perl regexp implementation.
#* Added support for tv-show format: "ShowName SSEE.avi"
#* bug fixes.
#version 0.9.1
#* Support for DVD rips under VIDEO_TS folder (as MythVideo requires).
#* bug fixes.
#version 0.9
#* It is possible to override the search for a tv show or movie, by creating a file within the video file folder ("nfo" extension)
#which includes the video file info:
# * TV Show:
# * To override the series: any .nfo file within the video file folder which contain ''
# * To override the entire video file information: create a file with the same name as the file but with .nfo extension. The file should contain ''
# * To override to a specific episode (e.g., a special): create a file with the same name as the file but with .nfo extension. The file should contain ''
# * Movie:
# * To override the video file: create a file with the same name as the file but with .nfo extension. The file should contain ''
# * Skip markers:
# * To skip a file complete (just ignore, whatever in the database , if any, is OK): create a file with the same name as the file but with .nfo extension. The file should contain ''
# * To skip a file parsing, and just add the file with a snapshot to the database (usefull for private videos): create a file with the same name as the file but with .nfo extension. The file should contain ''
#NOTE: NFO files can be hidden.
#* Selects the most similar TV show from all results, rather than the first.
#* New command line argument:
# * Work on a specific file (can be usefull for replacing imdb.pl script): -F [full path to file]
# * Change the default snapshot width (height is calcualted by the aspect ratio): -SNAPSHOT_WIDTH [number]
# * Output episode titles in a short or long format (by paulyche): -SHORT_NAME [1/0]
# * Change the IP of THE-TV-DB (this should be used rarely!): -TVIP [HOST/IP]
#* SQL password is taken from the MythTV MySQL text file (by Lorenzo1985).
#* bug fixes - thanks to Uter, Lorenzo1985 and paulyche.
#version 0.8
#* Imaegs are saved in the artwork folder - now it is possible to get the images in mythweb! (by Lorenzo1985)
#* images names will no longer have spaces in them (by Lorenzo1985)
#* Redundant DB entries (e.g., video file does not exist) will be removed.
#* Un-needed images (e.g., of deleted video files), will be deleted from the artwork folder
#version 0.7:
#* Moved away from WWW::TV perl module. Now uses www.thetvdb.com API!
#* New command line arguments:
# * Take snapshots for movies (don't take IMDB's poster) - "0" for take from IMDB.COM, "1" generate snapshot from file: -MOVIE_SNAP [1/0]
# * Take snapshots for TV shows (don't take The TV DB's poster) - "0" for take from www.thetvdb.com, "1" generate snapshot from file: -TV_SNAP [1/0]
#* major change in images download.
#* bug fixes
#* Known bug: images are not saved in the ART folder, but next to the video files - which means no images in the MythWeb.
#version 0.6:
#* command line support:
# * Scan specific directory, recursive (overriding the automatic media folder detection): -D [path]
# * Perform "full" (0)/"new files only" (1) scan (overriding the default specified): -N [1/0]
# * Perform subtitles download: -S [1/0]
# * Specify DB password: -DBP [whatever]
#* better IMDB handling... Will take data only if the title is levenshtein similar.
#* bug fixes - including spaces in cover filenames
#version 0.5:
#* support for downloading subtitles - will be downloaded if no subtitle file exists.
#* video snapshot will be created anyway.
#* if file was not found in TV.COM it will be handled as a movie
#* bug fixes
#version 0.4:
#* better posters handling
#* IMDB support
#* Since this script supports TV and Movies, there is no need to specify the folder. It will be taken from the database.
#* No need for extention specification. It will be taken from the database.
#* New filesystem files will be automatically be added to MythVideo database.
#* Bug fixes
#version 0.3:
#* bug fixes
#version 0.2:
#* A bit more logic into the parent folder art.
#* support for [ShowName] [SeasonNumber(in one digit)][EpisodeNumber(two digits]: "My.Show 108.avi"
#* better image naming.
#version 0.1: Initial release
use DBI;
use LWP::UserAgent;
use Sys::Hostname;
use POSIX qw(strftime);
use strict;
#Your SQL server host. If the backend is in this computer, put 'localhost' here.
my $dbhost = 'localhost';
#This is the default setting of MythTV
my $db = 'mythconverg';
#this is the default user of MythTV
my $dbuser = 'mythtv';
#Here you should put the SQL password
my $dbpass = '';
#Set as 1 if you want to scan for new files only,
#or 0 if you want to get information for all files (even scanned ones)
my $only_new_files = 1;
#Set as 1 it will download picture files,
#or if set to 0 it will not download any pictures
my $download_picture_files = 1;
#Set as 1 if you want to automatically download subtitles for TV-shows
my $download_subtitles = 0;
my $subtitles_lang = "english";
#Set as 0 if you want to take posters from themoviedb.org,
#or 1 if you want to generate from file.
#or 2 if you want to take posters from an external script
my $movies_snapshot = 0;
my $external_poster_command_line = '/usr/share/mythtv/mythvideo/scripts/tmdb.pl -P ';
#Set as 0 if you want to take posters from thetvdb.com,
#or 1 if you want to generate from file.
my $tv_snapshot = 1;
#Sets the video snapshot width. Height is calculated from the video's aspect ratio.
my $snapshot_width = 320;
#this API key can easily be given if you register at www.thetvdb.com.
#do not use this API key for other scripts!
my $thetvdb_API_key = "6770D263BF045B96";
my $THETVDB = "www.thetvdb.com";
#this API key can be obtained by asking it from themoviedb.org admin.
#do not use this API key for other scripts!
my $themoviedb_API_key = "79302e9ad1a5d71e8d62a82334cdbda4";
#Overrides the auto-detection. Use "-ART_FOLDER" parameter.
my $ArtworkDirectory = '';
my $BannerDirectory = '';
my $FanartDirectory = '';
my $ScreenshotDirectory = '';
my $cleanArtFolder = 1;
#sets the tv show title format:
#you should use the command line argument: -TV_TITLE_TYPE [0/1/2]
# 0-[Filename]
# 1(default)-[Episode number]: [Episode name]
# 2-[Show] S[Season number]E[Episode number] [Episode name]
# 3-[Show] [Season number]x[Episode number] [Episode name]
my $tv_show_title_format = 1;
#sets the movie title format:
#you should use the command line argument: -MOVIE_TITLE_TYPE [0/1/2]
# 0-[Filename]
# 1(default)-[Movie name from themoviedb.org]
my $movie_title_format = 1;
#Sets this value to something higher than 0, if you want the video snapshot to be from a specific time point,
#else it will be a random point in the video.
my $video_thumb_offset = -1;
#Set as 1 if you have mythtv 0.22,
#or 0 if you a lower version of mythtv
my $mythtv_022 = 0;
my $mythtv_023 = 0;
# Lock file. Set this to the name of a file to use as a lock file
# so that only one instance of the script is running at a time
my $lock_file = "";
# Force date added to be the same as the creation date of the file
my $force_date_added_to_create_date = 1;
#
# NOTICE!
#
# Do not touch anything pass this point!
#
#global variables
my $global_user_agent = LWP::UserAgent->new;
$global_user_agent->timeout(45);
$global_user_agent->agent("MythVideoFiller/".$script_version);
#this is for HTTP debuging.
#$global_user_agent->show_progress(1);
sub get_http_response_lwp
{
my $request_url = $_[0];
print "About to call GET HTTP url: '$request_url'\n";
my $req = HTTP::Request->new(GET => $request_url);
# Pass request to the user agent and get a response back
my $res = $global_user_agent->request($req);
# Check the outcome of the response
if ($res->is_success)
{
my $response_content = $res->content;
#print "Got HTTP response:\n".$response_content."\n";
return $response_content;
}
else
{
print "Failed to get response! Status '".$res->status_line."'\n";
return "";
}
}
sub get_http_response_wget
{
my $request_url = $_[0];
print "About to call WGET HTTP url: '$request_url'\n";
my $target_file = "/tmp/myth_video_filler_resp.html";
system("wget ".$request_url." -O ".$target_file);
open FILE, $target_file;
my $string = join("", );
close FILE;
return $string;
}
my %urls_cache = ();
sub get_http_response
{
my $url = $_[0];
#checking if URL is cached already
my $cachedContect = $urls_cache{$url};
if ($cachedContect)
{
#print "'".$url."' is cached.\n";
return $cachedContect;
}
print "'".$url."' is not cached.\n";
my $content = get_http_response_lwp($url);
$content =~ s/(\n|\r|\f)/ /gi;
$urls_cache{$url} = $content;
return $content;
}
my $videodir = "";
my @myfiles = ();#empty list to begin with. May it will be overriden with a command line argument
#functions
sub convert_for_url
{
my $show_name = $_[0];
$show_name =~ s/ /%20/gi;
return $show_name;
}
my $poster_download_last_url = '';
my $poster_download_last_target = '';
sub download_poster
{
my $poster_url = $_[0];
my $target = $_[1];
my $is_this_motech = $poster_url =~ m/motechposters/;
my $motech_referer = 0;
if ($is_this_motech) {
$motech_referer = $poster_url;
$motech_referer =~ s/http:\/\/www.motechposters.com\/posters\//http:\/\/www.motechposters.com\/title\//;
$motech_referer =~ s/_poster.jpg/\//;
}
if ((! -e "$target" || ($only_new_files eq 0)) && ($download_picture_files eq 1))
{
#downloading or local copy?
if ($poster_download_last_url eq $poster_url)
{
print "No need to download $poster_url. I have it locally at $poster_download_last_target.\n";
system("cp '$poster_download_last_target' '$target'");
return 1;
}
else
{
my $return_code;
if ($motech_referer) {
my @args = ('wget',$poster_url,'-O',$target,'-U',"MythVideoFiller/".$script_version,'--referer',$motech_referer);
print "Downloading $poster_url with referer $motech_referer to $target\n";
$return_code = system( @args );
} else {
my @args = ('wget',$poster_url,'-O',$target,'-U',"MythVideoFiller/".$script_version);
print "Downloading $poster_url to $target\n";
$return_code = system( @args );
}
my $this_poster_filesize = -s $target;
if (!$this_poster_filesize) {$this_poster_filesize = 0;}
if (($return_code eq 0) && ($this_poster_filesize != 0))
{
$poster_download_last_url = $poster_url;
$poster_download_last_target = $target;
return 1;
}
else
{
if ($this_poster_filesize == 0) {
unlink($target);
print "Poster retrieved is zero bytes!\n";
return 0;
}
else
{
print "Failed to download poster! Return code: ".$return_code."\n";
return 0;
}
}
}
}
else
{
print "Folder art for '$target' already exist.\n";
}
}
sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
sub get_video_length
{
my $fullfilename = $_[0];
my ($video_len) = grep(/^ID_LENGTH=/, (`mplayer -identify \"$fullfilename\" -nosound -vc dummy -vo null`));
#in DVD rips (VIDEO_TS), the mplayer will not return the length.
if (($video_len) && ($video_len =~ /^[^=]+=(.*)$/ ))
{
$video_len = 0+$1;
#myth like it in minutes
$video_len = $video_len / 60;
}
else
{
$video_len = 0;
}
return $video_len;
}
sub create_video_thumb
{
my $fullfilename = $_[0];
my $video_length = $_[1];
my $thumb_path = $_[2];
my $thumb_offset;
#it comes in minutes. I need in seconds.
$video_length = $video_length * 60;
if ($video_thumb_offset > 0)
{
if ($video_thumb_offset >= $video_length)
{
$thumb_offset = int($video_length * 0.5);
}
else
{
$thumb_offset = int($video_thumb_offset);
}
}
else
{
$thumb_offset = int((0.3 + (rand() * 0.5)) * $video_length);
print "Random point at second: $thumb_offset\n";
}
my $cmd = "mplayer -zoom -ss $thumb_offset -nosound -vo jpeg:outdir=/tmp -frames 1 -vf scale=$snapshot_width:-3 \"$fullfilename\" > /dev/null";
system($cmd);
system ("mv /tmp/*1.jpg \"$thumb_path\"");
}
my $set_show_level = 1;#default yes. It will by overwritten on startup, when readying from the database.
my $show_level_1 = '';
my $show_level_2 = '';
my $show_level_3 = '';
my $show_level_4 = '';
my $default_show_level = 1;
#my $showlevel = parse_show_level($content_rating);
sub parse_show_level
{
my $rating_string = $_[0];
if (($set_show_level eq 0) || (!$rating_string))
{
return 'showlevel';#this will force the re-assignment of whatever already stored in the database.
}
#In myth, levels 2, 3, and 4 requires passwords
#Level 1 (the lowest) does not require password.
if ($rating_string =~ m/($show_level_1)/i)
{
return 1;
}
if ($rating_string =~ m/($show_level_2)/i)
{
return 2;
}
if ($rating_string =~ m/($show_level_3)/i)
{
return 3;
}
if ($rating_string =~ m/($show_level_4)/i)
{
return 4;
}
return $default_show_level;
}
sub ensure_string_is_valid_for_SQL
{
my $text = $_[0];
if (!$text)
{
return "";
}
else
{
#http://www.theukwebdesigncompany.com/articles/entity-escape-characters.php
#issue36: sometimes, the string is already fixed!
$text =~ s/\\?\"/\\"/gi;
#html escape codes
$text =~ s/&/&/gi;
$text =~ s/ / /gi;
$text =~ s/"/\\"/gi;
$text =~ s/'/\\'/gi;
$text =~ s/<//gi;
#issue 57. Now we suppose to support HTML escape codes.
$text =~ s/(\&\#\d{2}\;)/chr(substr($1, 2, 2))/eg;
$text =~ s/(\&\#x[a-fA-F0-9]{2}\;)/chr(hex(substr($1, 3, 2)))/eg;
#if I missed something.
$text =~ s/\d{1,8}?;/ /gi;
$text =~ s/\d{1,8}?;/ /gi;
return $text;
}
}
my $subtitles_front_page_cache = '';
my $show_subtitles_name_cache = '';
my $show_subtitles_season_cache = '';
my $show_subtitles_show_id = '';
my $show_subtitles_page_cache = '';
sub download_tv_subtitle
{
my $tv_show = $_[0];
my $full_subtitle_filename = $_[1];
my $season = $_[2];
my $episode = $_[3];
if ($episode < 10)
{
$episode = "0".$episode;
}
if (-e $full_subtitle_filename)
{
print "Subtitle exists.\n";
return;
}
if ($subtitles_front_page_cache eq '')
{
my $url = "http://www.tvsubtitles.net/tvshows.html";
$subtitles_front_page_cache = get_http_response($url);
}
if ($show_subtitles_name_cache ne $tv_show)
{
$show_subtitles_season_cache = '';
$show_subtitles_show_id = '';
$show_subtitles_page_cache = '';
#print "page content:\n$subtitles_front_page_cache\n";
if ($subtitles_front_page_cache =~ m/$tv_show/i)
{
$show_subtitles_name_cache = $tv_show;
$show_subtitles_show_id = $1;
print "Show ID for subtitle is '$show_subtitles_show_id'\n";
}
else
{
print "Unable to locate show '$tv_show' subtitles page.\n";
return;
}
}
if ($show_subtitles_season_cache ne $season)
{
my $show_subtitles_url = "http://www.tvsubtitles.net/tvshow-".$show_subtitles_show_id."-".$season.".html";
print "Loading season subttitles page from '$show_subtitles_url'\n";
$show_subtitles_page_cache = get_http_response($show_subtitles_url);
$show_subtitles_season_cache = $season;
}
my $episode_key = $season."x".$episode;
#print "page content:\n$show_subtitles_page_cache\n";
if ($show_subtitles_page_cache =~ m/| $episode_key<\/td>.*?/i)
{
my $download_the_subtitle_url = "http://www.tvsubtitles.net/download-".$1.".html";
print "Download subtitle for $episode_key from '$download_the_subtitle_url'\n";
system("wget $download_the_subtitle_url -O subtitle.gz");
system("gzip -d -c -f subtitle.gz >> '$full_subtitle_filename'");
}
else
{
print "Can not locate $subtitles_lang subtitles!\n";
return;
}
}
else
{
print "Can not locate subtitle for $episode_key!\n";
return;
}
}
sub levenshtein
{
# $s1 and $s2 are the two strings
# $len1 and $len2 are their respective lengths
#
my ($s1, $s2) = @_;
# Enhancement by Laurie Odgers
# I want only letters digits and spaces
$s1 =~ s/[^a-zA-Z\d\s]*//g;
$s2 =~ s/[^a-zA-Z\d\s]*//g;
#ofcourse, all should be lowercase.
$s1 =~ tr/[A-Z]/[a-z]/;
$s2 =~ tr/[A-Z]/[a-z]/;
#no n-spaces.
$s1 =~ s/\s+/ /g;
$s2 =~ s/\s+/ /g;
#print "s1: '$s1'. s2: '$s2'\n";
my ($len1, $len2) = (length $s1, length $s2);
# If one of the strings is empty, the distance is the length
# of the other string
#
return $len2 if ($len1 == 0);
return $len1 if ($len2 == 0);
# if the strings match exactly then the distance is 0
return 0 if ($s1 eq $s2);
my %mat;
# Init the distance matrix
#
# The first row to 0..$len1
# The first column to 0..$len2
# The rest to 0
#
# The first row and column are initialized so to denote distance
# from the empty string
#
for (my $i = 0; $i <= $len1; ++$i)
{
for (my $j = 0; $j <= $len2; ++$j)
{
$mat{$i}{$j} = 0;
$mat{0}{$j} = $j;
}
$mat{$i}{0} = $i;
}
# Some char-by-char processing is ahead, so prepare
# array of chars from the strings
#
my @ar1 = split(//, $s1);
my @ar2 = split(//, $s2);
for (my $i = 1; $i <= $len1; ++$i)
{
for (my $j = 1; $j <= $len2; ++$j)
{
# Set the cost to 1 iff the ith char of $s1
# equals the jth of $s2
#
# Denotes a substitution cost. When the char are equal
# there is no need to substitute, so the cost is 0
#
my $cost = ($ar1[$i-1] eq $ar2[$j-1]) ? 0 : 1;
# Cell $mat{$i}{$j} equals the minimum of:
#
# - The cell immediately above plus 1
# - The cell immediately to the left plus 1
# - The cell diagonally above and to the left plus the cost
#
# We can either insert a new char, delete a char or
# substitute an existing char (with an associated cost)
#
$mat{$i}{$j} = min([$mat{$i-1}{$j} + 1,
$mat{$i}{$j-1} + 1,
$mat{$i-1}{$j-1} + $cost]);
}
}
# Finally, the Levenshtein distance equals the rightmost bottom cell
# of the matrix
#
# Note that $mat{$x}{$y} denotes the distance between the substrings
# 1..$x and 1..$y
#
my $lev_result = $mat{$len1}{$len2};
return $lev_result;
#Now, I want to soften it a bit
#So, i'm taking the distance between the strings, but not the added letters.
#my $string_length_diff = abs($len1 - $len2);
#return abs($lev_result - $string_length_diff);
}
# minimal element of a list
#
sub min
{
my @list = @{$_[0]};
my $min = $list[0];
foreach my $i (@list)
{
$min = $i if ($i < $min);
}
return $min;
}
sub no_folder_art_at_folder
{
my $directory = $_[0];
if ((-e $directory."folder.jpg") ||
(-e $directory."folder.png") ||
(-e $directory."folder.gif") ||
(-e $directory."folder.bmp"))
{
return 0;
}
else
{
return 1;
}
}
sub locate_thetvdb_data_in_file
{
my $possible_nfo = $_[0];
open NFO_FILE, "<", $possible_nfo;
my @file_lines = ;
close NFO_FILE;
foreach(@file_lines)
{
my $a_line = $_;
if ($a_line =~ m//i)
{
#print "Found seriesid = $1\n";
return ($1, "", "", "");
}
elsif ($a_line =~ m//i)
{
#print "Found seriesid=$1, season=$2, episode=$3\n";
return ($1, $2, $3, "");
}
elsif ($a_line =~ m//i)
{
#print "Found episodeid=$1\n";
return ("", "", "", $1);
}
}
#no data in file in file
return ("", "", "", "");
}
my $cached_nfo_folder = "";
my $cached_nfo_folder_series_id = "";
sub locate_thetvdb_series_id_in_any_nfo_file
{
my $folder = $_[0];
if ($cached_nfo_folder eq $folder)
{
print "Returning cached series ID '$cached_nfo_folder_series_id' for folder '$folder'\n";
return $cached_nfo_folder_series_id;
}
#my $search_path = $folder."*.nfo";
print "Will look at '$folder'\n";
opendir(DIR, $folder);
my @all_nfo_files = grep { /\.nfo$/ } readdir(DIR);
closedir(DIR);
#globbing does not work when files/folders contain spaces.
#my @all_nfo_files = glob($search_path);
foreach(@all_nfo_files)
{
my $possible_nfo = $folder.$_;
print "nfo: '$possible_nfo'\n";
#looking for series id inside the file (open for read)
my ($seriesid, $season, $episode, $episode_id) = locate_thetvdb_data_in_file($possible_nfo);
if (length $seriesid > 0)
{
print "Found id=$seriesid in file $possible_nfo, will not search for the searies in THETVDB.\n";
#saving for future calls
$cached_nfo_folder = $folder;
$cached_nfo_folder_series_id = $seriesid;
return $seriesid;
}
}
#did not find - caching this too..
$cached_nfo_folder = $folder;
$cached_nfo_folder_series_id = "";
return "";
}
sub is_simple_meta_data
{
my $possible_nfo = $_[0];
if (-e $possible_nfo)
{
open NFO_FILE, "<", $possible_nfo;
my @file_lines = ;
close NFO_FILE;
foreach(@file_lines)
{
my $a_line = $_;
if ($a_line =~ m//i)
{
return 1;
}
}
}
return 0;
}
sub is_skip_file
{
my $possible_nfo = $_[0];
if (-e $possible_nfo)
{
open NFO_FILE, "<", $possible_nfo;
my @file_lines = ;
close NFO_FILE;
foreach(@file_lines)
{
my $a_line = $_;
if ($a_line =~ m//i)
{
return 1;
}
}
}
return 0;
}
sub locate_imdb_data_in_file
{
my $possible_nfo = $_[0];
open NFO_FILE, "<", $possible_nfo;
my @file_lines = ;
close NFO_FILE;
foreach(@file_lines)
{
my $a_line = $_;
#I just need the digit code.
if ($a_line =~ m//i)
{
#print "Found imdb id = $1\n";
return $1;
}
}
return "";
}
my $cached_tmdb_movie_id = "";
my $cached_imdb_movie_name = "";
my $cached_imdb_movie_id = "";
my ($cached_imdb_title_url, $cached_imdb_title, $cached_imdb_plot, $cached_imdb_director, $cached_imdb_release_date, $cached_imdb_rating, $cached_imdb_poster, $cached_imdb_fanart, $cached_motechnet_poster, $cached_content_rating);
sub get_movie_meta_data_from_tmdb
{
#TMDB added by Mark Nolan
my $imdb_id = $_[0];
my $tmdb_id= $_[1];
if ((!$tmdb_id) || length($tmdb_id) eq 0)
{
#Get TMDB_ID
my $url = "http://api.themoviedb.org/2.1/Movie.imdbLookup/en/xml/".$themoviedb_API_key."/tt".$imdb_id;
my $id_page = get_http_response($url);
if ($id_page =~ m/(.*?)<\/id>/i)
{
$tmdb_id = $1;
}
}
if (($tmdb_id ne $cached_tmdb_movie_id))
{
my $cached_tmdb_title_url = "http://api.themoviedb.org/2.1/Movie.getInfo/en/xml/".$themoviedb_API_key."/".$tmdb_id;
my $movie_page = get_http_response($cached_tmdb_title_url);
($cached_imdb_title) = $movie_page =~ m/(.*?)<\/name>/i;
($cached_imdb_poster) = $movie_page =~ m/(.*?)<\/rating>/i;
if (!$cached_imdb_rating) { $cached_imdb_rating = 0; }
($cached_imdb_director) = $movie_page =~ m//i;
if (!$cached_imdb_director) {$cached_imdb_director = "";}
($cached_imdb_release_date) = $movie_page =~ m/(\d{4}).*?;
if (!$cached_imdb_release_date) {$cached_imdb_release_date = "";}
($cached_imdb_plot) = $movie_page =~ m/(.*?)<\/overview>/i;
if (!$cached_imdb_plot) {$cached_imdb_plot = "-";}
if (!$cached_content_rating) {$cached_content_rating = "NR";}
print "title: '$cached_imdb_title'\n";
print "poster: '$cached_imdb_poster'\n";
print "rating: '$cached_imdb_rating'\n";
print "director: '$cached_imdb_director'\n";
print "release_date: '$cached_imdb_release_date'\n";
print "plot: '$cached_imdb_plot'\n";
$cached_imdb_movie_id = $imdb_id;
my $cached_imdb_movie_id = $tmdb_id;
}
return ($cached_imdb_movie_id, $cached_imdb_title_url, $cached_imdb_title, $cached_imdb_plot, $cached_imdb_director, $cached_imdb_release_date, $cached_imdb_poster, $cached_imdb_fanart, $cached_imdb_rating, $cached_motechnet_poster, $cached_content_rating);
}
my $cached_tmdb_ID = "";
my $cached_imdb_ID = "";
sub get_imdb_ID_for_movie_name_tmdb
{
my $movie_name = $_[0];
my $releaseYear = $_[1];
my $imdb_ID = "";
my $tmdb_ID = "";
if ($movie_name ne $cached_imdb_movie_name)
{
$cached_imdb_movie_name = $movie_name;
#http://api.themoviedb.org/2.0/Movie.search?title=Transformers&api_key=79302e9ad1a5d71e8d62a82334cdbda4
#http://api.themoviedb.org/2.1/Movie.search/en/xml/79302e9ad1a5d71e8d62a82334cdbda4/Transformers
my $tmdb_response = get_http_response("http://api.themoviedb.org/2.1/Movie.search/en/xml/".$themoviedb_API_key."/".$movie_name);
my $best_similarity = 1000000;
while ($tmdb_response =~ m/(.+?)<\/movie>/gi)
{
my $movie = $1;
if ($movie eq "Your query didn't return any results.")
{
print "Can not locate movie '$movie_name' in themoviedb.\n";
return ("", "");
}
my $possible_name = "";
($possible_name) = $movie =~ m/(.*?)<\/name>/i;
my $possible_tmdb = "";
($possible_tmdb) = $movie =~ m/(.*?)<\/id>/i;
my $possible_imdb = "";
($possible_imdb) = $movie =~ m/tt(.*?)<\/imdb_id>/i;
my $possible_year = "";
($possible_year) = $movie =~ m/(.+?)-(.+?)-(.+?)<\/released>/i;
my $current_similarity = levenshtein($movie_name, $possible_name);
if ($releaseYear)
{#Check Release Date
if ($releaseYear ne $possible_year)
{
$current_similarity = 1000000;
}
else
{
$current_similarity = $current_similarity - 1000;
}
}
if ($current_similarity < $best_similarity)
{
if ($tmdb_ID eq "")
{
print "Found a possible match for '$movie_name' as '$possible_name' (ID $possible_tmdb)\n";
}
else
{
print "Found a better possible match for '$movie_name' as '$possible_name' (ID $possible_tmdb)\n";
}
$best_similarity = $current_similarity;
$imdb_ID = $possible_imdb;
$tmdb_ID = $possible_tmdb;
}
}
if ($tmdb_ID)
{
print "Found ID '$tmdb_ID' for movie '$movie_name' at themoviedb.\n";
$cached_imdb_ID = $imdb_ID;
$cached_tmdb_ID = $tmdb_ID;
return ($cached_imdb_ID, $cached_tmdb_ID);
}
else
{
print "Can not locate movie '$movie_name' in themoviedb.\n";
return ("", "");
}
}
return ($cached_imdb_ID, $cached_tmdb_ID);
}
sub search_the_tv_db_for_series
{
my $series = $_[0];
print "Searching THE-TV-DB for series '$series'\n";
my $series_for_url = $series;
my $scontent = get_http_response("http://".$THETVDB."/api/GetSeries.php?seriesname=$series_for_url");
my $series_id = "";
my $plot = "";
my $tvdb_series_name = "";
my $best_similarity = 1000000;
#? marks the regexp as ungreedy (don't look for the longest, look for the first - which is actually IS a greedy algorithm...)
#"gi" at the end makes it recursive
#while ($scontent =~ m/(.+?)<\/seriesid>.*?(.+?)<\/seriesname>.*?(.+?)<\/banner>.*?(.+?)<\/overview>/gi)
while ($scontent =~ m/.*?(.+?)<\/seriesid>.*?(.+?)<\/seriesname>(.+?)<\/series>/gi)
{
my $temp_series_id = $1;
my $temp_series_name = $2;
my $current_similarity = levenshtein($series, $temp_series_name);
#print "++++++++++++++++++++++++++++++++++++++++++\n";
#print "Best similarity: $best_similarity Current: $current_similarity\n";
if ($current_similarity < $best_similarity)
{
if ($series_id eq "")
{
print "Found a possible match for '$series' as '$temp_series_name' (ID $temp_series_id)\n";
}
else
{
print "Found a better possible match for '$series' as '$temp_series_name' (ID $temp_series_id)\n";
}
$best_similarity = $current_similarity;
$series_id = $1;
$tvdb_series_name = $2;
my $rest_of_the_data = $3;
if ($rest_of_the_data =~ m/(.+?)<\/overview>/i){$plot = $1;}
else {$plot = "";}
}
#print "++++++++++++++++++++++++++++++++++++++++++\n";
}
if ((length $series_id) > 0)
{
print "Found ID '$series_id' for series '$series' at THE-TV-DB.\n";
return ($series_id);
}
else
{
print "Can not locate series '$series' in THE-TV-DB.\n";
return ("");
}
}
sub get_series_meta_data
{
my $series_id = $_[0];
my $series_name = $_[1];
my $folder_path = $_[2];
my $actual_show_name;
if ((length $series_id) eq 0)
{
$series_id = search_the_tv_db_for_series($series_name);
}
if ((length $series_id) gt 0)
{
print "the-tv-db info found '$series_name' at '$folder_path'.\n";
my $scontent = get_http_response("http://".$THETVDB."/api/".$thetvdb_API_key."/series/".$series_id."/en.xml");
my $content_rating = "NR";
my $imdb;
my $poster = "";
my $banner = "";
my $fanart = "";
my $plot = "";
if ($scontent =~ m/(.+)<\/ContentRating>/i)
{
$content_rating = $1;
}
if ($scontent =~ m/(.+)<\/IMDB_ID>/i)
{
$imdb = $1;
$imdb =~ s/tt//g;
}
if ($scontent =~ m/(.+)<\/overview>/i)
{
$plot = $1;
}
if ($scontent =~ m/(.+)<\/seriesname>/i)
{
$actual_show_name = $1;
}
if ($scontent =~ m/(.+)<\/banner>/i)
{
$banner = "http://".$THETVDB."/banners/".$1;
}
if ($scontent =~ m/(.+)<\/fanart>/i)
{
$fanart = "http://".$THETVDB."/banners/".$1;
}
if ($scontent =~ m/(.+)<\/poster>/i)
{
$poster = "http://".$THETVDB."/banners/".$1;
}
if ((length $series_name) eq 0)
{#if the name was not provided, we'll take it from the response. This will help us cache the series ID (see the call of 'get_series_meta_data' function).
$series_name = $actual_show_name;
}
if ($content_rating eq "")
{
$content_rating = "NR"
}
return ($series_id, $series_name, $poster, $banner, $fanart, $plot, $actual_show_name, $content_rating, $imdb);
}
return ("", "", "", "", "", "", "");
}
sub get_season_banners
{
my $series_id = $_[0];
my $season = $_[1];
if (((length $series_id) gt 0) && ((length $season) gt 0))
{
#http://www.thetvdb.com/api/6770D263BF045B96/series/80348/banners.xml
my $seacontent = get_http_response("http://".$THETVDB."/api/".$thetvdb_API_key."/series/".$series_id."/banners.xml");
while ($seacontent =~ m/.*?(.+?)<\/id>.*?(.+?)<\/BannerPath>.*?(.+?)<\/BannerType>.*?en<\/Language>.*?(.+?)<\/Season>.*?<\/Banner>/gi)
{
if (($4 eq $season) && ($3 eq "season")) {return ("http://".$THETVDB."/banners/".$2);}
}
}
return ("");
}
sub create_episode_url
{
my $series_id = $_[0];
my $season = $_[1];
my $episode = $_[2];
return "http://".$THETVDB."/api/".$thetvdb_API_key."/series/".$series_id."/default/".$season."/".$episode."/en.xml";
}
sub create_episode_url_by_episode_id
{
my $episode_id = $_[0];
#http://www.thetvdb.com/api/6770D263BF045B96/episodes/54545/en.xml
return "http://".$THETVDB."/api/".$thetvdb_API_key."/episodes/".$episode_id."/en.xml";
}
sub get_episode_meta_data
{
my $series_id = $_[0];
my $season = $_[1];
my $episode = $_[2];
my $episode_url = create_episode_url($series_id, $season, $episode);
my $scontent = get_http_response($episode_url);
#if the episode is 0 (a pilot?), and there is no content, we'll try the first episode
if (((length $scontent) eq 0) && ($episode eq '0'))
{
$episode_url = create_episode_url($series_id, $season, "1");
$scontent = get_http_response($episode_url);
}
return parse_episode_content($scontent);
}
my $cached_get_episode_identifies_id = "";
my $cached_get_episode_identifies_content = "";
sub get_episode_meta_data_by_episode_id
{
my $episode_id = $_[0];
if ($episode_id ne $cached_get_episode_identifies_id)
{
my $episode_url = create_episode_url_by_episode_id($episode_id);
$cached_get_episode_identifies_content = get_http_response($episode_url);
$cached_get_episode_identifies_id = $episode_id;
}
return parse_episode_content($cached_get_episode_identifies_content);
}
sub parse_episode_content
{
my $content = $_[0];
#print "parse_episode_content: ".$content."\n";
my $episode_name = "";
my $plot = "";
my $rating = 0;
my $poster = "";
my $director = "";
my $air_date = 0;
my $episode_number = "";
my $season_number = "";
my $series_id = "";
my $episode_id = "";
my $imdb_id = "";
if ($content =~ m/(.+)<\/EpisodeName>/i)
{
$episode_name = $1;
}
if ($content =~ m/((.|\n|\r|\f)+)<\/Overview>/i)
{
$plot = $1;
}
if ($content =~ m/(.+)<\/Rating>/i)
{
$rating = int($1);
}
if ($content =~ m/(.+)<\/filename>/i)
{
$poster = "http://".$THETVDB."/banners/".$1;
}
if ($content =~ m/(.+)<\/Director>/i)
{
$director = $1;
if ($director =~ m/\|(.+)\|/i)
{
$director = $1;
}
$director =~ s/\|/, /g;
}
if ($content =~ m/(\d+).*<\/FirstAired>/i)#just the year
{
$air_date = int($1);
}
if ($content =~ m/(.+)<\/id>/i)
{
$episode_id = $1;
}
if ($content =~ m/(.+)<\/EpisodeNumber>/i)
{
$episode_number = $1;
}
if ($content =~ m/(.+)<\/SeasonNumber>/i)
{
$season_number = $1;
}
if ($content =~ m/(.+)<\/seriesid>/i)
{
$series_id = $1;
}
if ($content =~ m/(.+)<\/IMDB_ID>/i)
{
$imdb_id = $1;
$imdb_id =~ s/tt//g;
}
return ($series_id, $episode_id, $season_number, $episode_number, $episode_name, $plot, $rating, $poster, $director, $air_date, $imdb_id);
}
sub format_episode_title
{
my $filename = $_[0];
my $episode = $_[1];
my $episode_name = $_[2];
my $show = $_[3];
my $season = $_[4];
my $tv_show_title_format = $_[5];
my($episode_with_zero,$season_with_zero);
if (length $episode eq 1) {$episode_with_zero = "0".$episode;}
else{$episode_with_zero = $episode;}
if (length $season eq 1) {$season_with_zero = "0".$season;}
else{$season_with_zero = $season;}
if ($tv_show_title_format eq 0)
{
return $filename;
}
elsif ($tv_show_title_format eq 2)
{
return $show." S".$season_with_zero."E".$episode_with_zero." ".$episode_name;
}
elsif ($tv_show_title_format eq 3)
{
return $show." ".$season."x".$episode_with_zero." ".$episode_name;
}
#default
return $episode_with_zero.": ".$episode_name;
}
sub format_movie_title
{
my $filename = $_[0];
my $movie_name = $_[1];
my $movie_title_format = $_[2];
if ($movie_title_format eq 0)
{
return $filename;
}
#default
return $movie_name;
}
# extracts the year released from the movie filename
# takes 1 argument - the filename of the movie & returns the most appropriate year that it found
sub extract_year_released {
# an array to hold the found years
my @foundYears;
my @possibleYears;
my $possibleYear;
my $filename = $_[0];
# Get the local year
(my $sec,my $min,my $hour,my $mday,my $mon,my $thisYear,my $wday,my $yday,my $isdst) = localtime(time);
$thisYear += 1900;
@possibleYears = $filename =~ /[\[,\(,\{]\d{4}[\],\),\}]/g;
foreach $possibleYear (@possibleYears)
{
# strip the delimeter characters from the string
$possibleYear =~ s/[\[,\(,\{,\],\),\}]//g;
# if the digits are > 1900 and <= the current year its safe to assume its a year
if (($possibleYear >= 1900) && ($possibleYear <= $thisYear)) {
push(@foundYears, $possibleYear);
}
}
# if we have a number of years in the array then we will use the one at the end
if (scalar(@foundYears) > 1) {
return $foundYears[scalar(@foundYears)-1];
}
#print "COUNT: " . scalar(@foundYears) . "\n\n\n";
if ((scalar(@foundYears) eq 0) || (!$foundYears[0]))
{
return "";
}
else
{
return $foundYears[0];
}
}
sub validate_lock_file
{
if( length($lock_file) == 0 )
{
# No lock file specified ignore it and return
return;
}
if( -e $lock_file )
{
print "Lock file exists. '$lock_file'. Exiting\n";
exit;
}
open(my $fh_lock, '>>', $lock_file) or die "Could not open '$lock_file' - $!\n";
close($fh_lock) or die "Could not close '$lock_file' - $!\n";
}
sub release_lock_file
{
if( length($lock_file) == 0 )
{
# No lock file specified ignore it and return
return;
}
print "Releasing lock file ('$lock_file').\n";
unlink($lock_file);
}
######################################################################################
#
#######################################################
#program start.
my $local_machine_hostname = "";
#checking command line arguments
for (my $arg_index = 0; $arg_index < (1 + $#ARGV); $arg_index++)
{
my $arg_type = $ARGV[$arg_index];
print "looking at '$arg_type'\n";
if ($arg_type eq "-D")
{
$arg_index++;
$videodir = $ARGV[$arg_index];
if ($videodir !~ /\/$/)
{
$videodir = $videodir."/";
}
print "Overriding DB folder. Will use '$videodir'\n";
}
elsif($arg_type eq "-N")
{
$arg_index++;
if ($ARGV[$arg_index] eq "1")
{
$only_new_files = 1;
}
else
{
$only_new_files = 0;
}
print "Overriding new files scan. Will use '$only_new_files'\n";
}
elsif($arg_type eq "-P")
{
$arg_index++;
if ($ARGV[$arg_index] eq "1")
{
$download_picture_files = 1;
}
else
{
$download_picture_files = 0;
}
print "Overriding download pictures. Will use '$download_picture_files'\n";
}
elsif($arg_type eq "-S")
{
$arg_index++;
if ($ARGV[$arg_index] eq "1")
{
$download_subtitles = 1;
}
else
{
$download_subtitles = 0;
}
print "Overriding subtitles download. Will use '$download_subtitles'\n";
}
elsif($arg_type eq "-DBP")
{
$arg_index++;
$dbpass = $ARGV[$arg_index];
print "Overriding DB password.\n";
}
elsif($arg_type eq "-MOVIE_SNAP")
{
$arg_index++;
if ($ARGV[$arg_index] eq '1')
{
$movies_snapshot = 1;
}
elsif ($ARGV[$arg_index] eq '2')
{
$movies_snapshot = 2;
}
else
{
$movies_snapshot = 0;
}
print "Overriding movies snapshot to '$movies_snapshot'.\n";
}
elsif($arg_type eq "-TV_SNAP")
{
$arg_index++;
if ($ARGV[$arg_index] eq '1')
{
$tv_snapshot = 1;
}
else
{
$tv_snapshot = 0;
}
print "Overriding tv show snapshot to '$tv_snapshot'.\n";
}
elsif($arg_type eq "-SHORT_NAME")
{
$arg_index++;
my $short_tv_name = int($ARGV[$arg_index]);
if ($short_tv_name eq 0) {$tv_show_title_format = 2;}
else {$tv_show_title_format = 1;}
print "Obsolete! use '-TV_TITLE_TYPE' instead!..\n";
}
elsif($arg_type eq "-TV_TITLE_TYPE")
{
$arg_index++;
$tv_show_title_format = int($ARGV[$arg_index]);
print "Overriding TV title name format to '$tv_show_title_format'.\n";
}
elsif($arg_type eq "-MOVIE_TITLE_TYPE")
{
$arg_index++;
$movie_title_format = int($ARGV[$arg_index]);
print "Overriding movie title name format to '$movie_title_format'.\n";
}
elsif($arg_type eq "-F")
{
$arg_index++;
@myfiles = ($ARGV[$arg_index]);
print "One file mode. Target file is '$ARGV[$arg_index]'.\n";
}
elsif($arg_type eq "-SNAPSHOT_WIDTH")
{
$arg_index++;
$snapshot_width = int($ARGV[$arg_index]);
print "Snapshot width has been set to $snapshot_width pixels.\n";
}
elsif($arg_type eq "-TVIP")
{
$arg_index++;
$THETVDB = $ARGV[$arg_index];
print "THE-TV-DV is at '$THETVDB'.\n";
}
elsif($arg_type eq "-ARTFOLDER")
{
$arg_index++;
$ArtworkDirectory = $ARGV[$arg_index];
print "Artwork folder is at '$ArtworkDirectory'.\n";
}
elsif($arg_type eq "-CLEAN_ARTFOLDER")
{
$arg_index++;
if ($ARGV[$arg_index] eq "1")
{
$cleanArtFolder = 1;
}
else
{
$cleanArtFolder = 0;
}
print "Overriding clean art folder. Will use '$cleanArtFolder'\n";
}
elsif($arg_type eq "-HOSTNAME")
{
$arg_index++;
$local_machine_hostname = $ARGV[$arg_index];
print "machine hostname is '$local_machine_hostname'.\n";
}
elsif($arg_type eq "-THUMB_OFFSET")
{
$arg_index++;
$video_thumb_offset = int($ARGV[$arg_index]);
print "Snapshot offset will be taken from second '$video_thumb_offset'.\n";
}
elsif($arg_type eq "-PROXY")
{
$arg_index++;
my $proxyadr =$ARGV[$arg_index];;#ip
$proxyadr ="http://$proxyadr/";
$global_user_agent->proxy('http', $proxyadr) if length($proxyadr) >4;
$global_user_agent->timeout(45);
print "proxy server is '$proxyadr'.\n";
}
elsif($arg_type eq "-PARENTAL")
{
$arg_index++;
if ($ARGV[$arg_index] eq '0')
{
$set_show_level = 0;
}
else
{
$set_show_level = 1;
}
}
elsif($arg_type eq "-LOCKFILE")
{
$arg_index++;
$lock_file = $ARGV[$arg_index];
print "Lock file is '$lock_file'.\n";
}
elsif($arg_type eq "-FORCEDATE")
{
$arg_index++;
if ($ARGV[$arg_index] eq '0')
{
$force_date_added_to_create_date = 0;
}
else
{
$force_date_added_to_create_date = 1;
}
}
else
{
print "Fill MythVideo Meta-Data v$script_version\n";
print "Command line arguments (all these arguments are optionals):\n";
print "-N [1/0]\n";
print " Perform \"full\" (0)/\"new files only\" (1) scan (overriding the default specified)\n";
print "-P [1/0]\n";
print " Download Pictures (0) Skip picture download (1)\n";
print "-D [path]\n";
print " Scan specific directory, recursive (overriding the automatic media folder detection).\n";
print "-F [full path to file]\n";
print " Work on a specific file (can be usefull for replacing imdb.pl script)\n";
print "-S [1/0]\n";
print " Perform subtitles download\n";
print "-DBP [whatever]\n";
print " Specify DB password\n";
print "-MOVIE_SNAP [0/1/2]\n";
print " For movies - generate snapshot from file (1)\n";
print " For movies - take snapshot from themoviedb.org (0)\n";
print " For movies - take snapshot from external script (command line must be defined) (2)\n";
print "-TV_SNAP [0/1]\n";
print " For TV shows - generate snapshot from file (1), or take it from the-tv-db.com (0)\n";
print "-SNAPSHOT_WIDTH [number]\n";
print " Change the default snapshot width (height is calcualted by the aspect ratio)\n";
print "-THUMB_OFFSET [seconds]\n";
print " Take the video snaphost image from the specified time\n";
print "-SHORT_NAME [0/1]\n";
print " Obsolete. Please use -TV_TITLE_TYPE.\n";
print "-TV_TITLE_TYPE [0/1/2]\n";
print " 0-[Filename]\n";
print " 1(default)-[Episode number]: [Episode name]\n";
print " 2-[Show] S[Season number]E[Episode number] [Episode name]\n";
print " 3-[Show] [Season number]x[Episode number] [Episode name]\n";
print "-MOVIE_TITLE_TYPE [0/1/2]\n";
print " 0-[Filename]\n";
print " 1(default)-[Movie name from the-movie-db.org]\n";
print "-ARTFOLDER [full path to folder]\n";
print " Override Art-Work folder. Usefull in case the script fails to detect the correct folder (in multi boxes environment)\n";
print "-CLEAN_ARTFOLDER [1/0]\n";
print " Clean files not referenced in database (1), or leave files alone.\n";
print "-HOST [hostname]\n";
print " Override the automatic hostname resolving.\n";
print "-TVIP [HOST/IP]\n";
print " Change the IP of THE-TV-DB (this should be used rarely!)\n";
print "-PROXY [ip_address:port]\n";
print " Use a proxy server eg. '10.1.0.254:3128'.\n";
print "-PARENTAL [0/1]\n";
print " 1(default)-store parental show level \n";
print " 0-don't handle parental level\n";
print "-LOCKFILE [filename]\n";
print " Use [filename] as a lock file to ensure only one script at a time\n";
print "-FORCEDATE [0/1]\n";
print " 1(default)-force the date added field of metadata to match file creation date\n";
print " 0-leave date added field as when metadata record created\n";
print "\n";
exit;
}
}
validate_lock_file();
if ((length $local_machine_hostname) < 1)
{
$local_machine_hostname = hostname();
}
print "Local machine hostname is '$local_machine_hostname'\n";
if ((length $dbpass) < 1)
{
if (-e "/etc/mythtv/mysql.txt")
{
print "Using password from mysql.txt\n";
open( my $R, '<', "/etc/mythtv/mysql.txt" ) or die "couldn't open mysql.txt\n";
while ( my $line = <$R> )
{
if ( $line =~ /DBPassword/ )
{
$dbpass = $line;
}
}
close $R;
$dbpass =~ s/DBPassword=//g;
chomp($dbpass);
}
}
#checking variables
if ((length $dbpass) < 1)
{
die "Please provide the SQL server password. Use the '-DBP' command argument.\nUse '-h' command argument for more details.\n";
}
if ($only_new_files eq 0)
{
print "NOTICE: You have selected to update ALL files! This will overwrite all previous data with new data.\n";
}
my $last_series_id = '';#this is saved across files. Will be reset if file parsing is required.
#my @season_information;
my $last_show_name = '';
#this member will be used for show title (actual, from the internet).
my $actual_show_name = '';
my $last_folder_name = '';
my $last_folder_poster = '';
my $content_rating = "NR";
my $thetvdb_imdb_id = '';
my $season_banner= '';
my $banner = '';
my $fanart = '';
my $total_files_count = 0;
my $updated_files = 0;
print "Connecting to database...\n";
my $dbh = DBI->connect("dbi:mysql:$db:$dbhost","$dbuser","$dbpass") || die "Database connection not made: $DBI::errstr";
my $sqlstat;
my $sth;
#querying for videos folder
my $mythvideo_video_dir;
$sqlstat=qq {select data from settings where value="VideoStartupDir" and hostname="$local_machine_hostname"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$mythvideo_video_dir );
$sth->fetch();
print "MythVideos folder is: $mythvideo_video_dir\n";
#querying for Banner folder
$sqlstat=qq {select data from settings where value="mythvideo.bannerDir" and hostname="$local_machine_hostname"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$BannerDirectory);
$sth->fetch();
#making sure it does not end with '/', cause we add it.
if ($BannerDirectory =~ m/(.+)\/$/gi)
{
$BannerDirectory = $1;
}
print "Banner folder is: $BannerDirectory\n";
if ((length $BannerDirectory gt 0) && (!-e $BannerDirectory))
{
print "*** Banners folder does not exists!!!!!!!\n";
}
#querying for Fanart folder
$sqlstat=qq {select data from settings where value="mythvideo.fanartDir" and hostname="$local_machine_hostname"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$FanartDirectory);
$sth->fetch();
if ($FanartDirectory =~ m/(.+)\/$/gi)
{
$FanartDirectory = $1;
}
print "Fanart folder is: $FanartDirectory\n";
if ((length $FanartDirectory gt 0) && (!-e $FanartDirectory))
{
print "*** Fan art folder does not exists!!!!!!!\n";
}
#querying for Screenshot folder
$sqlstat=qq {select data from settings where value="mythvideo.screenshotDir" and hostname="$local_machine_hostname"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$ScreenshotDirectory);
$sth->fetch();
if ($ScreenshotDirectory =~ m/(.+)\/$/gi)
{
$ScreenshotDirectory = $1;
}
print "Screenshot folder is: $ScreenshotDirectory\n";
if ((length $ScreenshotDirectory gt 0) && (!-e $ScreenshotDirectory))
{
print "*** Screenshots folder does not exists!!!!!!!\n";
}
if (length $videodir == 0)
{
$videodir = $mythvideo_video_dir;
}
print "Will scan videos from folder: $videodir\n";
if (length $ArtworkDirectory == 0)
{
#querying for Artwork folder
$sqlstat=qq {select data from settings where value="VideoArtworkDir" and hostname="$local_machine_hostname"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$ArtworkDirectory );
$sth->fetch();
if ($ArtworkDirectory =~ m/(.+)\/$/gi)
{
$ArtworkDirectory = $1;
}
}
print "Artwork folder is: $ArtworkDirectory\n";
$sqlstat=qq {select extension from videotypes where f_ignore=0};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
my $a_video_ext;
$sth->bind_columns( undef, \$a_video_ext );
$sth->fetch();
my $video_exts = $a_video_ext;
while($sth->fetch())
{
$video_exts = $video_exts."|".$a_video_ext;
}
print "Extensions: $video_exts\n";
if (scalar(@myfiles) eq 0)
{
#it may be ":" separated.
my @video_folders = split(':', $videodir);
foreach(@video_folders)
{
my $a_video_folder = $_;
my @video_files = `find -L "$a_video_folder"`;
push(@myfiles, @video_files);
}
}
$sqlstat=qq {select data from settings where value = 'DBSchemaVer'};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
#I'm doing the query, and defining the variable in the global scoop, so we'll have this
#easily accessable for any future needs.
my $mythtvDBSchemaVersion;
$sth->bind_columns( undef, \$mythtvDBSchemaVersion );
$sth->fetch();
print "Found DB schema version: $mythtvDBSchemaVersion.\n";
#check if the user has specified the special mythtv 0.22 features usages.
#see issue 55 about this.
if ($mythtvDBSchemaVersion >= 1244)
{
print "DB schema is of Myth TV 0.22 (or higher). Enabling extended features.\n";
$mythtv_022 = 1;
}
if ($mythtvDBSchemaVersion >= 1254)
{
print "DB schema is of Myth TV 0.23 (or higher).\n";
$mythtv_023 = 1;
}
if ($mythtv_022 eq 1)
{
$sqlstat=qq {select data from settings where value = 'mythvideo.ParentalLevelFromRating'};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$set_show_level );
$sth->fetch();
my $enabled = 'NO';
if ($set_show_level ne 0)
{
$enabled = 'YES';
}
print "Parental level support: $enabled.\n";
if ($set_show_level ne 0)#should do it
{
$sqlstat=qq {select data from settings where value = 'mythvideo.AutoR2PL1'};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$show_level_1 );
$sth->fetch();
$sqlstat=qq {select data from settings where value = 'mythvideo.AutoR2PL2'};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$show_level_2 );
$sth->fetch();
$sqlstat=qq {select data from settings where value = 'mythvideo.AutoR2PL3'};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$show_level_3 );
$sth->fetch();
$sqlstat=qq {select data from settings where value = 'mythvideo.AutoR2PL4'};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$sth->bind_columns( undef, \$show_level_4 );
$sth->fetch();
#fixing the regex from 'R:NC-17' to '^(R|NC-17)$'
$show_level_1 =~ s/:/\x7C/g;
$show_level_2 =~ s/:/\x7C/g;
$show_level_3 =~ s/:/\x7C/g;
$show_level_4 =~ s/:/\x7C/g;
#prefix and postfix
$show_level_1 = '^('.$show_level_1.')$';
$show_level_2 = '^('.$show_level_2.')$';
$show_level_3 = '^('.$show_level_3.')$';
$show_level_4 = '^('.$show_level_4.')$';
print 'Parental Level regex are:\nLevel 1: '.$show_level_1.'\nLevel 2: '.$show_level_2.'\nLevel 3: '.$show_level_3.'\nLevel 4: '.$show_level_4.'\n';
}
else
{
}
}
else
{
#i'm only supporting 0.22 with this.
$set_show_level = 0;
}
foreach (@myfiles)
{
my $isDVD = 0;#issue 53
my $fullfilename = $_;
$fullfilename =~ s/\W*$//gi;
#skiping any file which is not in the file extension list
if ($fullfilename !~ m/($video_exts)$/gi)
{
#print "file '$fullfilename' is not in the file extensions list. Skipping.\n";
next;
}
elsif ($fullfilename =~ m/\/VIDEO_TS.+$/i)
{
#print "Skipping DVD rip file...\n";
next;
}
elsif ($fullfilename =~ m/\/AUDIO_TS.+$/i)
{
#print "Skipping DVD rip file (audio files)...\n";
next;
}
elsif ($fullfilename =~ m/\/VIDEO_TS$/i)
{
$isDVD = 1;#issue 53
print "DVD root folder...\n";
$fullfilename =~ s/\/VIDEO_TS$//i;
print "New fullfilename is $fullfilename\n";
#next;
}
print "======================================================================\n";
print "File ".$total_files_count." out of ".scalar(@myfiles)."...\n";
$total_files_count++;
#print "File: $fullfilename\n";
#next;
my($directory, $filename) = $fullfilename =~ m/(.*\/)(.*)$/;
my $sql_fullfilename = ensure_string_is_valid_for_SQL($fullfilename);
$sqlstat=qq {select inetref from videometadata where filename="$sql_fullfilename"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
my $current_show_ref;
$sth->bind_columns( undef, \$current_show_ref );
my $video_has_meta_data = 0;
if (!$sth->fetch())
{
print "Video file '$filename' does not exist in the DB metadata. Inserting dummy row...\n";
my $sql_filename = ensure_string_is_valid_for_SQL($filename);
$sqlstat=qq {insert videometadata (title,rating,showlevel,browse,filename) values ("$sql_filename","NR", $default_show_level, 1, "$sql_fullfilename")};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
$video_has_meta_data = 0;
$current_show_ref = "";
}
elsif (($current_show_ref) && (length $current_show_ref > 0))
{
print "Video file '$filename' has metadata in the database.\n";
$video_has_meta_data = 1;
#maybe the cover is not complete, in this case we also query for the meta-data
$sqlstat=qq {select coverfile from videometadata where filename="$sql_fullfilename"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
my $coverfile;
$sth->bind_columns( undef, \$coverfile );
my $invalid_cover_file = 0;
if (!$sth->fetch())
{
print "Could not locate cover file in the database.\n";
$invalid_cover_file = 1;
}
elsif ((!$coverfile) || (length $coverfile eq 0) || (!-e $coverfile) || (-s $coverfile < 100) || ($coverfile =~ m/folder\.\w{3}$/))#empty or ends with folder.*
{
print "Invalid cover file '$coverfile'!\n";
$invalid_cover_file = 1;
}
if ($invalid_cover_file eq 1)
{
print "The cover of the video file is invalid! I'll try to regenerate it...\n";
$video_has_meta_data = 0;
}
}
else
{
print "Video file '$filename' does have not metadata in database.\n";
$video_has_meta_data = 0;
$current_show_ref = "";
}
#did the user requested full override?
if ($only_new_files eq 0)
{
$video_has_meta_data = 0;
}
if( $video_has_meta_data eq 0 and $force_date_added_to_create_date eq 1 )
{
my $ctime;
$ctime = (stat($fullfilename))[10];
my $time_string = strftime "%Y-%m-%d %T", localtime($ctime);
my $sql_fullfilename = ensure_string_is_valid_for_SQL($fullfilename);
$sqlstat =
qq {
update videometadata
set
insertdate="$time_string"
where filename="$sql_fullfilename"
};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
}
print "D=$directory, F=$filename\n";
my $is_tv_show = 0;
my($series_id, $show, $season, $episode, $episode_id) = ("", "", "", "", "");
my $imdb_id = "";
#before anything, I'll check for NFO file
my $filename_parsing_required = 1;#it will be changed to '0' if I'll find NFO for the file
my $video_file_with_no_ext;
if ($isDVD eq 1)#issue 53
{#Ho, it is a DVD in the HD
#print "Note: DVD in the HD, This is partly supported (filenames with spaces)...\n";
$filename_parsing_required = 0;
$is_tv_show = 0;
print "DVD Folder: $directory\n";
print "DVD Name: $filename\n";
$video_file_with_no_ext = $filename;
print "The NFO file will be looked from at '".$directory.$video_file_with_no_ext.".nfo\n";
}
else
{
($video_file_with_no_ext) = $filename =~ m/(.*)\..*/;
}
#support for same filename with nfo ext
my $video_nfo_file;
if ($video_file_with_no_ext)#it could be that the file is not a file, but a folder (VIDEO_TS?)
{
$video_nfo_file = $directory.$video_file_with_no_ext.".nfo";
if (!-e $video_nfo_file)
{
#support for same filename with nfo ext, but hidden
$video_nfo_file = $directory.".".$video_file_with_no_ext.".nfo";
if (!-e $video_nfo_file)
{
#maybe entire folder override?
my ($currect_folder_name) = $directory =~ m/^.*\/(.*?)\/$/;
$video_nfo_file = $directory."folder.".$currect_folder_name.".nfo";
}
}
}
#print "looking for '$video_nfo_file' for video file details.\n";
if (($video_nfo_file) && (-e $video_nfo_file))
{
print "Video file has NFO file. Looking for video information in it...\n";
#my guess is that mostly it will be used for movies, so i'll check it first
$imdb_id = locate_imdb_data_in_file($video_nfo_file);
if (length $imdb_id > 0)
{
$is_tv_show = 0;#movie, nota tv show
$filename_parsing_required = 0;
if ($imdb_id eq $current_show_ref)
{
#print "same imdb ID in the database, and in the NFO file. No need to update\n";
#leaving the '$video_has_meta_data' as it was (maybe "-N 0" was used)
}
else
{
print "Found IMDB information in NFO file (imdb id: $imdb_id), using it to get meta-data about the file\n";
$video_has_meta_data = 0;
}
}
else
{
($series_id, $season, $episode, $episode_id) = locate_thetvdb_data_in_file($video_nfo_file);
print "Located TV show data in NFO file: Series ID:".$series_id." Season:".$season." Episode:".$episode." Episode ID:".$episode_id."\n";
if ((length $series_id > 0) && (length $season > 0) && (length $episode > 0))
{
$filename_parsing_required = 0;
$is_tv_show = 1;#a tv show
my $episode_url = create_episode_url($series_id, $season, $episode);
if ($current_show_ref eq $episode_url)
{
#print "same URL in the database, and in the NFO file. No need to update\n";
#leaving the '$video_has_meta_data' as it was (maybe "-N 0" was used)
}
else
{
print "Found THE-TV-DB information in NFO file (series id: $series_id, season: $season, episode: $episode), using it to get meta-data about the file\n";
$video_has_meta_data = 0;
$show = "id_".$series_id;
}
}
elsif (length $episode_id > 0)
{
$filename_parsing_required = 0;
$is_tv_show = 1;#a tv show
my $episode_url = create_episode_url_by_episode_id($episode_id);
#print "Will get episode data from ".$episode_url."\n";
if (($video_has_meta_data eq 1) && $current_show_ref eq $episode_url)
{
#print "same URL in the database, and in the NFO file. No need to update\n";
#leaving the '$video_has_meta_data' as it was (maybe "-N 0" was used)
}
else
{
print "Found THE-TV-DB information in NFO file (episode id: $episode_id). Getting identifies parameters...\n";
($series_id, $episode_id, $season, $episode) = get_episode_meta_data_by_episode_id($episode_id);
print "Found THE-TV-DB information in NFO file (series id: $series_id, season: $season, episode: $episode), using it to get meta-data about the file\n";
$video_has_meta_data = 0;
$show = "id_".$series_id;
}
}
else
{
#maybe skippers
#they are two types of skipper: enitre data, or just get simple data
if (is_skip_file($video_nfo_file))
{
$filename_parsing_required = 0;
print "File have been marked as 'no_update'. Skiping it, what's in the database will stay as is.\n";
next;
}
elsif (is_simple_meta_data($video_nfo_file))
{
$filename_parsing_required = 0;
print "File have been marked as 'simple_update'. Clearing meta-data, and setting snapshot.\n";
#getting video length
my $video_length = get_video_length($fullfilename);
#creating video snapshot
my $thumb_path = $filename.".jpg";
#making the name a bit more friendly...
$thumb_path =~ s/ /_/gi;
$thumb_path =~ s/'/_/gi;
#now adding to the full path - this is done here, so it will be possible to have spaces in the artwork folder
$thumb_path = $ArtworkDirectory."/".$thumb_path;
if (-e $thumb_path)
{
print "Video file already exists. Not over-writing.\n";
}
else
{
create_video_thumb($fullfilename, $video_length, $thumb_path);
}
my $sql_filename = ensure_string_is_valid_for_SQL($filename);
my $sql_path = ensure_string_is_valid_for_SQL($thumb_path);
my $sql_fullfilename = ensure_string_is_valid_for_SQL($fullfilename);
$sqlstat=
qq {
update videometadata
set
title="$sql_filename", plot="", director="", year=0, inetref="",
coverfile="$sql_path", length=$video_length, userrating=0
where filename="$sql_fullfilename"
};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
#next file please.
next;
}
else
{
print "NFO file is irrelevant.\n";
}
}
}
}
#now I know if their is a need to get meta-data for the file
if ($video_has_meta_data eq 1)
{
print "No need to get meta-data for file.\n";
next;
}
if ($filename_parsing_required == 1)#did not file NFO file
{
#no nfo, and the parsing will get a new show ID
$series_id = "";#resetting, so it will be searched.
#scrubs S04E22.tvrip.avi
if ($filename =~ m/^(.+)S(\d{1,2})E(\d{1,2})\D.*$/i)
{
$show = $1;
$season = $2;
$episode = $3;
print "TV format 1: Show: '$show', S:'$season', E:'$episode'\n";
$is_tv_show = 1;
}
#scrubs.4x22.tvrip.avi
elsif ($filename =~ m/^(.+)\W+(\d{1,2})x(\d{1,2})\D.*$/i)
{
$show = $1;
$season = $2;
$episode = $3;
print "TV format 2: Show: '$show', S:'$season', E:'$episode'\n";
$is_tv_show = 1;
}
#should support the following:
#scrubs.422.tvrip.avi
#My Name is Earl 422 - Pinky.720p.h264.tvrip.mkv
#The Simpsons 2015 - Wedding For Disaster.720p.h264.tvrip.mkv
#Big Bang Theory, The 301 - The Electric Can Opener Fluctuation.720p.h264.tvrip.avi
#will ignore (2000) as movie year and ?,000 for 10,000 BC
#will ignore (Dates 2009-01-01) Series - 2009-01-01
elsif (!($filename =~ /[\[,\,\{]\d{4}[\],\,\}]/g)
&& !($filename =~ m/^.+\d{1,2},\d{3}.*$/i)
&& !($filename =~ m/^.+\d{2,4}-\d{1,2}-\d{1,2}.*$/i)
&& ($filename =~ m/^(.*?)\D(\d{1,2})(\d{2})\D.*$/i))#This must be the last one, since we are in search for its tokens.
{
$show = $1;
$season = $2;
$episode = $3;
print "TV format 3: Show: '$show', S:'$season', E:'$episode'\n";
$is_tv_show = 1;
}
else
{
print "Can not parse '$filename' as tv show. Will try as a movie...\n";
#$is_tv_show = 0;#starting with 0, why change?
}
}
if ($is_tv_show eq 1)
{
#handling meta-data as TV show
#fixing stuff
$show =~ tr/[\.\_\-\[\]!\(\)]/ /;
#to lower-case
$show =~ tr/[A-Z]/[a-z]/;
$show = trim($show);
if ($show eq "hi 5")
{
$show = "hi-5";
}
print "Show '$show' actual '$actual_show_name'.\n";
if ((length $show) eq 0) {exit;}
$season = trim($season);
$episode = trim($episode);
#removing leading zeros
$season =~ s/^0*//;
$episode =~ s/^0*//;
#ensuring that the items are not empty
if ((length $season) eq 0) {$season = "0";}
if ((length $episode) eq 0) {$episode = "0";}
print "Found Show: (id: $series_id), '$show', season '$season', episode '$episode'. last ID: $last_series_id\n";
eval
{
#I want to get the meta-data for the file
#I need the series ID, the season, and the episode.
#The season and the episode are correct: They either parsed, or retreived from an NFO file
#The series ID can be NFO parsed one or empty.
#if it is not empty, then it is the correct one (I mean, I took it from an NFO file)
#if it is empty, then I can search the current folder for NFO file which contains the series ID
#series ID was found? Good. Not found: I may want to use the previous series ID.
#the previous ID is valid ONLY if i'm in the same folder and the series name was not changed!
#otherwise, I need to look for the series name in THE-TV-DB
if ((length $series_id) eq 0)
{
#I have not detected a special NFO for the file, maybe there is for the show
#looking for an nfo file inside the folder, maybe it wants to override the data
#note: this function caches, so it is OK to call it multiple times.
$series_id = locate_thetvdb_series_id_in_any_nfo_file($directory);
#ok, I'll check the last_series_id
if (($last_folder_name ne $directory) || ($last_show_name ne $show))
{#moved on, not valid anymore.
$last_series_id = "";
}
if ((length $series_id) eq 0)
{#all my tries had not provided any series ID. I'll take the last (even if it is empty)
$series_id = $last_series_id;
}
}
print "Getting metadata for '$filename'...\n";
#note: the series_id may still be empty! But if so, the show name is not empty!!
if (((length $series_id) eq 0) && ((length $show) eq 0))
{
print "FATAL ERROR!! no series_id and no show name!!\n";
next;
}
#OK, everything I need
#If I'm missing the ID I need to get the ID from the series name
#If I moved to a new folder, I want to make sure I'm setting the correct folder art
if (((length $series_id) eq 0) || ($last_folder_name ne $directory))
{
if ((length $series_id) eq 0)
{
print "Missing series ID. Searching by series name '$show'...\n";
}
else
{
print "Moved to a new folder. Need to get series meta-data for folder art...\n";
}
my $plot;
$thetvdb_imdb_id="";
($series_id, $show, $last_folder_poster, $banner, $fanart, $plot, $actual_show_name, $content_rating, $thetvdb_imdb_id) = get_series_meta_data($series_id, $show, $directory);
if (length($last_folder_poster) eq 0)
{
$last_folder_poster = $banner
}
#Download Banner
if (($banner) && ($BannerDirectory))
{
download_poster($banner, $BannerDirectory."/".$show.".jpg");
}
#Download Fanart
if (($fanart) && ($FanartDirectory))
{
download_poster($fanart, $FanartDirectory."/".$show.".jpg");
}
if ($last_folder_name ne $directory)
{
$last_folder_name = $directory;
#show have a poster. I want to set the folder's art
if (length $last_folder_poster > 0)
{
print "Downloading folder art for series from '$last_folder_poster' to '$directory'...\n";
#downloading poster for the series. This is for the parent folder!
#this folder will get the season poster!
my $parent_folder = $directory;
# Skip Season directory will get later
print "Skipping folder art at directory '$parent_folder'\n";
if ($parent_folder =~ m/^(\/.+\/).+\/$/) {$parent_folder = $1;}
while(((length $parent_folder) >= (length $videodir)) && ((length $parent_folder) > (length $mythvideo_video_dir."/")))
{
print "Checking folder art at directory '$parent_folder'\n";
#there could be a previous folder.jpg/png there
if (no_folder_art_at_folder($parent_folder) eq 1)
{
download_poster($last_folder_poster, $parent_folder."folder.jpg");
}
#now to check my parent
if ($parent_folder =~ m/^(\/.+\/).+\/$/) {$parent_folder = $1;}
else {last;}
}
}
}
}
#if series_id is empty, then we could not locate the series in the-tv-db
if (length $series_id eq 0)
{
$is_tv_show = 0;
}
else
{
#at this point, series_id holds the corrrect ID
$last_series_id = $series_id;
$last_show_name = $show;
print "Getting episode information...\n";
my ($episode_name, $description, $rating, $episode_poster, $directors, $year);
if ((length $episode_id) > 0)#I have the episode ID, I'll use it!
{#($series_id, $episode_id, $season_number, $episode_number, $episode_name, $plot, $rating, $poster, $director, $air_date)
my $temp_holder;
my $temp_imdb_id;
($temp_holder, $episode_id, $temp_holder, $temp_holder, $episode_name, $description, $rating, $episode_poster, $directors, $year, $temp_imdb_id) = get_episode_meta_data_by_episode_id($episode_id);
if ($temp_imdb_id)
{
$thetvdb_imdb_id = $temp_imdb_id;
}
else
{
$thetvdb_imdb_id = "";
}
}
else
{#($series_id, $episode_id, $season_number, $episode_number, $episode_name, $plot, $rating, $poster, $director, $air_date)
my $temp_holder;
my $temp_imdb_id;
($temp_holder, $episode_id, $temp_holder, $temp_holder, $episode_name, $description, $rating, $episode_poster, $directors, $year, $temp_imdb_id) = get_episode_meta_data($series_id, $season, $episode);
if ($temp_imdb_id)
{
$thetvdb_imdb_id = $temp_imdb_id;
}
else
{
$thetvdb_imdb_id = "";
}
}
print "Found meta-data: series id: $series_id, show: '$show', season: $season, episode: $episode.\n";
if (length $episode_name > 0)
{
$updated_files++;
#print "$episode\n";
#print "$episode_name\n";
#print "$actual_show_name\n";
#print "$season\n";
#print "$tv_show_title_format\n";
$season_banner = get_season_banners($series_id, $season);
if (! -e $directory."folder.jpg")
{
if (length($season_banner) gt 0)
{
download_poster($season_banner, $directory."folder.jpg");
}
else
{
#Use Series poster
download_poster($last_folder_poster, $directory."folder.jpg");
}
}
my $episode_title = format_episode_title($filename, $episode, $episode_name, $actual_show_name, $season, $tv_show_title_format);
#filename should be in the plot
$description .= "\n".$filename;
my $video_length = get_video_length($fullfilename);
#the video image filename (not fullpath)
my $thumb_path = $show."-".$episode."-".$season.".jpg";
#the season image
my $poster_path = $ArtworkDirectory."/".$show."-".$season.".jpg";
#the show image
my $banner_path = $BannerDirectory."/".$show.".jpg";
my $fanart_path = $FanartDirectory."/".$show.".jpg";
#making the name a bit more friendly...
$thumb_path =~ s/ /_/gi;
$thumb_path =~ s/'/_/gi;
#now adding to the full path - this is done here, so it will be possible to have spaces in the artwork folder
if ($mythtv_022 eq 0)
{
$thumb_path = $ArtworkDirectory."/".$thumb_path;
}
else
{
#video image is stored in the screenshot folder
$thumb_path = $ScreenshotDirectory."/".$thumb_path;
if (length($season_banner) gt 0)
{
#we have a season banner, so we'll use that.
download_poster($season_banner, $poster_path);
}
else
{
#no season banner, then show banner please.
$poster_path = $banner_path;
if (length($last_folder_poster) gt 0)
{
download_poster($last_folder_poster, $poster_path);
}
else
{
#have no show banner url, so I'll take the screenshot.
$poster_path = $thumb_path;
}
}
}
if (($tv_snapshot eq 0) && (length $episode_poster > 0))
{
print "downloading poster from '$episode_poster'...\n";
if (! -e $thumb_path)
{
download_poster($episode_poster, $thumb_path);
}
}
else
{
print "Creating snapshot for '$fullfilename'...\n";
create_video_thumb($fullfilename, $video_length, $thumb_path);
}
#making sure that the cover is fine (I mean, it may be bad...)
if ((! -e $thumb_path) || ((-s $thumb_path) < 100))
{
print "The cover is invalid! Using the folder art instead.\n";
if (no_folder_art_at_folder($directory) eq 1)
{
$thumb_path = "";
}
else
{
$thumb_path = $directory."folder.jpg";
if (! -e $thumb_path)
{
$thumb_path = $directory."folder.png";
if (! -e $thumb_path)
{
$thumb_path = $directory."folder.gif";
if (! -e $thumb_path)
{
$thumb_path = "";
}
}
}
}
}
print "found '$episode_title': $description\n";
my $episode_url_for_inetref = "";
if (length($thetvdb_imdb_id) > 0)
{
$episode_url_for_inetref = $thetvdb_imdb_id;
}
else
{
$episode_url_for_inetref = create_episode_url_by_episode_id($episode_id);
}
my $sql_description = ensure_string_is_valid_for_SQL($description);
my $sql_directors = ensure_string_is_valid_for_SQL($directors);
my $sql_episode_url_for_inetref = ensure_string_is_valid_for_SQL($episode_url_for_inetref);
my $sql_thumb_path = ensure_string_is_valid_for_SQL($thumb_path);
my $sql_content_rating = ensure_string_is_valid_for_SQL($content_rating);
my $sql_fullfilename = ensure_string_is_valid_for_SQL($fullfilename);
my $showlevel = parse_show_level($content_rating);
if ($mythtv_022 eq 0)
{
my $sql_episode_title = ensure_string_is_valid_for_SQL($episode_title);
$sqlstat = qq {
update videometadata
set
title="$sql_episode_title", plot="$sql_description", director="$sql_directors", year=$year, inetref="$sql_episode_url_for_inetref",
coverfile="$sql_thumb_path", length=$video_length, userrating=$rating, rating="$sql_content_rating", showlevel=$showlevel
where filename="$sql_fullfilename"
};
}
else
{
my $sql_show = ensure_string_is_valid_for_SQL($show);
my $sql_episode_name = ensure_string_is_valid_for_SQL($episode_name);
my $sql_poster_path = ensure_string_is_valid_for_SQL($poster_path);
my $sql_banner_path = ensure_string_is_valid_for_SQL($banner_path);
my $sql_fanart_path = ensure_string_is_valid_for_SQL($fanart_path);
if ($mythtv_023 eq 0)
{
$sqlstat = qq {
update videometadata
set
title="$sql_show", subtitle="$sql_episode_name", plot="$sql_description", director="$sql_directors", year=$year, inetref="$sql_episode_url_for_inetref",
coverfile="$sql_poster_path", length=$video_length, userrating=$rating, rating="$sql_content_rating", season=$season, episode=$episode,
screenshot="$sql_thumb_path", banner="$sql_banner_path", fanart="$sql_fanart_path", showlevel=$showlevel
where filename="$sql_fullfilename"
};
}
else
{
#fixing paths to NOT include the top folder
print "prior: \n$sql_poster_path\n$sql_thumb_path\n$sql_banner_path\n$sql_fanart_path\n$sql_fullfilename\n";
$sql_poster_path = substr($sql_poster_path, length($ArtworkDirectory."/"));
$sql_thumb_path = substr($sql_thumb_path, length($ScreenshotDirectory."/"));
$sql_banner_path = substr($sql_banner_path, length($BannerDirectory."/"));
$sql_fanart_path = substr($sql_fanart_path, length($FanartDirectory."/"));
$sql_fullfilename = substr($sql_fullfilename, length($mythvideo_video_dir."/"));
print "after: \n$sql_poster_path\n$sql_thumb_path\n$sql_banner_path\n$sql_fanart_path\n$sql_fullfilename\n";
$sqlstat = qq {
update videometadata
set
title="$sql_show", subtitle="$sql_episode_name", plot="$sql_description", director="$sql_directors", year=$year, inetref="$sql_episode_url_for_inetref",
coverfile="$sql_poster_path", length=$video_length, userrating=$rating, rating="$sql_content_rating", season=$season, episode=$episode,
screenshot="$sql_thumb_path", banner="$sql_banner_path", fanart="$sql_fanart_path", showlevel=$showlevel, host="$local_machine_hostname"
where filename="$sql_fullfilename"
};
}
}
$sth = $dbh->prepare($sqlstat);
$sth->execute();
print "'$episode_title' is set!\n";
}
else
{
print "Did not find meta-data for episode! Will try as a movie...\n";
$is_tv_show = 0;
}
}
if ($download_subtitles eq 1)
{
my $full_subtitle_filename = substr($fullfilename, 0, rindex($fullfilename, '.')).".srt";
print "About to download subtitles for file '$fullfilename'. Target subtitle file is '$full_subtitle_filename'\n";
download_tv_subtitle($show, $full_subtitle_filename, $season, $episode);
}
};
if($@)
{
print "Error while working on file '$filename'! Will try it as a Movie. Error: $@\n";
$is_tv_show = 0;
}
}
if ($is_tv_show eq 0)#this can be 0 if it was not parsed, or if it could not be found in the TV web-site
{
#handling meta-data as movie
#fixing stuff
# Give the filename a more meaningful name
my $movie_name = $filename;
# Enhanced metadata extraction/removal by Laurie Odgers
# Remove metadata from the filename to get the movie name
$movie_name =~ s/\.\w+$//; # the extension
$movie_name =~ s/^\d+(\.|_|-|\s)//; # track number?
$movie_name =~ s/\[\d{4}\](.*)$//; # sometimes videos include "[2008]", I want to remove EVERYTHING after that
$movie_name =~ s/[\[,\(,\{]\d{4}[\],\),\}]//; #remove year
$movie_name =~ tr/[\.\_\-\[\]!\(\)\:]/ /; # turn delimeter characters into spaces
$movie_name =~ s/\s+/ /g; # convert n-whitespaces into a single whitespace
$movie_name =~ tr/[A-Z]/[a-z]/; # change movie name to lower case
$movie_name =~ s/\s(xvid|divx|h264|x264|ac3|mpg)(.*)$//g; # remove codecs - and everything after
$movie_name =~ s/\s(internal|repack|proper|fixed|read nfo|readnfo|unrated|widescreen)(.*)$//g;# remove notes - and everything after
$movie_name =~ s/\s(dvdrip|screener|hdtv|dsrip|dsr|dvd|bluray|blueray|720p|hr|workprint)(.*)$//g;# remove sources - and everything after
# Part removal enhancement by Laurie Odgers
# Remove anything after "part", "cd", "ep" or "webisode"
$movie_name =~ s/((part|cd|ep|webisode)[\s]+\d+)(.*)$//g; # Numbering, matches: part 1, cd.1, ep1
# Roman Numerals, matches: part I, cd.V, webisodeX
$movie_name =~ s/((part|cd|ep|webisode)[\s]+[i,v,x]+[\s])(.*)$//g; # Matches "moviename - part i [DivX]"
$movie_name =~ s/((part|cd|ep|webisode)[\s]+[i,v,x]+$)(.*)$//g; # Matches "moviename - part i"
$movie_name = trim($movie_name);
if ($movie_name eq "hi 5")
{
$movie_name = "hi-5";
}
eval
{
my $bad_movie = 0;
#this is a movie?
my ($imdb_title_url, $imdb_title, $imdb_plot, $imdb_director, $imdb_release_date, $imdb_poster, $imdb_fanart, $imdb_rating, $motechnet_poster);
$content_rating ="NR";
if ((length $imdb_id) > 0)
{
($imdb_id, $imdb_title_url, $imdb_title, $imdb_plot, $imdb_director, $imdb_release_date, $imdb_poster, $imdb_fanart, $imdb_rating, $motechnet_poster, $content_rating) = get_movie_meta_data_from_tmdb($imdb_id);
}
else
{
# get the year released from the filename if possible &
my $yearReleased = extract_year_released($filename);
my $imdb_possible_ID;
my $tmdb_possible_ID;
($imdb_possible_ID, $tmdb_possible_ID) = get_imdb_ID_for_movie_name_tmdb($movie_name, $yearReleased);
if (($imdb_possible_ID) or ($tmdb_possible_ID))
{
($imdb_id, $imdb_title_url, $imdb_title, $imdb_plot, $imdb_director, $imdb_release_date, $imdb_poster, $imdb_fanart, $imdb_rating, $motechnet_poster, $content_rating) = get_movie_meta_data_from_tmdb($imdb_possible_ID, $tmdb_possible_ID);
}
else
{
print "Can not load movie data for '$movie_name'.\n";
$bad_movie = 1;
}
}
if ($bad_movie == 1)
{
my $sql_movie_name = ensure_string_is_valid_for_SQL($movie_name);
$sqlstat=qq {update videometadata set title = "$sql_movie_name", browse=1 where filename="$sql_fullfilename"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
next;
}
my $video_length = get_video_length($fullfilename);
my $thumb_path = $filename.".jpg";
my $fanart_path = $filename.".jpg";
#making the name a bit more freindly...
$thumb_path =~ s/ /_/gi;
$thumb_path =~ s/'/_/gi;
$fanart_path =~ s/ /_/gi;
$fanart_path =~ s/'/_/gi;
#now adding to the full path - this is done here, so it will be possible to have spaces in the artwork folder
$thumb_path = $ArtworkDirectory."/".$thumb_path;
$fanart_path = $FanartDirectory."/".$fanart_path;
if ($movies_snapshot eq 2) # use external script to retrieve posters
{
print "Attempting to get poster using the following command:\n";
print "$external_poster_command_line $imdb_id\n";
my $poster_url = qx{$external_poster_command_line $imdb_id};
download_poster($poster_url, $thumb_path);
}
elsif ($movies_snapshot eq 0) # retrieve posters from the-movie-db
{
my $good = 0;
if ($motechnet_poster)
{
print "downloading poster from '$motechnet_poster'...\n";
$good = download_poster($motechnet_poster, $thumb_path); # first download from motechnet
}
if ($good eq 0) # if the motechnet download failed
{
if ($imdb_poster) # check to see if we have an imdb poster queued up, and if so download it
{
print "downloading poster from '$imdb_poster'...\n";
$good = download_poster($imdb_poster, $thumb_path);
}
if ($good eq 0) # if all this poster downloading business fails, just create a snapshot and use that
{
print "Creating snapshot for '$fullfilename'...\n";
create_video_thumb($fullfilename, $video_length, $thumb_path);
}
}
}
else # anything else means just create a thumbnail for the snapshot
{
print "Creating snapshot for '$fullfilename'...\n";
create_video_thumb($fullfilename, $video_length, $thumb_path);
}
if (($mythtv_022 ne 0) && ($imdb_fanart) && ($fanart_path))
{
#download fanart
download_poster($imdb_fanart, $fanart_path);
}
#what about the folder?
my $folder_thumb_path = $directory."folder.jpg";
if ((-e $thumb_path) && (no_folder_art_at_folder($directory) eq 1))
{
system("cp '$thumb_path' '$folder_thumb_path'");
}
$imdb_plot .= "\n".$filename;
print "found ($imdb_id) $imdb_title: $imdb_plot\n";
$imdb_title = format_movie_title($filename, $imdb_title, $movie_title_format);
my $sql_imdb_title = ensure_string_is_valid_for_SQL($imdb_title);
my $sql_imdb_plot = ensure_string_is_valid_for_SQL($imdb_plot);
my $sql_imdb_director = ensure_string_is_valid_for_SQL($imdb_director);
my $sql_imdb_release_date = ensure_string_is_valid_for_SQL($imdb_release_date);
my $sql_thumb_path = ensure_string_is_valid_for_SQL($thumb_path);
my $sql_imdb_id = ensure_string_is_valid_for_SQL($imdb_id);
my $sql_content_rating = ensure_string_is_valid_for_SQL($content_rating);
my $sql_fullfilename = ensure_string_is_valid_for_SQL($fullfilename);
my $showlevel = parse_show_level($content_rating);
if ($mythtv_022 eq 0)
{
$sqlstat = qq {
update videometadata
set
title="$sql_imdb_title", plot="$sql_imdb_plot", director="$sql_imdb_director", year="$sql_imdb_release_date", coverfile="$sql_thumb_path",
length=$video_length, userrating=$imdb_rating, inetref="$sql_imdb_id", rating="$sql_content_rating", showlevel=$showlevel
where filename="$sql_fullfilename"
};
}
else
{
my $sql_fanart_path = ensure_string_is_valid_for_SQL($fanart_path);
$sqlstat = qq {
update videometadata
set
title="$sql_imdb_title", plot="$sql_imdb_plot", director="$sql_imdb_director", year="$sql_imdb_release_date", coverfile="$sql_thumb_path",
length=$video_length, userrating=$imdb_rating, inetref="$sql_imdb_id", rating="$sql_content_rating",
fanart="$sql_fanart_path", showlevel=$showlevel
where filename="$sql_fullfilename"
};
}
#print "SQL:\n".$sqlstat."\n";
$sth = $dbh->prepare($sqlstat);
$sth->execute();
print "'$imdb_title' is set!\n";
$updated_files++;
};
if ($@)
{
print "Error while working on file '$filename'! Error: $@\n";
}
}
}
print "======================================================================\n";
print "Finished going over all the files: Found $total_files_count, updated $updated_files files.\n";
my $files_count_for_deletion = 0;
print "Going over all video files in the database, and deleting any redundant entries (i.e., video files no longer exist)...\n";
$sqlstat=qq {select filename from videometadata};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
my $video_file_name;
$sth->bind_columns( undef, \$video_file_name );
my @files_to_delete;
while ($sth->fetch())
{
if ((! $video_file_name) || (length $video_file_name == 0) || (! -e $video_file_name))
{
#print "Video file '$video_file_name' does not exist in filsystem! Will be removed from DB...\n";
push(@files_to_delete, $video_file_name);
$files_count_for_deletion++;
}
else
{
#print "Video file '$video_file_name' exists in filsystem.\n";
}
}
foreach(@files_to_delete)
{
my $file_to_delete = $_;
print "Deleting '$file_to_delete' from database...\n";
my $sql_file_to_delete = ensure_string_is_valid_for_SQL($file_to_delete);
$sqlstat=qq {delete from videometadata where filename="$sql_file_to_delete"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
}
print "Deleted $files_count_for_deletion entries from database!\n";
print "======================================================================\n";
if ($cleanArtFolder eq 1)
{
print "Going over all image files in the artwork folder (at '$ArtworkDirectory'), and deleting any redundant image files (i.e., owner video file does not exist)...\n";
$files_count_for_deletion = 0;
my $image_files_path = $ArtworkDirectory."/*.jpg";
my @image_files = glob($image_files_path);
foreach (@image_files)
{
my $full_image_filename = $_;
#print "Image: '$full_image_filename'\n";
eval
{
my $sql_full_image_filename = ensure_string_is_valid_for_SQL($full_image_filename);
$sqlstat=qq {select coverfile from videometadata where coverfile="$sql_full_image_filename"};
$sth = $dbh->prepare($sqlstat);
$sth->execute();
my $cover_file;
$sth->bind_columns( undef, \$cover_file );
my $video_exists = 0;
if (!$sth->fetch())
{
$video_exists = 0;
}
elsif (($cover_file) && (length $cover_file > 0))
{
$video_exists = 1;
}
else
{
$video_exists = 0;
}
if ($video_exists eq 1)
{
#print "'$full_image_filename' is a cover for a video. It will not be deleted.\n";
}
else
{
print "Image '$full_image_filename' does not exist in the DB metadata. deleting the file...\n";
unlink($full_image_filename);
$files_count_for_deletion++;
}
};
if ($@)
{
print "Error while working on file '$full_image_filename'! Error: $@\n";
}
}
print "Deleted $files_count_for_deletion redundant image files from the artwork folder.\n";
print "======================================================================\n";
}
print "Completing database...\n";
$sth->finish();
$dbh->disconnect();
print "======================================================================\n";
print "Thanks for using MythVideo Metadata Updater v$script_version.\n";
print "======================================================================\n";
release_lock_file();
|