/** * Sync the media. Oh sync the media. * * @param string|null $path * @param array $tags The tags to sync. * Only taken into account for existing records. * New records will have all tags synced in regardless. * @param bool $force Whether to force syncing even unchanged files * @param SyncMedia $syncCommand The SyncMedia command object, to log to console if executed by artisan. */ public function sync($path = null, $tags = [], $force = false, SyncMedia $syncCommand = null) { if (!app()->runningInConsole()) { set_time_limit(env('APP_MAX_SCAN_TIME', 600)); } $path = $path ?: Setting::get('media_path'); $this->setTags($tags); $results = ['good' => [], 'bad' => [], 'ugly' => []]; $getID3 = new getID3(); foreach ($this->gatherFiles($path) as $file) { $file = new File($file, $getID3); $song = $file->sync($this->tags, $force); if ($song === true) { $results['ugly'][] = $file; } elseif ($song === false) { $results['bad'][] = $file; } else { $results['good'][] = $file; } if ($syncCommand) { $syncCommand->logToConsole($file->getPath(), $song); } } // Delete non-existing songs. $hashes = array_map(function ($f) { return self::getHash($f->getPath()); }, array_merge($results['ugly'], $results['good'])); Song::whereNotIn('id', $hashes)->delete(); // Trigger LibraryChanged, so that TidyLibrary handler is fired to, erm, tidy our library. event(new LibraryChanged()); }
/** * Sync the media. Oh sync the media. * * @param string|null $path * @param SyncMedia $syncCommand The SyncMedia command object, to log to console if executed by artisan. */ public function sync($path = null, SyncMedia $syncCommand = null) { set_time_limit(env('APP_MAX_SCAN_TIME', 600)); $path = $path ?: Setting::get('media_path'); $results = ['good' => [], 'bad' => [], 'ugly' => []]; // For now we only care about mp3 and ogg files. // Support for other formats (AAC?) may be added in the future. $files = Finder::create()->files()->name('/\\.(mp3|ogg)$/')->in($path); foreach ($files as $file) { $song = $this->syncFile($file); if ($song === true) { $results['ugly'][] = $file; } elseif ($song === false) { $results['bad'][] = $file; } else { $results['good'][] = $file; } if ($syncCommand) { $syncCommand->logToConsole($file->getPathname(), $song); } } // Delete non-existing songs. $hashes = array_map(function ($f) { return $this->getHash($f->getPathname()); }, array_merge($results['ugly'], $results['good'])); Song::whereNotIn('id', $hashes)->delete(); // Empty albums and artists should be gone as well. $inUseAlbums = Song::select('album_id')->groupBy('album_id')->get()->lists('album_id'); $inUseAlbums[] = Album::UNKNOWN_ID; Album::whereNotIn('id', $inUseAlbums)->delete(); $inUseArtists = Album::select('artist_id')->groupBy('artist_id')->get()->lists('artist_id'); $inUseArtists[] = Artist::UNKNOWN_ID; Artist::whereNotIn('id', $inUseArtists)->delete(); }
public function testGet() { Setting::set('foo', 'bar'); Setting::set('bar', ['baz' => 'qux']); $this->assertEquals('bar', Setting::get('foo')); $this->assertEquals(['baz' => 'qux'], Setting::get('bar')); }
public function testApplicationSetting() { Media::shouldReceive('sync')->once(); $dir = dirname(__FILE__); $this->actingAs(factory(User::class, 'admin')->create())->post('/api/settings', ['media_path' => $dir])->seeStatusCode(200); $this->assertEquals($dir, Setting::get('media_path')); }
/** * Stream the current song using nginx's X-Accel-Redirect. */ public function stream() { header('X-Accel-Redirect: ' . str_replace(Setting::get('media_path'), '/media/', $this->song->path)); header("Content-Type: {$this->contentType}"); header('Content-Disposition: inline; filename="' . basename($this->song->path) . '"'); exit; }
/** * Execute the console command. * * @return mixed */ public function handle() { if (!Setting::get('media_path')) { $this->error("Media path hasn't been configured. Exiting."); return; } $this->info('Koel syncing started. All we need now is just a little patience…'); Media::sync(null, $this); $this->output->writeln("<info>Completed! {$this->synced} new or updated songs(s)</info>, " . "{$this->ignored} unchanged song(s), " . "and <comment>{$this->invalid} invalid file(s)</comment>."); }
/** * Execute the console command. * * @return mixed */ public function handle() { if (!Setting::get('media_path')) { $this->error("Media path hasn't been configured. Exiting."); return; } if (!($record = $this->argument('record'))) { $this->syncAll(); return; } $this->syngle($record); }
/** * Stream the current song using nginx's X-Accel-Redirect. */ public function stream() { $relativePath = str_replace(Setting::get('media_path'), '', $this->song->path); // We send our media_path value as a 'X-Media-Root' header to downstream (nginx) // It will then be use as `alias` in X-Accel config location block. // See nginx.conf.example. header('X-Media-Root: ' . Setting::get('media_path')); header('X-Accel-Redirect: /media/' . $relativePath); header("Content-Type: {$this->contentType}"); header('Content-Disposition: inline; filename="' . basename($this->song->path) . '"'); exit; }
/** * Sync the media. Oh sync the media. * * @param string|null $path * @param array $tags The tags to sync. * Only taken into account for existing records. * New records will have all tags synced in regardless. * @param bool $force Whether to force syncing even unchanged files * @param SyncMedia $syncCommand The SyncMedia command object, to log to console if executed by artisan. */ public function sync($path = null, $tags = [], $force = false, SyncMedia $syncCommand = null) { if (!app()->runningInConsole()) { set_time_limit(config('koel.sync.timeout')); } $path = $path ?: Setting::get('media_path'); $this->setTags($tags); $results = ['good' => [], 'bad' => [], 'ugly' => []]; $getID3 = new getID3(); $files = $this->gatherFiles($path); if ($syncCommand) { $syncCommand->createProgressBar(count($files)); } foreach ($files as $file) { $file = new File($file, $getID3); $song = $file->sync($this->tags, $force); if ($song === true) { $results['ugly'][] = $file; } elseif ($song === false) { $results['bad'][] = $file; } else { $results['good'][] = $file; } if ($syncCommand) { $syncCommand->updateProgressBar(); $syncCommand->logToConsole($file->getPath(), $song, $file->getSyncError()); } } // Delete non-existing songs. $hashes = array_map(function ($f) { return self::getHash($f->getPath()); }, array_merge($results['ugly'], $results['good'])); Song::deleteWhereIDsNotIn($hashes); // Trigger LibraryChanged, so that TidyLibrary handler is fired to, erm, tidy our library. event(new LibraryChanged()); }