AzuraCast/app/src/AzuraCast/Sync/Media.php

217 lines
6.4 KiB
PHP

<?php
namespace AzuraCast\Sync;
use App\Debug;
use Doctrine\Common\Persistence\Mapping\MappingException;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Entity;
use Monolog\Logger;
class Media extends SyncAbstract
{
/** @var EntityManager */
protected $em;
/**
* @param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function run($force = false)
{
$stations = $this->em->getRepository(Entity\Station::class)->findAll();
foreach ($stations as $station) {
$this->importMusic($station);
}
}
public function importMusic(Entity\Station $station)
{
$base_dir = $station->getRadioMediaDir();
if (empty($base_dir)) {
return;
}
$music_files_raw = $this->globDirectory($base_dir);
$music_files = [];
foreach ($music_files_raw as $music_file_path) {
$path_short = str_replace($base_dir . '/', '', $music_file_path);
$path_hash = md5($path_short);
$music_files[$path_hash] = $path_short;
}
/** @var Entity\Repository\SongRepository $song_repo */
$song_repo = $this->em->getRepository(Entity\Song::class);
$existing_media_q = $this->em->createQuery('SELECT sm FROM Entity\StationMedia sm WHERE sm.station_id = :station_id')
->setParameter('station_id', $station->getId());
$existing_media = $existing_media_q->iterate();
$i = 0;
foreach ($existing_media as $media_row_iteration) {
/** @var Entity\StationMedia $media_row */
$media_row = $media_row_iteration[0];
// Check if media file still exists.
$full_path = $base_dir . '/' . $media_row->getPath();
if (file_exists($full_path)) {
$force_reprocess = false;
if (empty($media_row->getUniqueId())) {
$media_row->generateUniqueId();
$force_reprocess = true;
}
// Check for modifications.
$song_info = $media_row->loadFromFile($force_reprocess);
if (is_array($song_info)) {
$media_row->setSong($song_repo->getOrCreate($song_info));
}
$this->em->persist($media_row);
$path_hash = md5($media_row->getPath());
unset($music_files[$path_hash]);
} else {
// Delete the now-nonexistent media item.
$this->em->remove($media_row);
}
// Batch processing
if ($i % 20 === 0) {
$this->_flushAndClearRecords();
}
++$i;
}
$this->_flushAndClearRecords();
// Create files that do not currently exist.
$i = 0;
foreach ($music_files as $new_file_path) {
$media_row = new Entity\StationMedia($station, $new_file_path);
$song_info = $media_row->loadFromFile();
if (is_array($song_info)) {
$media_row->setSong($song_repo->getOrCreate($song_info));
}
$this->em->persist($media_row);
if ($i % 20 === 0) {
$this->_flushAndClearRecords();
}
++$i;
}
$this->_flushAndClearRecords();
}
/**
* Flush the Doctrine Entity Manager and clear associated records to save memory space.
*/
protected function _flushAndClearRecords()
{
$this->em->flush();
try {
$this->em->clear(Entity\StationMedia::class);
$this->em->clear(Entity\StationMediaArt::class);
$this->em->clear(Entity\Song::class);
} catch (MappingException $e) {}
}
public function importPlaylists(Entity\Station $station)
{
$base_dir = $station->getRadioPlaylistsDir();
if (empty($base_dir)) {
return;
}
// Create a lookup cache of all valid imported media.
$media_lookup = [];
foreach ($station->getMedia() as $media) {
/** @var Entity\StationMedia $media */
$media_path = $media->getFullPath();
$media_hash = md5($media_path);
$media_lookup[$media_hash] = $media;
}
// Iterate through playlists.
$playlist_files_raw = $this->globDirectory($base_dir, '/^.+\.(m3u|pls)$/i');
foreach ($playlist_files_raw as $playlist_file_path) {
// Create new StationPlaylist record.
$record = new Entity\StationPlaylist($station);
$path_parts = pathinfo($playlist_file_path);
$playlist_name = str_replace('playlist_', '', $path_parts['filename']);
$record->setName($playlist_name);
$playlist_file = file_get_contents($playlist_file_path);
$playlist_lines = explode("\n", $playlist_file);
$this->em->persist($record);
foreach ($playlist_lines as $line_raw) {
$line = trim($line_raw);
if (empty($line) || $line[0] === '#') {
continue;
}
if (file_exists($line)) {
$line_hash = md5($line);
if (isset($media_lookup[$line_hash])) {
/** @var Entity\StationMedia $media_record */
$media_record = $media_lookup[$line_hash];
$spm = new Entity\StationPlaylistMedia($record, $media_record);
$this->em->persist($spm);
}
}
}
@unlink($playlist_file_path);
}
$this->em->flush();
}
public function globDirectory($base_dir, $regex_pattern = null)
{
$directory = new \RecursiveDirectoryIterator($base_dir);
$iterator = new \RecursiveIteratorIterator($directory);
$files = [];
if ($regex_pattern !== null) {
$regex = new \RegexIterator($iterator, $regex_pattern, \RecursiveRegexIterator::GET_MATCH);
foreach($regex as $path_match) {
$files[] = $path_match[0];
}
} else {
foreach ($iterator as $file) {
if ($file->isDir()){
continue;
}
$files[] = $file->getPathname();
}
}
return $files;
}
}