- Add videodb PHP/MySQL media collection manager (Blu-ray, DVD, CD) - Dockerfile: PHP 8.1 + Apache with GD/mysqli/exif extensions - docker-compose.yml: app on port 6761 + MySQL 8.0 with health checks - docker-entrypoint.sh: auto-generates config.inc.php from env vars, waits for MySQL, initializes DB schema idempotently - init-db.php: CLI schema installer using app's own prefix_query() logic - Persistent volumes for DB, cache, and cover images Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
453 lines
11 KiB
PHP
453 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* Multi-engine glue logic
|
|
*
|
|
* @package Engines
|
|
*
|
|
* @todo Remove global $cache variable
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @version $Id: engines.php,v 1.45 2010/10/15 08:13:01 andig2 Exp $
|
|
*/
|
|
|
|
require_once './core/httpclient.php'; // include for all engines
|
|
require_once './core/encoding.php';
|
|
|
|
/**
|
|
* Determine the default engine
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @return string engine name
|
|
*/
|
|
function engineGetDefault()
|
|
{
|
|
global $config;
|
|
|
|
if (!empty($config['enginedefault']))
|
|
{
|
|
$engine = $config['enginedefault'];
|
|
}
|
|
elseif (count($engine_list = array_keys($config['engines'])))
|
|
{
|
|
// first valid engine from list
|
|
$engine = $engine_list[0];
|
|
}
|
|
else $engine = 'imdb'; // last resort
|
|
|
|
return $engine;
|
|
}
|
|
|
|
/**
|
|
* Determine engine from id
|
|
*
|
|
* @todo Enhance DB schema to store engine type explicitly
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @param string item id
|
|
* @return string engine name
|
|
*/
|
|
function engineGetEngine($id)
|
|
{
|
|
global $config;
|
|
|
|
// recognize engine from id
|
|
if ($id)
|
|
{
|
|
// engine prefixed (imdb:081547)
|
|
// currently working for imdb, amazon, amazoncom and tvcom
|
|
if (preg_match('/^(\w+):/', $id, $match)) $engine = $match[1];
|
|
elseif (preg_match('/^[0-9A-Z]{10,}$/', $id)) $engine = 'amazonaws'; // Amazon
|
|
}
|
|
if (empty($engine)) $engine = 'imdb';
|
|
return $engine;
|
|
}
|
|
|
|
/**
|
|
* Include engine file and retrieve item data
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @param string item id
|
|
* @param string engine name
|
|
* @return array item data
|
|
*/
|
|
function engineGetData($id, $engine = 'imdb')
|
|
{
|
|
global $lang, $cache;
|
|
|
|
if (!engine_load_engine($engine)) return array();
|
|
$func = $engine.'Data';
|
|
|
|
$result = array();
|
|
if (function_exists($func))
|
|
{
|
|
$cache = true;
|
|
$result = $func($id);
|
|
}
|
|
|
|
// make sure all engines properly return the encoding type
|
|
if (empty($result['encoding'])) errorpage('Engine Error', 'Engine '.$engine.' does not properly return encoding');
|
|
|
|
// set default encoding iso-8859-1
|
|
$source_encoding = ($result['encoding']) ? $result['encoding'] : $lang['encoding'];
|
|
$target_encoding = 'utf-8';
|
|
unset($result['encoding']);
|
|
|
|
// convert to unicode
|
|
if ($source_encoding != $target_encoding)
|
|
{
|
|
$result = iconv_array($source_encoding, $target_encoding, $result);
|
|
}
|
|
engine_clean_input($result);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Include engine file and execute item search
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @param string search string
|
|
* @param string engine name
|
|
* @return array list of item data
|
|
*/
|
|
function engineSearch($find, $engine = 'imdb', $para1 = null, $para2 = null)
|
|
{
|
|
global $lang, $cache;
|
|
|
|
if (!engine_load_engine($engine)) return array();
|
|
$func = $engine.'Search';
|
|
|
|
$result = array();
|
|
if (function_exists($func))
|
|
{
|
|
$cache = true;
|
|
// check if additional parameters given to avoid overriding default values
|
|
$result = (isset($para1)) ? $func($find, $para1, $para2) : $func($find);
|
|
}
|
|
|
|
// make sure all engines properly return the encoding type
|
|
# if (empty($result['encoding'])) errorpage('Engine Error', 'Engine does not properly return encoding');
|
|
|
|
// set default encoding iso-8859-1
|
|
$source_encoding = ($result['encoding']) ? $result['encoding'] : $lang['encoding'];
|
|
$target_encoding = 'utf-8';
|
|
unset($result['encoding']);
|
|
|
|
// convert to unicode
|
|
if ($source_encoding != $target_encoding)
|
|
{
|
|
#dump("Converting from $source_encoding to $target_encoding");
|
|
$result = iconv_array($source_encoding, $target_encoding, $result);
|
|
}
|
|
|
|
// obtain unique entries
|
|
$result = engine_deduplicate_result($result);
|
|
|
|
engine_clean_input($result);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Get item details URL in external site
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @param string item id
|
|
* @param string engine name
|
|
* @return string item details url
|
|
*/
|
|
function engineGetContentUrl($id, $engine = 'imdb')
|
|
{
|
|
if (empty($id)) return '';
|
|
if (!engine_load_engine($engine)) return '';
|
|
|
|
$func = $engine.'ContentUrl';
|
|
|
|
$result = '';
|
|
if (function_exists($func))
|
|
{
|
|
$result = $func($id);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Get recommendations for a specific movie that meets the requirements
|
|
* of rating and release year.
|
|
*
|
|
* @author Klaus Christiansen <klaus_edwin@hotmail.com>
|
|
* @param int $id The external movie id.
|
|
* @param float $rating The minimum rating for the recommended movies.
|
|
* @param int $year The minimum year for the recommended movies.
|
|
* @return array Associative array with: id, title, rating, year.
|
|
*/
|
|
function engineGetRecommendations($id, $rating, $year, $engine = 'imdb')
|
|
{
|
|
if (empty($id)) return '';
|
|
|
|
if (!engine_load_engine($engine)) return '';
|
|
$func = $engine.'Recommendations';
|
|
|
|
if (function_exists($func))
|
|
{
|
|
return $func($id, $rating, $year);
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Get complete search URL for external site
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @param string search string
|
|
* @param string engine name
|
|
* @return string item search url
|
|
*/
|
|
function engineGetSearchUrl($find, $engine = 'imdb')
|
|
{
|
|
if (!engine_load_engine($engine)) return '';
|
|
$func = $engine.'SearchUrl';
|
|
|
|
$result = '';
|
|
if (function_exists($func))
|
|
{
|
|
$result = $func($find);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* This function is used internally by setup and engines to add meta-engine of the engine's capability type
|
|
* e.g. if the youtube engine provides 'trailer' capability, this will add $config[engine][trailer] = (youtube)
|
|
*/
|
|
function engine_setup_meta($engine, $meta)
|
|
{
|
|
global $config;
|
|
|
|
if (array_key_exists('capabilities', $meta) && is_array($meta['capabilities'])) {
|
|
foreach ($meta['capabilities'] as $caps) {
|
|
$config['engine'][$caps][] = $engine;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve meta information about all available engines
|
|
*
|
|
* @author Andreas Goetz <cpuidle@gmx.de>
|
|
* @return array engines array containing engine names
|
|
*/
|
|
function engineMeta()
|
|
{
|
|
$engines = array();
|
|
|
|
if ($dh = @opendir(__DIR__))
|
|
{
|
|
while (($file = readdir($dh)) !== false)
|
|
{
|
|
if ((preg_match("/(.*)\.php$/", $file, $matches)) && ($matches[1] != 'engines'))
|
|
{
|
|
// engine file
|
|
$engine = $matches[1];
|
|
|
|
// get meta data
|
|
engine_load_engine($engine);
|
|
|
|
$func = $engine.'Meta';
|
|
|
|
if (function_exists($func))
|
|
{
|
|
$meta = $func();
|
|
$engines[$engine] = $meta;
|
|
|
|
// required php version present?
|
|
if (array_key_exists( 'php', $engines[$engine] ) && (version_compare(phpversion(), $engines[$engine]['php']) < 0))
|
|
{
|
|
unset($engines[$engine]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
closedir($dh);
|
|
}
|
|
|
|
return $engines;
|
|
}
|
|
|
|
/**
|
|
* Determine actor engine from actor id, defaults to imdb
|
|
*
|
|
* @author Michael Kollmann <acidity@online.de>
|
|
* @param string actor id
|
|
* @return string engine name
|
|
*/
|
|
function engineGetActorEngine($id)
|
|
{
|
|
// recognize engine from id
|
|
if ($id)
|
|
{
|
|
// actor engine prefixed, too? (imdb:nm0347149)
|
|
if (preg_match('/^(\w+):/', $id, $match)) $engine = $match[1];
|
|
elseif (preg_match('/^tv\d+$/', $id)) $engine = 'tvcom';
|
|
}
|
|
if (empty($engine)) $engine = 'imdb';
|
|
|
|
return $engine;
|
|
}
|
|
|
|
/**
|
|
* Get actors details URL in external site
|
|
*
|
|
* @author Michael Kollmann <acidity@online.de>
|
|
* @param string actor name
|
|
* @param string actor id
|
|
* @param string engine name
|
|
* @return string actor details url
|
|
*/
|
|
function engineGetActorUrl($name, $id, $engine = 'imdb')
|
|
{
|
|
if (!engine_load_engine($engine)) return '';
|
|
$func = $engine.'ActorUrl';
|
|
|
|
$result = '';
|
|
if (function_exists($func))
|
|
{
|
|
$id = preg_replace('|^'.$engine.':|', '', $id);
|
|
$result = $func($name, $id);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Include engine file and execute item search
|
|
*
|
|
* @author Michael Kollmann <acidity@online.de>
|
|
* @param string actor name
|
|
* @param string actor id
|
|
* @param string engine name
|
|
* @return array array with Actor-URL and Thumbnail
|
|
*/
|
|
function engineActor($name, $id, $engine = 'imdb')
|
|
{
|
|
global $cache;
|
|
|
|
if (!engine_load_engine($engine)) return array();
|
|
$func = $engine.'Actor';
|
|
|
|
$result = array();
|
|
if (function_exists($func))
|
|
{
|
|
$id = preg_replace('|^'.$engine.':|', '', $id);
|
|
|
|
$cache = true;
|
|
$result = $func($name, $id);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Callback function for validating if an engine has a certain capability
|
|
*/
|
|
function engine_get_capability($engine, $searchtype)
|
|
{
|
|
global $config;
|
|
|
|
// get the meta information
|
|
$engine = $config['engines'][$engine];
|
|
|
|
if (array_key_exists( 'capabilities', $engine) && is_array($engine['capabilities']))
|
|
{
|
|
return in_array($searchtype, $engine['capabilities']);
|
|
}
|
|
else
|
|
{
|
|
return $searchtype == 'movie';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get list of engines which have certain capability
|
|
*
|
|
* 'movie' search capability is assumed as default, either if
|
|
* $searchtype is empty or engine does not maintain specific capability
|
|
*
|
|
* @return array list of capable engines
|
|
*/
|
|
function engine_get_capable_engines($searchtype)
|
|
{
|
|
global $config;
|
|
|
|
if (!$searchtype) $searchtype = 'movie';
|
|
|
|
$engines = array();
|
|
foreach ($config['engines'] as $engine => $meta)
|
|
{
|
|
$enabled = $config['engine'][$engine];
|
|
if ($enabled && engine_get_capability($engine, $searchtype)) $engines[$engine] = $enabled;
|
|
}
|
|
|
|
return $engines;
|
|
}
|
|
|
|
/**
|
|
* Clean HTML tags from hierarchical associative array
|
|
*
|
|
* @param array $data string or hierarchical array to convert
|
|
*/
|
|
function engine_clean_input(&$data)
|
|
{
|
|
if (is_array($data)) foreach ($data as $key => $val)
|
|
{
|
|
if (is_array($val))
|
|
engine_clean_input($data[$key]);
|
|
else
|
|
{
|
|
$val = html_to_text($val);
|
|
$data[$key] = html_clean_utf8($val);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter result set for unique engine ids.
|
|
* This avoids deduplication of search results inside every single engine.
|
|
*/
|
|
function engine_deduplicate_result($data)
|
|
{
|
|
$keys = array();
|
|
for ($i=0; $i<count($data); $i++)
|
|
{
|
|
$id = $data[$i]['id'];
|
|
// early exit if engine (e.g. google images) doesn't return ids
|
|
if (!$id) return $data;
|
|
// exclude duplicates
|
|
if (in_array($id, $keys))
|
|
unset($data[$i]);
|
|
else
|
|
$keys[] = $id;
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Load the selected engine without errors
|
|
*
|
|
* @param string $engine
|
|
* @return bool
|
|
*/
|
|
function engine_load_engine($engine) {
|
|
if (file_exists(__DIR__ . '/' . $engine.'.php')) {
|
|
include_once __DIR__ . '/' . $engine.'.php';
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|