- 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>
423 lines
13 KiB
PHP
423 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* Add movies on a file system to the DB
|
|
*
|
|
* Pre-requsisions:
|
|
* mplayer:
|
|
* Test if installed with this command: mplayer -v
|
|
* If not installed use this command (Ubuntu) to install: sudo apt install mplayer
|
|
*
|
|
* Please change following variables
|
|
*
|
|
* movie_dirs -- list of directories to search for a new files
|
|
* update_missing -- if set to TRUE, the movie with a file in DB but not on a disk will be set as wanted
|
|
* update_moved -- if set to TRUE, if file was moved to a different location on a disk, the location in a DB will be updated to a new path
|
|
* clean_file_name -- is a substring in a name of the file you want to be removed when setting movie name
|
|
* skip_folders -- a list of subfolders to be skipped
|
|
*
|
|
* @package pages
|
|
* @author Alexander Mondshain <alex_mond@yahoo.com>
|
|
* @author Alexander Mondshain <klaus_edwin@hotmail.com>
|
|
* @version $Id: videoadd.php,v 1.3 2018/09/23 13:02:11 kec2 Exp $
|
|
*/
|
|
chdir('..');
|
|
|
|
require './core/functions.php';
|
|
|
|
// Movies on the file system.
|
|
// File name is key and full path is value.
|
|
$moviesFS = array();
|
|
// duplicate file on file system.
|
|
// File name is key and full path is value.
|
|
$doubles = array();
|
|
|
|
// NOTE : as a minimum change the following movie_dirs variable to point to a movie directory $movieDirs = array("/moviedir1","/moviedir2);
|
|
$movieDirs = array();
|
|
$movieExts = '(avi|mpg|bin|mpeg|ogm|bin|mkv|m2ts|iso)';
|
|
$cleanFileName = '(.avi|.mkv|.iso|.m2ts|XVID|XviD|XViD|Xvid|CD1)';
|
|
$skipFolders = '/^\.|^CVS|^lost|^photos|^music|^staff/';
|
|
|
|
// NOTE:update_missing, update missing files and associeted movies as wanted
|
|
// NOTE:update_moved. update moved files with a new file location
|
|
$update_missing = false;
|
|
$update_moved = false;
|
|
|
|
/**
|
|
* Check if MPlayer is installed.
|
|
*
|
|
* @return boolean True if it is installed.
|
|
*/
|
|
function isMPlayerInstalled()
|
|
{
|
|
$out = null;
|
|
$ret = - 1;
|
|
@exec("mplayer -v", $out, $ret);
|
|
return $ret == '0';
|
|
}
|
|
|
|
/**
|
|
* If a movies consits of multiple file then all but one will be removed.
|
|
* fx. Thor_CD1.avi, Thor_CD2.avi and Thor_CD3.avi => Thor_CD1.avi.
|
|
*/
|
|
function removeCDNumbers($moviesFS)
|
|
{
|
|
foreach ($moviesFS as $movie) {
|
|
$filePathParts = preg_split("/\//", $movie);
|
|
$fileName = end($filePathParts);
|
|
|
|
if (preg_match("/CD2/i", $movie)) {
|
|
unset($moviesFS[$fileName]);
|
|
} else if (preg_match("/CD3/i", $movie)) {
|
|
unset($moviesFS[$fileName]);
|
|
} else if (preg_match("/CD4/i", $movie)) {
|
|
unset($moviesFS[$fileName]);
|
|
}
|
|
}
|
|
return $moviesFS;
|
|
}
|
|
|
|
function getFileSizeLinux($file)
|
|
{
|
|
$out = null;
|
|
$ret = - 1;
|
|
@exec("stat -c %s \"$file\"", $out, $ret);
|
|
if ($ret != '0') {
|
|
return FALSE;
|
|
} else {
|
|
return ($out[0]);
|
|
}
|
|
}
|
|
|
|
function getFileTimeLinux($file)
|
|
{
|
|
$out = null;
|
|
$ret = - 1;
|
|
@exec("stat -c %Y \"$file\"", $out, $ret);
|
|
if ($ret != '0') {
|
|
return FALSE;
|
|
} else {
|
|
return ($out[0]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Get all movie files requrcily starting from \$dir.
|
|
*
|
|
* @param String $dir
|
|
* The starting point.
|
|
* @param String $ext
|
|
* Files with these file extensions are or included in the result.
|
|
* @param String $skip
|
|
* Directories to skip.
|
|
*/
|
|
function recurseDir($dir, $ext, $skip)
|
|
{
|
|
// echo "In DIR $dir<br>";
|
|
global $moviesFS, $doubles;
|
|
if ($dh = opendir($dir)) {
|
|
while ($file = readdir($dh)) {
|
|
// Exclude all dot file, CVS and lost+found directories
|
|
if (preg_match($skip, $file)) {
|
|
continue;
|
|
}
|
|
|
|
// If the file is a movie, we add it to the list
|
|
if (preg_match("/\.$ext$/", $file)) {
|
|
if (isset($moviesFS[$file])) {
|
|
array_push($doubles, $moviesFS[$file]);
|
|
array_push($doubles, "$dir/$file");
|
|
} else {
|
|
$moviesFS[$file] = "$dir/$file";
|
|
}
|
|
}
|
|
|
|
// If this is a directory we search it
|
|
if (is_dir("$dir/$file")) {
|
|
recurseDir("$dir/$file", $ext, $skip);
|
|
}
|
|
}
|
|
closedir($dh);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get combined file size of a movies with multiple files.
|
|
* fx. Thor_CD1.avi (100k), Thor_CD2.avi (200k) and Thor_CD3.avi (150k) => 450k.
|
|
*
|
|
* @param string $filePath
|
|
* Path to the first file.
|
|
* @return integer The size of the file(s).
|
|
*/
|
|
function getFileSize($filePath)
|
|
{
|
|
$fileSize = getFileSizeLinux($filePath);
|
|
|
|
if (preg_match("/CD1/i", $filePath)) {
|
|
$newfile = preg_replace("/(CD)(\d)/i", '${1}2', $filePath);
|
|
$fileSize += getFileSizeLinux($newfile);
|
|
|
|
$newfile = preg_replace("/(CD)(\d)/i", '${1}3', $filePath);
|
|
$fileSize += getFileSizeLinux($newfile);
|
|
|
|
$newfile = preg_replace("/(CD)(\d)/i", '${1}4', $filePath);
|
|
$fileSize += getFileSizeLinux($newfile);
|
|
}
|
|
|
|
return $fileSize;
|
|
}
|
|
|
|
/**
|
|
* Get metadata of a movie.
|
|
* Data include video codec, audio codec, video width and video height.
|
|
* MPlayer is used to retrive these data.
|
|
*
|
|
* @param String $filePath
|
|
* File path to the movie.
|
|
* @return array An assosiative array with keys: videoCodec, audioCodec, videoHeight and videoWidth.
|
|
*/
|
|
function getMetadata($filePath)
|
|
{
|
|
$metadata = array();
|
|
$command = "mplayer -vo null -ao null -frames 3 -identify \"$filePath\"";
|
|
// echo "command: ".$command."<br>";
|
|
$output = array();
|
|
$return_var = 0;
|
|
|
|
$match = array();
|
|
exec($command, $output, $return_var);
|
|
// parse mplayer output
|
|
foreach ($output as $line) {
|
|
trim($line);
|
|
|
|
if (preg_match("/ID_VIDEO_CODEC=(.*)/", $line, $match)) {
|
|
$videoCodec = strtolower($match[1]);
|
|
switch ($videoCodec) {
|
|
case 'ffh264':
|
|
$metadata['videoCodec'] = 'H.264';
|
|
break;
|
|
case 'ffvc1':
|
|
$metadata['videoCodec'] = 'VC1';
|
|
break;
|
|
case '0x10000001':
|
|
$metadata['videoCodec'] = 'MPEG1';
|
|
break;
|
|
case 'ffmpeg2':
|
|
$metadata['videoCodec'] = 'MPEG2';
|
|
break;
|
|
case '0x10000002':
|
|
$metadata['videoCodec'] = 'MPEG2';
|
|
break;
|
|
case 'mpg4':
|
|
$metadata['videoCodec'] = 'MPEG4';
|
|
break;
|
|
case 'div3':
|
|
$metadata['videoCodec'] = 'DivX3';
|
|
break;
|
|
case 'div4':
|
|
$metadata['videoCodec'] = 'DivX4';
|
|
break;
|
|
case 'divx':
|
|
$metadata['videoCodec'] = 'DivX4';
|
|
break;
|
|
case 'dx50':
|
|
$metadata['videoCodec'] = 'DivX5';
|
|
break;
|
|
case 'xvid':
|
|
$metadata['videoCodec'] = 'XviD';
|
|
break;
|
|
default:
|
|
$metadata['videoCodec'] = 'Unknown';
|
|
echo 'Unknown Video Codec: ' . $match[1] . '<br>';
|
|
}
|
|
} else if (preg_match("/ID_AUDIO_CODEC=(.*)/", $line, $match)) {
|
|
$audioCodec = strtolower($match[1]);
|
|
switch ($audioCodec) {
|
|
case 'fftruehd':
|
|
$metadata['audioCodec'] = 'Dolby TrueHD';
|
|
break;
|
|
case 'ffdca':
|
|
$metadata['audioCodec'] = 'DTS-HD Master Audio';
|
|
break;
|
|
case 'ffac3':
|
|
$metadata['audioCodec'] = 'AC-3';
|
|
break;
|
|
case 'a52':
|
|
$metadata['audioCodec'] = 'AC3';
|
|
break;
|
|
case 'pcm':
|
|
$metadata['audioCodec'] = 'Uncompressed PCM';
|
|
break;
|
|
case 'dvdpcm':
|
|
$metadata['audioCodec'] = 'Uncompressed DVD/VOB LPCM';
|
|
break;
|
|
case 'mad':
|
|
$metadata['audioCodec'] = 'MP3';
|
|
break;
|
|
case 'mp3':
|
|
$metadata['audioCodec'] = 'MP3';
|
|
break;
|
|
case 'ffvorbis':
|
|
$metadata['audioCodec'] = 'Vorbis';
|
|
break;
|
|
case 'ffwmav1':
|
|
$metadata['audioCodec'] = 'WMA1';
|
|
break;
|
|
case 'ffwmav2':
|
|
$metadata['audioCodec'] = 'WMA2';
|
|
break;
|
|
default:
|
|
$metadata['audioCodec'] = 'Unknown';
|
|
echo 'Unknown Audio Codec: ' . $match[1] . '<br>';
|
|
}
|
|
} else if (preg_match("/ID_VIDEO_WIDTH=(.*)/", $line, $match)) {
|
|
$metadata['videoWidth'] = $match[1];
|
|
} else if (preg_match("/ID_VIDEO_HEIGHT=(.*)/", $line, $match)) {
|
|
$metadata['videoHeight'] = $match[1];
|
|
}
|
|
}
|
|
|
|
return $metadata;
|
|
}
|
|
?>
|
|
|
|
<html>
|
|
<head>
|
|
<title>Add and move files</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
<meta name="description" content="VideoDB" />
|
|
<link rel="stylesheet" href="../<?php echo $config['style'] ?>"
|
|
type="text/css" />
|
|
</head>
|
|
<body>
|
|
<?php
|
|
|
|
if (!isMPlayerInstalled()) {
|
|
echo '<h1 style="color:red;">mplayer is not installed! Please install it.</h1><br>';
|
|
exit();
|
|
}
|
|
|
|
if (count($movieDirs) == 0) {
|
|
echo '<h1 style="color:red;">PLEASE edit the script and set at least one folder in \$movie_dirs variable </h1><br>';
|
|
exit();
|
|
}
|
|
|
|
// get all files. Result is in $moviesFS and $doubles;
|
|
foreach ($movieDirs as $dir) {
|
|
recurseDir($dir, $movieExts, $skipFolders);
|
|
}
|
|
|
|
// Get all movies that are not on the whishlist (50) or inserted by this tool (51)
|
|
$SELECT = 'SELECT id, filename FROM ' . TBL_DATA . ' WHERE mediatype < 50 ORDER BY filename';
|
|
$rows = runSQL($SELECT);
|
|
|
|
echo '<h3>Scanning...</h3>';
|
|
echo '<b>Total movie files found on disk:</b> ' . sizeof($moviesFS) . '<br>';
|
|
echo '<b>Total movie files found in DB:</b> ' . count($rows) . '<br><br>';
|
|
echo '<h3>Comparing results.</h3>';
|
|
|
|
foreach ($rows as $row) {
|
|
$filePathParts = preg_split("/\//", $row['filename']);
|
|
$fileName = end($filePathParts);
|
|
$id = $row['id'];
|
|
|
|
// The path does not match the path found in the database
|
|
if ($moviesFS[$fileName] != $row['filename']) {
|
|
if (! isset($moviesFS[$fileName])) {
|
|
echo "<b>MISSING</b> - <a href='../show.php?id={$id}'>{$fileName}</a><br>";
|
|
if ($update_missing) {
|
|
$UPDATE = "UPDATE " . TBL_DATA . " SET mediatype='" . MEDIA_WISHLIST . "' WHERE id='{$id}'";
|
|
runSQL($UPDATE);
|
|
}
|
|
} else {
|
|
echo "<b>MOVED</b> - <a href='../show.php?id={$id}'>{$fileName}</a><br>";
|
|
if ($update_moved) {
|
|
$UPDATE = "UPDATE " . TBL_DATA . " SET filename='" . escapeSQL($moviesFS[$fileName]) . "' WHERE id='{$id}'";
|
|
runSQL($UPDATE);
|
|
}
|
|
}
|
|
} else {
|
|
unset($moviesFS[$fileName]);
|
|
}
|
|
}
|
|
|
|
echo '<br><b>New files found:</b> ' . sizeof($moviesFS) . '<br>';
|
|
asort($moviesFS);
|
|
$moviesFS = removeCDNumbers($moviesFS);
|
|
echo '<b>New files found with no CD[2-3-4]:</b> ' . sizeof($moviesFS) . '<br>';
|
|
|
|
// remove all movies added last time and not updated with real information
|
|
// mediatype 51 indicates that the movie was inserted/modified by this tool.
|
|
$UPDATE = "DELETE FROM " . TBL_DATA . " WHERE mediatype='51'";
|
|
runSQL($UPDATE);
|
|
|
|
echo '<h3>Data on movies to add.</h3>';
|
|
echo "<table class='collapse'>
|
|
<tr>
|
|
<th>File Name</th>
|
|
<th>Title</th>
|
|
<th>File Size</th>
|
|
<th>Audio Codec</th>
|
|
<th>Video Codec</th>
|
|
<th>Video Width</th>
|
|
<th>Video Height</th>
|
|
<th>File Date</th>
|
|
</tr>";
|
|
|
|
$currentUserId = get_current_user_id();
|
|
|
|
foreach ($moviesFS as $movie) {
|
|
$filePathParts = preg_split("/\//", $movie);
|
|
$fileName = end($filePathParts);
|
|
$title = preg_replace($cleanFileName, '', $fileName);
|
|
$title = str_replace('_', ' ', $title);
|
|
|
|
$filePath = $moviesFS[end($filePathParts)];
|
|
$fileSize = (int) getFileSize($filePath);
|
|
$fileDate = getFileTimeLinux($filePath);
|
|
|
|
$metadata = getMetadata($filePath);
|
|
$audioCodec = $metadata['audioCodec'];
|
|
$videoCodec = $metadata['videoCodec'];
|
|
$videoWidth = (int) $metadata['videoWidth'];
|
|
$videoHeight = (int) $metadata['videoHeight'];
|
|
|
|
echo "<tr>
|
|
<td>$filePath</td>
|
|
<td>$title</td>
|
|
<td>$fileSize</td>
|
|
<td>$audioCodec</td>
|
|
<td>$videoCodec</td>
|
|
<td>$videoWidth</td>
|
|
<td>$videoHeight</td>
|
|
<td>$fileDate</td>
|
|
</tr>";
|
|
|
|
$UPDATE = "INSERT " . TBL_DATA . " SET filename='" . escapeSQL($filePath) . "',
|
|
mediatype = 51,
|
|
title = '$title',
|
|
filesize = $fileSize,
|
|
audio_codec = '$audioCodec',
|
|
video_codec = '$videoCodec',
|
|
video_width = $videoWidth,
|
|
video_height = $videoHeight,
|
|
owner_id = $currentUserId,
|
|
filedate = FROM_UNIXTIME($fileDate)";
|
|
|
|
runSQL($UPDATE);
|
|
}
|
|
echo '</table>';
|
|
|
|
$SELECT = "SELECT id, title FROM " . TBL_DATA . " WHERE mediatype='51' ORDER BY title";
|
|
$rows = runSQL($SELECT);
|
|
|
|
echo '<br><br><h3><New movies added (click to edit):</h3>';
|
|
foreach ($rows as $row) {
|
|
echo "<a href='../edit.php?id={$row['id']}'>{$row['title']}</a><br>";
|
|
}
|
|
|
|
?>
|
|
<h3>All Done</h3>
|
|
</body>
|
|
</html>
|