mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-25 06:27:59 +01:00
[#9] Add functionality to add/change versions of tracks
This commit is contained in:
parent
cf7bd8b9e6
commit
775de16bfe
14 changed files with 489 additions and 89 deletions
|
@ -20,15 +20,15 @@
|
||||||
|
|
||||||
namespace Poniverse\Ponyfm\Commands;
|
namespace Poniverse\Ponyfm\Commands;
|
||||||
|
|
||||||
|
use AudioCache;
|
||||||
use FFmpegMovie;
|
use FFmpegMovie;
|
||||||
|
use File;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Poniverse\Ponyfm\Exceptions\InvalidEncodeOptionsException;
|
use Poniverse\Ponyfm\Exceptions\InvalidEncodeOptionsException;
|
||||||
use Poniverse\Ponyfm\Jobs\EncodeTrackFile;
|
use Poniverse\Ponyfm\Jobs\EncodeTrackFile;
|
||||||
use Poniverse\Ponyfm\Models\Track;
|
use Poniverse\Ponyfm\Models\Track;
|
||||||
use Poniverse\Ponyfm\Models\TrackFile;
|
use Poniverse\Ponyfm\Models\TrackFile;
|
||||||
use AudioCache;
|
|
||||||
use File;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use SplFileInfo;
|
use SplFileInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,6 +45,9 @@ class GenerateTrackFilesCommand extends CommandBase
|
||||||
private $track;
|
private $track;
|
||||||
private $autoPublish;
|
private $autoPublish;
|
||||||
private $sourceFile;
|
private $sourceFile;
|
||||||
|
private $isForUpload;
|
||||||
|
private $isReplacingTrack;
|
||||||
|
private $version;
|
||||||
|
|
||||||
protected static $_losslessFormats = [
|
protected static $_losslessFormats = [
|
||||||
'flac',
|
'flac',
|
||||||
|
@ -53,11 +56,14 @@ class GenerateTrackFilesCommand extends CommandBase
|
||||||
'alac'
|
'alac'
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(Track $track, SplFileInfo $sourceFile, bool $autoPublish = false)
|
public function __construct(Track $track, SplFileInfo $sourceFile, bool $autoPublish = false, bool $isForUpload = false, bool $isReplacingTrack = false, int $version = 1)
|
||||||
{
|
{
|
||||||
$this->track = $track;
|
$this->track = $track;
|
||||||
$this->autoPublish = $autoPublish;
|
$this->autoPublish = $autoPublish;
|
||||||
$this->sourceFile = $sourceFile;
|
$this->sourceFile = $sourceFile;
|
||||||
|
$this->isForUpload = $isForUpload;
|
||||||
|
$this->isReplacingTrack = $isReplacingTrack;
|
||||||
|
$this->version = $version;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,6 +104,7 @@ class GenerateTrackFilesCommand extends CommandBase
|
||||||
$trackFile->is_master = true;
|
$trackFile->is_master = true;
|
||||||
$trackFile->format = $masterFormat;
|
$trackFile->format = $masterFormat;
|
||||||
$trackFile->track_id = $this->track->id;
|
$trackFile->track_id = $this->track->id;
|
||||||
|
$trackFile->version = $this->version;
|
||||||
$trackFile->save();
|
$trackFile->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,13 +133,14 @@ class GenerateTrackFilesCommand extends CommandBase
|
||||||
$trackFile->is_master = $name === 'FLAC' ? true : false;
|
$trackFile->is_master = $name === 'FLAC' ? true : false;
|
||||||
$trackFile->format = $name;
|
$trackFile->format = $name;
|
||||||
$trackFile->status = TrackFile::STATUS_PROCESSING_PENDING;
|
$trackFile->status = TrackFile::STATUS_PROCESSING_PENDING;
|
||||||
|
$trackFile->version = $this->version;
|
||||||
|
|
||||||
if (in_array($name, Track::$CacheableFormats) && !$trackFile->is_master) {
|
if (in_array($name, Track::$CacheableFormats) && !$trackFile->is_master) {
|
||||||
$trackFile->is_cacheable = true;
|
$trackFile->is_cacheable = true;
|
||||||
} else {
|
} else {
|
||||||
$trackFile->is_cacheable = false;
|
$trackFile->is_cacheable = false;
|
||||||
}
|
}
|
||||||
$this->track->trackFiles()->save($trackFile);
|
$this->track->trackFilesForAllVersions()->save($trackFile);
|
||||||
|
|
||||||
// All TrackFile records we need are synchronously created
|
// All TrackFile records we need are synchronously created
|
||||||
// before kicking off the encode jobs in order to avoid a race
|
// before kicking off the encode jobs in order to avoid a race
|
||||||
|
@ -142,16 +150,31 @@ class GenerateTrackFilesCommand extends CommandBase
|
||||||
|
|
||||||
try {
|
try {
|
||||||
foreach ($trackFiles as $trackFile) {
|
foreach ($trackFiles as $trackFile) {
|
||||||
$this->dispatch(new EncodeTrackFile($trackFile, false, true, $this->autoPublish));
|
// Don't re-encode master files when replacing tracks with an already-uploaded version
|
||||||
|
if ($trackFile->is_master && !$this->isForUpload && $this->isReplacingTrack) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->dispatch(new EncodeTrackFile($trackFile, false, false, $this->isForUpload, $this->isReplacingTrack));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (InvalidEncodeOptionsException $e) {
|
} catch (InvalidEncodeOptionsException $e) {
|
||||||
$this->track->delete();
|
// Only delete the track if the track is not being replaced
|
||||||
|
if ($this->isReplacingTrack) {
|
||||||
|
$this->track->version_upload_status = Track::STATUS_ERROR;
|
||||||
|
$this->track->update();
|
||||||
|
} else {
|
||||||
|
$this->track->delete();
|
||||||
|
}
|
||||||
return CommandResponse::fail(['track' => [$e->getMessage()]]);
|
return CommandResponse::fail(['track' => [$e->getMessage()]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->track->delete();
|
if ($this->isReplacingTrack) {
|
||||||
|
$this->track->version_upload_status = Track::STATUS_ERROR;
|
||||||
|
$this->track->update();
|
||||||
|
} else {
|
||||||
|
$this->track->delete();
|
||||||
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +191,8 @@ class GenerateTrackFilesCommand extends CommandBase
|
||||||
* @param FFmpegMovie|string $file object or full path of the file we're checking
|
* @param FFmpegMovie|string $file object or full path of the file we're checking
|
||||||
* @return bool whether the given file is lossless
|
* @return bool whether the given file is lossless
|
||||||
*/
|
*/
|
||||||
private function isLosslessFile($file) {
|
private function isLosslessFile($file)
|
||||||
|
{
|
||||||
if (is_string($file)) {
|
if (is_string($file)) {
|
||||||
$file = AudioCache::get($file);
|
$file = AudioCache::get($file);
|
||||||
}
|
}
|
||||||
|
@ -180,7 +204,8 @@ class GenerateTrackFilesCommand extends CommandBase
|
||||||
* @param string $format
|
* @param string $format
|
||||||
* @return TrackFile|null
|
* @return TrackFile|null
|
||||||
*/
|
*/
|
||||||
private function trackFileExists(string $format) {
|
private function trackFileExists(string $format)
|
||||||
return $this->track->trackFiles()->where('format', $format)->first();
|
{
|
||||||
|
return $this->track->trackFilesForAllVersions()->where('format', $format)->where('version', $this->version)->first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ use Gate;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Input;
|
use Input;
|
||||||
use Poniverse\Ponyfm\Models\Track;
|
use Poniverse\Ponyfm\Models\Track;
|
||||||
use AudioCache;
|
|
||||||
use Poniverse\Ponyfm\Models\User;
|
use Poniverse\Ponyfm\Models\User;
|
||||||
use Validator;
|
use Validator;
|
||||||
|
|
||||||
|
@ -40,6 +39,21 @@ class UploadTrackCommand extends CommandBase
|
||||||
private $_allowShortTrack;
|
private $_allowShortTrack;
|
||||||
private $_customTrackSource;
|
private $_customTrackSource;
|
||||||
private $_autoPublishByDefault;
|
private $_autoPublishByDefault;
|
||||||
|
private $_track;
|
||||||
|
private $_version;
|
||||||
|
private $_isReplacingTrack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
if ($this->_isReplacingTrack) {
|
||||||
|
return $this->_track && Gate::allows('edit', $this->_track);
|
||||||
|
} else {
|
||||||
|
return Gate::allows('create-track', $this->_artist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UploadTrackCommand constructor.
|
* UploadTrackCommand constructor.
|
||||||
|
@ -48,12 +62,16 @@ class UploadTrackCommand extends CommandBase
|
||||||
* @param bool $allowShortTrack allow tracks shorter than 30 seconds
|
* @param bool $allowShortTrack allow tracks shorter than 30 seconds
|
||||||
* @param string|null $customTrackSource value to set in the track's "source" field; if left blank, "direct_upload" is used
|
* @param string|null $customTrackSource value to set in the track's "source" field; if left blank, "direct_upload" is used
|
||||||
* @param bool $autoPublishByDefault
|
* @param bool $autoPublishByDefault
|
||||||
|
* @param int $version
|
||||||
|
* @param Track $track | null
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
bool $allowLossy = false,
|
bool $allowLossy = false,
|
||||||
bool $allowShortTrack = false,
|
bool $allowShortTrack = false,
|
||||||
string $customTrackSource = null,
|
string $customTrackSource = null,
|
||||||
bool $autoPublishByDefault = false
|
bool $autoPublishByDefault = false,
|
||||||
|
int $version = 1,
|
||||||
|
$track = null
|
||||||
) {
|
) {
|
||||||
$userSlug = Input::get('user_slug', null);
|
$userSlug = Input::get('user_slug', null);
|
||||||
$this->_artist =
|
$this->_artist =
|
||||||
|
@ -65,14 +83,9 @@ class UploadTrackCommand extends CommandBase
|
||||||
$this->_allowShortTrack = $allowShortTrack;
|
$this->_allowShortTrack = $allowShortTrack;
|
||||||
$this->_customTrackSource = $customTrackSource;
|
$this->_customTrackSource = $customTrackSource;
|
||||||
$this->_autoPublishByDefault = $autoPublishByDefault;
|
$this->_autoPublishByDefault = $autoPublishByDefault;
|
||||||
}
|
$this->_version = $version;
|
||||||
|
$this->_track = $track;
|
||||||
/**
|
$this->_isReplacingTrack = $this->_track !== null && $version > 1;
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return Gate::allows('create-track', $this->_artist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,22 +95,32 @@ class UploadTrackCommand extends CommandBase
|
||||||
public function execute()
|
public function execute()
|
||||||
{
|
{
|
||||||
$trackFile = Input::file('track', null);
|
$trackFile = Input::file('track', null);
|
||||||
$coverFile = Input::file('cover', null);
|
if (!$this->_isReplacingTrack) {
|
||||||
|
$coverFile = Input::file('cover', null);
|
||||||
|
}
|
||||||
|
|
||||||
if (null === $trackFile) {
|
if (null === $trackFile) {
|
||||||
|
if ($this->_isReplacingTrack) {
|
||||||
|
$this->_track->version_upload_status = Track::STATUS_ERROR;
|
||||||
|
$this->_track->update();
|
||||||
|
}
|
||||||
return CommandResponse::fail(['track' => ['You must upload an audio file!']]);
|
return CommandResponse::fail(['track' => ['You must upload an audio file!']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$audio = \AudioCache::get($trackFile->getPathname());
|
$audio = \AudioCache::get($trackFile->getPathname());
|
||||||
|
|
||||||
$track = new Track();
|
if (!$this->_isReplacingTrack) {
|
||||||
$track->user_id = $this->_artist->id;
|
$this->_track = new Track();
|
||||||
// The title set here is a placeholder; it'll be replaced by ParseTrackTagsCommand
|
$this->_track->user_id = $this->_artist->id;
|
||||||
// if the file contains a title tag.
|
// The title set here is a placeholder; it'll be replaced by ParseTrackTagsCommand
|
||||||
$track->title = Input::get('title', pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME));
|
// if the file contains a title tag.
|
||||||
$track->duration = $audio->getDuration();
|
$this->_track->title = Input::get('title', pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME));
|
||||||
$track->save();
|
// The duration/version of the track cannot be changed until the encoding is successful
|
||||||
$track->ensureDirectoryExists();
|
$this->_track->duration = $audio->getDuration();
|
||||||
|
$this->_track->current_version = $this->_version;
|
||||||
|
$this->_track->save();
|
||||||
|
}
|
||||||
|
$this->_track->ensureDirectoryExists();
|
||||||
|
|
||||||
if (!is_dir(Config::get('ponyfm.files_directory').'/tmp')) {
|
if (!is_dir(Config::get('ponyfm.files_directory').'/tmp')) {
|
||||||
mkdir(Config::get('ponyfm.files_directory').'/tmp', 0755, true);
|
mkdir(Config::get('ponyfm.files_directory').'/tmp', 0755, true);
|
||||||
|
@ -106,13 +129,15 @@ class UploadTrackCommand extends CommandBase
|
||||||
if (!is_dir(Config::get('ponyfm.files_directory').'/queued-tracks')) {
|
if (!is_dir(Config::get('ponyfm.files_directory').'/queued-tracks')) {
|
||||||
mkdir(Config::get('ponyfm.files_directory').'/queued-tracks', 0755, true);
|
mkdir(Config::get('ponyfm.files_directory').'/queued-tracks', 0755, true);
|
||||||
}
|
}
|
||||||
$trackFile = $trackFile->move(Config::get('ponyfm.files_directory').'/queued-tracks', $track->id);
|
$trackFile = $trackFile->move(Config::get('ponyfm.files_directory').'/queued-tracks', $this->_track->id . 'v' . $this->_version);
|
||||||
|
|
||||||
$input = Input::all();
|
$input = Input::all();
|
||||||
$input['track'] = $trackFile;
|
$input['track'] = $trackFile;
|
||||||
$input['cover'] = $coverFile;
|
if (!$this->_isReplacingTrack) {
|
||||||
|
$input['cover'] = $coverFile;
|
||||||
|
}
|
||||||
|
|
||||||
$validator = \Validator::make($input, [
|
$rules = [
|
||||||
'track' =>
|
'track' =>
|
||||||
'required|'
|
'required|'
|
||||||
. ($this->_allowLossy
|
. ($this->_allowLossy
|
||||||
|
@ -120,44 +145,61 @@ class UploadTrackCommand extends CommandBase
|
||||||
: 'audio_format:flac,alac,pcm,adpcm|')
|
: 'audio_format:flac,alac,pcm,adpcm|')
|
||||||
. ($this->_allowShortTrack ? '' : 'min_duration:30|')
|
. ($this->_allowShortTrack ? '' : 'min_duration:30|')
|
||||||
. 'audio_channels:1,2',
|
. 'audio_channels:1,2',
|
||||||
|
];
|
||||||
'auto_publish' => 'boolean',
|
if (!$this->_isReplacingTrack) {
|
||||||
'title' => 'string',
|
array_push($rules, [
|
||||||
'track_type_id' => 'exists:track_types,id',
|
'cover' => 'image|mimes:png,jpeg|min_width:350|min_height:350',
|
||||||
'genre' => 'string',
|
'auto_publish' => 'boolean',
|
||||||
'album' => 'string',
|
'title' => 'string',
|
||||||
'track_number' => 'integer',
|
'track_type_id' => 'exists:track_types,id',
|
||||||
'released_at' => 'date_format:'.Carbon::ISO8601,
|
'genre' => 'string',
|
||||||
'description' => 'string',
|
'album' => 'string',
|
||||||
'lyrics' => 'string',
|
'track_number' => 'integer',
|
||||||
'is_vocal' => 'boolean',
|
'released_at' => 'date_format:'.Carbon::ISO8601,
|
||||||
'is_explicit' => 'boolean',
|
'description' => 'string',
|
||||||
'is_downloadable' => 'boolean',
|
'lyrics' => 'string',
|
||||||
'is_listed' => 'boolean',
|
'is_vocal' => 'boolean',
|
||||||
'cover' => 'image|mimes:png,jpeg|min_width:350|min_height:350',
|
'is_explicit' => 'boolean',
|
||||||
'metadata' => 'json',
|
'is_downloadable' => 'boolean',
|
||||||
]);
|
'is_listed' => 'boolean',
|
||||||
|
'metadata' => 'json'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$validator = \Validator::make($input, $rules);
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
$track->delete();
|
if ($this->_isReplacingTrack) {
|
||||||
|
$this->_track->version_upload_status = Track::STATUS_ERROR;
|
||||||
|
$this->_track->update();
|
||||||
|
} else {
|
||||||
|
$this->_track->delete();
|
||||||
|
}
|
||||||
return CommandResponse::fail($validator);
|
return CommandResponse::fail($validator);
|
||||||
}
|
}
|
||||||
$autoPublish = (bool) ($input['auto_publish'] ?? $this->_autoPublishByDefault);
|
|
||||||
$track->source = $this->_customTrackSource ?? 'direct_upload';
|
|
||||||
|
|
||||||
// If json_decode() isn't called here, Laravel will surround the JSON
|
if (!$this->_isReplacingTrack) {
|
||||||
// string with quotes when storing it in the database, which breaks things.
|
// If json_decode() isn't called here, Laravel will surround the JSON
|
||||||
$track->metadata = json_decode(Input::get('metadata', null));
|
// string with quotes when storing it in the database, which breaks things.
|
||||||
$track->save();
|
$this->_track->metadata = json_decode(Input::get('metadata', null));
|
||||||
|
}
|
||||||
|
$autoPublish = (bool)($input['auto_publish'] ?? $this->_autoPublishByDefault);
|
||||||
|
$this->_track->source = $this->_customTrackSource ?? 'direct_upload';
|
||||||
|
$this->_track->save();
|
||||||
|
|
||||||
// Parse any tags in the uploaded files.
|
if (!$this->_isReplacingTrack) {
|
||||||
$parseTagsCommand = new ParseTrackTagsCommand($track, $trackFile, $input);
|
// Parse any tags in the uploaded files.
|
||||||
$result = $parseTagsCommand->execute();
|
$parseTagsCommand = new ParseTrackTagsCommand($this->_track, $trackFile, $input);
|
||||||
if ($result->didFail()) {
|
$result = $parseTagsCommand->execute();
|
||||||
return $result;
|
if ($result->didFail()) {
|
||||||
|
if ($this->_isReplacingTrack) {
|
||||||
|
$this->_track->version_upload_status = Track::STATUS_ERROR;
|
||||||
|
$this->_track->update();
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$generateTrackFiles = new GenerateTrackFilesCommand($track, $trackFile, $autoPublish);
|
$generateTrackFiles = new GenerateTrackFilesCommand($this->_track, $trackFile, $autoPublish, true, $this->_isReplacingTrack, $this->_version);
|
||||||
return $generateTrackFiles->execute();
|
return $generateTrackFiles->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ class RebuildTrack extends Command
|
||||||
$track->restore();
|
$track->restore();
|
||||||
$this->info("Attempting to finish this track's upload...");
|
$this->info("Attempting to finish this track's upload...");
|
||||||
|
|
||||||
$sourceFile = new \SplFileInfo($track->getTemporarySourceFile());
|
$sourceFile = new \SplFileInfo($track->getTemporarySourceFileForVersion($track->current_version));
|
||||||
$generateTrackFiles = new GenerateTrackFilesCommand($track, $sourceFile, false);
|
$generateTrackFiles = new GenerateTrackFilesCommand($track, $sourceFile, false);
|
||||||
$result = $generateTrackFiles->execute();
|
$result = $generateTrackFiles->execute();
|
||||||
// The GenerateTrackFiles command will re-encode all TrackFiles.
|
// The GenerateTrackFiles command will re-encode all TrackFiles.
|
||||||
|
|
97
app/Console/Commands/VersionFiles.php
Normal file
97
app/Console/Commands/VersionFiles.php
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pony.fm - A community for pony fan music.
|
||||||
|
* Copyright (C) 2016 Kelvin Zhang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Poniverse\Ponyfm\Console\Commands;
|
||||||
|
|
||||||
|
use File;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Poniverse\Ponyfm\Models\TrackFile;
|
||||||
|
|
||||||
|
class VersionFiles extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'version-files
|
||||||
|
{--force : Skip all prompts.}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Replaces track files of format [name].[ext] with [name]-v[version].[ext]';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$this->info('This will only version track files which exist on disk; non-existent files will be skipped.');
|
||||||
|
|
||||||
|
if ($this->option('force') || $this->confirm('Are you sure you want to rename all unversioned track files? [y|N]', false)) {
|
||||||
|
|
||||||
|
TrackFile::chunk(200, function ($trackFiles) {
|
||||||
|
|
||||||
|
$this->info('========== Start Chunk ==========');
|
||||||
|
|
||||||
|
foreach ($trackFiles as $trackFile) {
|
||||||
|
/** @var TrackFile $trackFile */
|
||||||
|
|
||||||
|
// Check whether the unversioned file exists
|
||||||
|
if (!File::exists($trackFile->getUnversionedFile())) {
|
||||||
|
$this->info('ID ' . $trackFile->id . ' skipped - file not found');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version the file and check the outcome
|
||||||
|
if (File::move($trackFile->getUnversionedFile(), $trackFile->getFile())) {
|
||||||
|
$this->info('ID ' . $trackFile->id . ' processed');
|
||||||
|
} else {
|
||||||
|
$this->error('ID ' . $trackFile->id . ' was unable to be renamed');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('=========== End Chunk ===========');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->info('Rebuild complete. Exiting.');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->info('Rebuild cancelled. Exiting.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ class Kernel extends ConsoleKernel
|
||||||
\Poniverse\Ponyfm\Console\Commands\RebuildSearchIndex::class,
|
\Poniverse\Ponyfm\Console\Commands\RebuildSearchIndex::class,
|
||||||
\Poniverse\Ponyfm\Console\Commands\MergeAccounts::class,
|
\Poniverse\Ponyfm\Console\Commands\MergeAccounts::class,
|
||||||
\Poniverse\Ponyfm\Console\Commands\FixMLPMAImages::class,
|
\Poniverse\Ponyfm\Console\Commands\FixMLPMAImages::class,
|
||||||
|
\Poniverse\Ponyfm\Console\Commands\VersionFiles::class
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,23 +20,24 @@
|
||||||
|
|
||||||
namespace Poniverse\Ponyfm\Http\Controllers\Api\Web;
|
namespace Poniverse\Ponyfm\Http\Controllers\Api\Web;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Auth;
|
||||||
use File;
|
use File;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Input;
|
||||||
use Poniverse\Ponyfm\Commands\DeleteTrackCommand;
|
use Poniverse\Ponyfm\Commands\DeleteTrackCommand;
|
||||||
use Poniverse\Ponyfm\Commands\EditTrackCommand;
|
use Poniverse\Ponyfm\Commands\EditTrackCommand;
|
||||||
|
use Poniverse\Ponyfm\Commands\GenerateTrackFilesCommand;
|
||||||
use Poniverse\Ponyfm\Commands\UploadTrackCommand;
|
use Poniverse\Ponyfm\Commands\UploadTrackCommand;
|
||||||
use Poniverse\Ponyfm\Http\Controllers\ApiControllerBase;
|
use Poniverse\Ponyfm\Http\Controllers\ApiControllerBase;
|
||||||
use Poniverse\Ponyfm\Jobs\EncodeTrackFile;
|
use Poniverse\Ponyfm\Jobs\EncodeTrackFile;
|
||||||
use Poniverse\Ponyfm\Models\Genre;
|
use Poniverse\Ponyfm\Models\Genre;
|
||||||
use Poniverse\Ponyfm\Models\ResourceLogItem;
|
use Poniverse\Ponyfm\Models\ResourceLogItem;
|
||||||
use Poniverse\Ponyfm\Models\TrackFile;
|
|
||||||
use Poniverse\Ponyfm\Models\Track;
|
use Poniverse\Ponyfm\Models\Track;
|
||||||
use Poniverse\Ponyfm\Models\TrackType;
|
use Poniverse\Ponyfm\Models\TrackType;
|
||||||
use Poniverse\Ponyfm\Models\TrackTypes;
|
use Poniverse\Ponyfm\Models\TrackFile;
|
||||||
use Auth;
|
|
||||||
use Input;
|
|
||||||
use Poniverse\Ponyfm\Models\User;
|
use Poniverse\Ponyfm\Models\User;
|
||||||
use Response;
|
use Response;
|
||||||
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
|
||||||
class TracksController extends ApiControllerBase
|
class TracksController extends ApiControllerBase
|
||||||
{
|
{
|
||||||
|
@ -74,6 +75,75 @@ class TracksController extends ApiControllerBase
|
||||||
return $this->execute(new EditTrackCommand($id, Input::all()));
|
return $this->execute(new EditTrackCommand($id, Input::all()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function postUploadNewVersion($trackId)
|
||||||
|
{
|
||||||
|
session_write_close();
|
||||||
|
|
||||||
|
$track = Track::find($trackId);
|
||||||
|
if (!$track) {
|
||||||
|
return $this->notFound('Track not found!');
|
||||||
|
}
|
||||||
|
$this->authorize('edit', $track);
|
||||||
|
|
||||||
|
$track->version_upload_status = Track::STATUS_PROCESSING;
|
||||||
|
$track->update();
|
||||||
|
return $this->execute(new UploadTrackCommand(true, false, null, false, $track->getNextVersion(), $track));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVersionUploadStatus($trackId)
|
||||||
|
{
|
||||||
|
$track = Track::findOrFail($trackId);
|
||||||
|
$this->authorize('edit', $track);
|
||||||
|
|
||||||
|
if ($track->version_upload_status === Track::STATUS_PROCESSING) {
|
||||||
|
return Response::json(['message' => 'Processing...'], 202);
|
||||||
|
|
||||||
|
} elseif ($track->version_upload_status === Track::STATUS_COMPLETE) {
|
||||||
|
return Response::json(['message' => 'Processing complete!'], 201);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// something went wrong
|
||||||
|
return Response::json(['error' => 'Processing failed!'], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVersionList($trackId)
|
||||||
|
{
|
||||||
|
$track = Track::findOrFail($trackId);
|
||||||
|
$this->authorize('edit', $track);
|
||||||
|
|
||||||
|
$versions = [];
|
||||||
|
$trackFiles = $track->trackFilesForAllVersions()->where('is_master', 'true')->get();
|
||||||
|
foreach($trackFiles as $trackFile) {
|
||||||
|
$versions[] = [
|
||||||
|
'version' => $trackFile->version,
|
||||||
|
'url' => '/tracks/' . $track->id . '/version-change/' . $trackFile->version,
|
||||||
|
'created_at' => $trackFile->created_at->timestamp
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response::json(['current_version' => $track->current_version, 'versions' => $versions], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChangeVersion($trackId, $newVersion)
|
||||||
|
{
|
||||||
|
$track = Track::find($trackId);
|
||||||
|
if (!$track) {
|
||||||
|
return $this->notFound('Track not found!');
|
||||||
|
}
|
||||||
|
$this->authorize('edit', $track);
|
||||||
|
|
||||||
|
$masterTrackFile = $track->trackFilesForVersion($newVersion)->where('is_master', true)->first();
|
||||||
|
if (!$masterTrackFile) {
|
||||||
|
return $this->notFound('Version not found!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$track->version_upload_status = Track::STATUS_PROCESSING;
|
||||||
|
$track->update();
|
||||||
|
$sourceFile = new UploadedFile($masterTrackFile->getFile(), $masterTrackFile->getFilename());
|
||||||
|
return $this->execute(new GenerateTrackFilesCommand($track, $sourceFile, false, false, true, $newVersion));
|
||||||
|
}
|
||||||
|
|
||||||
public function getShow($id)
|
public function getShow($id)
|
||||||
{
|
{
|
||||||
$track = Track::userDetails()->withComments()->find($id);
|
$track = Track::userDetails()->withComments()->find($id);
|
||||||
|
|
|
@ -114,6 +114,11 @@ Route::group(['prefix' => 'api/web'], function() {
|
||||||
Route::post('/tracks/delete/{id}', 'Api\Web\TracksController@postDelete');
|
Route::post('/tracks/delete/{id}', 'Api\Web\TracksController@postDelete');
|
||||||
Route::post('/tracks/edit/{id}', 'Api\Web\TracksController@postEdit');
|
Route::post('/tracks/edit/{id}', 'Api\Web\TracksController@postEdit');
|
||||||
|
|
||||||
|
Route::post('/tracks/{id}/version-upload', 'Api\Web\TracksController@postUploadNewVersion');
|
||||||
|
Route::get('/tracks/{id}/version-change/{version}', 'Api\Web\TracksController@getChangeVersion');
|
||||||
|
Route::get('/tracks/{id}/version-upload-status', 'Api\Web\TracksController@getVersionUploadStatus');
|
||||||
|
Route::get('/tracks/{id}/versions', 'Api\Web\TracksController@getVersionList');
|
||||||
|
|
||||||
Route::post('/albums/create', 'Api\Web\AlbumsController@postCreate');
|
Route::post('/albums/create', 'Api\Web\AlbumsController@postCreate');
|
||||||
Route::post('/albums/delete/{id}', 'Api\Web\AlbumsController@postDelete');
|
Route::post('/albums/delete/{id}', 'Api\Web\AlbumsController@postDelete');
|
||||||
Route::post('/albums/edit/{id}', 'Api\Web\AlbumsController@postEdit');
|
Route::post('/albums/edit/{id}', 'Api\Web\AlbumsController@postEdit');
|
||||||
|
|
|
@ -22,15 +22,15 @@
|
||||||
namespace Poniverse\Ponyfm\Jobs;
|
namespace Poniverse\Ponyfm\Jobs;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Config;
|
||||||
use DB;
|
use DB;
|
||||||
use File;
|
use File;
|
||||||
use Config;
|
|
||||||
use Log;
|
|
||||||
use Poniverse\Ponyfm\Exceptions\InvalidEncodeOptionsException;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Contracts\Bus\SelfHandling;
|
use Illuminate\Contracts\Bus\SelfHandling;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Log;
|
||||||
|
use Poniverse\Ponyfm\Exceptions\InvalidEncodeOptionsException;
|
||||||
use Poniverse\Ponyfm\Models\Track;
|
use Poniverse\Ponyfm\Models\Track;
|
||||||
use Poniverse\Ponyfm\Models\TrackFile;
|
use Poniverse\Ponyfm\Models\TrackFile;
|
||||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||||
|
@ -47,6 +47,10 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
* @var
|
* @var
|
||||||
*/
|
*/
|
||||||
protected $isExpirable;
|
protected $isExpirable;
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $autoPublishWhenComplete;
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
|
@ -54,16 +58,17 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected $autoPublishWhenComplete;
|
protected $isReplacingTrack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
* @param TrackFile $trackFile
|
* @param TrackFile $trackFile
|
||||||
* @param bool $isExpirable
|
* @param bool $isExpirable
|
||||||
* @param bool $isForUpload indicates whether this encode job is for an upload
|
|
||||||
* @param bool $autoPublish
|
* @param bool $autoPublish
|
||||||
|
* @param bool $isForUpload indicates whether this encode job is for an upload
|
||||||
|
* @param bool $isReplacingTrack
|
||||||
*/
|
*/
|
||||||
public function __construct(TrackFile $trackFile, $isExpirable, $isForUpload = false, $autoPublish = false)
|
public function __construct(TrackFile $trackFile, $isExpirable, $autoPublish = false, $isForUpload = false, $isReplacingTrack = false)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(!$isForUpload && $trackFile->is_master) ||
|
(!$isForUpload && $trackFile->is_master) ||
|
||||||
|
@ -74,8 +79,9 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
|
|
||||||
$this->trackFile = $trackFile;
|
$this->trackFile = $trackFile;
|
||||||
$this->isExpirable = $isExpirable;
|
$this->isExpirable = $isExpirable;
|
||||||
$this->isForUpload = $isForUpload;
|
|
||||||
$this->autoPublishWhenComplete = $autoPublish;
|
$this->autoPublishWhenComplete = $autoPublish;
|
||||||
|
$this->isForUpload = $isForUpload;
|
||||||
|
$this->isReplacingTrack = $isReplacingTrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,7 +98,7 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
Log::warning('Track file #'.$this->trackFile->id.' (track #'.$this->trackFile->track_id.') is already being processed!');
|
Log::warning('Track file #'.$this->trackFile->id.' (track #'.$this->trackFile->track_id.') is already being processed!');
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} elseif (!$this->trackFile->is_expired) {
|
} elseif (!$this->trackFile->is_expired && File::exists($this->trackFile->getFile())) {
|
||||||
Log::warning('Track file #'.$this->trackFile->id.' (track #'.$this->trackFile->track_id.') is still valid! No need to re-encode it.');
|
Log::warning('Track file #'.$this->trackFile->id.' (track #'.$this->trackFile->track_id.') is still valid! No need to re-encode it.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -103,11 +109,11 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
|
|
||||||
// Use the track's master file as the source
|
// Use the track's master file as the source
|
||||||
if ($this->isForUpload) {
|
if ($this->isForUpload) {
|
||||||
$source = $this->trackFile->track->getTemporarySourceFile();
|
$source = $this->trackFile->track->getTemporarySourceFileForVersion($this->trackFile->version);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$source = TrackFile::where('track_id', $this->trackFile->track_id)
|
$source = TrackFile::where('track_id', $this->trackFile->track_id)
|
||||||
->where('is_master', true)
|
->where('is_master', true)
|
||||||
|
->where('version', $this->trackFile->version)
|
||||||
->first()
|
->first()
|
||||||
->getFile();
|
->getFile();
|
||||||
}
|
}
|
||||||
|
@ -151,7 +157,7 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
$this->trackFile->status = TrackFile::STATUS_NOT_BEING_PROCESSED;
|
$this->trackFile->status = TrackFile::STATUS_NOT_BEING_PROCESSED;
|
||||||
$this->trackFile->save();
|
$this->trackFile->save();
|
||||||
|
|
||||||
if ($this->isForUpload) {
|
if ($this->isForUpload || $this->isReplacingTrack) {
|
||||||
if (!$this->trackFile->is_master && $this->trackFile->is_cacheable) {
|
if (!$this->trackFile->is_master && $this->trackFile->is_cacheable) {
|
||||||
File::delete($this->trackFile->getFile());
|
File::delete($this->trackFile->getFile());
|
||||||
}
|
}
|
||||||
|
@ -166,7 +172,29 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
$this->trackFile->track->save();
|
$this->trackFile->track->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
File::delete($this->trackFile->track->getTemporarySourceFile());
|
if ($this->isReplacingTrack) {
|
||||||
|
$oldVersion = $this->trackFile->track->current_version;
|
||||||
|
|
||||||
|
// Update the version of the track being uploaded
|
||||||
|
$this->trackFile->track->duration = \AudioCache::get($source)->getDuration();
|
||||||
|
$this->trackFile->track->current_version = $this->trackFile->version;
|
||||||
|
$this->trackFile->track->version_upload_status = Track::STATUS_COMPLETE;
|
||||||
|
$this->trackFile->track->update();
|
||||||
|
|
||||||
|
// Delete the non-master files for the old version
|
||||||
|
if ($oldVersion !== $this->trackFile->version) {
|
||||||
|
$trackFilesToDelete = $this->trackFile->track->trackFilesForVersion($oldVersion)->where('is_master', false)->get();
|
||||||
|
foreach ($trackFilesToDelete as $trackFileToDelete) {
|
||||||
|
if (File::exists($trackFileToDelete->getFile())) {
|
||||||
|
File::delete($trackFileToDelete->getFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isForUpload) {
|
||||||
|
File::delete($this->trackFile->track->getTemporarySourceFileForVersion($this->trackFile->version));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,5 +209,21 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
||||||
$this->trackFile->status = TrackFile::STATUS_PROCESSING_ERROR;
|
$this->trackFile->status = TrackFile::STATUS_PROCESSING_ERROR;
|
||||||
$this->trackFile->expires_at = null;
|
$this->trackFile->expires_at = null;
|
||||||
$this->trackFile->save();
|
$this->trackFile->save();
|
||||||
|
|
||||||
|
if ($this->isReplacingTrack) {
|
||||||
|
// If a new version is being uploaded to replace a file, yet the upload fails,
|
||||||
|
// all track files for that version should be deleted as it would other clutter the version
|
||||||
|
if ($this->isForUpload) {
|
||||||
|
$trackFiles = $this->trackFile->track->trackFilesForVersion($this->trackFile->version)->get();
|
||||||
|
foreach ($trackFiles as $trackFile) {
|
||||||
|
if (File::exists($trackFile->getFile())) {
|
||||||
|
File::delete($trackFile->getFile());
|
||||||
|
}
|
||||||
|
$trackFile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->trackFile->track->version_upload_status = Track::STATUS_ERROR;
|
||||||
|
$this->trackFile->track->update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,8 @@ class Album extends Model implements Searchable, Commentable, Favouritable
|
||||||
}
|
}
|
||||||
|
|
||||||
public function trackFiles() {
|
public function trackFiles() {
|
||||||
return $this->hasManyThrough(TrackFile::class, Track::class, 'album_id', 'track_id');
|
$trackIds = $this->tracks->lists('id');
|
||||||
|
return TrackFile::join('tracks', 'tracks.current_version', '=', 'track_files.version')->whereIn('track_id', $trackIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function comments():HasMany
|
public function comments():HasMany
|
||||||
|
|
|
@ -226,7 +226,7 @@ class Playlist extends Model implements Searchable, Commentable, Favouritable
|
||||||
public function trackFiles()
|
public function trackFiles()
|
||||||
{
|
{
|
||||||
$trackIds = $this->tracks->lists('id');
|
$trackIds = $this->tracks->lists('id');
|
||||||
return TrackFile::whereIn('track_id', $trackIds);
|
return TrackFile::join('tracks', 'tracks.current_version', '=', 'track_files.version')->whereIn('track_id', $trackIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function users()
|
public function users()
|
||||||
|
|
|
@ -536,10 +536,21 @@ class Track extends Model implements Searchable, Commentable, Favouritable
|
||||||
}
|
}
|
||||||
|
|
||||||
public function trackFiles()
|
public function trackFiles()
|
||||||
|
{
|
||||||
|
return $this->hasMany(TrackFile::class)->where('version', $this->current_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function trackFilesForAllVersions()
|
||||||
{
|
{
|
||||||
return $this->hasMany(TrackFile::class);
|
return $this->hasMany(TrackFile::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function trackFilesForVersion(int $version)
|
||||||
|
{
|
||||||
|
return $this->hasMany(TrackFile::class)->where('track_files.version', $version);
|
||||||
|
}
|
||||||
|
|
||||||
public function notifications()
|
public function notifications()
|
||||||
{
|
{
|
||||||
return $this->morphMany(Activity::class, 'notification_type');
|
return $this->morphMany(Activity::class, 'notification_type');
|
||||||
|
@ -688,7 +699,7 @@ class Track extends Model implements Searchable, Commentable, Favouritable
|
||||||
|
|
||||||
$format = self::$Formats[$format];
|
$format = self::$Formats[$format];
|
||||||
|
|
||||||
return "{$this->id}.{$format['extension']}";
|
return "{$this->id}-v{$this->current_version}.{$format['extension']}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDownloadFilenameFor($format)
|
public function getDownloadFilenameFor($format)
|
||||||
|
@ -715,7 +726,7 @@ class Track extends Model implements Searchable, Commentable, Favouritable
|
||||||
|
|
||||||
$format = self::$Formats[$format];
|
$format = self::$Formats[$format];
|
||||||
|
|
||||||
return "{$this->getDirectory()}/{$this->id}.{$format['extension']}";
|
return "{$this->getDirectory()}/{$this->id}-v{$this->current_version}.{$format['extension']}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -723,10 +734,11 @@ class Track extends Model implements Searchable, Commentable, Favouritable
|
||||||
* This file is used during the upload process to generate the actual master
|
* This file is used during the upload process to generate the actual master
|
||||||
* file stored by Pony.fm.
|
* file stored by Pony.fm.
|
||||||
*
|
*
|
||||||
|
* @param int $version
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getTemporarySourceFile():string {
|
public function getTemporarySourceFileForVersion(int $version):string {
|
||||||
return Config::get('ponyfm.files_directory').'/queued-tracks/'.$this->id;
|
return Config::get('ponyfm.files_directory').'/queued-tracks/'.$this->id.'v'.$version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -914,4 +926,9 @@ class Track extends Model implements Searchable, Commentable, Favouritable
|
||||||
public function getResourceType():string {
|
public function getResourceType():string {
|
||||||
return 'track';
|
return 'track';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getNextVersion()
|
||||||
|
{
|
||||||
|
return $this->current_version + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,11 @@ class TrackFile extends Model
|
||||||
*/
|
*/
|
||||||
public static function findOrFailByExtension($trackId, $extension)
|
public static function findOrFailByExtension($trackId, $extension)
|
||||||
{
|
{
|
||||||
|
$track = Track::find($trackId);
|
||||||
|
if (!$track) {
|
||||||
|
App::abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
// find the extension's format
|
// find the extension's format
|
||||||
$requestedFormatName = null;
|
$requestedFormatName = null;
|
||||||
foreach (Track::$Formats as $name => $format) {
|
foreach (Track::$Formats as $name => $format) {
|
||||||
|
@ -96,6 +101,7 @@ class TrackFile extends Model
|
||||||
with('track')
|
with('track')
|
||||||
->where('track_id', $trackId)
|
->where('track_id', $trackId)
|
||||||
->where('format', $requestedFormatName)
|
->where('format', $requestedFormatName)
|
||||||
|
->where('version', $track->current_version)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if ($trackFile === null) {
|
if ($trackFile === null) {
|
||||||
|
@ -148,11 +154,21 @@ class TrackFile extends Model
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFile()
|
public function getFile()
|
||||||
|
{
|
||||||
|
return "{$this->getDirectory()}/{$this->track_id}-v{$this->version}.{$this->extension}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnversionedFile()
|
||||||
{
|
{
|
||||||
return "{$this->getDirectory()}/{$this->track_id}.{$this->extension}";
|
return "{$this->getDirectory()}/{$this->track_id}.{$this->extension}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFilename()
|
public function getFilename()
|
||||||
|
{
|
||||||
|
return "{$this->track_id}-v{$this->track->current_version}.{$this->extension}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnversionedFilename()
|
||||||
{
|
{
|
||||||
return "{$this->track_id}.{$this->extension}";
|
return "{$this->track_id}.{$this->extension}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pony.fm - A community for pony fan music.
|
||||||
|
* Copyright (C) 2016 Kelvin Zhang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddVersionColumnToTrackFilesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('track_files', function (Blueprint $table) {
|
||||||
|
$table->integer('version')->unsigned()->default(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('track_files', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('version');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddVersionColumnToTracksTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('tracks', function (Blueprint $table) {
|
||||||
|
$table->integer('current_version')->unsigned()->default(1);
|
||||||
|
$table->integer('version_upload_status')->unsigned()->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('tracks', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('current_version');
|
||||||
|
$table->dropColumn('version_upload_status');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue