Просмотр исходного кода

Allow multiple items with the same name; apply most-specific-match-wins logic to arbitrate.

Consolidate attribute definitions to the app config
Zachary Kotlarek 13 лет назад
Родитель
Сommit
c3316a8dce
1 измененных файлов с 94 добавлено и 52 удалено
  1. 94 52
      dmx/rifftrax.pl

+ 94 - 52
dmx/rifftrax.pl

@@ -2,6 +2,7 @@
 use strict;
 use warnings;
 use File::Temp qw( tempfile );
+use Scalar::Util qw( refaddr );
 use Time::HiRes qw( usleep sleep time );
 use IPC::System::Simple qw( system capture );
 
@@ -38,6 +39,15 @@ my $OUTPUT_FILE  = $DATA_DIR . $STATE_SOCK;
 my $PULL_TIMEOUT = 60;
 my $DELAY        = $PULL_TIMEOUT / 3;
 my %RIFFS        = ();
+my %ATTRS        = (
+	'name'    => { 'dmx'   => 'PLAYING_TITLE',   'regex' => qr/^\s*Name:[ \t]*(\S.*\S)\s*$/mi },
+	'year'    => { 'dmx'   => 'PLAYING_YEAR',    'regex' => qr/^\s*Year:[ \t]*(\d{4})\s*$/mi },
+	'series'  => { 'dmx'   => 'PLAYING_SERIES',  'regex' => qr/^\s*Series:[ \t]*(\S.*\S)\s*$/mi },
+	'season'  => { 'dmx'   => 'PLAYING_SEASON',  'regex' => qr/^\s*Season:[ \t]*(\d+)\s*$/mi },
+	'episode' => { 'dmx'   => 'PLAYING_EPISODE', 'regex' => qr/^\s*Episode:[ \t]*(\d+)\s*$/mi },
+	'file'    => { 'regex' => qr/^\s*File:[ \t]*(\S.*\S)\s*$/mi },
+	'offset'  => { 'regex' => qr/^\s*Offset:[ \t]*([\-\+]?\d+(?:\.\d+)?)\s*$/mi },
+);
 
 # Debug
 my $DEBUG = 0;
