Explorar o código

Merge branch 'master' of github.com:profplump/UberZach-Video

Zachary Kotlarek %!s(int64=9) %!d(string=hai) anos
pai
achega
a57789138a
Modificáronse 1 ficheiros con 217 adicións e 212 borrados
  1. 217 212
      findTorrent.pl

+ 217 - 212
findTorrent.pl

@@ -19,7 +19,8 @@ use Fetch;
 
 # Prototypes
 sub confDefault($;$);
-sub readExcludes($);
+sub readGlobalExcludes($);
+sub readInputDir($);
 sub parseNZB($);
 sub badTor($);
 sub seedCleanup($);
@@ -180,133 +181,17 @@ if ($CONFIG{'SYSLOG'}) {
 }
 
 # Read the torrent excludes list
-$CONFIG{'EXCLUDES'} = readExcludes($CONFIG{'EXCLUDES_FILE'});
-
-# Figure out what we're searching for
-my $show          = '';
-my @urls          = ();
-my $CUSTOM_SEARCH = 0;
-my $season        = 0;
-my @need          = ();
-my %need          = ();
-
-# Clean up the input "directory" path
-{
-
-	# Allow use of the raw series name
-	if (!($dir =~ /\//)) {
-		$show = $dir;
-		$dir  = $CONFIG{'TV_DIR'} . '/' . $dir;
-	}
-
-	# Allow use of relative paths
-	$dir = File::Spec->rel2abs($dir);
-
-	# Sanity check
-	if (!-d $dir) {
-		die('Invalid input directory: ' . $dir . "\n");
-	}
-
-	# Isolate the season from the path, if provided
-	$dir =~ /\/Season\s+(\d+)\/?$/i;
-	if ($1) {
-		$season = $1;
-		$dir    = dirname($dir);
-	}
-
-	# If no season is provided find the latest
-	if (!$season) {
-		opendir(SERIES, $dir)
-		  or die("Unable to open series directory: ${!}\n");
-		while (my $file = readdir(SERIES)) {
-			if ($file =~ /^Season\s+(\d+)$/i) {
-				if (!$season || $season < $1) {
-					$season = $1;
-				}
-			}
-		}
-		closedir(SERIES);
-	}
-
-	# Isolate and clean the series name
-	if (!$show) {
-		$show = basename($dir);
-	}
-	$show =~ s/[\'\"\.]//g;
-
-	if ($DEBUG) {
-		print STDERR 'Checking directory: ' . $dir . "\n";
-	}
-	if ($CONFIG{'SYSLOG'}) {
-		syslog(LOG_NOTICE, $show);
-	}
-}
-
-# Allow the show name to be overriden
-{
-	my $search_name = $dir . '/search_name';
-	if (-e $search_name) {
-		local ($/, *FH);
-		open(FH, $search_name)
-		  or die('Unable to read search_name for show: ' . $show . ': ' . $! . "\n");
-		my $text = <FH>;
-		close(FH);
-		if ($text =~ /^\s*(\S.*\S)\s*$/) {
-			$show = $1;
-		} else {
-			print STDERR 'Skipping invalid search_name for show: ' . $show . ': ' . $text . "\n";
-		}
-	}
-	if ($DEBUG) {
-		print STDERR 'Searching with series title: ' . $show . "\n";
-	}
-}
-
-# Allow quality checks to be disabled
-if (-e $dir . '/no_quality_checks') {
-	$CONFIG{'NO_QUALITY_CHECKS'} = 1;
-	if ($DEBUG) {
-		print STDERR 'Searching with no quality checks: ' . $show . "\n";
-	}
-}
-
-# Allow use of more number formats
-if (-e $dir . '/more_number_formats') {
-	$CONFIG{'MORE_NUMBER_FORMATS'} = 1;
-	if ($DEBUG) {
-		print STDERR 'Searching with more number formats: ' . $show . "\n";
-	}
-}
-
-# Read the search excludes file, if any
-my $exclude        = '';
-my %TITLE_EXCLUDES = ();
-if (-e $dir . '/excludes') {
-	local $/ = undef;
-	open(EX, $dir . '/excludes')
-	  or die("Unable to open series excludes file: ${!}\n");
-	my $ex = <EX>;
-	close(EX);
-
-	$ex =~ s/^\s+//;
-	$ex =~ s/\s+$//;
-	my @excludes = split(/\s*,\s*/, $ex);
-	foreach my $ex (@excludes) {
-		$TITLE_EXCLUDES{$ex} = 1;
-
-		if (length($exclude)) {
-			$exclude .= ' ';
-		}
-		$exclude .= '-"' . $ex . '"';
-	}
-
-	$exclude = uri_encode(' ' . $exclude);
-}
+$CONFIG{'EXCLUDES'} = readGlobalExcludes($CONFIG{'EXCLUDES_FILE'});
 
 # Setup our sources
 $SOURCES = initSources();
 $CONFIG{'DELAY'} /= scalar(keys(%{$SOURCES})) / 2;
 
+# Figure out what we're searching for
+my @urls          = ();
+my $CUSTOM_SEARCH = 0;
+my $SERIES        = readInputDir($dir);
+
 # Handle custom searches
 if ((scalar(@urls) < 1) && defined($search) && length($search) > 0) {
 
@@ -319,12 +204,12 @@ if ((scalar(@urls) < 1) && defined($search) && length($search) > 0) {
 	# Create the relevent search strings
 	foreach my $key (keys(%{$SOURCES})) {
 		my $source = $SOURCES->{$key};
-		push(@urls, $source->{'search_url'} . $search . $exclude . $source->{'search_suffix'});
+		push(@urls, $source->{'search_url'} . $search . $SERIES->{'exclude'} . $source->{'search_suffix'});
 	}
 }
 
 # Handle search-by-date series
-if ((scalar(@urls) < 1) && -e $dir . '/search_by_date') {
+if ((scalar(@urls) < 1) && -e $SERIES->{'path'} . '/search_by_date') {
 
 	# Note the search-by-date status
 	# Set the CUSTOM_SERACH flag to skip season/epsiode matching
@@ -333,14 +218,14 @@ if ((scalar(@urls) < 1) && -e $dir . '/search_by_date') {
 	# Read the find-by-date string
 	my $search_by_date = '';
 	local ($/, *FH);
-	open(FH, $dir . '/search_by_date')
-	  or die('Unable to read search_by_date for show: ' . $show . ': ' . $! . "\n");
+	open(FH, $SERIES->{'path'} . '/search_by_date')
+	  or die('Unable to read search_by_date for show: ' . $SERIES->{'name'} . ': ' . $! . "\n");
 	my $text = <FH>;
 	close(FH);
 	if ($text =~ /^\s*(\S.*\S)\s*$/) {
 		$search_by_date = $1;
 	} else {
-		die('Skipping invalid search_by_date for show: ' . $show . ': ' . $text . "\n");
+		die('Skipping invalid search_by_date for show: ' . $SERIES->{'name'} . ': ' . $text . "\n");
 	}
 
 	# Create search strings for each date in the range, unless the related file already exists
@@ -358,7 +243,7 @@ if ((scalar(@urls) < 1) && -e $dir . '/search_by_date') {
 		# Check for an existing file
 		my $exists = 0;
 		{
-			my $season_dir = $dir . '/Season ' . $year;
+			my $season_dir = $SERIES->{'path'} . '/Season ' . $year;
 			my $prefix     = qr/${year}\-${month}\-${day}\s*\-\s*/;
 			opendir(SEASON, $season_dir)
 			  or die('Unable to open season directory (' . $season_dir . '): ' . $! . "\n");
@@ -386,7 +271,7 @@ if ((scalar(@urls) < 1) && -e $dir . '/search_by_date') {
 		$search_str =~ s/%d/${day}/g;
 		foreach my $key (keys(%{$SOURCES})) {
 			my $source = $SOURCES->{$key};
-			push(@urls, $source->{'search_url'} . $search_str . $exclude . $source->{'search_suffix'});
+			push(@urls, $source->{'search_url'} . $search_str . $SERIES->{'exclude'} . $source->{'search_suffix'});
 		}
 	}
 
@@ -407,73 +292,8 @@ if ((scalar(@urls) < 1) && -e $dir . '/search_by_date') {
 # Handle standard series
 if (scalar(@urls) < 1) {
 
-	# Validate the season number
-	if (!defined($season) || $season < 1 || $season > 2000) {
-		die('Invalid season number: ' . $show . ' => ' . $season . "\n");
-	}
-
-	# Get the last episode number
-	my $no_next  = 0;
-	my %episodes = ();
-	my $highest  = 0;
-	opendir(SEASON, $dir . '/Season ' . $season)
-	  or die("Unable to open season directory: ${!}\n");
-	while (my $file = readdir(SEASON)) {
-
-		# Skip support files
-		if ($file =~ /\.(?:png|xml|jpg|gif|tbn|txt|nfo|torrent)\s*$/i) {
-			next;
-		}
-
-		# Check for a season_done file
-		if ($file eq 'season_done') {
-			$no_next = 1;
-			next;
-		}
-
-		# Extract the episode number
-		my ($num) = $file =~ /^\s*\.?(\d+)\s*\-\s*/i;
-		if (defined($num)) {
-			$num = int($num);
-			if ($DEBUG) {
-				print STDERR 'Found episode number: ' . $num . ' in file: ' . $file . "\n";
-			}
-
-			# Record it
-			$episodes{$num} = 1;
-
-			# Track the highest episode number
-			if ($num > $highest) {
-				$highest = $num;
-			}
-		}
-	}
-	close(SEASON);
-
-	# Assume we need the next 2 episodes, unless no_next is set (i.e. season_done)
-	if (!$no_next) {
-		for (my $i = 1 ; $i <= $CONFIG{'NEXT_EPISODES'} ; $i++) {
-			push(@need, $highest + $i);
-		}
-	}
-
-	# Find any missing episodes
-	for (my $i = 1 ; $i <= $highest ; $i++) {
-		if (!$episodes{$i}) {
-			push(@need, $i);
-		}
-	}
-	if ($DEBUG) {
-		print STDERR 'Needed episodes: ' . join(', ', @need) . "\n";
-	}
-
-	# Reverse the array for later matching
-	foreach my $episode (@need) {
-		$need{$episode} = 1;
-	}
-
 	# Construct a URL-friendly show name
-	my $safeShow = $show;
+	my $safeShow = $SERIES->{'name'};
 	$safeShow =~ s/\s+\&\s+/ and /i;
 	$safeShow =~ s/^\s*The\b//i;
 	$safeShow =~ s/\s+\-\s+/ /g;
@@ -502,14 +322,14 @@ if (scalar(@urls) < 1) {
 
 	# Construct the URL for each title varient of each needed episode
 	foreach my $urlShow (@urlShowVarients) {
-		foreach my $episode (@need) {
+		foreach my $episode ($SERIES->{'need'}) {
 			my $episode_long = sprintf('%02d', $episode);
-			my $season_long  = sprintf('%02d', $season);
+			my $season_long  = sprintf('%02d', $SERIES->{'season'});
 			foreach my $source (values(%{$SOURCES})) {
 
 				# Allow custom handling
 				if (defined($source->{'custom_search'}) && ref($source->{'custom_search'}) eq 'CODE') {
-					$source->{'custom_search'}->(\@urls, $urlShow, $season, $episode);
+					$source->{'custom_search'}->(\@urls, $urlShow, $SERIES->{'season'}, $episode);
 					next;
 				}
 
@@ -523,7 +343,7 @@ if (scalar(@urls) < 1) {
 				my $prefix = $source->{'search_url'} . $quote . $urlShow . $quote;
 				my $suffix = '';
 				if ($source->{'search_exclude'}) {
-					$suffix .= $exclude;
+					$suffix .= $SERIES->{'exclude'};
 				}
 				if ($source->{'search_suffix'}) {
 					$suffix .= $source->{'search_suffix'};
@@ -537,8 +357,8 @@ if (scalar(@urls) < 1) {
 				if ($CONFIG{'MORE_NUMBER_FORMATS'}) {
 
 					# SXEY
-					if ($season_long ne $season || $episode_long ne $episode) {
-						$url = $prefix . '+s' . $season . 'e' . $episode . $suffix;
+					if ($season_long ne $SERIES->{'season'} || $episode_long ne $episode) {
+						$url = $prefix . '+s' . $SERIES->{'season'} . 'e' . $episode . $suffix;
 						push(@urls, $url);
 					}
 
@@ -551,16 +371,16 @@ if (scalar(@urls) < 1) {
 					push(@urls, $url);
 
 					# Series X Episode Y
-					$url = $prefix . '+series+' . $season . '+episode+' . $episode . $suffix;
+					$url = $prefix . '+series+' . $SERIES->{'season'} . '+episode+' . $episode . $suffix;
 					push(@urls, $url);
 
 					# SxEE
-					$url = $prefix . '+' . $season . 'x' . $episode_long . $suffix;
+					$url = $prefix . '+' . $SERIES->{'season'} . 'x' . $episode_long . $suffix;
 					push(@urls, $url);
 
 					# Season X
 					if ($CONFIG{'NO_QUALITY_CHECKS'}) {
-						$url = $prefix . '+Season+' . $season . $suffix;
+						$url = $prefix . '+Season+' . $SERIES->{'season'} . $suffix;
 						push(@urls, $url);
 					}
 				}
@@ -1111,7 +931,7 @@ foreach my $content (@json_content) {
 my %tors      = ();
 my $showRegex = undef();
 {
-	my $showClean = $show;
+	my $showClean = $SERIES->{'name'};
 	$showClean =~ s/[\"\']//g;
 	$showClean =~ s/[\W_]+/\[\\W_\].*/g;
 	$showRegex = qr/^${showClean}[\W_]/i;
@@ -1129,7 +949,7 @@ foreach my $tor (@tors) {
 
 	# Skip files that contain a word from the series exclude list
 	my $exclude = undef();
-	foreach my $ex (keys(%TITLE_EXCLUDES)) {
+	foreach my $ex (keys(%{ $SERIES->{'exclude_hash'} })) {
 		$ex = quotemeta($ex);
 		if ($tor->{'title'} =~ m/${ex}/i) {
 			$exclude = $ex;
@@ -1147,14 +967,14 @@ foreach my $tor (@tors) {
 	if (!$CUSTOM_SEARCH) {
 
 		# Skip files that don't contain the right season number
-		if (!defined($tor->{'season'}) || $tor->{'season'} != $season) {
+		if (!defined($tor->{'season'}) || $tor->{'season'} != $SERIES->{'season'}) {
 			if ($DEBUG) {
-				print STDERR 'Skipping file: No match for season number (' . $season . '): ' . $tor->{'title'} . "\n";
+				print STDERR 'Skipping file: No match for season number (' . $SERIES->{'season'} . '): ' . $tor->{'title'} . "\n";
 			}
 			next;
 
 			# Skip files that don't contain a needed episode number, unless there is no episode number and NO_QUALITY_CHECKS is set
-		} elsif ((defined($tor->{'episode'}) && !$need{ $tor->{'episode'} })
+		} elsif ((defined($tor->{'episode'}) && !$SERIES->{'need_hash'}->{ $tor->{'episode'} })
 			|| (!defined($tor->{'episode'}) && !$CONFIG{'NO_QUALITY_CHECKS'}))
 		{
 			if ($DEBUG) {
@@ -1296,7 +1116,7 @@ foreach my $episode (keys(%tors)) {
 		$urls{$episode} = resolveTrackers($urls{$episode});
 		print $urls{$episode} . "\n";
 		if ($CONFIG{'SYSLOG'}) {
-			syslog(LOG_NOTICE, $show . ': ' . getHash($urls{$episode}));
+			syslog(LOG_NOTICE, $SERIES->{'name'} . ': ' . getHash($urls{$episode}));
 		}
 		if ($DEBUG) {
 			print STDERR 'Final URL: ' . $urls{$episode} . "\n";
@@ -1336,7 +1156,7 @@ sub confDefault($;$) {
 	}
 }
 
-sub readExcludes($) {
+sub readGlobalExcludes($) {
 	my ($file) = @_;
 	my %excludes = ();
 	if (!$file || !-r $file) {
@@ -1370,6 +1190,191 @@ sub readExcludes($) {
 	return \%excludes;
 }
 
+# Find an input directory and read the local config
+sub readInputDir($) {
+	my ($path) = @_;
+	my %series = (
+		'path'                => undef(),
+		'name'                => '',
+		'path_name'           => '',
+		'season'              => 0,
+		'episodes'            => {},
+		'exclude'             => '',
+		'exclude_hash'        => {},
+		'need'                => (),
+		'need_hash'           => {},
+		'season_done'         => 0,
+		'search_name'         => 0,
+		'no_quality_checks'   => 0,
+		'more_number_formats' => 0,
+	);
+
+	# Allow use of the raw series name
+	if (!($path =~ /\//)) {
+		$series{'name'} = $path;
+		$series{'path'} = $CONFIG{'TV_DIR'} . '/' . $path;
+	} else {
+		$series{'path'} = $path;
+	}
+
+	# Allow use of relative paths
+	$series{'path'} = File::Spec->rel2abs($series{'path'});
+
+	# Isolate the season from the path, if provided
+	if ($series{'path'} =~ /\/Season\s+(\d+)\/?$/i) {
+		$series{'season'} = $1;
+		$series{'path'}   = dirname($series{'path'});
+	}
+
+	# Sanity check
+	if ($DEBUG) {
+		print STDERR 'Checking directory: ' . $series{'path'} . "\n";
+	}
+	if (!-d $series{'path'}) {
+		die('Invalid input directory: ' . $series{'path'} . "\n");
+	}
+
+	# Allow the series name to be overriden
+	my $search_name = $series{'path'} . '/search_name';
+	if (-e $search_name) {
+		local ($/, *FH);
+		open(FH, $search_name)
+		  or die('Unable to read search_name for series: ' . $series{'name'} . ': ' . $! . "\n");
+		my $text = <FH>;
+		close(FH);
+		if ($text =~ /^\s*(\S.*\S)\s*$/) {
+			$series{'name'} = $1;
+		} else {
+			warn('Skipping invalid search_name for series: ' . $series{'name'} . ': ' . $text . "\n");
+		}
+	}
+	if ($DEBUG) {
+		print STDERR 'Searching with series title: ' . $series{'name'} . "\n";
+	}
+
+	# Final series name
+	if (!$series{'name'}) {
+		$series{'name'} = basename($series{'path'});
+	}
+	$series{'name'} =~ s/[\'\"\.]//g;
+	$series{'path_name'} = $series{'name'};
+
+	# If no explicit season is provided find the latest
+	if (!$series{'season'}) {
+		opendir(SERIES, $series{'path'})
+		  or die("Unable to open series directory: ${!}\n");
+		while (my $file = readdir(SERIES)) {
+			if ($file =~ /^Season\s+(\d+)$/i) {
+				if (!$series{'season'} || $series{'season'} < $1) {
+					$series{'season'} = $1;
+				}
+			}
+		}
+		closedir(SERIES);
+	}
+
+	# Validate the season number
+	if (!defined($series{'season'}) || $series{'season'} < 1 || $series{'season'} > 2000) {
+		die('Invalid season number: ' . $series{'name'} . ' => ' . $series{'season'} . "\n");
+	}
+
+	# Allow quality checks to be disabled
+	if (-e $series{'path'} . '/no_quality_checks') {
+		$series{'no_quality_checks'} = 1;
+		$CONFIG{'NO_QUALITY_CHECKS'} = 1;
+		if ($DEBUG) {
+			print STDERR 'Searching with no quality checks: ' . $series{'name'} . "\n";
+		}
+	}
+
+	# Allow use of more number formats
+	if (-e $series{'path'} . '/more_number_formats') {
+		$series{'more_number_formats'} = 1;
+		$CONFIG{'MORE_NUMBER_FORMATS'} = 1;
+		if ($DEBUG) {
+			print STDERR 'Searching with more number formats: ' . $series{'name'} . "\n";
+		}
+	}
+
+	# Read the search excludes file, if any
+	if (-e $series{'path'} . '/excludes') {
+		local $/ = undef;
+		open(EX, $series{'path'} . '/excludes')
+		  or die("Unable to open series excludes file: ${!}\n");
+		my $ex = <EX>;
+		close(EX);
+
+		$ex =~ s/^\s+//;
+		$ex =~ s/\s+$//;
+		my @excludes = split(/\s*,\s*/, $ex);
+		foreach my $ex (@excludes) {
+			$series{'excludes_hash'}->{$ex} = 1;
+			if (length($series{'exclude'})) {
+				$series{'exclude'} .= ' ';
+			}
+			$series{'exclude'} .= '-"' . $ex . '"';
+		}
+		$series{'exclude'} = uri_encode(' ' . $series{'exclude'});
+	}
+
+	# Get the last episode number
+	opendir(SEASON, $series{'path'} . '/Season ' . $series{'season'})
+	  or die("Unable to open season directory: ${!}\n");
+	while (my $file = readdir(SEASON)) {
+
+		# Skip support files
+		if ($file =~ /\.(?:png|xml|jpg|gif|tbn|txt|nfo|torrent)\s*$/i) {
+			next;
+		}
+
+		# Check for a season_done file
+		if ($file eq 'season_done') {
+			$series{'season_done'} = 1;
+			next;
+		}
+
+		# Extract the episode number
+		my ($num) = $file =~ /^\s*\.?(\d+)\s*\-\s*/i;
+		if (defined($num)) {
+			$num = int($num);
+			if ($DEBUG) {
+				print STDERR 'Found episode number: ' . $num . ' in file: ' . $file . "\n";
+			}
+
+			# Record it
+			$series{'episodes'}->{$num} = 1;
+		}
+	}
+	close(SEASON);
+
+	# Assume we need any missing episodes, and the next few (unless season_done is set)
+	my $highest = (sort { $b <=> $a } @{ $series{'need'} })[0];
+	for (my $i = 1 ; $i <= $highest ; $i++) {
+		if (!$series{'episodes'}->{$i}) {
+			push(@{ $series{'need'} }, $i);
+		}
+	}
+	if (!$series{'season_done'}) {
+		for (my $i = 1 ; $i <= $CONFIG{'NEXT_EPISODES'} ; $i++) {
+			push(@{ $series{'need'} }, $highest + $i);
+		}
+	}
+	if ($DEBUG) {
+		print STDERR 'Needed episodes: ' . join(', ', @{ $series{'need'} }) . "\n";
+	}
+
+	# Reverse the array for later matching
+	foreach my $episode (@{ $series{'need'} }) {
+		$series{'need_hash'}->{$episode} = 1;
+	}
+
+	# Log and return
+	if ($CONFIG{'SYSLOG'}) {
+		syslog(LOG_NOTICE, $series{'name'});
+	}
+	return \%series;
+}
+
 sub parseNZB($) {
 	my ($item) = @_;
 	if (!$item || ref($item) ne 'HASH' || !exists($item->{'guid'})) {