This is an old revision of the document!


mplayer-resume

mplayer-resume is a PHP shell script I wrote to resume playback of files through mplayer. It works using slave mode and LIRC with mplayer, which outputs the variables to stdout. The wrapper script then keeps these values, and uses them to jump to that last point.

Note that this code is an archived copy of the source code. It's unmaintained, but probably works.

README

MPlayer playback / resume position script This PHP script will save the playback position of a file you watch with MPlayer. Once you start playing the same file again, it will resume from last playback position. The *only* way this script will work is if you pass the “get_time_pos” command to MPlayer through an input event, mapped by either LIRC or the keyboard. The script captures the output and saves it to a file in the playback directory for each media file. See http://www.mplayerhq.hu/DOCS/tech/slave.txt for more commands that work on both backends. Installation: To execute this program, either call it using the PHP binary, or make it executable. Whichever you like best. :) $ php mplayer-resume movie.avi # cp mplayer-resume /usr/local/bin/ # chmod +x /usr/local/bin/mplayer-resume $ mplayer-resume –filename movie.avi The script should parse any arguments that you want to send mplayer at the same time, regardless of whether you start it as a standalone program or with php. Standalone: $ mplayer-resume –filename movie.avi -vo xv With php: $ php mplayer-resume –filename movie.avi -vo xv Syntax: mplayer-resume –filename <filename> [options] [mplayer options] As of v2.0, the syntax has changed. Previously, mplayer-resume would attempt to guess the correct filename, but in cases of movies with spaces in the file, it would cause problems. Now, you must define the filename manually with the –filename argument. MPlayer optional arguments: You can still pass all the normal arguments you would normally use when running mplayer. They will be passed to the command line after mplayer-resume has added it's own. $ mplayer-resume –filename “My movie.mkv” -vo xv -fs -ao sdl The *only* extra arguments that this script will add to your mplayer command is -ss to seek to resume a file, and -quiet so it can correctly grab the output. The script will also strip out any commands that are known to break the output. Currently the only one being stripped is “-really-quiet”. Optional arguments: Currently, mplayer-resume only supports one extra argument, a small feature added to the script to scratch a personal itch of mine. Passing –use-dir-conf to mplayer-resume will look for a file named “mplayer.conf” in the same directory of the filename you are playing, and if one exists, it will pass “-include <filename>” to the mplayer binary. This is just a little workaround to add a feature that mplayer doesn't currently implement. :) LIRC: Setup your ~/.lircrc file to do three things when you hit the stop button: 1) Get the time position 2) Get the filename 3) Stop playing Here's an example configuration: begin prog = mplayer button = stop config = get_time_pos end begin prog = mplayer button = stop config = get_filename end begin prog = mplayer button = stop config = quit end You can of course map any button on your remote that you'd like to use this function for. Keyboard: Map a key with ~/.mplayer/input.conf to run 'get_time_pos' Sample entry: g get_time_pos When you want to save the position, hit 'g', and then 'q' to quit playback. You can also do it manually using mplayer's slave mode, which is useful for debugging: $ mplayer -slave -quiet movie.avi get_time_pos quit Configuration: This script will save a text file for each media file you watch using this script. The text files are saved in the config variable $save_files_to defined in the script, which must be a directory that this script can read / write to. The script will try to automatically create a directory, and uses /home/username/.mplayer/resume/ by default. MythTV: If you are using MythVideo (http://www.mythtv.org/) and want to use mplayer-resume as your playback script instead of mplayer, it's easy to setup. From the main menu, go to: Utilities/Setup Video Settings Player Settings Change the entry for Default Player to: mplayer-resume %s Please note that you *do not* need to put quotes around the filename (as of v0.20.x), as MythTV will do it by itself. You can of course add any other extra MPlayer arguments as you normally may here. mplayer-resume -fs -vo xv -aspect 16/9 %s Notes: If your CLI version of PHP is dumping version information each time it runs, add -q to the top line to supress the output. #!/usr/bin/php -q Bugs: Doesn't save cwd with the file, so you can only have one entry per filename Help: If you get stuck, don't hesitate to contact me. http://wonkabar.org/contact-me

