public function processMpdDatabasefile() { $this->jobPhase = 1; $app = \Slim\Slim::getInstance(); $this->beginJob(array('msg' => $app->ll->str('importer.processing.mpdfile')), __FUNCTION__); // check if mpd_db_file exists if (is_file($app->config['mpd']['dbfile']) == FALSE || is_readable($app->config['mpd']['dbfile']) === FALSE) { $msg = $app->ll->str('error.mpd.dbfile', array($app->config['mpd']['dbfile'])); cliLog($msg, 1, 'red', TRUE); $this->finishJob(array('msg' => $msg)); $app->stop(); } # TODO: check if mpd-database file is plaintext or gzipped or sqlite # TODO: processing mpd-sqlite db or gzipped db $this->updateJob(array('msg' => $app->ll->str('importer.collecting.mysqlitems'))); // get timestamps of all tracks and directories from mysql database $fileTimestampsMysql = array(); $directoryTimestampsMysql = array(); // get all existing track-ids to determine orphans $deadMysqlFiles = array(); $query = "SELECT id, relativePathHash, relativeDirectoryPathHash, filemtime, directoryMtime FROM rawtagdata;"; $result = $app->db->query($query); while ($record = $result->fetch_assoc()) { $deadMysqlFiles[$record['relativePathHash']] = $record['id']; $fileTimestampsMysql[$record['relativePathHash']] = $record['filemtime']; // get the oldest directory timestamp stored in rawtagdata if (isset($directoryTimestampsMysql[$record['relativeDirectoryPathHash']]) === FALSE) { $directoryTimestampsMysql[$record['relativeDirectoryPathHash']] = 9999999999; } if ($record['directoryMtime'] < $directoryTimestampsMysql[$record['relativeDirectoryPathHash']]) { $directoryTimestampsMysql[$record['relativeDirectoryPathHash']] = $record['directoryMtime']; } } $dbFilePath = $app->config['mpd']['dbfile']; $this->updateJob(array('msg' => $app->ll->str('importer.testdbfile'))); // check if we have a plaintext or gzipped mpd-databasefile $isBinary = testBinary($dbFilePath); if ($isBinary === TRUE) { $this->updateJob(array('msg' => $app->ll->str('importer.gunzipdbfile'))); // decompress databasefile $bufferSize = 4096; // read 4kb at a time (raising this value may increase performance) $outFileName = APP_ROOT . 'cache/mpd-database-plaintext'; // Open our files (in binary mode) $inFile = gzopen($app->config['mpd']['dbfile'], 'rb'); $outFile = fopen($outFileName, 'wb'); // Keep repeating until the end of the input file while (!gzeof($inFile)) { // Read buffer-size bytes // Both fwrite and gzread and binary-safe fwrite($outFile, gzread($inFile, $bufferSize)); } // Files are done, close files fclose($outFile); gzclose($inFile); $dbFilePath = $outFileName; } $dbfile = explode("\n", file_get_contents($dbFilePath)); $currentDirectory = ""; $currentSong = ""; $currentPlaylist = ""; $currentSection = ""; $dirs = array(); //$songs = array(); //$playlists = array(); $dircount = 0; $unmodifiedFiles = 0; $level = -1; $opendirs = array(); // set initial attributes $mtime = 0; $time = 0; $artist = ''; $title = ''; $track = ''; $album = ''; $date = ''; $genre = ''; $mtimeDirectory = 0; foreach ($dbfile as $line) { if (trim($line) === "") { continue; // skip empty lines } $attr = explode(": ", $line, 2); array_map('trim', $attr); if (count($attr === 1)) { switch ($attr[0]) { case 'info_begin': break; case 'info_end': break; case 'playlist_end': // TODO: what to do with playlists fetched by mpd-database??? //$playlists[] = $currentDirectory . DS . $currentPlaylist; $currentPlaylist = ""; $currentSection = ""; break; case 'song_end': $this->itemCountChecked++; // single music files directly in mpd-musicdir-root must not get a leading slash $dirRelativePath = $currentDirectory === '' ? '' : $currentDirectory . DS; $directoryHash = getFilePathHash($dirRelativePath); // further we have to read directory-modified-time manually because there is no info // about mpd-root-directory in mpd-database-file $mtimeDirectory = $currentDirectory === '' ? filemtime($app->config['mpd']['musicdir']) : $mtimeDirectory; $trackRelativePath = $dirRelativePath . $currentSong; $trackHash = getFilePathHash($trackRelativePath); $this->updateJob(array('msg' => 'processed ' . $this->itemCountChecked . ' files', 'currentfile' => $currentDirectory . DS . $currentSong, 'deadfiles' => count($deadMysqlFiles), 'unmodified_files' => $unmodifiedFiles)); $insertOrUpdateRawtagData = FALSE; // compare timestamps of mysql-database-entry(rawtagdata) and mpddatabase if (isset($fileTimestampsMysql[$trackHash]) === FALSE) { cliLog('mpd-file does not exist in rawtagdata: ' . $trackRelativePath, 5); $insertOrUpdateRawtagData = TRUE; } else { if ($mtime > $fileTimestampsMysql[$trackHash]) { cliLog('mpd-file timestamp is newer: ' . $trackRelativePath, 5); $insertOrUpdateRawtagData = TRUE; } } if (isset($directoryTimestampsMysql[$directoryHash]) === FALSE) { cliLog('mpd-directory does not exist in rawtagdata: ' . $dirRelativePath, 5); $insertOrUpdateRawtagData = TRUE; } else { if ($mtimeDirectory > $directoryTimestampsMysql[$directoryHash]) { cliLog('mpd-directory timestamp is newer: ' . $trackRelativePath, 5); $insertOrUpdateRawtagData = TRUE; } } if ($insertOrUpdateRawtagData === FALSE) { // track has not been modified - no need for updating unset($fileTimestampsMysql[$trackHash]); unset($deadMysqlFiles[$trackHash]); $unmodifiedFiles++; } else { $t = new Rawtagdata(); if (isset($deadMysqlFiles[$trackHash])) { $t->setId($deadMysqlFiles[$trackHash]); // file is alive - remove it from dead items unset($deadMysqlFiles[$trackHash]); } $t->setArtist($artist); $t->setTitle($title); $t->setAlbum($album); $t->setGenre($genre); $t->setYear($date); $t->setTrackNumber($track); $t->setRelativePath($trackRelativePath); $t->setRelativePathHash($trackHash); $t->setRelativeDirectoryPath($dirRelativePath); $t->setRelativeDirectoryPathHash($directoryHash); $t->setDirectoryMtime($mtimeDirectory); $t->setFilemtime($mtime); $t->setMiliseconds($time * 1000); $t->setlastScan(0); $t->setImportStatus(1); $t->update(); unset($t); $this->itemCountProcessed++; } cliLog("#" . $this->itemCountChecked . " " . $currentDirectory . DS . $currentSong, 2); //$songs[] = $currentDirectory . DS . $currentSong; $currentSong = ""; $currentSection = ""; // reset song attributes $mtime = 0; $time = 0; $artist = ''; $title = ''; $track = ''; $album = ''; $date = ''; $genre = ''; break; default: break; } } if (isset($attr[1]) === TRUE) { // believe it or not - some people store html in their tags $attr[1] = preg_replace('!\\s+!', ' ', trim(strip_tags($attr[1]))); } switch ($attr[0]) { case 'directory': $currentSection = "directory"; break; case 'begin': $level++; $opendirs = explode(DS, $attr[1]); $currentSection = "directory"; $currentDirectory = $attr[1]; break; case 'song_begin': $currentSection = "song"; $currentSong = $attr[1]; break; case 'playlist_begin': $currentSection = "playlist"; $currentPlaylist = $attr[1]; break; case 'end': $level--; //$dirs[$currentDirectory] = TRUE; $dircount++; array_pop($opendirs); $currentDirectory = join(DS, $opendirs); $currentSection = ""; break; case 'mtime': if ($currentSection == "directory") { $mtimeDirectory = $attr[1]; } else { $mtime = $attr[1]; } break; case 'Time': $time = $attr[1]; break; case 'Artist': $artist = $attr[1]; break; case 'Title': $title = $attr[1]; break; case 'Track': $track = $attr[1]; break; case 'Album': $album = $attr[1]; break; case 'Genre': $genre = $attr[1]; break; case 'Date': $date = $attr[1]; break; } } // delete dead items in table:rawtagdata & table:track if (count($deadMysqlFiles) > 0) { \Slimpd\Rawtagdata::deleteRecordsByIds($deadMysqlFiles); \Slimpd\Track::deleteRecordsByIds($deadMysqlFiles); } cliLog("dircount: " . $dircount); cliLog("songs: " . $this->itemCountChecked); //cliLog("playlists: " . count($playlists)); # TODO: flag&handle dead items in mysql-database //cliLog("dead dirs: " . count($deadMysqlDirectories)); cliLog("dead songs: " . count($deadMysqlFiles)); #print_r($deadMysqlFiles); $this->itemCountTotal = $this->itemCountChecked; $this->finishJob(array('msg' => 'processed ' . $this->itemCountChecked . ' files', 'directorycount' => $dircount, 'deletedRecords' => count($deadMysqlFiles), 'unmodified_files' => $unmodifiedFiles), __FUNCTION__); // destroy large arrays unset($deadMysqlFiles); unset($fileTimestampsMysql); unset($directoryTimestampsMysql); return; }
$config['renderitems'] = array('genres' => \Slimpd\Genre::getInstancesForRendering($config['item']), 'labels' => \Slimpd\Label::getInstancesForRendering($config['item']), 'artists' => \Slimpd\Artist::getInstancesForRendering($config['item']), 'albums' => \Slimpd\Album::getInstancesForRendering($config['item'])); $config['totalitems'] = \Slimpd\Track::getCountAll(); $app->render('surrounding.twig', $config); }); $app->get('/maintainance/albumdebug/:itemParams+', function ($itemParams) use($app, $config) { $config['action'] = 'maintainance.albumdebug'; if (count($itemParams) === 1 && is_numeric($itemParams[0])) { $search = array('id' => (int) $itemParams[0]); } $config['album'] = \Slimpd\Album::getInstanceByAttributes($search); $tmp = \Slimpd\Track::getInstancesByAttributes(array('albumId' => $config['album']->getId())); $trackInstances = array(); $rawTagDataInstances = array(); foreach ($tmp as $t) { $config['itemlist'][$t->getId()] = $t; $config['itemlistraw'][$t->getId()] = \Slimpd\Rawtagdata::getInstanceByAttributes(array('id' => (int) $t->getId())); } #echo "<pre>" . print_r(array_keys($trackInstances),1) . "</pre>"; unset($tmp); $config['discogstracks'] = array(); $config['matchmapping'] = array(); $discogsId = $app->request->get('discogsid'); if ($discogsId !== NULL) { /* possible usecases: * we have same track amount on local side and discogs side * each local track matches to one discogs track * one ore more local track does not have a match on the discogs side * two local tracks matches one discogs-track * * we have more tracks on the local side * we have dupes on the local side