diff --git a/lib/RippingCluster/Config.class.php b/lib/RippingCluster/Config.class.php index 88d6064..66785a5 100644 --- a/lib/RippingCluster/Config.class.php +++ b/lib/RippingCluster/Config.class.php @@ -132,8 +132,8 @@ class RippingCluster_Config { } switch ($this->settings[$key]['type']) { - case TYPE_STRING_LIST: - return explode("\n", $this->settings[$key]['value']); + case self::TYPE_STRING_LIST: + return array_map('trim', explode("\n", $this->settings[$key]['value'])); default: return $this->settings[$key]['value']; diff --git a/lib/RippingCluster/Source.class.php b/lib/RippingCluster/Source.class.php index e602767..c3e907c 100644 --- a/lib/RippingCluster/Source.class.php +++ b/lib/RippingCluster/Source.class.php @@ -18,7 +18,7 @@ class RippingCluster_Source { $this->plugin = $plugin; } - public static function isCached($source_filename) { + public static function isSourceCached($source_filename) { $main = RippingCluster_Main::instance(); $cache = $main->cache(); $config = $main->config(); @@ -26,6 +26,14 @@ class RippingCluster_Source { return $cache->exists($source_filename, $config->get('rips.cache_ttl')); } + public function isCached() { + $main = RippingCluster_Main::instance(); + $cache = $main->cache(); + $config = $main->config(); + + return $cache->exists($this->filename, $config->get('rips.cache_ttl')); + } + public function cache() { if (!$this->exists) { throw new RippingCluster_Exception_InvalidSourceDirectory(); diff --git a/lib/RippingCluster/Source/Plugin/Bluray.class.php b/lib/RippingCluster/Source/Plugin/Bluray.class.php index b3a8c80..96c6082 100644 --- a/lib/RippingCluster/Source/Plugin/Bluray.class.php +++ b/lib/RippingCluster/Source/Plugin/Bluray.class.php @@ -19,13 +19,12 @@ class RippingCluster_Source_Plugin_Bluray extends RippingCluster_PluginBase impl $config = RippingCluster_Main::instance()->config(); $directories = $config->get('source.bluray.dir'); + $sources = array(); foreach ($directories as $directory) { if (!is_dir($directory)) { throw new RippingCluster_Exception_InvalidSourceDirectory($directory); } - $sources = array(); - $iterator = new RippingCluster_Utility_BlurayDirectoryIterator(new RippingCluster_Utility_VisibleFilesIterator(new DirectoryIterator($directory))); foreach ($iterator as /** @var SplFileInfo */ $source_vts) { $sources[] = self::load($source_vts->getPathname(), false); diff --git a/lib/RippingCluster/Source/Plugin/HandBrake.class.php b/lib/RippingCluster/Source/Plugin/HandBrake.class.php index d961023..aec5f88 100644 --- a/lib/RippingCluster/Source/Plugin/HandBrake.class.php +++ b/lib/RippingCluster/Source/Plugin/HandBrake.class.php @@ -25,13 +25,12 @@ class RippingCluster_Source_Plugin_HandBrake extends RippingCluster_PluginBase i $config = RippingCluster_Main::instance()->config(); $directories = $config->get('source.handbrake.dir'); + $sources = array(); foreach ($directories as $directory) { if (!is_dir($directory)) { throw new RippingCluster_Exception_InvalidSourceDirectory($directory); } - $sources = array(); - $iterator = new RippingCluster_Utility_DvdDirectoryIterator(new RippingCluster_Utility_VisibleFilesIterator(new DirectoryIterator($directory))); foreach ($iterator as /** @var SplFileInfo */ $source_vts) { $sources[] = self::load($source_vts->getPathname(), false); @@ -207,15 +206,15 @@ class RippingCluster_Source_Plugin_HandBrake extends RippingCluster_PluginBase i // Check all of the source directories specified in the config $source_directories = $config->get('source.handbrake.dir'); - foreach ($source_directories as $source_basedir) { + foreach ($source_directories as $source_basedir) { $real_source_basedir = realpath($source_basedir); - if (substr($real_source_filename, 0, strlen($real_source_basedir)) != $real_source_basedir) { - return false; + if (substr($real_source_filename, 0, strlen($real_source_basedir)) == $real_source_basedir) { + return true; } } - return true; + return false; } } diff --git a/lib/RippingCluster/Source/Plugin/MkvInfo.class.php b/lib/RippingCluster/Source/Plugin/MkvInfo.class.php new file mode 100644 index 0000000..c16ea8c --- /dev/null +++ b/lib/RippingCluster/Source/Plugin/MkvInfo.class.php @@ -0,0 +1,128 @@ +config(); + $directories = $config->get(self::CONFIG_SOURCE_DIR); + + $sources = array(); + foreach ($directories as $directory) { + if (!is_dir($directory)) { + throw new RippingCluster_Exception_InvalidSourceDirectory($directory); + } + + $iterator = new RippingCluster_Utility_MkvFileIterator(new RecursiveIteratorIterator(new RippingCluster_Utility_VisibleFilesRecursiveIterator(new RecursiveDirectoryIterator($directory)))); + foreach ($iterator as /** @var SplFileInfo */ $source_mkv) { + $sources[] = self::load($source_mkv->getPathname(), false); + } + } + + return $sources; + } + + /** + * Creates an object to represent the given source. + * + * The source is not actually scanned unless specifically requested. + * An unscanned object cannot be used until it has been manually scanned. + * + * If requested, the source can be cached to prevent high load, and long scan times. + * + * @param string $source_filename Filename of the source + * @param bool $scan Request that the source be scanned for content. Defaults to true. + * @param bool $use_cache Request that the cache be used. Defaults to true. + * @return RippingCluster_Source + */ + public static function load($source_filename, $scan = true, $use_cache = true) { + $cache = RippingCluster_Main::instance()->cache(); + + // Ensure the source is a valid directory, and lies below the configured source_dir + if ( ! self::isValidSource($source_filename)) { + return new RippingCluster_Source($source_filename, self::name(), false); + } + + $source = null; + if ($use_cache && $cache->exists($source_filename)) { + $source = unserialize($cache->fetch($source_filename)); + } else { + $source = new RippingCluster_Source($source_filename, self::name(), true); + + // TODO Populate source object with content + + // If requested, store the new source object in the cache + if ($use_cache) { + $source->cache(); + } + } + } + + /** + * Creates an object to represent the given source using an encoded filename. + * + * Wraps the call to load the source after the filename has been decoded. + * + * @param string $encoded_filename Encoded filename of the source + * @param bool $scan Request that the source be scanned for content. Defaults to true. + * @param bool $use_cache Request that the cache be used. Defaults to true. + * @return RippingCluster_Source + * + * @see RippingCluster_Source_IPlugin::load() + */ + public static function loadEncoded($encoded_filename, $scan = true, $use_cache = true) { + // Decode the filename + $source_filename = base64_decode(str_replace('-', '/', $encoded_filename)); + + return self::load($source_filename, $scan, $use_cache); + } + + /** + * Determins if a filename is a valid source loadable using this plugin + * + * @param string $source_filename Filename of the source + * @return bool + */ + public static function isValidSource($source_filename) { + $config = RippingCluster_Main::instance()->config(); + + // Ensure the source is a valid directory, and lies below the configured source_dir + if ( ! is_dir($source_filename)) { + return false; + } + $real_source_filename = realpath($source_filename); + + // Check all of the source directories specified in the config + $source_directories = $config->get(self::CONFIG_SOURCE_DIR); + foreach ($source_directories as $source_basedir) { + $real_source_basedir = realpath($source_basedir); + + if (substr($real_source_filename, 0, strlen($real_source_basedir)) != $real_source_basedir) { + return false; + } + } + + return true; + } + +} + +?> \ No newline at end of file diff --git a/lib/RippingCluster/Source/PluginFactory.class.php b/lib/RippingCluster/Source/PluginFactory.class.php index 89d6618..ec25bdc 100644 --- a/lib/RippingCluster/Source/PluginFactory.class.php +++ b/lib/RippingCluster/Source/PluginFactory.class.php @@ -31,7 +31,7 @@ class RippingCluster_Source_PluginFactory extends RippingCluster_PluginFactory { $sources = array(); foreach (self::getValidPlugins() as $plugin) { - $sources = array_merge($sources, self::enumerate($plugin)); + $sources[$plugin] = self::enumerate($plugin); } return $sources; diff --git a/lib/RippingCluster/Utility/MkvFileIterator.class.php b/lib/RippingCluster/Utility/MkvFileIterator.class.php new file mode 100644 index 0000000..37bd51d --- /dev/null +++ b/lib/RippingCluster/Utility/MkvFileIterator.class.php @@ -0,0 +1,9 @@ +current()->getFilename()); + } +} + +?> \ No newline at end of file diff --git a/lib/RippingCluster/Utility/VisibleFilesRecursiveIterator.class.php b/lib/RippingCluster/Utility/VisibleFilesRecursiveIterator.class.php new file mode 100644 index 0000000..151d938 --- /dev/null +++ b/lib/RippingCluster/Utility/VisibleFilesRecursiveIterator.class.php @@ -0,0 +1,9 @@ +current()->getFilename(), 0, 1) == '.'); + } +} + +?> \ No newline at end of file diff --git a/lib/RippingCluster/Worker/Plugin/FfmpegTranscode.class.php b/lib/RippingCluster/Worker/Plugin/FfmpegTranscode.class.php new file mode 100644 index 0000000..8d63063 --- /dev/null +++ b/lib/RippingCluster/Worker/Plugin/FfmpegTranscode.class.php @@ -0,0 +1,85 @@ +string) + */ + private $rip_options; + + /** + * Constructs a new instance of this Worker class + * + * @param GearmanJob $gearman_job GearmanJob object describing the task distributed to this worker + * @throws RippingCluster_Exception_LogicException + */ + private function __construct(GearmanJob $gearman_job) { + $this->output = ''; + + $this->gearman_job = $gearman_job; + + $this->rip_options = unserialize($this->gearman_job->workload()); + + if ( ! $this->rip_options['id']) { + throw new RippingCluster_Exception_LogicException("Job ID must not be zero/null"); + } + $this->job = RippingCluster_Job::fromId($this->rip_options['id']); + } + + /** + * Returns the list of functions (and names) implemented by this plugin for registration with Gearman + * + * @return array(string => callback) + */ + public static function workerFunctions() { + return array( + 'bluray_rip' => array(__CLASS__, 'rip'), + ); + } + + /** + * Creates an instance of the Worker plugin, and uses it to execute a single job + * + * @param GearmanJob $job Gearman Job object, describing the work to be done + */ + public static function rip(GearmanJob $job) { + $rip = new self($job); + $rip->execute(); + } + + /** + * Executes the process for ripping the source to the final output + * + */ + private function execute() { + // TODO + } + +} + +?> \ No newline at end of file diff --git a/webui/pages/rips/sources.php b/webui/pages/rips/sources.php index 3aadca0..b9fc539 100644 --- a/webui/pages/rips/sources.php +++ b/webui/pages/rips/sources.php @@ -3,14 +3,7 @@ $main = RippingCluster_Main::instance(); $config = $main->config(); -$sources = RippingCluster_Source_PluginFactory::enumerateAll(); - -$sources_cached = array(); -foreach ($sources as $source) { - $sources_cached[$source->filename()] = RippingCluster_Source::isCached($source->filename()); -} - -$this->smarty->assign('sources', $sources); -$this->smarty->assign('sources_cached', $sources_cached); +$all_sources = RippingCluster_Source_PluginFactory::enumerateAll(); +$this->smarty->assign('all_sources', $all_sources); ?> \ No newline at end of file diff --git a/webui/templates/rips/sources.tpl b/webui/templates/rips/sources.tpl index 46951af..c0cbb1a 100644 --- a/webui/templates/rips/sources.tpl +++ b/webui/templates/rips/sources.tpl @@ -1,6 +1,6 @@

Sources

-{if $sources} +{if $all_sources}

The list below contains all the DVD sources that are available and ready for ripping.

@@ -9,19 +9,32 @@ Sources that have not been cached will be scanned when the link is clicked, and this may take several minutes so please be patient.

{else}

- There are currently no DVD sources available to rip. + There are currently no sources available to rip.

{/if}