mplayer-resume 2.0
#!/usr/bin/env php
<?
 
	// By default, save files in ~/.mplayer/playback/
	$home = getenv('HOME');
	$save_files_to = "$home/.mplayer/playback/";
 
	/**
	 *
	 * @author Steve Dibb <steve dot dibb at gmail dot com>
	 * @copyright public-domain
	 * @date 2009-08-11
	 * @version 2.0
	 * @homepage http://spaceparanoids.org/trac/bend/wiki/mplayer-resume
	 * 
	 * Run time dependencies:
	 * PHP >= 4.3.0 with CLI and PCRE - http://php.net/
	 * MPlayer - http://mplayerhq.hu/
	 *
	 * See README for documentation on usage
	 * Quick example: mplayer-resume --filename "movie.mkv"
	 *
	 */
 
	/**
	 * Sends a string to stdout with a terminating line break
	 *
	 * @param string
	 * @param boolean display "mplayer-resume:" before each string
	 * 
	 */
	function stdout($str, $leading_string = true) {
		if(is_string($str)) {
			$str = rtrim($str);
			if($leading_string)
				$str = "mplayer-resume: $str";
			fwrite(STDOUT, "$str\n");
			return true;
		} else
			return false;
	}
 
	/**
	 * Sends a string to stderr with a terminating line break
	 *
	 * @param string
	 * 
	 */
	function stderr($str) {
		if(is_string($str)) {
			$str = rtrim($str);
			fwrite(STDERR, "mplayer-resume: $str\n");
			return true;
		} else
			return false;
	}
 
	/**
	 * Parse CLI arguments
	 *
	 * If a value is unset, it will be set to true
	 *
	 * @param $argc argument count (system variable)
	 * @param $argv argument array (system variable)
	 * @return array
	 */
	function parseArguments($argc, $argv) {
 
		$arr = array();
 
		if($argc > 1) {
			// Drop the binary command
			array_shift($argv);
 
			for($x = 0; $x < count($argv); $x++) {
				if(preg_match('/^--\w+/', $argv[$x]) > 0) {
					$argv[$x] = preg_replace('/^--/', '', $argv[$x]);
					$arr[$argv[$x]] = true;
				} elseif(in_array($argv[($x-1)], array_keys($arr))) {
					$arr[$argv[($x-1)]] = $argv[$x];
				}
			}
 
			return $arr;
		}
		else
			return array();
	}
 
	// Get the mplayer-resume arguments (not mplayer's)
	$args = parseArguments($argc, $argv);
 
	if($args['help'] || !count($args) || is_bool($movie) || $argc === 1) {
		stdout("Usage:\tmplayer-resume --filename <filename> [options] [mplayer options]", false);
		stdout("", false);
		stdout("Basic options:", false);
		stdout("", false);
		stdout(" --filename <filename>\tFilename to play with MPlayer", false);
		stdout(" --help \t\tThis help output", false);
		stdout("", false);
		stdout("Extended options:", false);
		stdout("", false);
		stdout(" --use-dir-conf\t\tPass \"-include <dirname of filename>/mplayer.conf\" to", false);
		stdout("\t\t\tmplayer if config file exists in same directory of", false);
		stdout("\t\t\tmedia file.  Similar to -use-filedir-conf.", false);
		stdout("", false);
		stdout("Example: $ mplayer-resume --filename \"A Man For All Seasons.mkv\" -fs -ao alsa", false);
		stdout("", false);
		stdout("mplayer-resume works by capturing events sent to MPlayer's slave mode", false);
		stdout("when exiting.  You will need to setup your MPlayer configuration files", false);
		stdout("to send the correct events in slave mode before this script will work.", false);
		stdout("", false);
		stdout("See the webpage for documentation:", false);
		stdout("http://spaceparanoids.org/trac/bend/wiki/mplayer-resume", false);
		die;
	}
 
	// Movie filename (used internally)
 	$movie = $filename = $args['filename'];
 
 	// PHP doesn't parse ~ as $HOME, so fix it ourselves
 	if(substr($movie, 0, 1) === "~")
 		$movie = $home.substr($movie, 1);
 
 	// Filename (escaped, ready to send to mplayer)
 	$mplayer_filename = escapeshellarg($movie);
 
 	stdout($movie);
 	stdout($mplayer_filename);
 
	// Check to see the config directory exists.  If not, try and create it.
	if(!is_dir($save_files_to)) {
		if(!mkdir($save_files_to)) {
			stderr("Please make sure the directory $save_files_to exists and is both readable and writable by this user");
			exit(1);
		}
	}
 
	// Make sure I can save playback files
	if(!is_writable($save_files_to) || !is_readable($save_files_to)) {
		stderr("I can't read from and/or write to $save_files_to");
		exit(1);
	}
 
	// Correct *some* human error ;)
	if(substr($save_files_to, -1, 1) != '/')
		$save_files_to .= '/';
 
	// Drop the binary from list of arguments
 	array_shift($argv);
 
	// Put the arguments back together again
	$str_args = implode(' ', $argv);
 
	// Drop the filename command
	$str_args = str_replace('--filename', '', $str_args);
 
	// Keep the movie filename separate from args
  	$str_args = str_replace($filename, '', $str_args);
 
	// Remove arguments which will break the script
	// -really-quiet means no output to our slave commands
	$str_args = str_replace('-really-quiet', '', $str_args);
 
	// Where the seek position will be saved
	$basename = basename($movie);
	$txt = $save_files_to.$basename.".txt";
 
	// If there is already a playback file, read it and start
	// from that position.
	if(file_exists($txt)) {
		$ss = trim(file_get_contents($txt));
		// One more check for garbage
		if(is_numeric($ss) && $ss > 0)
			$flags = " -ss $ss ";
	}
 
	/** Custom MPlayer workarounds */
 
	$custom_flags = array();
	$str_custom_flags = "";
 
	// --use-dir-conf
	// This is similar to -use-filedir-conf in mplayer.  It checks
	// to see if an "mplayer.conf" file exists in the directory of the
	// media file, and includes that.
	if($args['use-dir-conf']) {
 
		$str_args = str_replace("--use-dir-conf", "", $str_args);
 
		$conf = dirname($movie)."/mplayer.conf";
		if(file_exists($conf))
			$custom_flags[] = "-include ".escapeshellarg("$conf");
	}
 
 	if(count($custom_flags))
 		$str_custom_flags = implode(" ", $custom_flags);
 
	// Build the execution string
	$exec = "mplayer $mplayer_filename -quiet ".escapeshellcmd("$flags $str_args")." $str_custom_flags";
	stdout($exec);
 
	// Execute the command, save output to an array, and grab
	// return code to see if mplayer throws an error.
	exec($exec, $arr, $return);
 
	// If mplayer dies with a positive exit code, then it failed.
	// Don't write to or delete the saved position, and die
	// with the same exit code.
	if($return !== 0) {
		stderr("mplayer died unexpectedly");
		exit($return);
	}
 
	// If the file didn't even exist, mplayer will die, and so will me
	if(!file_exists($movie)) {
		stderr("Couldn't find the filename $movie");
		exit(1);
	}
 
	// Grep out the details we need from output
	$key_position = current(preg_grep('/^ANS_TIME_POSITION\b/', $arr));
	$key_filename = current(preg_grep('/^ANS_FILENAME\b/', $arr));
 
	// Get the position (in seconds) of the movie
	// Original format is ANS_TIME_POSITION=123.45
	$endpos = preg_replace('/^ANS_TIME_POSITION\=/', '', $key_position);
 
	// Get the filename of the movie we were playing
	// Original format is ANS_FILENAME='Your_Movie.avi'
	$slave_filename = preg_replace(
		array('/^ANS_FILENAME\=\'/', '/\'$/'), 
		array('', ''),
		$key_filename);
 
	// If we are playing from a playlist, then the two filenames
	// will not match.  Change the filename to be what we were
	// actually playing versus what we started out playing.
	if($slave_filename != $movie && !empty($slave_filename)) {
		$movie =& $slave_filename;
		$txt = $save_files_to.basename($movie).".txt";
	}
 
	// If it's a negative value, that means you've seeked
	// past/to the end of the file, so just remove the old one.
	if($endpos < 1 && file_exists($txt))
		unlink($txt);
	// No end position passed to mplayer-resume, so exit quietly
	elseif(empty($endpos)) {
		stderr("No end position sent to save.");
		exit(0);
	}
	// Save the (positive) playback position to the file
	else {
		// Generic error message, fix your stupid permissions
		$error_msg = "Cannot save file, please check write permissions for this user in $save_files_to";
		fwrite(fopen($txt, 'w'), $endpos) or stderr($error_msg);
	}
?>

ChangeLog

2.0 (2009-08-11)
	
	- Add --filename argument to specify filename directly, instead
	  of trying to guess what it is.
	- Add optional argument --use-filedir-conf, to include mplayer.conf
	  in local directory, and pass -include mplayer.conf to mplayer.

1.6 (2008-12-16)

	- Check exit codes on mplayer, so that if mplayer quits
	  unexpectedly, mplayer-resume won't kill the resume point.
	- Send exit codes

1.5 (2008-01-12)
	
	- Allow spaces in filenames.  Use mplayer-resume "filename"
	- Get the filename from MPlayer on exit, and use that to save
	the file to.  Useful for playlists.  See README.

1.3 (2006-09-15)

	- Call env instead of php directly
	- Get $HOME environment variable to save files to

1.2

	- Documentation updates

Navigation