@@ -177,7 +187,7 @@ while (1) {
 
 			# Close the audio file
 			Audio::unload('RIFF');
-			$riff   = 0;
+			$riff   = undef();
 			$leadin = 0;
 
 			# Warm fuzzies
@@ -186,49 +196,85 @@ while (1) {
 
 		# Activate a new RIFF, if applicable
 		# Always match on title, validate year if provided
-		if (   $RIFFS{$title}
-			&& (!exists($RIFFS{$title}{'year'})    || $RIFFS{$title}{'year'} eq $exists{'PLAYING_YEAR'})
-			&& (!exists($RIFFS{$title}{'series'})  || $RIFFS{$title}{'series'} eq $exists{'PLAYING_SERIES'})
-			&& (!exists($RIFFS{$title}{'season'})  || $RIFFS{$title}{'season'} eq $exists{'PLAYING_SEASON'})
-			&& (!exists($RIFFS{$title}{'episode'}) || $RIFFS{$title}{'episode'} eq $exists{'PLAYING_EPISODE'}))
-		{
-
+		if ($RIFFS{$title}) {
 			if ($DEBUG) {
-				print STDERR 'Matched RIFF: ' . $title . ' => ' . $RIFFS{$title}->{'file'} . "\n";
+				print STDERR 'Matched RIFF title: ' . $title . "\n";
 			}
-			$riff = $title;
 
-			# Warm fuzzies
-			DMX::say('RiffTrax initiated');
+			# Find the best available match among media with identical titles
+			my $match = undef();
+			{
+				my $matchAttrCount = 0;
+				foreach my $data (@{ $RIFFS{$title} }) {
+					my $valid     = 1;
+					my $attrCount = 0;
+					if ($DEBUG) {
+						print STDERR '';
+					}
+					foreach my $attr (keys(%ATTRS)) {
+						if (!exists($data->{$attr}) || !exists($ATTRS{$attr}{'dmx'})) {
+							next;
+						}
+						if ($data->{$attr} eq $exists{ $ATTRS{$attr}{'dmx'} }) {
+							if ($DEBUG) {
+								print STDERR "\t\tMatched attr: " . $attr . ' => ' . $data->{$attr} . "\n";
+							}
+							$attrCount++;
+						} else {
+							if ($DEBUG) {
+								print STDERR "\t\tFailed match for attr: " . $attr . ' => ' . $data->{$attr} . "\n";
+							}
+							$valid = 0;
+							last;
+						}
+					}
 
-			# Load and start the audio file
-			Audio::load('RIFF', $RIFFS{$riff}->{'file'});
-			playRiff();
+					# Record the match if it's better than previous matches
+					if ($valid && $attrCount > $matchAttrCount) {
+						$match          = $data;
+						$matchAttrCount = $attrCount;
+					}
+				}
+			}
+
+			# Match exists -- activate
+			if ($match) {
+				$riff = $match;
+
+				# Warm fuzzies
+				DMX::say('RiffTrax initiated');
+
+				# Load and start the audio file
+				Audio::load('RIFF', $riff->{'file'});
+				playRiff();
 
-			# Set volume when we load -- riffs should be louder than normal system sounds
-			Audio::systemVolume($VOLUME_RIFF);
-			Audio::volume('RIFF', 1.0);
+				# Set volume when we load -- riffs should be louder than normal system sounds
+				Audio::systemVolume($VOLUME_RIFF);
+				Audio::volume('RIFF', 1.0);
 
-			# Reduce the delay while playing so we sync faster
-			$delay = 1;
+				# Reduce the delay while playing so we sync faster
+				$delay = 1;
 
-			# Enable LEADIN if we're near the beginning of the movie
-			if ($RIFFS{$riff}->{'offset'} > $LEADIN_TIME && $videoTime < $LEADIN_TIME) {
-				playPausePlex();
-				$leadin = 1;
+				# Enable LEADIN if we're near the beginning of the movie
+				if ($riff->{'offset'} > $LEADIN_TIME && $videoTime < $LEADIN_TIME) {
+					playPausePlex();
+					$leadin = 1;
+				}
 			}
 		}
 	}
 
 	# If the RIFF has changed, save the state to disk
-	if ($riff ne $riffLast) {
+	if (   (defined($riff) != defined($riffLast))
+		|| (defined($riff) && ref($riff) && defined($riffLast) && ref($riffLast) && refaddr($riff) == refaddr($riffLast)))
+	{
 		my $new = '<none>';
 		if ($riff) {
-			$new = $RIFFS{$riff}->{'name'};
+			$new = $riff->{'name'};
 		}
 		my $old = $new;
 		if ($riffLast) {
-			$old = $RIFFS{$riffLast}->{'name'};
+			$old = $riffLast->{'name'};
 		}
 
 		if ($DEBUG) {
@@ -284,14 +330,14 @@ while (1) {
 		}
 
 		# Calculate the adjusted riff time and the error between the riff and video times
-		my $riffAdjTime = $riffTime - $RIFFS{$riff}->{'offset'};
+		my $riffAdjTime = $riffTime - $riff->{'offset'};
 		my $error       = $videoTime - $riffAdjTime;
 		my $errorAbs    = abs($error);
 
 		# Debug
 		if ($DEBUG) {
 			print STDERR "\tRate: " . $rate . "\n";
-			print STDERR "\tOffset: " . $RIFFS{$riff}->{'offset'} . "\n";
+			print STDERR "\tOffset: " . $riff->{'offset'} . "\n";
 			print STDERR "\tRiff time: " . $riffTime . "\n";
 			print STDERR "\tVideo time: " . $videoTime . "\n";
 			print STDERR "\tAdjusted riff time: " . $riffAdjTime . "\n";
@@ -311,7 +357,7 @@ while (1) {
 			}
 
 			# Start the movie when we reach the sync point
-			if ($RIFFS{$riff}->{'offset'} <= $riffTime) {
+			if ($riff->{'offset'} <= $riffTime) {
 				if (!$exists{'PLAYING'}) {
 					playPausePlex();
 				}
@@ -442,26 +488,13 @@ sub parseConfig($$) {
 
 			# Parse out the data we care about
 			my %data = ();
-			if ($text =~ /^\s*Name:[ \t]*(\S.*\S)\s*$/mi) {
-				$data{'name'} = $1;
-			}
-			if ($text =~ /^\s*Year:[ \t]*(\d{4})\s*$/mi) {
-				$data{'year'} = $1;
-			}
-			if ($text =~ /^\s*Series:[ \t]*(\S.*\S)\s*$/mi) {
-				$data{'series'} = $1;
-			}
-			if ($text =~ /^\s*Season:[ \t]*(\d+)\s*$/mi) {
-				$data{'season'} = $1;
-			}
-			if ($text =~ /^\s*Episode:[ \t]*(\d+)\s*$/mi) {
-				$data{'episode'} = $1;
-			}
-			if ($text =~ /^\s*File:[ \t]*(\S.*\S)\s*$/mi) {
-				$data{'file'} = $1;
-			}
-			if ($text =~ /^\s*Offset:[ \t]*([\-\+]?\d+(?:\.\d+)?)\s*$/mi) {
-				$data{'offset'} = $1 * 1.0;
+			foreach my $attr (keys(%ATTRS)) {
+				if (!exists($ATTRS{$attr}{'regex'})) {
+					next;
+				}
+				if ($text =~ $ATTRS{$attr}{'regex'}) {
+					$data{$attr} = $1;
+				}
 			}
 
 			# Ensure we have a valid record
@@ -485,11 +518,20 @@ sub parseConfig($$) {
 
 			# Debug
 			if ($DEBUG) {
-				print STDERR 'Added RiffTrax: ' . $data{'name'} . "\n\tFile: " . $data{'file'} . "\n\tOffset: " . $data{'offset'} . "\n";
+				print STDERR 'Added RiffTrax: ' . $file . "\n";
+				foreach my $attr (keys(%ATTRS)) {
+					if ($data{$attr}) {
+						print STDERR "\t" . $attr . ': ' . $data{$attr} . "\n";
+					}
+				}
 			}
 
 			# Push the data up the chain
-			$riffs->{ $data{'name'} } = \%data;
+			if (!exists($riffs->{ $data{'name'} })) {
+				my @tmp = ();
+				$riffs->{ $data{'name'} } = \@tmp;
+			}
+			push(@{ $riffs->{ $data{'name'} } }, \%data);
 		}
 	}
 	closedir(CONF);