- 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>
332 lines
10 KiB
PHP
Executable File
332 lines
10 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Dvdfr Parser
|
|
*
|
|
* Parses data from www.dvdfr.com (french site)
|
|
* 2006-08-12 Update Sebastien Koechlin <seb.videodb@koocotte.org>
|
|
*
|
|
* @package Engines
|
|
* @author tedemo <tedemo@free.fr>
|
|
* @link http://www.dvdfr.com
|
|
* @version $Id: dvdfr.php,v 1.7 2011/06/23 12:27:28 robelix Exp $
|
|
*/
|
|
|
|
require_once './core/compatibility.php';
|
|
|
|
$GLOBALS['dvdfrServer'] = 'https://www.dvdfr.com';
|
|
$GLOBALS['dvdfrIdPrefix'] = 'dvdfr:';
|
|
|
|
/**
|
|
* Get meta information about the engine
|
|
*
|
|
* @todo Include image search capabilities etc in meta information
|
|
*/
|
|
function dvdfrMeta()
|
|
{
|
|
return array('name' => 'Dvdfr (fr)', 'stable' => 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Clean a string
|
|
*
|
|
* @param string The string to clean
|
|
* @return string The cleaned string
|
|
*/
|
|
function dvdfrCleanStr($str)
|
|
{
|
|
// Remove spaces
|
|
$str = trim($str);
|
|
|
|
// Translate strange (MS-Word?) quotes
|
|
$str = preg_replace( '/'/', '\'', $str );
|
|
|
|
// Remove HTML entities
|
|
$str = html_entity_decode($str);
|
|
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* Get Url to search Dvdfr for a movie
|
|
*
|
|
* @param string The search string
|
|
* @return string The search URL (GET)
|
|
*/
|
|
function dvdfrSearchUrl($title)
|
|
{
|
|
global $dvdfrServer;
|
|
return $dvdfrServer.'/api/search.php?title='.urlencode(mb_convert_encoding($title,'ISO-8859-15','UTF-8'));
|
|
}
|
|
|
|
/**
|
|
* Get Url to visit Dvdfr for a specific movie
|
|
*
|
|
* @param string $id The movie's external id
|
|
* @return string The visit URL
|
|
*/
|
|
function dvdfrContentUrl($id)
|
|
{
|
|
list($engineword, $dvdfrID) = explode(':',$id,2);
|
|
global $dvdfrServer;
|
|
return $dvdfrServer.'/api/dvd.php?id='.$dvdfrID;
|
|
#return 'http://koocotte.org/DVDMARK';
|
|
}
|
|
|
|
/**
|
|
* Search a Movie
|
|
*
|
|
* Searches for a given title on Dvdfr and returns the found links in
|
|
* an array
|
|
*
|
|
* @return array Associative array with id and title
|
|
*/
|
|
function dvdfrSearch($title)
|
|
{
|
|
global $dvdfrServer;
|
|
global $CLIENTERROR;
|
|
|
|
$para['useragent'] = 'VideoDB (http://www.videodb.net/)';
|
|
|
|
$resp = httpClient(dvdfrSearchUrl($title), 1, $para);
|
|
if (!$resp['success']) $CLIENTERROR .= $resp['error']."\n";
|
|
|
|
// Encoding
|
|
$ary['encoding'] = $resp['encoding'];
|
|
|
|
/* No more direct match with XLM API
|
|
|
|
// direct match (redirecting to individual title)?
|
|
$single = array();
|
|
if (preg_match('/\/dvd\/dvd\.php\?id=(\d+)/', $resp['url'], $single))
|
|
{
|
|
$ary[0]['id'] = 'dvdfr:'.$single[1];
|
|
preg_match('/<td><div class=\"dvd_title\">([^<]+)<\/div>[^<]*<div class=\"dvd_titlevo\">([^<]+)<\/div>[^<]*<div class=\"dvd_titleinfo\">([^<]+)</is', $resp['data'], $single);
|
|
$ary[0]['title']= $single[1].' ('.$single[2].'/'.$single[3].')';
|
|
return $ary;
|
|
}
|
|
*/
|
|
// multiple matches
|
|
/*
|
|
<dvd>
|
|
<id>16892</id> <= $1
|
|
<media>DVD</media> <= $2
|
|
<titres>
|
|
<fr>Star Wars - Clone Wars - Vol. 1</fr> <= $3
|
|
<vo>Star Wars: Clone Wars</vo> <= $4
|
|
<alternatif></alternatif>
|
|
<alternatif_vo></alternatif_vo>
|
|
</titres>
|
|
<annee>2003</annee> <= $5
|
|
<edition></edition> <= $6
|
|
<editeur>20th Century Fox</editeur> <= $7
|
|
<stars>
|
|
<star type="Réalisateur" id="49661">Genndy Tartakovsky</star>
|
|
</stars>
|
|
</dvd>
|
|
*/
|
|
|
|
preg_match_all('#<dvd>\s*<id>(\d+)</id>\s*<media>(\w+)</media>\s*<titres>\s*<fr>(.+?)</fr>\s*<vo>(.*?)</vo>.*?<annee>(.*?)</annee>\s*<edition>(.*?)</edition>\s*<editeur>(.*?)</editeur>\s*.*?</dvd>#is', $resp['data'], $data, PREG_SET_ORDER);
|
|
foreach ($data as $row)
|
|
{
|
|
$info['id'] = 'dvdfr:'.$row[1];
|
|
$title = dvdfrCleanStr($row[3]);
|
|
// add native title
|
|
if( !empty($row[4]) ) $title .= " / " . dvdfrCleanStr($row[4]);
|
|
|
|
if( !empty($row[5]) and !empty($row[6]) and !empty($row[7]) ) {
|
|
$title .= ' (';
|
|
// add year (helpful in case of multiple matches)
|
|
if( !empty($row[5]) ) $title .= dvdfrCleanStr($row[5]);
|
|
$title .= '/';
|
|
// add edition and editor
|
|
if( !empty($row[6]) ) $title .= dvdfrCleanStr($row[6]);
|
|
$title .= '/';
|
|
if( !empty($row[7]) ) $title .= dvdfrCleanStr($row[7]);
|
|
$title .=')';
|
|
}
|
|
|
|
// Add record
|
|
$info['title'] = $title;
|
|
$ary[] = $info;
|
|
}
|
|
|
|
return $ary;
|
|
}
|
|
|
|
/**
|
|
* Fetches the data for a given Dvdfr-ID
|
|
*
|
|
* @param int IMDB-ID
|
|
* @return array Result data
|
|
*/
|
|
function dvdfrData($imdbID)
|
|
{
|
|
global $dvdfrServer;
|
|
global $CLIENTERROR;
|
|
|
|
$data= array(); // result
|
|
$ary = array(); // temp
|
|
|
|
$para['useragent'] = 'VideoDB (http://www.videodb.net/)';
|
|
|
|
// fetch mainpage
|
|
$resp = httpClient(dvdfrContentUrl($imdbID), 1, $para); // added trailing / to avoid redirect
|
|
if (!$resp['success']) $CLIENTERROR .= $resp['error']."\n";
|
|
|
|
// add encoding
|
|
$data['encoding'] = $resp['encoding'];
|
|
|
|
// See http://www.dvdfr.com/api/dvd.php?id=2869 for output
|
|
|
|
// Titles
|
|
preg_match('#<titres>\s*<fr>(.+?)</fr>\s*<vo>(.+?)</vo>#is', $resp['data'], $ary);
|
|
$data['title'] = mb_convert_case(dvdfrCleanStr($ary[1]), MB_CASE_TITLE, $data['encoding']);
|
|
$data['subtitle'] = mb_convert_case(dvdfrCleanStr($ary[2]), MB_CASE_TITLE, $data['encoding']);
|
|
|
|
// I found: <div class="dvd_titleinfo">USA, Royaume-Uni , 2004<br />R&D TV, Sky TV, USA Cable Entertainment</div>
|
|
preg_match('#<listePays>\s*<pays.*?>(.+?)</pays>#is', $resp['data'], $ary);
|
|
$data['country'] = dvdfrCleanStr($ary[1]);
|
|
preg_match('#<annee>(\d+)</annee>#is', $resp['data'], $ary);
|
|
$data['year'] = dvdfrCleanStr($ary[1]);
|
|
|
|
// Cover URL
|
|
preg_match('#<cover>(.*?)</cover>#i', $resp['data'], $ary);
|
|
$data['coverurl'] = trim($ary[1]);
|
|
|
|
// Runtime
|
|
preg_match('#<duree>(\d+)</duree>#i', $resp['data'], $ary);
|
|
$data['runtime'] = $ary[1];
|
|
|
|
// Director (only the first one)
|
|
preg_match('#<star type="R.*?alisateur" id="\d+">(.*?)</star>#i', $resp['data'], $ary);
|
|
$data['director'] = dvdfrCleanStr($ary[1]);
|
|
|
|
// Plot
|
|
preg_match('#<synopsis>(.*?)</synopsis>#is', $resp['data'], $ary);
|
|
if (!empty($ary[1])) {
|
|
$data['plot'] = $ary[1];
|
|
// And cleanup
|
|
$data['plot'] = preg_replace('/[\n\r]/',' ', $data['plot']);
|
|
$data['plot'] = preg_replace('/\s+/',' ', $data['plot']);
|
|
$data['plot'] = dvdfrCleanStr($data['plot']);
|
|
}
|
|
|
|
// maps dvdfr category ids to videodb category names
|
|
$category_map = array
|
|
(
|
|
"1" => "Action",
|
|
"2" => "Animation",
|
|
"61" => "", // "Autres séries"
|
|
"3" => "Adventure",
|
|
"72" => "", //"Beaux-Arts"
|
|
"81" => "Musical", //"Bollywood"
|
|
"4" => "Comedy",
|
|
"5" => "Drama", // "Comédie dramatique"
|
|
"6" => "Musical", //"Comédie musicale"
|
|
"74" => "Romance", // "Comédie romantique"
|
|
"7" => "Music", //"Concert"
|
|
"8" => "" , //"Conte"
|
|
"9" => "Short", //"Court-Métrage"
|
|
"10" => "Documentary", //"Culture"
|
|
"78" => "Documentary", //"Culture Gay"
|
|
"11" => "Music", //"Danse"
|
|
"12" => "", //"Divers"
|
|
"13" => "Documentary", //"Documentaire"
|
|
"14" => "Drama", //"Drame"
|
|
"73" => "Drama", //"Emotion"
|
|
"15" => "Adult", //"Erotique"
|
|
"16" => "Action", //"Espionnage"
|
|
"17" => "Sci-Fi", //"Fantastique"
|
|
"30" => "Musical", //"Film musical"
|
|
"83" => "Sport", //"Freefight"
|
|
"18" => "War", //"Guerre"
|
|
"19" => "Musical", //"Hard-rock"
|
|
"20" => "History", //"Historique"
|
|
"21" => "Horror", //"Horreur"
|
|
"22" => "Comedy", //"Humour"
|
|
"23" => "Animation", //"Japanimation"
|
|
"24" => "Adult", //"Japanimation érotique"
|
|
"25" => "Music", //"Jazz & Blues"
|
|
"79" => "", //"Jeux"
|
|
"26" => "Music", //"Karaoke"
|
|
"27" => "Action", //"Kung Fu"
|
|
"28" => "", //"Méthode"
|
|
"57" => "", //"Mini-series / Feuilletons"
|
|
"29" => "Documentary", //"Muet"
|
|
"32" => "Music", //"Musique Classique"
|
|
"71" => "Music", //"Musiques du monde"
|
|
"31" => "Music", //"Opéra"
|
|
"33" => "War", //"Péplum"
|
|
"34" => "Crime", //"Policier"
|
|
"54" => "", //"Pour enfants"
|
|
"76" => "Music", //"R&B & Soul"
|
|
"55" => "Music", //"Rap"
|
|
"56" => "Sci-Fi", //"Science Fiction"
|
|
"60" => "", //"Série Anime / OAV"
|
|
"75" => "", //"Série d'animation enfants"
|
|
"58" => "", //"Série TV"
|
|
"59" => "", //"Sitcom"
|
|
"62" => "", //"Spectacle"
|
|
"63" => "Sport",
|
|
"82" => "Sport", //"Sports mécaniques"
|
|
"64" => "Music", //"Techno / Electro"
|
|
"65" => "", //"Theatre"
|
|
"66" => "Thriller",
|
|
"67" => "Music", //"Variété française"
|
|
"68" => "Music", //"Variété internationale"
|
|
"69" => "Documentary", //"Voyages"
|
|
"70" => "Western",
|
|
"Science Fiction" => "Sci-Fi",
|
|
);
|
|
|
|
// Genres (as Array)
|
|
if (preg_match_all('#<categorie>(.*?)</categorie>#i', $resp['data'], $ary, PREG_PATTERN_ORDER) > 0)
|
|
{
|
|
$count = 0;
|
|
while (isset($ary[1][$count]))
|
|
{
|
|
$data['genres'][] = $category_map[dvdfrCleanStr($ary[1][$count])];
|
|
$count ++;
|
|
}
|
|
}
|
|
|
|
// Cast
|
|
if( preg_match('#<stars>(.*)</stars>#is', $resp['data'], $Section) ) {
|
|
preg_match_all('#<star type="Acteur" id="(\d+)">(.*?)</star>#i', $Section[1], $ary,PREG_PATTERN_ORDER);
|
|
$cast = '';
|
|
for ($i=0; $i < sizeof($ary[0]); $i++)
|
|
{
|
|
$cast .= dvdfrCleanStr($ary[2][$i]) . '::::dvdfr' . dvdfrCleanStr($ary[1][$i]) . "\n";
|
|
#$cast .= "$actor::$character::$imdbIdPrefix$actorid\n";
|
|
}
|
|
$data['cast'] = dvdfrCleanStr($cast);
|
|
}
|
|
|
|
#// Convert ISO to UTF8
|
|
#$encoding = $data['encoding'];
|
|
#foreach( $data as $k => $v ) {
|
|
# $data[$k] = mb_convert_encoding(trim($v),'UTF-8',$encoding);
|
|
#}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Parses Actor-Details
|
|
*
|
|
* Find image and detail URL for actor, not sure if this can be made
|
|
* a one-step process? Completion waiting on update of actor
|
|
* functionality to support more than one engine.
|
|
*
|
|
* @param string $name Name of the Actor
|
|
* @return array array with Actor-URL and Thumbnail
|
|
*/
|
|
function dvdfrActor($name, $actorengineid)
|
|
{
|
|
global $dvdfrServer;
|
|
|
|
return;
|
|
}
|
|
|