mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2025-03-28 13:57:47 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
a90cc8395c
154 changed files with 1185 additions and 2672 deletions
3
.git-crypt/.gitattributes
vendored
3
.git-crypt/.gitattributes
vendored
|
@ -1,3 +0,0 @@
|
|||
# Do not edit this file. To specify the files to encrypt, create your own
|
||||
# .gitattributes file in the directory where your files are.
|
||||
* !filter !diff
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
.gitattributes
vendored
3
.gitattributes
vendored
|
@ -1,7 +1,4 @@
|
|||
* text=auto
|
||||
|
||||
resources/environments/.env.stage filter=git-crypt diff=git-crypt
|
||||
resources/environments/.env.production filter=git-crypt diff=git-crypt
|
||||
|
||||
*.css linguist-vendored
|
||||
*.less linguist-vendored
|
||||
|
|
4
Vagrantfile
vendored
4
Vagrantfile
vendored
|
@ -3,8 +3,8 @@ Vagrant.configure("2") do |config|
|
|||
config.hostmanager.enabled = true
|
||||
config.hostmanager.manage_host = true
|
||||
|
||||
config.vm.box = 'laravel/homestead'
|
||||
config.vm.box_version = '0.3.0'
|
||||
config.vm.box = 'laravel/homestead-7'
|
||||
config.vm.box_version = '0.2.0'
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.cpus = 4
|
||||
v.memory = 2048
|
||||
|
|
|
@ -28,7 +28,6 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
|
|||
use Auth;
|
||||
use Cache;
|
||||
use Poniverse\Ponyfm\Traits\TrackCollection;
|
||||
use URL;
|
||||
use Poniverse\Ponyfm\Traits\SlugTrait;
|
||||
use Venturecraft\Revisionable\RevisionableTrait;
|
||||
|
||||
|
@ -131,7 +130,7 @@ class Album extends Model
|
|||
$data['description'] = $album->description;
|
||||
$data['is_downloadable'] = $is_downloadable;
|
||||
$data['share'] = [
|
||||
'url' => URL::to('/a' . $album->id),
|
||||
'url' => action('AlbumsController@getShortlink', ['id' => $album->id]),
|
||||
'tumblrUrl' => 'http://www.tumblr.com/share/link?url=' . urlencode($album->url) . '&name=' . urlencode($album->title) . '&description=' . urlencode($album->description),
|
||||
'twitterUrl' => 'https://platform.twitter.com/widgets/tweet_button.html?text=' . $album->title . ' by ' . $album->user->display_name . ' on Pony.fm'
|
||||
];
|
||||
|
@ -198,12 +197,12 @@ class Album extends Model
|
|||
|
||||
public function getUrlAttribute()
|
||||
{
|
||||
return URL::to('albums/' . $this->id . '-' . $this->slug);
|
||||
return action('AlbumsController@getShow', ['id' => $this->id, 'slug' => $this->slug]);
|
||||
}
|
||||
|
||||
public function getDownloadUrl($format)
|
||||
{
|
||||
return URL::to('a' . $this->id . '/dl.' . Track::$Formats[$format]['extension']);
|
||||
return action('AlbumsController@getDownload', ['id' => $this->id, 'extension' => Track::$Formats[$format]['extension']]);
|
||||
}
|
||||
|
||||
public function getFilesize($format)
|
||||
|
|
|
@ -24,11 +24,25 @@ use Illuminate\Validation\Validator;
|
|||
|
||||
class CommandResponse
|
||||
{
|
||||
public static function fail($validator)
|
||||
/**
|
||||
* @var Validator
|
||||
*/
|
||||
private $_validator;
|
||||
private $_response;
|
||||
private $_didFail;
|
||||
|
||||
public static function fail($validatorOrMessages)
|
||||
{
|
||||
$response = new CommandResponse();
|
||||
$response->_didFail = true;
|
||||
$response->_validator = $validator;
|
||||
|
||||
if (is_array($validatorOrMessages)) {
|
||||
$response->_messages = $validatorOrMessages;
|
||||
$response->_validator = null;
|
||||
|
||||
} else {
|
||||
$response->_validator = $validatorOrMessages;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
@ -42,10 +56,6 @@ class CommandResponse
|
|||
return $cmdResponse;
|
||||
}
|
||||
|
||||
private $_validator;
|
||||
private $_response;
|
||||
private $_didFail;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
@ -73,4 +83,14 @@ class CommandResponse
|
|||
{
|
||||
return $this->_validator;
|
||||
}
|
||||
|
||||
public function getMessages()
|
||||
{
|
||||
if ($this->_validator !== null) {
|
||||
return $this->_validator->messages()->getMessages();
|
||||
|
||||
} else {
|
||||
return $this->_messages;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,17 +20,22 @@
|
|||
|
||||
namespace Poniverse\Ponyfm\Commands;
|
||||
|
||||
use Config;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Poniverse\Ponyfm\Exceptions\InvalidEncodeOptionsException;
|
||||
use Poniverse\Ponyfm\Jobs\EncodeTrackFile;
|
||||
use Poniverse\Ponyfm\Track;
|
||||
use Poniverse\Ponyfm\TrackFile;
|
||||
use AudioCache;
|
||||
use File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Storage;
|
||||
|
||||
class UploadTrackCommand extends CommandBase
|
||||
{
|
||||
use DispatchesJobs;
|
||||
|
||||
|
||||
private $_allowLossy;
|
||||
private $_allowShortTrack;
|
||||
private $_losslessFormats = [
|
||||
|
@ -68,6 +73,21 @@ class UploadTrackCommand extends CommandBase
|
|||
$trackFile = \Input::file('track');
|
||||
$audio = \AudioCache::get($trackFile->getPathname());
|
||||
|
||||
|
||||
$track = new Track();
|
||||
$track->user_id = $user->id;
|
||||
$track->title = pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
$track->duration = $audio->getDuration();
|
||||
$track->is_listed = true;
|
||||
|
||||
$track->save();
|
||||
$track->ensureDirectoryExists();
|
||||
|
||||
Storage::makeDirectory(Config::get('ponyfm.files_directory') . '/queued-tracks', 0755, false, true);
|
||||
$trackFile = $trackFile->move(Config::get('ponyfm.files_directory').'/queued-tracks', $track->id);
|
||||
|
||||
|
||||
|
||||
$validator = \Validator::make(['track' => $trackFile], [
|
||||
'track' =>
|
||||
'required|'
|
||||
|
@ -77,24 +97,13 @@ class UploadTrackCommand extends CommandBase
|
|||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
$track->delete();
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$track = new Track();
|
||||
|
||||
try {
|
||||
$track->user_id = $user->id;
|
||||
$track->title = pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
$track->duration = $audio->getDuration();
|
||||
$track->is_listed = true;
|
||||
|
||||
$track->save();
|
||||
|
||||
$destination = $track->getDirectory();
|
||||
$track->ensureDirectoryExists();
|
||||
|
||||
$source = $trackFile->getPathname();
|
||||
$index = 0;
|
||||
|
||||
// Lossy uploads need to be identified and set as the master file
|
||||
// without being re-encoded.
|
||||
|
@ -113,6 +122,7 @@ class UploadTrackCommand extends CommandBase
|
|||
|
||||
} else {
|
||||
$validator->messages()->add('track', 'The track does not contain audio in a known lossy format.');
|
||||
$track->delete();
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
|
@ -126,6 +136,9 @@ class UploadTrackCommand extends CommandBase
|
|||
File::copy($source, $trackFile->getFile());
|
||||
}
|
||||
|
||||
|
||||
$trackFiles = [];
|
||||
|
||||
foreach (Track::$Formats as $name => $format) {
|
||||
// Don't bother with lossless transcodes of lossy uploads, and
|
||||
// don't re-encode the lossy master.
|
||||
|
@ -136,6 +149,7 @@ class UploadTrackCommand extends CommandBase
|
|||
$trackFile = new TrackFile();
|
||||
$trackFile->is_master = $name === 'FLAC' ? true : false;
|
||||
$trackFile->format = $name;
|
||||
$trackFile->status = TrackFile::STATUS_PROCESSING;
|
||||
|
||||
if (in_array($name, Track::$CacheableFormats) && $trackFile->is_master == false) {
|
||||
$trackFile->is_cacheable = true;
|
||||
|
@ -144,29 +158,21 @@ class UploadTrackCommand extends CommandBase
|
|||
}
|
||||
$track->trackFiles()->save($trackFile);
|
||||
|
||||
// Encode track file
|
||||
$target = $trackFile->getFile();
|
||||
|
||||
$command = $format['command'];
|
||||
$command = str_replace('{$source}', '"' . $source . '"', $command);
|
||||
$command = str_replace('{$target}', '"' . $target . '"', $command);
|
||||
|
||||
Log::info('Encoding ' . $track->id . ' into ' . $target);
|
||||
$this->notify('Encoding ' . $name, $index / count(Track::$Formats) * 100);
|
||||
|
||||
$process = new Process($command);
|
||||
$process->mustRun();
|
||||
|
||||
// Update file size for track file
|
||||
$trackFile->updateFilesize();
|
||||
|
||||
// Delete track file if it is cacheable
|
||||
if ($trackFile->is_cacheable == true) {
|
||||
File::delete($trackFile->getFile());
|
||||
}
|
||||
// All TrackFile records we need are synchronously created
|
||||
// before kicking off the encode jobs in order to avoid a race
|
||||
// condition with the "temporary" source file getting deleted.
|
||||
$trackFiles[] = $trackFile;
|
||||
}
|
||||
|
||||
$track->updateTags();
|
||||
try {
|
||||
foreach($trackFiles as $trackFile) {
|
||||
$this->dispatch(new EncodeTrackFile($trackFile, false, true));
|
||||
}
|
||||
|
||||
} catch (InvalidEncodeOptionsException $e) {
|
||||
$track->delete();
|
||||
return CommandResponse::fail(['track' => [$e->getMessage()]]);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$track->delete();
|
||||
|
|
|
@ -365,7 +365,7 @@ class ImportMLPMA extends Command
|
|||
$result = $upload->execute();
|
||||
|
||||
if ($result->didFail()) {
|
||||
$this->error(json_encode($result->getValidator()->messages()->getMessages(), JSON_PRETTY_PRINT));
|
||||
$this->error(json_encode($result->getMessages(), JSON_PRETTY_PRINT));
|
||||
|
||||
} else {
|
||||
// Save metadata.
|
||||
|
|
|
@ -18,27 +18,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Poniverse\Ponyfm\Http\Controllers;
|
||||
namespace Poniverse\Ponyfm\Exceptions;
|
||||
|
||||
use Poniverse\Ponyfm\User;
|
||||
use File;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class UsersController extends Controller
|
||||
{
|
||||
public function getAvatar($id, $type)
|
||||
{
|
||||
$coverType = Cover::getCoverFromName($type);
|
||||
|
||||
if ($coverType == null) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$user = User::find($id);
|
||||
if (!$user) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
return File::inline($user->getAvatarFile($coverType['id']), 'image/png', 'cover.png');
|
||||
}
|
||||
}
|
||||
class InvalidEncodeOptionsException extends InvalidArgumentException {}
|
|
@ -25,7 +25,6 @@ use Illuminate\Database\Eloquent\Relations\Relation;
|
|||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Poniverse\Ponyfm\Traits\SlugTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use URL;
|
||||
use Venturecraft\Revisionable\RevisionableTrait;
|
||||
|
||||
class Genre extends Model
|
||||
|
@ -75,6 +74,6 @@ class Genre extends Model
|
|||
* @return string relative, Angular-friendly URL to this genre
|
||||
*/
|
||||
public function getUrlAttribute() {
|
||||
return URL::route('tracks.discover', ['filter' => "genres-{$this->id}"], false);
|
||||
return route('tracks.discover', ['filter' => "genres-{$this->id}"], false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ use Cover;
|
|||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Poniverse\Ponyfm\TrackFile;
|
||||
|
||||
class TracksController extends ApiControllerBase
|
||||
{
|
||||
|
@ -40,7 +41,31 @@ class TracksController extends ApiControllerBase
|
|||
{
|
||||
session_write_close();
|
||||
|
||||
return $this->execute(new UploadTrackCommand());
|
||||
try {
|
||||
return $this->execute(new UploadTrackCommand());
|
||||
|
||||
} catch (\InvalidEncodeOptions $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function getUploadStatus($trackId)
|
||||
{
|
||||
// TODO: authorize this
|
||||
|
||||
$track = Track::findOrFail($trackId);
|
||||
|
||||
if ($track->status === Track::STATUS_PROCESSING){
|
||||
return Response::json(['message' => 'Processing...'], 202);
|
||||
|
||||
} elseif ($track->status === Track::STATUS_COMPLETE) {
|
||||
return Response::json(['message' => 'Processing complete!'], 201);
|
||||
|
||||
} else {
|
||||
// something went wrong
|
||||
return Response::json(['error' => 'Processing failed!'], 500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function postDelete($id)
|
||||
|
@ -101,7 +126,7 @@ class TracksController extends ApiControllerBase
|
|||
// Return URL or begin encoding
|
||||
if ($trackFile->expires_at != null && File::exists($trackFile->getFile())) {
|
||||
$url = $track->getUrlFor($format);
|
||||
} elseif ($trackFile->is_in_progress === true) {
|
||||
} elseif ($trackFile->status === TrackFile::STATUS_PROCESSING) {
|
||||
$url = null;
|
||||
} else {
|
||||
$this->dispatch(new EncodeTrackFile($trackFile, true));
|
||||
|
|
|
@ -35,7 +35,7 @@ abstract class ApiControllerBase extends Controller
|
|||
if ($result->didFail()) {
|
||||
return Response::json([
|
||||
'message' => 'Validation failed',
|
||||
'errors' => $result->getValidator()->messages()->getMessages()
|
||||
'errors' => $result->getMessages()
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ use DB;
|
|||
use Input;
|
||||
use Poniverse;
|
||||
use Redirect;
|
||||
use URL;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
|
@ -36,7 +35,7 @@ class AuthController extends Controller
|
|||
public function __construct()
|
||||
{
|
||||
$this->poniverse = new Poniverse(Config::get('poniverse.client_id'), Config::get('poniverse.secret'));
|
||||
$this->poniverse->setRedirectUri(URL::to('/auth/oauth'));
|
||||
$this->poniverse->setRedirectUri(action('AuthController@getOAuth'));
|
||||
}
|
||||
|
||||
public function getLogin()
|
||||
|
@ -62,7 +61,7 @@ class AuthController extends Controller
|
|||
'authorization_code',
|
||||
[
|
||||
'code' => Input::query('code'),
|
||||
'redirect_uri' => URL::to('/auth/oauth')
|
||||
'redirect_uri' => action('AuthController@getOAuth')
|
||||
]);
|
||||
|
||||
if ($code['code'] != 200) {
|
||||
|
|
|
@ -25,7 +25,6 @@ use Config;
|
|||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Response;
|
||||
use URL;
|
||||
|
||||
class ImagesController extends Controller
|
||||
{
|
||||
|
@ -46,7 +45,7 @@ class ImagesController extends Controller
|
|||
$filename = $image->getFile($coverType['id']);
|
||||
|
||||
if (!is_file($filename)) {
|
||||
$redirect = URL::to('/images/icons/profile_' . Image::$ImageTypes[$coverType['id']]['name'] . '.png');
|
||||
$redirect = url('/images/icons/profile_' . Image::$ImageTypes[$coverType['id']]['name'] . '.png');
|
||||
|
||||
return Redirect::to($redirect);
|
||||
}
|
||||
|
|
|
@ -62,8 +62,6 @@ Route::get('/mlpforums-advertising-program', function() { return View::make('pag
|
|||
|
||||
Route::get('i{id}/{type}.png', 'ImagesController@getImage')->where('id', '\d+');
|
||||
|
||||
Route::get('u{id}/avatar_{type}.png', 'UsersController@getAvatar')->where('id', '\d+');
|
||||
|
||||
Route::get('playlist/{id}-{slug}', 'PlaylistsController@getPlaylist');
|
||||
Route::get('p{id}', 'PlaylistsController@getShortlink')->where('id', '\d+');
|
||||
Route::get('p{id}/dl.{extension}', 'PlaylistsController@getDownload' );
|
||||
|
@ -101,6 +99,7 @@ Route::group(['prefix' => 'api/web'], function() {
|
|||
|
||||
Route::group(['middleware' => 'auth'], function() {
|
||||
Route::post('/tracks/upload', 'Api\Web\TracksController@postUpload');
|
||||
Route::get('/tracks/{id}/upload-status', 'Api\Web\TracksController@getUploadStatus');
|
||||
Route::post('/tracks/delete/{id}', 'Api\Web\TracksController@postDelete');
|
||||
Route::post('/tracks/edit/{id}', 'Api\Web\TracksController@postEdit');
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ namespace Poniverse\Ponyfm;
|
|||
|
||||
use External;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Config;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
class Image extends Model
|
||||
|
@ -101,7 +100,7 @@ class Image extends Model
|
|||
{
|
||||
$type = self::$ImageTypes[$type];
|
||||
|
||||
return URL::to('i' . $this->id . '/' . $type['name'] . '.png');
|
||||
return action('ImagesController@getImage', ['id' => $this->id, 'type' => $type['name']]);
|
||||
}
|
||||
|
||||
public function getFile($type = self::NORMAL)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/**
|
||||
* Pony.fm - A community for pony fan music.
|
||||
* Copyright (C) 2015 Peter Deltchev
|
||||
* Copyright (C) 2015 Kelvin Zhang
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -21,9 +22,11 @@
|
|||
namespace Poniverse\Ponyfm\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use File;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use OAuth2\Exception;
|
||||
use Poniverse\Ponyfm\Exceptions\InvalidEncodeOptionsException;
|
||||
use Poniverse\Ponyfm\Jobs\Job;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
@ -45,16 +48,29 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
|||
* @var
|
||||
*/
|
||||
private $isExpirable;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isForUpload;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
* @param TrackFile $trackFile
|
||||
* @param $isExpirable
|
||||
* @param bool $isExpirable
|
||||
* @param bool $isForUpload indicates whether this encode job is for an upload
|
||||
*/
|
||||
public function __construct(TrackFile $trackFile, $isExpirable)
|
||||
public function __construct(TrackFile $trackFile, $isExpirable, $isForUpload = false)
|
||||
{
|
||||
if(
|
||||
(!$isForUpload && $trackFile->is_master) ||
|
||||
($isForUpload && $trackFile->is_master && !$trackFile->getFormat()['is_lossless'])
|
||||
) {
|
||||
throw new InvalidEncodeOptionsException("Master files cannot be encoded unless we're generating a lossless master file during the upload process.");
|
||||
}
|
||||
|
||||
$this->trackFile = $trackFile;
|
||||
$this->isExpirable = $isExpirable;
|
||||
$this->isForUpload = $isForUpload;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,14 +81,19 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
|||
public function handle()
|
||||
{
|
||||
// Start the job
|
||||
$this->trackFile->is_in_progress = true;
|
||||
$this->trackFile->status = TrackFile::STATUS_PROCESSING;
|
||||
$this->trackFile->update();
|
||||
|
||||
// Use the track's master file as the source
|
||||
$source = TrackFile::where('track_id', $this->trackFile->track_id)
|
||||
->where('is_master', true)
|
||||
->first()
|
||||
->getFile();
|
||||
if ($this->isForUpload) {
|
||||
$source = $this->trackFile->track->getTemporarySourceFile();
|
||||
|
||||
} else {
|
||||
$source = TrackFile::where('track_id', $this->trackFile->track_id)
|
||||
->where('is_master', true)
|
||||
->first()
|
||||
->getFile();
|
||||
}
|
||||
|
||||
// Assign the target
|
||||
$this->trackFile->track->ensureDirectoryExists();
|
||||
|
@ -111,8 +132,18 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
|||
$this->trackFile->updateFilesize();
|
||||
|
||||
// Complete the job
|
||||
$this->trackFile->is_in_progress = false;
|
||||
$this->trackFile->status = TrackFile::STATUS_NOT_BEING_PROCESSED;
|
||||
$this->trackFile->update();
|
||||
|
||||
if ($this->isForUpload) {
|
||||
if (!$this->trackFile->is_master && $this->trackFile->is_cacheable) {
|
||||
File::delete($this->trackFile->getFile());
|
||||
}
|
||||
|
||||
if ($this->trackFile->track->status === Track::STATUS_COMPLETE) {
|
||||
File::delete($this->trackFile->track->getTemporarySourceFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,7 +153,7 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue
|
|||
*/
|
||||
public function failed()
|
||||
{
|
||||
$this->trackFile->is_in_progress = false;
|
||||
$this->trackFile->status = TrackFile::STATUS_PROCESSING_ERROR;
|
||||
$this->trackFile->expires_at = null;
|
||||
$this->trackFile->update();
|
||||
}
|
||||
|
|
0
app/Library/getid3/.gitattributes
vendored
Executable file → Normal file
0
app/Library/getid3/.gitattributes
vendored
Executable file → Normal file
7
app/Library/getid3/.gitignore
vendored
Executable file → Normal file
7
app/Library/getid3/.gitignore
vendored
Executable file → Normal file
|
@ -1,4 +1,4 @@
|
|||
helperapps/sha1sum.exe
|
||||
helperapps/*.exe
|
||||
helperapps/*.dll
|
||||
|
||||
|
||||
|
@ -110,7 +110,9 @@ ClientBin
|
|||
stylecop.*
|
||||
~$*
|
||||
*.dbmdl
|
||||
Generated_Code #added for RIA/Silverlight projects
|
||||
|
||||
#added for RIA/Silverlight projects
|
||||
Generated_Code
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
|
@ -165,3 +167,4 @@ pip-log.txt
|
|||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
demos/php_error.log
|
||||
|
|
2
app/Library/getid3/README.md
Executable file → Normal file
2
app/Library/getid3/README.md
Executable file → Normal file
|
@ -186,7 +186,7 @@ if ($fp_remote = fopen($remotefilename, 'rb')) {
|
|||
fclose($fp_local);
|
||||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
$ThisFileInfo = $getID3->analyze($filename);
|
||||
$ThisFileInfo = $getID3->analyze($localtempfilename);
|
||||
// Delete temporary file
|
||||
unlink($localtempfilename);
|
||||
}
|
||||
|
|
11
app/Library/getid3/changelog.txt
Executable file → Normal file
11
app/Library/getid3/changelog.txt
Executable file → Normal file
|
@ -18,6 +18,17 @@
|
|||
Version History
|
||||
===============
|
||||
|
||||
1.9.10: [2015-09-14] James Heinrich
|
||||
* bugfix (G:49): Declaration of getID3_cached_sqlite3
|
||||
* bugfix (#1892): extension.cache.mysql
|
||||
* bugfix (#1891): duplicate default clause [Quicktime]
|
||||
* bugfix (G:41): incorrect MP3 playtime
|
||||
* bugfix: iconv problems on musl with //TRANSLIT
|
||||
* Add arguments to analyze() for original filesize (and filename)
|
||||
* ID3v2 simplify handling of multiple genres
|
||||
* Corrected merging of multiple genres for ID3v2
|
||||
* getid3_lib::GetDataImageSize return false on error
|
||||
|
||||
1.9.9: [2014-12-18] James Heinrich
|
||||
» Added basic support for OggOpus
|
||||
» Add ID3v2 CHAP + CTOC support
|
||||
|
|
0
app/Library/getid3/composer.json
Executable file → Normal file
0
app/Library/getid3/composer.json
Executable file → Normal file
0
app/Library/getid3/demos/demo.audioinfo.class.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.audioinfo.class.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.basic.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.basic.php
Executable file → Normal file
10
app/Library/getid3/demos/demo.browse.php
Executable file → Normal file
10
app/Library/getid3/demos/demo.browse.php
Executable file → Normal file
|
@ -480,8 +480,11 @@ function table_var_dump($variable, $wrap_in_td=false, $encoding='ISO-8859-1') {
|
|||
//if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
|
||||
if (($key == 'data') && isset($variable['image_mime'])) {
|
||||
$imageinfo = array();
|
||||
$imagechunkcheck = getid3_lib::GetDataImageSize($value, $imageinfo);
|
||||
$returnstring .= '</td>'."\n".'<td><img src="data:'.$variable['image_mime'].';base64,'.base64_encode($value).'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>'."\n";
|
||||
if ($imagechunkcheck = getid3_lib::GetDataImageSize($value, $imageinfo)) {
|
||||
$returnstring .= '</td>'."\n".'<td><img src="data:'.$variable['image_mime'].';base64,'.base64_encode($value).'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>'."\n";
|
||||
} else {
|
||||
$returnstring .= '</td>'."\n".'<td><i>invalid image data</i></td></tr>'."\n";
|
||||
}
|
||||
} else {
|
||||
$returnstring .= '</td>'."\n".table_var_dump($value, true, $encoding).'</tr>'."\n";
|
||||
}
|
||||
|
@ -515,8 +518,7 @@ function table_var_dump($variable, $wrap_in_td=false, $encoding='ISO-8859-1') {
|
|||
|
||||
default:
|
||||
$imageinfo = array();
|
||||
$imagechunkcheck = getid3_lib::GetDataImageSize($variable, $imageinfo);
|
||||
if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
|
||||
if (($imagechunkcheck = getid3_lib::GetDataImageSize($variable, $imageinfo)) && ($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
|
||||
$returnstring .= ($wrap_in_td ? '<td>' : '');
|
||||
$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
|
||||
$returnstring .= '<tr><td><b>type</b></td><td>'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]).'</td></tr>'."\n";
|
||||
|
|
0
app/Library/getid3/demos/demo.cache.dbm.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.cache.dbm.php
Executable file → Normal file
1
app/Library/getid3/demos/demo.cache.mysql.php
Executable file → Normal file
1
app/Library/getid3/demos/demo.cache.mysql.php
Executable file → Normal file
|
@ -17,6 +17,7 @@ die('Due to a security issue, this demo has been disabled. It can be enabled by
|
|||
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
require_once('../getid3/getid3.lib.php');
|
||||
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'extension.cache.mysql.php', __FILE__, true);
|
||||
|
||||
$getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password');
|
||||
|
|
72
app/Library/getid3/demos/demo.joinmp3.php
Executable file → Normal file
72
app/Library/getid3/demos/demo.joinmp3.php
Executable file → Normal file
|
@ -9,37 +9,47 @@
|
|||
// /demo/demo.joinmp3.php - part of getID3() //
|
||||
// Sample script for splicing two or more MP3s together into //
|
||||
// one file. Does not attempt to fix VBR header frames. //
|
||||
// Can also be used to extract portion from single file. //
|
||||
// See readme.txt for more details //
|
||||
// ///
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// sample usage:
|
||||
// $FilenameOut = 'combined.mp3';
|
||||
// $FilenamesIn[] = 'file1.mp3';
|
||||
// $FilenamesIn[] = 'file2.mp3';
|
||||
// $FilenamesIn[] = 'file3.mp3';
|
||||
// $FilenameOut = 'combined.mp3';
|
||||
// $FilenamesIn[] = 'first.mp3'; // filename with no start/length parameters
|
||||
// $FilenamesIn[] = array('second.mp3', 0, 0); // filename with zero for start/length is the same as not specified (start = beginning, length = full duration)
|
||||
// $FilenamesIn[] = array('third.mp3', 0, 10); // extract first 10 seconds of audio
|
||||
// $FilenamesIn[] = array('fourth.mp3', -10, 0); // extract last 10 seconds of audio
|
||||
// $FilenamesIn[] = array('fifth.mp3', 10, 0); // extract everything except first 10 seconds of audio
|
||||
// $FilenamesIn[] = array('sixth.mp3', 0, -10); // extract everything except last 10 seconds of audio
|
||||
// if (CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)) {
|
||||
// echo 'Successfully copied '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
|
||||
// } else {
|
||||
// echo 'Failed to copy '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
|
||||
// }
|
||||
//
|
||||
// if (CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)) {
|
||||
// echo 'Successfully copied '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
|
||||
// } else {
|
||||
// echo 'Failed to copy '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
|
||||
// }
|
||||
// Could also be called like this to extract portion from single file:
|
||||
// CombineMultipleMP3sTo('sample.mp3', array(array('input.mp3', 0, 30))); // extract first 30 seconds of audio
|
||||
|
||||
|
||||
function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
|
||||
|
||||
foreach ($FilenamesIn as $nextinputfilename) {
|
||||
if (is_array($nextinputfilename)) {
|
||||
$nextinputfilename = $nextinputfilename[0];
|
||||
}
|
||||
if (!is_readable($nextinputfilename)) {
|
||||
echo 'Cannot read "'.$nextinputfilename.'"<BR>';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!is_writeable($FilenameOut)) {
|
||||
if ((file_exists($FilenameOut) && !is_writeable($FilenameOut)) || (!file_exists($FilenameOut) && !is_writeable(dirname($FilenameOut)))) {
|
||||
echo 'Cannot write "'.$FilenameOut.'"<BR>';
|
||||
return false;
|
||||
}
|
||||
|
||||
require_once('../getid3/getid3.php');
|
||||
require_once(dirname(__FILE__).'/../getid3/getid3.php');
|
||||
ob_start();
|
||||
if ($fp_output = fopen($FilenameOut, 'wb')) {
|
||||
|
||||
|
@ -47,7 +57,11 @@ function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
|
|||
// Initialize getID3 engine
|
||||
$getID3 = new getID3;
|
||||
foreach ($FilenamesIn as $nextinputfilename) {
|
||||
|
||||
$startoffset = 0;
|
||||
$length_seconds = 0;
|
||||
if (is_array($nextinputfilename)) {
|
||||
@list($nextinputfilename, $startoffset, $length_seconds) = $nextinputfilename;
|
||||
}
|
||||
$CurrentFileInfo = $getID3->analyze($nextinputfilename);
|
||||
if ($CurrentFileInfo['fileformat'] == 'mp3') {
|
||||
|
||||
|
@ -58,17 +72,35 @@ function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
|
|||
$CurrentOutputPosition = ftell($fp_output);
|
||||
|
||||
// copy audio data from first file
|
||||
fseek($fp_source, $CurrentFileInfo['avdataoffset'], SEEK_SET);
|
||||
while (!feof($fp_source) && (ftell($fp_source) < $CurrentFileInfo['avdataend'])) {
|
||||
fwrite($fp_output, fread($fp_source, 32768));
|
||||
$start_offset_bytes = $CurrentFileInfo['avdataoffset'];
|
||||
if ($startoffset > 0) { // start X seconds from start of audio
|
||||
$start_offset_bytes = $CurrentFileInfo['avdataoffset'] + round($CurrentFileInfo['bitrate'] / 8 * $startoffset);
|
||||
} elseif ($startoffset < 0) { // start X seconds from end of audio
|
||||
$start_offset_bytes = $CurrentFileInfo['avdataend'] + round($CurrentFileInfo['bitrate'] / 8 * $startoffset);
|
||||
}
|
||||
$start_offset_bytes = max($CurrentFileInfo['avdataoffset'], min($CurrentFileInfo['avdataend'], $start_offset_bytes));
|
||||
|
||||
$end_offset_bytes = $CurrentFileInfo['avdataend'];
|
||||
if ($length_seconds > 0) { // seconds from start of audio
|
||||
$end_offset_bytes = $start_offset_bytes + round($CurrentFileInfo['bitrate'] / 8 * $length_seconds);
|
||||
} elseif ($length_seconds < 0) { // seconds from start of audio
|
||||
$end_offset_bytes = $CurrentFileInfo['avdataend'] + round($CurrentFileInfo['bitrate'] / 8 * $startoffset);
|
||||
}
|
||||
$end_offset_bytes = max($CurrentFileInfo['avdataoffset'], min($CurrentFileInfo['avdataend'], $end_offset_bytes));
|
||||
|
||||
if ($end_offset_bytes <= $start_offset_bytes) {
|
||||
echo 'failed to copy '.$nextinputfilename.' from '.$startoffset.'-seconds start for '.$length_seconds.'-seconds length (not enough data)';
|
||||
fclose($fp_source);
|
||||
fclose($fp_output);
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek($fp_source, $start_offset_bytes, SEEK_SET);
|
||||
while (!feof($fp_source) && (ftell($fp_source) < $end_offset_bytes)) {
|
||||
fwrite($fp_output, fread($fp_source, min(32768, $end_offset_bytes - ftell($fp_source))));
|
||||
}
|
||||
fclose($fp_source);
|
||||
|
||||
// trim post-audio data (if any) copied from first file that we don't need or want
|
||||
$EndOfFileOffset = $CurrentOutputPosition + ($CurrentFileInfo['avdataend'] - $CurrentFileInfo['avdataoffset']);
|
||||
fseek($fp_output, $EndOfFileOffset, SEEK_SET);
|
||||
ftruncate($fp_output, $EndOfFileOffset);
|
||||
|
||||
} else {
|
||||
|
||||
$errormessage = ob_get_contents();
|
||||
|
|
0
app/Library/getid3/demos/demo.mimeonly.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.mimeonly.php
Executable file → Normal file
29
app/Library/getid3/demos/demo.mp3header.php
Executable file → Normal file
29
app/Library/getid3/demos/demo.mp3header.php
Executable file → Normal file
|
@ -29,10 +29,10 @@ if (!function_exists('table_var_dump')) {
|
|||
$returnstring = '';
|
||||
switch (gettype($variable)) {
|
||||
case 'array':
|
||||
$returnstring .= '<TABLE BORDER="1" CELLSPACING="0" CELLPADDING="2">';
|
||||
$returnstring .= '<table border="1" cellspacing="0" cellpadding="2">';
|
||||
foreach ($variable as $key => $value) {
|
||||
$returnstring .= '<TR><TD VALIGN="TOP"><B>'.str_replace(chr(0), ' ', $key).'</B></TD>';
|
||||
$returnstring .= '<TD VALIGN="TOP">'.gettype($value);
|
||||
$returnstring .= '<tr><td valign="top"><b>'.str_replace(chr(0), ' ', $key).'</b></td>';
|
||||
$returnstring .= '<td valign="top">'.gettype($value);
|
||||
if (is_array($value)) {
|
||||
$returnstring .= ' ('.count($value).')';
|
||||
} elseif (is_string($value)) {
|
||||
|
@ -41,18 +41,21 @@ if (!function_exists('table_var_dump')) {
|
|||
if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
|
||||
require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php');
|
||||
$imageinfo = array();
|
||||
$imagechunkcheck = GetDataImageSize($value, $imageinfo);
|
||||
$DumpedImageSRC = (!empty($_REQUEST['filename']) ? $_REQUEST['filename'] : '.getid3').'.'.$variable['dataoffset'].'.'.ImageTypesLookup($imagechunkcheck[2]);
|
||||
if ($tempimagefile = fopen($DumpedImageSRC, 'wb')) {
|
||||
fwrite($tempimagefile, $value);
|
||||
fclose($tempimagefile);
|
||||
if ($imagechunkcheck = GetDataImageSize($value, $imageinfo)) {
|
||||
$DumpedImageSRC = (!empty($_REQUEST['filename']) ? $_REQUEST['filename'] : '.getid3').'.'.$variable['dataoffset'].'.'.ImageTypesLookup($imagechunkcheck[2]);
|
||||
if ($tempimagefile = fopen($DumpedImageSRC, 'wb')) {
|
||||
fwrite($tempimagefile, $value);
|
||||
fclose($tempimagefile);
|
||||
}
|
||||
$returnstring .= '</td><td><img src="'.$DumpedImageSRC.'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>';
|
||||
} else {
|
||||
$returnstring .= '</td><td><i>invalid image data</i></td></tr>';
|
||||
}
|
||||
$returnstring .= '</TD><TD><IMG SRC="'.$DumpedImageSRC.'" WIDTH="'.$imagechunkcheck[0].'" HEIGHT="'.$imagechunkcheck[1].'"></TD></TR>';
|
||||
} else {
|
||||
$returnstring .= '</TD><TD>'.table_var_dump($value).'</TD></TR>';
|
||||
$returnstring .= '</td><td>'.table_var_dump($value).'</td></tr>';
|
||||
}
|
||||
}
|
||||
$returnstring .= '</TABLE>';
|
||||
$returnstring .= '</table>';
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
|
@ -86,9 +89,7 @@ if (!function_exists('table_var_dump')) {
|
|||
default:
|
||||
require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php');
|
||||
$imageinfo = array();
|
||||
$imagechunkcheck = GetDataImageSize(substr($variable, 0, 32768), $imageinfo);
|
||||
|
||||
if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
|
||||
if (($imagechunkcheck = GetDataImageSize(substr($variable, 0, 32768), $imageinfo)) && ($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
|
||||
$returnstring .= '<table border="1" cellspacing="0" cellpadding="2">';
|
||||
$returnstring .= '<tr><td><b>type</b></td><td>'.ImageTypesLookup($imagechunkcheck[2]).'</td></tr>';
|
||||
$returnstring .= '<tr><td><b>width</b></td><td>'.number_format($imagechunkcheck[0]).' px</td></tr>';
|
||||
|
|
0
app/Library/getid3/demos/demo.mysql.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.mysql.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.simple.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.simple.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.simple.write.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.simple.write.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.write.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.write.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.zip.php
Executable file → Normal file
0
app/Library/getid3/demos/demo.zip.php
Executable file → Normal file
0
app/Library/getid3/demos/getid3.css
vendored
Executable file → Normal file
0
app/Library/getid3/demos/getid3.css
vendored
Executable file → Normal file
0
app/Library/getid3/demos/getid3.demo.dirscan.php
Executable file → Normal file
0
app/Library/getid3/demos/getid3.demo.dirscan.php
Executable file → Normal file
0
app/Library/getid3/demos/index.php
Executable file → Normal file
0
app/Library/getid3/demos/index.php
Executable file → Normal file
0
app/Library/getid3/dependencies.txt
Executable file → Normal file
0
app/Library/getid3/dependencies.txt
Executable file → Normal file
2
app/Library/getid3/getid3/extension.cache.dbm.php
Executable file → Normal file
2
app/Library/getid3/getid3/extension.cache.dbm.php
Executable file → Normal file
|
@ -74,7 +74,7 @@ class getID3_cached_dbm extends getID3
|
|||
{
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
public function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) {
|
||||
public function __construct($cache_type, $dbm_filename, $lock_filename) {
|
||||
|
||||
// Check for dba extension
|
||||
if (!extension_loaded('dba')) {
|
||||
|
|
10
app/Library/getid3/getid3/extension.cache.mysql.php
Executable file → Normal file
10
app/Library/getid3/getid3/extension.cache.mysql.php
Executable file → Normal file
|
@ -80,7 +80,7 @@ class getID3_cached_mysql extends getID3
|
|||
|
||||
|
||||
// public: constructor - see top of this file for cache type and cache_options
|
||||
public function getID3_cached_mysql($host, $database, $username, $password, $table='getid3_cache') {
|
||||
public function __construct($host, $database, $username, $password, $table='getid3_cache') {
|
||||
|
||||
// Check for mysql support
|
||||
if (!function_exists('mysql_pconnect')) {
|
||||
|
@ -134,7 +134,7 @@ class getID3_cached_mysql extends getID3
|
|||
|
||||
|
||||
// public: analyze file
|
||||
public function analyze($filename) {
|
||||
public function analyze($filename, $filesize=null, $original_filename='') {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
|
||||
|
@ -157,7 +157,7 @@ class getID3_cached_mysql extends getID3
|
|||
}
|
||||
|
||||
// Miss
|
||||
$analysis = parent::analyze($filename);
|
||||
$analysis = parent::analyze($filename, $filesize, $original_filename);
|
||||
|
||||
// Save result
|
||||
if (file_exists($filename)) {
|
||||
|
@ -178,11 +178,11 @@ class getID3_cached_mysql extends getID3
|
|||
private function create_table($drop=false) {
|
||||
|
||||
$SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` (';
|
||||
$SQLquery .= '`filename` VARCHAR(255) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= '`filename` VARCHAR(500) NOT NULL DEFAULT \'\'';
|
||||
$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
|
||||
$SQLquery .= ', `value` TEXT NOT NULL';
|
||||
$SQLquery .= ', `value` LONGTEXT NOT NULL';
|
||||
$SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM';
|
||||
$this->cursor = mysql_query($SQLquery, $this->connection);
|
||||
echo mysql_error($this->connection);
|
||||
|
|
55
app/Library/getid3/getid3/extension.cache.sqlite3.php
Executable file → Normal file
55
app/Library/getid3/getid3/extension.cache.sqlite3.php
Executable file → Normal file
|
@ -49,20 +49,20 @@
|
|||
*
|
||||
* sqlite3 table='getid3_cache', hide=false (PHP5)
|
||||
*
|
||||
|
||||
*** database file will be stored in the same directory as this script,
|
||||
*** webserver must have write access to that directory!
|
||||
*** set $hide to TRUE to prefix db file with .ht to pervent access from web client
|
||||
*** this is a default setting in the Apache configuration:
|
||||
|
||||
# The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients.
|
||||
|
||||
<Files ~ "^\.ht">
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
Satisfy all
|
||||
</Files>
|
||||
|
||||
*
|
||||
* *** database file will be stored in the same directory as this script,
|
||||
* *** webserver must have write access to that directory!
|
||||
* *** set $hide to TRUE to prefix db file with .ht to pervent access from web client
|
||||
* *** this is a default setting in the Apache configuration:
|
||||
*
|
||||
* The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients.
|
||||
*
|
||||
* <Files ~ "^\.ht">
|
||||
* Order allow,deny
|
||||
* Deny from all
|
||||
* Satisfy all
|
||||
* </Files>
|
||||
*
|
||||
********************************************************************************
|
||||
*
|
||||
* -------------------------------------------------------------------
|
||||
|
@ -159,13 +159,13 @@ class getID3_cached_sqlite3 extends getID3 {
|
|||
* @param type $filename
|
||||
* @return boolean
|
||||
*/
|
||||
public function analyze($filename) {
|
||||
public function analyze($filename, $filesize=null, $original_filename='') {
|
||||
if (!file_exists($filename)) {
|
||||
return false;
|
||||
}
|
||||
// items to track for caching
|
||||
$filetime = filemtime($filename);
|
||||
$filesize = filesize($filename);
|
||||
$filesize_real = filesize($filename);
|
||||
// this will be saved for a quick directory lookup of analized files
|
||||
// ... why do 50 seperate sql quries when you can do 1 for the same result
|
||||
$dirname = dirname($filename);
|
||||
|
@ -173,25 +173,25 @@ class getID3_cached_sqlite3 extends getID3 {
|
|||
$db = $this->db;
|
||||
$sql = $this->get_id3_data;
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
|
||||
$res = $stmt->execute();
|
||||
list($result) = $res->fetchArray();
|
||||
if (count($result) > 0 ) {
|
||||
return unserialize(base64_decode($result));
|
||||
}
|
||||
// if it hasn't been analyzed before, then do it now
|
||||
$analysis = parent::analyze($filename);
|
||||
$analysis = parent::analyze($filename, $filesize, $original_filename);
|
||||
// Save result
|
||||
$sql = $this->cache_file;
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
|
||||
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
|
||||
$res = $stmt->execute();
|
||||
return $analysis;
|
||||
}
|
||||
|
@ -253,7 +253,8 @@ class getID3_cached_sqlite3 extends getID3 {
|
|||
return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
|
||||
break;
|
||||
case 'make_table':
|
||||
return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname VARCHAR(255) NOT NULL DEFAULT '', filesize INT(11) NOT NULL DEFAULT '0', filetime INT(11) NOT NULL DEFAULT '0', analyzetime INT(11) NOT NULL DEFAULT '0', val text not null, PRIMARY KEY (filename, filesize, filetime))";
|
||||
//return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname VARCHAR(255) NOT NULL DEFAULT '', filesize INT(11) NOT NULL DEFAULT '0', filetime INT(11) NOT NULL DEFAULT '0', analyzetime INT(11) NOT NULL DEFAULT '0', val text not null, PRIMARY KEY (filename, filesize, filetime))";
|
||||
return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) DEFAULT '', dirname VARCHAR(255) DEFAULT '', filesize INT(11) DEFAULT '0', filetime INT(11) DEFAULT '0', analyzetime INT(11) DEFAULT '0', val text, PRIMARY KEY (filename, filesize, filetime))";
|
||||
break;
|
||||
case 'get_cached_dir':
|
||||
return "SELECT val FROM $this->table WHERE dirname = :dirname";
|
||||
|
|
47
app/Library/getid3/getid3/getid3.lib.php
Executable file → Normal file
47
app/Library/getid3/getid3/getid3.lib.php
Executable file → Normal file
|
@ -414,6 +414,20 @@ class getid3_lib
|
|||
return $newarray;
|
||||
}
|
||||
|
||||
public static function flipped_array_merge_noclobber($array1, $array2) {
|
||||
if (!is_array($array1) || !is_array($array2)) {
|
||||
return false;
|
||||
}
|
||||
# naturally, this only works non-recursively
|
||||
$newarray = array_flip($array1);
|
||||
foreach (array_flip($array2) as $key => $val) {
|
||||
if (!isset($newarray[$key])) {
|
||||
$newarray[$key] = count($newarray);
|
||||
}
|
||||
}
|
||||
return array_flip($newarray);
|
||||
}
|
||||
|
||||
|
||||
public static function ksort_recursive(&$theArray) {
|
||||
ksort($theArray);
|
||||
|
@ -522,12 +536,12 @@ class getid3_lib
|
|||
if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
|
||||
// http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
|
||||
// https://core.trac.wordpress.org/changeset/29378
|
||||
$loader = libxml_disable_entity_loader(true);
|
||||
$XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT);
|
||||
$return = self::SimpleXMLelement2array($XMLobject);
|
||||
libxml_disable_entity_loader($loader);
|
||||
return $return;
|
||||
}
|
||||
$loader = libxml_disable_entity_loader(true);
|
||||
$XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT);
|
||||
$return = self::SimpleXMLelement2array($XMLobject);
|
||||
libxml_disable_entity_loader($loader);
|
||||
return $return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -606,7 +620,7 @@ class getid3_lib
|
|||
|
||||
if (empty($tempdir)) {
|
||||
// yes this is ugly, feel free to suggest a better way
|
||||
require_once(dirname(__FILE__) . '/getid3.php');
|
||||
require_once(dirname(__FILE__).'/getid3.php');
|
||||
$getid3_temp = new getID3();
|
||||
$tempdir = $getid3_temp->tempdir;
|
||||
unset($getid3_temp);
|
||||
|
@ -1153,11 +1167,19 @@ class getid3_lib
|
|||
public static function GetDataImageSize($imgData, &$imageinfo=array()) {
|
||||
static $tempdir = '';
|
||||
if (empty($tempdir)) {
|
||||
if (function_exists('sys_get_temp_dir')) {
|
||||
$tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52
|
||||
}
|
||||
|
||||
// yes this is ugly, feel free to suggest a better way
|
||||
require_once(dirname(__FILE__) . '/getid3.php');
|
||||
$getid3_temp = new getID3();
|
||||
$tempdir = $getid3_temp->tempdir;
|
||||
unset($getid3_temp);
|
||||
if (include_once(dirname(__FILE__).'/getid3.php')) {
|
||||
if ($getid3_temp = new getID3()) {
|
||||
if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
|
||||
$tempdir = $getid3_temp_tempdir;
|
||||
}
|
||||
unset($getid3_temp, $getid3_temp_tempdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
$GetDataImageSize = false;
|
||||
if ($tempfilename = tempnam($tempdir, 'gI3')) {
|
||||
|
@ -1165,6 +1187,9 @@ class getid3_lib
|
|||
fwrite($tmp, $imgData);
|
||||
fclose($tmp);
|
||||
$GetDataImageSize = @getimagesize($tempfilename, $imageinfo);
|
||||
if (($GetDataImageSize === false) || !isset($GetDataImageSize[0]) || !isset($GetDataImageSize[1])) {
|
||||
return false;
|
||||
}
|
||||
$GetDataImageSize['height'] = $GetDataImageSize[0];
|
||||
$GetDataImageSize['width'] = $GetDataImageSize[1];
|
||||
}
|
||||
|
|
39
app/Library/getid3/getid3/getid3.php
Executable file → Normal file
39
app/Library/getid3/getid3/getid3.php
Executable file → Normal file
|
@ -109,7 +109,7 @@ class getID3
|
|||
protected $startup_error = '';
|
||||
protected $startup_warning = '';
|
||||
|
||||
const VERSION = '1.9.9-20141121';
|
||||
const VERSION = '1.9.10-201511241457';
|
||||
const FREAD_BUFFER_SIZE = 32768;
|
||||
|
||||
const ATTACHMENTS_NONE = false;
|
||||
|
@ -166,7 +166,7 @@ class getID3
|
|||
}
|
||||
|
||||
// Load support library
|
||||
if (!include_once(GETID3_INCLUDEPATH . 'getid3.lib.php')) {
|
||||
if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
|
||||
$this->startup_error .= 'getid3.lib.php is missing or corrupt';
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,7 @@ class getID3
|
|||
}
|
||||
|
||||
|
||||
public function openfile($filename) {
|
||||
public function openfile($filename, $filesize=null) {
|
||||
try {
|
||||
if (!empty($this->startup_error)) {
|
||||
throw new getid3_exception($this->startup_error);
|
||||
|
@ -287,7 +287,7 @@ class getID3
|
|||
throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
|
||||
}
|
||||
|
||||
$this->info['filesize'] = filesize($filename);
|
||||
$this->info['filesize'] = (!is_null($filesize) ? $filesize : filesize($filename));
|
||||
// set redundant parameters - might be needed in some include file
|
||||
// filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
|
||||
$filename = str_replace('\\', '/', $filename);
|
||||
|
@ -342,9 +342,9 @@ class getID3
|
|||
}
|
||||
|
||||
// public: analyze file
|
||||
public function analyze($filename) {
|
||||
public function analyze($filename, $filesize=null, $original_filename='') {
|
||||
try {
|
||||
if (!$this->openfile($filename)) {
|
||||
if (!$this->openfile($filename, $filesize)) {
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
|
@ -389,7 +389,7 @@ class getID3
|
|||
$formattest = fread($this->fp, 32774);
|
||||
|
||||
// determine format
|
||||
$determined_format = $this->GetFileFormat($formattest, $filename);
|
||||
$determined_format = $this->GetFileFormat($formattest, ($original_filename ? $original_filename : $filename));
|
||||
|
||||
// unable to determine file format
|
||||
if (!$determined_format) {
|
||||
|
@ -876,7 +876,7 @@ class getID3
|
|||
'pattern' => '^(RIFF|SDSS|FORM)',
|
||||
'group' => 'audio-video',
|
||||
'module' => 'riff',
|
||||
'mime_type' => 'audio/x-wave',
|
||||
'mime_type' => 'audio/x-wav',
|
||||
'fail_ape' => 'WARNING',
|
||||
),
|
||||
|
||||
|
@ -1235,6 +1235,29 @@ class getID3
|
|||
}
|
||||
}
|
||||
|
||||
// ID3v1 encoding detection hack start
|
||||
// ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets
|
||||
// Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess
|
||||
if ($comment_name == 'id3v1') {
|
||||
if ($encoding == 'ISO-8859-1') {
|
||||
if (function_exists('iconv')) {
|
||||
foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
|
||||
foreach ($valuearray as $key => $value) {
|
||||
if (preg_match('#^[\\x80-\\xFF]+$#', $value)) {
|
||||
foreach (array('windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
|
||||
if (@iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
|
||||
$encoding = $id3v1_bad_encoding;
|
||||
break 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ID3v1 encoding detection hack end
|
||||
|
||||
$this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted!
|
||||
}
|
||||
|
||||
|
|
0
app/Library/getid3/getid3/module.archive.gzip.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.gzip.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.rar.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.rar.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.szip.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.szip.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.tar.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.tar.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.zip.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.archive.zip.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.asf.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.asf.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.bink.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.bink.php
Executable file → Normal file
2
app/Library/getid3/getid3/module.audio-video.flv.php
Executable file → Normal file
2
app/Library/getid3/getid3/module.audio-video.flv.php
Executable file → Normal file
|
@ -541,7 +541,7 @@ class AMFReader {
|
|||
// Long string
|
||||
default:
|
||||
$value = '(unknown or unsupported data type)';
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
|
33
app/Library/getid3/getid3/module.audio-video.matroska.php
Executable file → Normal file
33
app/Library/getid3/getid3/module.audio-video.matroska.php
Executable file → Normal file
|
@ -457,6 +457,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"');
|
||||
break;
|
||||
}
|
||||
|
||||
$info['audio']['streams'][] = $track_info;
|
||||
|
@ -524,6 +525,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('header', __LINE__, $element_data);
|
||||
break;
|
||||
}
|
||||
|
||||
unset($element_data['offset'], $element_data['end']);
|
||||
|
@ -562,6 +564,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
|
||||
break;
|
||||
}
|
||||
|
||||
if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
|
||||
|
@ -571,6 +574,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('seekhead', __LINE__, $seek_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -653,6 +657,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('track.video', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -678,6 +683,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('track.audio', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -713,6 +719,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -736,24 +743,28 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->unhandledElement('track', __LINE__, $subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -762,6 +773,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('tracks', __LINE__, $track_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -825,6 +837,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$info_entry[$subelement['id_name']] = $chaptertranslate_entry;
|
||||
|
@ -832,6 +845,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('info', __LINE__, $subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$info['matroska']['info'][] = $info_entry;
|
||||
|
@ -868,6 +882,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry;
|
||||
|
@ -879,6 +894,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$cues_entry[] = $cuepoint_entry;
|
||||
|
@ -886,6 +902,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('cues', __LINE__, $subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$info['matroska']['cues'] = $cues_entry;
|
||||
|
@ -927,6 +944,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$tag_entry[$sub_subelement['id_name']] = $targets_entry;
|
||||
|
@ -938,6 +956,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('tags.tag', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$tags_entry[] = $tag_entry;
|
||||
|
@ -945,6 +964,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('tags', __LINE__, $subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$info['matroska']['tags'] = $tags_entry;
|
||||
|
@ -985,6 +1005,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$info['matroska']['attachments'][] = $attachedfile_entry;
|
||||
|
@ -992,6 +1013,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('attachments', __LINE__, $subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1051,6 +1073,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry;
|
||||
|
@ -1070,6 +1093,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry;
|
||||
|
@ -1077,6 +1101,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry;
|
||||
|
@ -1084,6 +1109,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$info['matroska']['chapters'][] = $editionentry_entry;
|
||||
|
@ -1091,6 +1117,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('chapters', __LINE__, $subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1119,6 +1146,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks;
|
||||
|
@ -1149,6 +1177,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$cluster_entry[$subelement['id_name']][] = $cluster_block_group;
|
||||
|
@ -1160,6 +1189,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('cluster', __LINE__, $subelement);
|
||||
break;
|
||||
}
|
||||
$this->current_offset = $subelement['end'];
|
||||
}
|
||||
|
@ -1181,12 +1211,14 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('segment', __LINE__, $element_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->unhandledElement('root', __LINE__, $top_element);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1339,6 +1371,7 @@ class getid3_matroska extends getid3_handler
|
|||
|
||||
default:
|
||||
$this->unhandledElement('tag.simpletag', __LINE__, $element);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
0
app/Library/getid3/getid3/module.audio-video.mpeg.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.mpeg.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.nsv.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.nsv.php
Executable file → Normal file
563
app/Library/getid3/getid3/module.audio-video.quicktime.php
Executable file → Normal file
563
app/Library/getid3/getid3/module.audio-video.quicktime.php
Executable file → Normal file
|
@ -81,6 +81,81 @@ class getid3_quicktime extends getid3_handler
|
|||
unset($info['avdataend_tmp']);
|
||||
}
|
||||
|
||||
if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
|
||||
$durations = $this->quicktime_time_to_sample_table($info);
|
||||
for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) {
|
||||
$bookmark = array();
|
||||
$bookmark['title'] = $info['quicktime']['comments']['chapters'][$i];
|
||||
if (isset($durations[$i])) {
|
||||
$bookmark['duration_sample'] = $durations[$i]['sample_duration'];
|
||||
if ($i > 0) {
|
||||
$bookmark['start_sample'] = $info['quicktime']['bookmarks'][($i - 1)]['start_sample'] + $info['quicktime']['bookmarks'][($i - 1)]['duration_sample'];
|
||||
} else {
|
||||
$bookmark['start_sample'] = 0;
|
||||
}
|
||||
if ($time_scale = $this->quicktime_bookmark_time_scale($info)) {
|
||||
$bookmark['duration_seconds'] = $bookmark['duration_sample'] / $time_scale;
|
||||
$bookmark['start_seconds'] = $bookmark['start_sample'] / $time_scale;
|
||||
}
|
||||
}
|
||||
$info['quicktime']['bookmarks'][] = $bookmark;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($info['quicktime']['temp_meta_key_names'])) {
|
||||
unset($info['quicktime']['temp_meta_key_names']);
|
||||
}
|
||||
|
||||
if (!empty($info['quicktime']['comments']['location.ISO6709'])) {
|
||||
// https://en.wikipedia.org/wiki/ISO_6709
|
||||
foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) {
|
||||
$latitude = false;
|
||||
$longitude = false;
|
||||
$altitude = false;
|
||||
if (preg_match('#^([\\+\\-])([0-9]{2}|[0-9]{4}|[0-9]{6})(\\.[0-9]+)?([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?(([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?)?/$#', $ISO6709string, $matches)) {
|
||||
@list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches;
|
||||
|
||||
if (strlen($lat_deg) == 2) { // [+-]DD.D
|
||||
$latitude = floatval(ltrim($lat_deg, '0').$lat_deg_dec);
|
||||
} elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M
|
||||
$latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60);
|
||||
} elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S
|
||||
$latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600);
|
||||
}
|
||||
|
||||
if (strlen($lon_deg) == 3) { // [+-]DDD.D
|
||||
$longitude = floatval(ltrim($lon_deg, '0').$lon_deg_dec);
|
||||
} elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M
|
||||
$longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60);
|
||||
} elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S
|
||||
$longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600);
|
||||
}
|
||||
|
||||
if (strlen($alt_deg) == 3) { // [+-]DDD.D
|
||||
$altitude = floatval(ltrim($alt_deg, '0').$alt_deg_dec);
|
||||
} elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M
|
||||
$altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60);
|
||||
} elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S
|
||||
$altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600);
|
||||
}
|
||||
|
||||
if ($latitude !== false) {
|
||||
$info['quicktime']['comments']['gps_latitude'][] = (($lat_sign == '-') ? -1 : 1) * floatval($latitude);
|
||||
}
|
||||
if ($longitude !== false) {
|
||||
$info['quicktime']['comments']['gps_longitude'][] = (($lon_sign == '-') ? -1 : 1) * floatval($longitude);
|
||||
}
|
||||
if ($altitude !== false) {
|
||||
$info['quicktime']['comments']['gps_altitude'][] = (($alt_sign == '-') ? -1 : 1) * floatval($altitude);
|
||||
}
|
||||
}
|
||||
if ($latitude === false) {
|
||||
$info['warning'][] = 'location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
|
||||
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
|
||||
}
|
||||
|
@ -120,6 +195,7 @@ class getid3_quicktime extends getid3_handler
|
|||
|
||||
public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
|
||||
// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
|
||||
// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
|
@ -222,81 +298,88 @@ class getid3_quicktime extends getid3_handler
|
|||
break;
|
||||
|
||||
|
||||
case "\xA9".'alb': // ALBum
|
||||
case "\xA9".'ART': //
|
||||
case "\xA9".'art': // ARTist
|
||||
case "\xA9".'aut': //
|
||||
case "\xA9".'cmt': // CoMmenT
|
||||
case "\xA9".'com': // COMposer
|
||||
case "\xA9".'cpy': //
|
||||
case "\xA9".'day': // content created year
|
||||
case "\xA9".'dir': //
|
||||
case "\xA9".'ed1': //
|
||||
case "\xA9".'ed2': //
|
||||
case "\xA9".'ed3': //
|
||||
case "\xA9".'ed4': //
|
||||
case "\xA9".'ed5': //
|
||||
case "\xA9".'ed6': //
|
||||
case "\xA9".'ed7': //
|
||||
case "\xA9".'ed8': //
|
||||
case "\xA9".'ed9': //
|
||||
case "\xA9".'enc': //
|
||||
case "\xA9".'fmt': //
|
||||
case "\xA9".'gen': // GENre
|
||||
case "\xA9".'grp': // GRouPing
|
||||
case "\xA9".'hst': //
|
||||
case "\xA9".'inf': //
|
||||
case "\xA9".'lyr': // LYRics
|
||||
case "\xA9".'mak': //
|
||||
case "\xA9".'mod': //
|
||||
case "\xA9".'nam': // full NAMe
|
||||
case "\xA9".'ope': //
|
||||
case "\xA9".'PRD': //
|
||||
case "\xA9".'prf': //
|
||||
case "\xA9".'req': //
|
||||
case "\xA9".'src': //
|
||||
case "\xA9".'swr': //
|
||||
case "\xA9".'too': // encoder
|
||||
case "\xA9".'trk': // TRacK
|
||||
case "\xA9".'url': //
|
||||
case "\xA9".'wrn': //
|
||||
case "\xA9".'wrt': // WRiTer
|
||||
case '----': // itunes specific
|
||||
case 'aART': // Album ARTist
|
||||
case 'akID': // iTunes store account type
|
||||
case 'apID': // Purchase Account
|
||||
case 'atID': //
|
||||
case 'catg': // CaTeGory
|
||||
case 'cmID': //
|
||||
case 'cnID': //
|
||||
case 'covr': // COVeR artwork
|
||||
case 'cpil': // ComPILation
|
||||
case 'cprt': // CoPyRighT
|
||||
case 'desc': // DESCription
|
||||
case 'disk': // DISK number
|
||||
case 'egid': // Episode Global ID
|
||||
case 'geID': //
|
||||
case 'gnre': // GeNRE
|
||||
case 'hdvd': // HD ViDeo
|
||||
case 'keyw': // KEYWord
|
||||
case 'ldes':
|
||||
case 'ldes': // Long DEScription
|
||||
case 'pcst': // PodCaST
|
||||
case 'pgap': // GAPless Playback
|
||||
case 'plID': //
|
||||
case 'purd': // PURchase Date
|
||||
case 'purl': // Podcast URL
|
||||
case 'rati':
|
||||
case 'rndu':
|
||||
case 'rpdu':
|
||||
case 'rati': //
|
||||
case 'rndu': //
|
||||
case 'rpdu': //
|
||||
case 'rtng': // RaTiNG
|
||||
case 'stik':
|
||||
case 'sfID': // iTunes store country
|
||||
case 'soaa': // SOrt Album Artist
|
||||
case 'soal': // SOrt ALbum
|
||||
case 'soar': // SOrt ARtist
|
||||
case 'soco': // SOrt COmposer
|
||||
case 'sonm': // SOrt NaMe
|
||||
case 'sosn': // SOrt Show Name
|
||||
case 'stik': //
|
||||
case 'tmpo': // TeMPO (BPM)
|
||||
case 'trkn': // TRacK Number
|
||||
case 'tven': // tvEpisodeID
|
||||
case 'tves': // TV EpiSode
|
||||
case 'tvnn': // TV Network Name
|
||||
case 'tvsh': // TV SHow Name
|
||||
case 'tvsn': // TV SeasoN
|
||||
case 'akID': // iTunes store account type
|
||||
case 'apID':
|
||||
case 'atID':
|
||||
case 'cmID':
|
||||
case 'cnID':
|
||||
case 'geID':
|
||||
case 'plID':
|
||||
case 'sfID': // iTunes store country
|
||||
case "\xA9".'alb': // ALBum
|
||||
case "\xA9".'art': // ARTist
|
||||
case "\xA9".'ART':
|
||||
case "\xA9".'aut':
|
||||
case "\xA9".'cmt': // CoMmenT
|
||||
case "\xA9".'com': // COMposer
|
||||
case "\xA9".'cpy':
|
||||
case "\xA9".'day': // content created year
|
||||
case "\xA9".'dir':
|
||||
case "\xA9".'ed1':
|
||||
case "\xA9".'ed2':
|
||||
case "\xA9".'ed3':
|
||||
case "\xA9".'ed4':
|
||||
case "\xA9".'ed5':
|
||||
case "\xA9".'ed6':
|
||||
case "\xA9".'ed7':
|
||||
case "\xA9".'ed8':
|
||||
case "\xA9".'ed9':
|
||||
case "\xA9".'enc':
|
||||
case "\xA9".'fmt':
|
||||
case "\xA9".'gen': // GENre
|
||||
case "\xA9".'grp': // GRouPing
|
||||
case "\xA9".'hst':
|
||||
case "\xA9".'inf':
|
||||
case "\xA9".'lyr': // LYRics
|
||||
case "\xA9".'mak':
|
||||
case "\xA9".'mod':
|
||||
case "\xA9".'nam': // full NAMe
|
||||
case "\xA9".'ope':
|
||||
case "\xA9".'PRD':
|
||||
case "\xA9".'prd':
|
||||
case "\xA9".'prf':
|
||||
case "\xA9".'req':
|
||||
case "\xA9".'src':
|
||||
case "\xA9".'swr':
|
||||
case "\xA9".'too': // encoder
|
||||
case "\xA9".'trk': // TRacK
|
||||
case "\xA9".'url':
|
||||
case "\xA9".'wrn':
|
||||
case "\xA9".'wrt': // WRiTer
|
||||
case '----': // itunes specific
|
||||
if ($atom_parent == 'udta') {
|
||||
// User data atom handler
|
||||
$atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
|
||||
|
@ -361,17 +444,21 @@ class getid3_quicktime extends getid3_handler
|
|||
case 21: // tmpo/cpil flag
|
||||
switch ($atomname) {
|
||||
case 'cpil':
|
||||
case 'hdvd':
|
||||
case 'pcst':
|
||||
case 'pgap':
|
||||
// 8-bit integer (boolean)
|
||||
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
|
||||
break;
|
||||
|
||||
case 'tmpo':
|
||||
// 16-bit integer
|
||||
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
|
||||
break;
|
||||
|
||||
case 'disk':
|
||||
case 'trkn':
|
||||
// binary
|
||||
$num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
|
||||
$num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
|
||||
$atom_structure['data'] = empty($num) ? '' : $num;
|
||||
|
@ -379,21 +466,25 @@ class getid3_quicktime extends getid3_handler
|
|||
break;
|
||||
|
||||
case 'gnre':
|
||||
// enum
|
||||
$GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
|
||||
$atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1);
|
||||
break;
|
||||
|
||||
case 'rtng':
|
||||
// 8-bit integer
|
||||
$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
|
||||
$atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
|
||||
break;
|
||||
|
||||
case 'stik':
|
||||
// 8-bit integer (enum)
|
||||
$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
|
||||
$atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
|
||||
break;
|
||||
|
||||
case 'sfID':
|
||||
// 32-bit integer
|
||||
$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
|
||||
$atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
|
||||
break;
|
||||
|
@ -403,7 +494,18 @@ class getid3_quicktime extends getid3_handler
|
|||
$atom_structure['data'] = substr($boxdata, 8);
|
||||
break;
|
||||
|
||||
case 'plID':
|
||||
// 64-bit integer
|
||||
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8));
|
||||
break;
|
||||
|
||||
case 'atID':
|
||||
case 'cnID':
|
||||
case 'geID':
|
||||
case 'tves':
|
||||
case 'tvsn':
|
||||
default:
|
||||
// 32-bit integer
|
||||
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
|
||||
}
|
||||
break;
|
||||
|
@ -928,13 +1030,13 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
|
||||
$atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
|
||||
$drefDataOffset += 4;
|
||||
$atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
|
||||
$atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
|
||||
$drefDataOffset += 4;
|
||||
$atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1));
|
||||
$drefDataOffset += 1;
|
||||
$atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000
|
||||
$drefDataOffset += 3;
|
||||
$atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
|
||||
$atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
|
||||
$drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
|
||||
|
||||
$atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
|
||||
|
@ -1004,7 +1106,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
$info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
|
||||
return false;
|
||||
}
|
||||
$info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
|
||||
$info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
|
||||
|
||||
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
|
||||
$atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
|
||||
|
@ -1019,7 +1121,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
case 'pnot': // Preview atom
|
||||
$atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format"
|
||||
$atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00
|
||||
$atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'
|
||||
$atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'
|
||||
$atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
|
||||
|
||||
$atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
|
||||
|
@ -1029,7 +1131,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
case 'crgn': // Clipping ReGioN atom
|
||||
$atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box,
|
||||
$atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields
|
||||
$atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.
|
||||
$atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.
|
||||
break;
|
||||
|
||||
|
||||
|
@ -1120,7 +1222,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
}
|
||||
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
|
||||
$atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
|
||||
$info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
|
||||
$info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
|
||||
$info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
|
||||
$info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
|
||||
break;
|
||||
|
@ -1240,14 +1342,20 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
}
|
||||
|
||||
// check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
|
||||
while (($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
|
||||
while (($mdat_offset < (strlen($atom_data) - 8))
|
||||
&& ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
|
||||
&& ($chapter_string_length < 1000)
|
||||
&& ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
|
||||
&& preg_match('#^[\x20-\xFF]+$#', substr($atom_data, $mdat_offset + 2, $chapter_string_length), $chapter_matches)) {
|
||||
&& preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) {
|
||||
list($dummy, $chapter_string_length_hex, $chapter_string) = $chapter_matches;
|
||||
$mdat_offset += (2 + $chapter_string_length);
|
||||
@$info['quicktime']['comments']['chapters'][] = $chapter_matches[0];
|
||||
}
|
||||
@$info['quicktime']['comments']['chapters'][] = $chapter_string;
|
||||
|
||||
// "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled)
|
||||
if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-8
|
||||
$mdat_offset += 12;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
|
||||
|
@ -1397,22 +1505,53 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
break;
|
||||
|
||||
case "\x00\x00\x00\x00":
|
||||
case 'meta': // METAdata atom
|
||||
// some kind of metacontainer, may contain a big data dump such as:
|
||||
// mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
|
||||
|
||||
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
|
||||
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
|
||||
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
//$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
break;
|
||||
|
||||
case 'meta': // METAdata atom
|
||||
// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html
|
||||
|
||||
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
|
||||
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
|
||||
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
|
||||
break;
|
||||
|
||||
case 'data': // metaDATA atom
|
||||
static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other
|
||||
// seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
|
||||
$atom_structure['language'] = substr($atom_data, 4 + 0, 2);
|
||||
$atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
|
||||
$atom_structure['data'] = substr($atom_data, 4 + 4);
|
||||
$atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++];
|
||||
|
||||
if ($atom_structure['key_name'] && $atom_structure['data']) {
|
||||
@$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'keys': // KEYS that may be present in the metadata atom.
|
||||
// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21
|
||||
// The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom.
|
||||
// This list is indexed starting with 1; 0 is a reserved index value. The metadata item keys atom is a full atom with an atom type of "keys".
|
||||
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
|
||||
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
|
||||
$atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
|
||||
$keys_atom_offset = 8;
|
||||
for ($i = 1; $i <= $atom_structure['entry_count']; $i++) {
|
||||
$atom_structure['keys'][$i]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4));
|
||||
$atom_structure['keys'][$i]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4);
|
||||
$atom_structure['keys'][$i]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8);
|
||||
$keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace
|
||||
|
||||
$info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value'];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1753,56 +1892,56 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
|
|||
static $QuicktimeIODSaudioProfileNameLookup = array();
|
||||
if (empty($QuicktimeIODSaudioProfileNameLookup)) {
|
||||
$QuicktimeIODSaudioProfileNameLookup = array(
|
||||
0x00 => 'ISO Reserved (0x00)',
|
||||
0x01 => 'Main Audio Profile @ Level 1',
|
||||
0x02 => 'Main Audio Profile @ Level 2',
|
||||
0x03 => 'Main Audio Profile @ Level 3',
|
||||
0x04 => 'Main Audio Profile @ Level 4',
|
||||
0x05 => 'Scalable Audio Profile @ Level 1',
|
||||
0x06 => 'Scalable Audio Profile @ Level 2',
|
||||
0x07 => 'Scalable Audio Profile @ Level 3',
|
||||
0x08 => 'Scalable Audio Profile @ Level 4',
|
||||
0x09 => 'Speech Audio Profile @ Level 1',
|
||||
0x0A => 'Speech Audio Profile @ Level 2',
|
||||
0x0B => 'Synthetic Audio Profile @ Level 1',
|
||||
0x0C => 'Synthetic Audio Profile @ Level 2',
|
||||
0x0D => 'Synthetic Audio Profile @ Level 3',
|
||||
0x0E => 'High Quality Audio Profile @ Level 1',
|
||||
0x0F => 'High Quality Audio Profile @ Level 2',
|
||||
0x10 => 'High Quality Audio Profile @ Level 3',
|
||||
0x11 => 'High Quality Audio Profile @ Level 4',
|
||||
0x12 => 'High Quality Audio Profile @ Level 5',
|
||||
0x13 => 'High Quality Audio Profile @ Level 6',
|
||||
0x14 => 'High Quality Audio Profile @ Level 7',
|
||||
0x15 => 'High Quality Audio Profile @ Level 8',
|
||||
0x16 => 'Low Delay Audio Profile @ Level 1',
|
||||
0x17 => 'Low Delay Audio Profile @ Level 2',
|
||||
0x18 => 'Low Delay Audio Profile @ Level 3',
|
||||
0x19 => 'Low Delay Audio Profile @ Level 4',
|
||||
0x1A => 'Low Delay Audio Profile @ Level 5',
|
||||
0x1B => 'Low Delay Audio Profile @ Level 6',
|
||||
0x1C => 'Low Delay Audio Profile @ Level 7',
|
||||
0x1D => 'Low Delay Audio Profile @ Level 8',
|
||||
0x1E => 'Natural Audio Profile @ Level 1',
|
||||
0x1F => 'Natural Audio Profile @ Level 2',
|
||||
0x20 => 'Natural Audio Profile @ Level 3',
|
||||
0x21 => 'Natural Audio Profile @ Level 4',
|
||||
0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
|
||||
0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
|
||||
0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
|
||||
0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
|
||||
0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
|
||||
0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
|
||||
0x28 => 'AAC Profile @ Level 1',
|
||||
0x29 => 'AAC Profile @ Level 2',
|
||||
0x2A => 'AAC Profile @ Level 4',
|
||||
0x2B => 'AAC Profile @ Level 5',
|
||||
0x2C => 'High Efficiency AAC Profile @ Level 2',
|
||||
0x2D => 'High Efficiency AAC Profile @ Level 3',
|
||||
0x2E => 'High Efficiency AAC Profile @ Level 4',
|
||||
0x2F => 'High Efficiency AAC Profile @ Level 5',
|
||||
0xFE => 'Not part of MPEG-4 audio profiles',
|
||||
0xFF => 'No audio capability required',
|
||||
0x00 => 'ISO Reserved (0x00)',
|
||||
0x01 => 'Main Audio Profile @ Level 1',
|
||||
0x02 => 'Main Audio Profile @ Level 2',
|
||||
0x03 => 'Main Audio Profile @ Level 3',
|
||||
0x04 => 'Main Audio Profile @ Level 4',
|
||||
0x05 => 'Scalable Audio Profile @ Level 1',
|
||||
0x06 => 'Scalable Audio Profile @ Level 2',
|
||||
0x07 => 'Scalable Audio Profile @ Level 3',
|
||||
0x08 => 'Scalable Audio Profile @ Level 4',
|
||||
0x09 => 'Speech Audio Profile @ Level 1',
|
||||
0x0A => 'Speech Audio Profile @ Level 2',
|
||||
0x0B => 'Synthetic Audio Profile @ Level 1',
|
||||
0x0C => 'Synthetic Audio Profile @ Level 2',
|
||||
0x0D => 'Synthetic Audio Profile @ Level 3',
|
||||
0x0E => 'High Quality Audio Profile @ Level 1',
|
||||
0x0F => 'High Quality Audio Profile @ Level 2',
|
||||
0x10 => 'High Quality Audio Profile @ Level 3',
|
||||
0x11 => 'High Quality Audio Profile @ Level 4',
|
||||
0x12 => 'High Quality Audio Profile @ Level 5',
|
||||
0x13 => 'High Quality Audio Profile @ Level 6',
|
||||
0x14 => 'High Quality Audio Profile @ Level 7',
|
||||
0x15 => 'High Quality Audio Profile @ Level 8',
|
||||
0x16 => 'Low Delay Audio Profile @ Level 1',
|
||||
0x17 => 'Low Delay Audio Profile @ Level 2',
|
||||
0x18 => 'Low Delay Audio Profile @ Level 3',
|
||||
0x19 => 'Low Delay Audio Profile @ Level 4',
|
||||
0x1A => 'Low Delay Audio Profile @ Level 5',
|
||||
0x1B => 'Low Delay Audio Profile @ Level 6',
|
||||
0x1C => 'Low Delay Audio Profile @ Level 7',
|
||||
0x1D => 'Low Delay Audio Profile @ Level 8',
|
||||
0x1E => 'Natural Audio Profile @ Level 1',
|
||||
0x1F => 'Natural Audio Profile @ Level 2',
|
||||
0x20 => 'Natural Audio Profile @ Level 3',
|
||||
0x21 => 'Natural Audio Profile @ Level 4',
|
||||
0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
|
||||
0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
|
||||
0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
|
||||
0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
|
||||
0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
|
||||
0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
|
||||
0x28 => 'AAC Profile @ Level 1',
|
||||
0x29 => 'AAC Profile @ Level 2',
|
||||
0x2A => 'AAC Profile @ Level 4',
|
||||
0x2B => 'AAC Profile @ Level 5',
|
||||
0x2C => 'High Efficiency AAC Profile @ Level 2',
|
||||
0x2D => 'High Efficiency AAC Profile @ Level 3',
|
||||
0x2E => 'High Efficiency AAC Profile @ Level 4',
|
||||
0x2F => 'High Efficiency AAC Profile @ Level 5',
|
||||
0xFE => 'Not part of MPEG-4 audio profiles',
|
||||
0xFF => 'No audio capability required',
|
||||
);
|
||||
}
|
||||
return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
|
||||
|
@ -2111,8 +2250,18 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
|
||||
static $handyatomtranslatorarray = array();
|
||||
if (empty($handyatomtranslatorarray)) {
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
|
||||
// http://atomicparsley.sourceforge.net/mpeg-4files.html
|
||||
// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
|
||||
$handyatomtranslatorarray["\xA9".'alb'] = 'album'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
|
||||
$handyatomtranslatorarray["\xA9".'art'] = 'artist'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'aut'] = 'author';
|
||||
$handyatomtranslatorarray["\xA9".'cmt'] = 'comment'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'com'] = 'comment';
|
||||
$handyatomtranslatorarray["\xA9".'cpy'] = 'copyright';
|
||||
$handyatomtranslatorarray["\xA9".'day'] = 'creation_date'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'day'] = 'creation_date'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'dir'] = 'director';
|
||||
$handyatomtranslatorarray["\xA9".'ed1'] = 'edit1';
|
||||
$handyatomtranslatorarray["\xA9".'ed2'] = 'edit2';
|
||||
|
@ -2123,64 +2272,60 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
$handyatomtranslatorarray["\xA9".'ed7'] = 'edit7';
|
||||
$handyatomtranslatorarray["\xA9".'ed8'] = 'edit8';
|
||||
$handyatomtranslatorarray["\xA9".'ed9'] = 'edit9';
|
||||
$handyatomtranslatorarray["\xA9".'enc'] = 'encoded_by';
|
||||
$handyatomtranslatorarray["\xA9".'fmt'] = 'format';
|
||||
$handyatomtranslatorarray["\xA9".'gen'] = 'genre'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'grp'] = 'grouping'; // iTunes 4.2
|
||||
$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
|
||||
$handyatomtranslatorarray["\xA9".'inf'] = 'information';
|
||||
$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics'; // iTunes 5.0
|
||||
$handyatomtranslatorarray["\xA9".'mak'] = 'make';
|
||||
$handyatomtranslatorarray["\xA9".'mod'] = 'model';
|
||||
$handyatomtranslatorarray["\xA9".'nam'] = 'title'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
|
||||
$handyatomtranslatorarray["\xA9".'prd'] = 'producer';
|
||||
$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
|
||||
$handyatomtranslatorarray["\xA9".'prf'] = 'performers';
|
||||
$handyatomtranslatorarray["\xA9".'req'] = 'system_requirements';
|
||||
$handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
|
||||
$handyatomtranslatorarray["\xA9".'wrt'] = 'writer';
|
||||
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
|
||||
$handyatomtranslatorarray["\xA9".'nam'] = 'title'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'cmt'] = 'comment'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
|
||||
$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
|
||||
$handyatomtranslatorarray["\xA9".'mak'] = 'make';
|
||||
$handyatomtranslatorarray["\xA9".'mod'] = 'model';
|
||||
$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
|
||||
$handyatomtranslatorarray["\xA9".'swr'] = 'software';
|
||||
$handyatomtranslatorarray["\xA9".'aut'] = 'author';
|
||||
$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
|
||||
$handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'trk'] = 'track';
|
||||
$handyatomtranslatorarray["\xA9".'alb'] = 'album'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'com'] = 'comment';
|
||||
$handyatomtranslatorarray["\xA9".'gen'] = 'genre'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
|
||||
$handyatomtranslatorarray["\xA9".'url'] = 'url';
|
||||
$handyatomtranslatorarray["\xA9".'enc'] = 'encoder';
|
||||
|
||||
// http://atomicparsley.sourceforge.net/mpeg-4files.html
|
||||
$handyatomtranslatorarray["\xA9".'art'] = 'artist'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
|
||||
$handyatomtranslatorarray["\xA9".'wrt'] = 'composer';
|
||||
$handyatomtranslatorarray['aART'] = 'album_artist';
|
||||
$handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'too'] = 'encoder'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0?
|
||||
$handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0
|
||||
$handyatomtranslatorarray["\xA9".'grp'] = 'grouping'; // iTunes 4.2
|
||||
$handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0
|
||||
$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics'; // iTunes 5.0
|
||||
$handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2
|
||||
$handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0
|
||||
|
||||
// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
|
||||
|
||||
|
||||
$handyatomtranslatorarray['apID'] = 'purchase_account';
|
||||
$handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0?
|
||||
$handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0
|
||||
$handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['hdvd'] = 'hd_video'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['ldes'] = 'description_long'; //
|
||||
$handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0
|
||||
$handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2
|
||||
$handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['soaa'] = 'sort_album_artist'; //
|
||||
$handyatomtranslatorarray['soal'] = 'sort_album'; //
|
||||
$handyatomtranslatorarray['soar'] = 'sort_artist'; //
|
||||
$handyatomtranslatorarray['soco'] = 'sort_composer'; //
|
||||
$handyatomtranslatorarray['sonm'] = 'sort_title'; //
|
||||
$handyatomtranslatorarray['sosn'] = 'sort_show'; //
|
||||
$handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9
|
||||
$handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0
|
||||
$handyatomtranslatorarray['tven'] = 'tv_episode_id'; //
|
||||
$handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0
|
||||
$handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0
|
||||
|
||||
// boxnames:
|
||||
/*
|
||||
|
@ -2225,7 +2370,14 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
$data = array('data'=>$data, 'image_mime'=>$image_mime);
|
||||
}
|
||||
}
|
||||
$info['quicktime']['comments'][$comment_key][] = $data;
|
||||
$gooddata = array($data);
|
||||
if ($comment_key == 'genre') {
|
||||
// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
|
||||
$gooddata = explode(';', $data);
|
||||
}
|
||||
foreach ($gooddata as $data) {
|
||||
$info['quicktime']['comments'][$comment_key][] = $data;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2243,4 +2395,79 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
|
|||
return substr($pascalstring, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// helper functions for m4b audiobook chapters
|
||||
// code by Steffen Hartmann 2015-Nov-08
|
||||
*/
|
||||
public function search_tag_by_key($info, $tag, $history, &$result) {
|
||||
foreach ($info as $key => $value) {
|
||||
$key_history = $history.'/'.$key;
|
||||
if ($key === $tag) {
|
||||
$result[] = array($key_history, $info);
|
||||
} else {
|
||||
if (is_array($value)) {
|
||||
$this->search_tag_by_key($value, $tag, $key_history, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function search_tag_by_pair($info, $k, $v, $history, &$result) {
|
||||
foreach ($info as $key => $value) {
|
||||
$key_history = $history.'/'.$key;
|
||||
if (($key === $k) && ($value === $v)) {
|
||||
$result[] = array($key_history, $info);
|
||||
} else {
|
||||
if (is_array($value)) {
|
||||
$this->search_tag_by_pair($value, $k, $v, $key_history, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function quicktime_time_to_sample_table($info) {
|
||||
$res = array();
|
||||
$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
|
||||
foreach ($res as $value) {
|
||||
$stbl_res = array();
|
||||
$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
|
||||
if (count($stbl_res) > 0) {
|
||||
$stts_res = array();
|
||||
$this->search_tag_by_key($value[1], 'time_to_sample_table', $value[0], $stts_res);
|
||||
if (count($stts_res) > 0) {
|
||||
return $stts_res[0][1]['time_to_sample_table'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
function quicktime_bookmark_time_scale($info) {
|
||||
$time_scale = '';
|
||||
$ts_prefix_len = 0;
|
||||
$res = array();
|
||||
$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
|
||||
foreach ($res as $value) {
|
||||
$stbl_res = array();
|
||||
$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
|
||||
if (count($stbl_res) > 0) {
|
||||
$ts_res = array();
|
||||
$this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res);
|
||||
foreach ($ts_res as $value) {
|
||||
$prefix = substr($value[0], 0, -12);
|
||||
if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) {
|
||||
$time_scale = $value[1]['time_scale'];
|
||||
$ts_prefix_len = strlen($prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $time_scale;
|
||||
}
|
||||
/*
|
||||
// END helper functions for m4b audiobook chapters
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
|
0
app/Library/getid3/getid3/module.audio-video.real.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.real.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.riff.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.riff.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.swf.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.swf.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.ts.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio-video.ts.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.aa.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.aa.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.aac.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.aac.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.ac3.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.ac3.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.amr.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.amr.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.au.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.au.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.avr.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.avr.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.bonk.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.bonk.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.dss.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.dss.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.dts.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.dts.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.flac.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.flac.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.la.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.la.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.lpac.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.lpac.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.midi.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.midi.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.mod.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.mod.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.monkey.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.monkey.php
Executable file → Normal file
18
app/Library/getid3/getid3/module.audio.mp3.php
Executable file → Normal file
18
app/Library/getid3/getid3/module.audio.mp3.php
Executable file → Normal file
|
@ -437,7 +437,6 @@ class getid3_mp3 extends getid3_handler
|
|||
// and $cc... is the audio data
|
||||
|
||||
$head4 = substr($headerstring, 0, 4);
|
||||
|
||||
static $MPEGaudioHeaderDecodeCache = array();
|
||||
if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
|
||||
$MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
|
||||
|
@ -648,9 +647,20 @@ class getid3_mp3 extends getid3_handler
|
|||
}
|
||||
|
||||
//if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
|
||||
if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
|
||||
//if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
|
||||
if (!empty($thisfile_mpeg_audio['VBR_frames'])) {
|
||||
$used_filesize = 0;
|
||||
if (!empty($thisfile_mpeg_audio['VBR_bytes'])) {
|
||||
$used_filesize = $thisfile_mpeg_audio['VBR_bytes'];
|
||||
} elseif (!empty($info['filesize'])) {
|
||||
$used_filesize = $info['filesize'];
|
||||
$used_filesize -= intval(@$info['id3v2']['headerlength']);
|
||||
$used_filesize -= (isset($info['id3v1']) ? 128 : 0);
|
||||
$used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0);
|
||||
$info['warning'][] = 'MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes';
|
||||
}
|
||||
|
||||
$framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames'];
|
||||
$framelengthfloat = $used_filesize / $thisfile_mpeg_audio['VBR_frames'];
|
||||
|
||||
if ($thisfile_mpeg_audio['layer'] == '1') {
|
||||
// BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
|
||||
|
@ -948,7 +958,7 @@ class getid3_mp3 extends getid3_handler
|
|||
}
|
||||
$thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0);
|
||||
if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) {
|
||||
$info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate'];
|
||||
$info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate'];
|
||||
$thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion
|
||||
}
|
||||
break;
|
||||
|
|
0
app/Library/getid3/getid3/module.audio.mpc.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.mpc.php
Executable file → Normal file
1
app/Library/getid3/getid3/module.audio.ogg.php
Executable file → Normal file
1
app/Library/getid3/getid3/module.audio.ogg.php
Executable file → Normal file
|
@ -562,6 +562,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
|
|||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
|
||||
|
|
0
app/Library/getid3/getid3/module.audio.optimfrog.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.optimfrog.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.rkau.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.rkau.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.shorten.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.shorten.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.tta.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.tta.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.voc.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.voc.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.vqf.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.vqf.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.wavpack.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.audio.wavpack.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.bmp.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.bmp.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.efax.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.efax.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.gif.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.gif.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.jpg.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.jpg.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.pcd.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.pcd.php
Executable file → Normal file
32
app/Library/getid3/getid3/module.graphic.png.php
Executable file → Normal file
32
app/Library/getid3/getid3/module.graphic.png.php
Executable file → Normal file
|
@ -17,8 +17,10 @@
|
|||
|
||||
class getid3_png extends getid3_handler
|
||||
{
|
||||
public $max_data_bytes = 10000000; // if data chunk is larger than this do not read it completely (getID3 only needs the first few dozen bytes for parsing)
|
||||
|
||||
public function Analyze() {
|
||||
|
||||
$info = &$this->getid3->info;
|
||||
|
||||
// shortcut
|
||||
|
@ -44,14 +46,24 @@ class getid3_png extends getid3_handler
|
|||
|
||||
while ((($this->ftell() - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
|
||||
$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
|
||||
$offset += 4;
|
||||
while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && ($this->ftell() < $info['filesize'])) {
|
||||
$PNGfiledata .= $this->fread($this->getid3->fread_buffer_size());
|
||||
if ($chunk['data_length'] === false) {
|
||||
$info['error'][] = 'Failed to read data_length at offset '.$offset;
|
||||
return false;
|
||||
}
|
||||
$chunk['type_text'] = substr($PNGfiledata, $offset, 4);
|
||||
$offset += 4;
|
||||
$truncated_data = false;
|
||||
while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && ($this->ftell() < $info['filesize'])) {
|
||||
if (strlen($PNGfiledata) < $this->max_data_bytes) {
|
||||
$PNGfiledata .= $this->fread($this->getid3->fread_buffer_size());
|
||||
} else {
|
||||
$info['warning'][] = 'At offset '.$offset.' chunk "'.substr($PNGfiledata, $offset, 4).'" exceeded max_data_bytes value of '.$this->max_data_bytes.', data chunk will be truncated at '.(strlen($PNGfiledata) - 8).' bytes';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$chunk['type_text'] = substr($PNGfiledata, $offset, 4);
|
||||
$offset += 4;
|
||||
$chunk['type_raw'] = getid3_lib::BigEndian2Int($chunk['type_text']);
|
||||
$chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']);
|
||||
$chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']);
|
||||
$offset += $chunk['data_length'];
|
||||
$chunk['crc'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
|
||||
$offset += 4;
|
||||
|
@ -162,7 +174,7 @@ class getid3_png extends getid3_handler
|
|||
|
||||
case 'iCCP': // Embedded ICC Profile
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($profilename, $compressiondata) = explode("\x00", $chunk['data'], 2);
|
||||
list($profilename, $compressiondata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['profile_name'] = $profilename;
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1);
|
||||
|
@ -173,7 +185,7 @@ class getid3_png extends getid3_handler
|
|||
|
||||
case 'tEXt': // Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $text) = explode("\x00", $chunk['data'], 2);
|
||||
list($keyword, $text) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['text'] = $text;
|
||||
|
||||
|
@ -183,7 +195,7 @@ class getid3_png extends getid3_handler
|
|||
|
||||
case 'zTXt': // Compressed Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compressed_text'] = substr($otherdata, 1);
|
||||
|
@ -206,7 +218,7 @@ class getid3_png extends getid3_handler
|
|||
|
||||
case 'iTXt': // International Textual Data
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['keyword'] = $keyword;
|
||||
$thisfile_png_chunk_type_text['compression'] = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
|
||||
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1));
|
||||
|
@ -307,7 +319,7 @@ class getid3_png extends getid3_handler
|
|||
|
||||
case 'sPLT': // Suggested Palette
|
||||
$thisfile_png_chunk_type_text['header'] = $chunk;
|
||||
list($palettename, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
list($palettename, $otherdata) = explode("\x00", $chunk['data'], 2);
|
||||
$thisfile_png_chunk_type_text['palette_name'] = $palettename;
|
||||
$sPLToffset = 0;
|
||||
$thisfile_png_chunk_type_text['sample_depth_bits'] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1));
|
||||
|
|
0
app/Library/getid3/getid3/module.graphic.svg.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.svg.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.tiff.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.graphic.tiff.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.cue.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.cue.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.exe.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.exe.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.iso.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.iso.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.msoffice.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.msoffice.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.par2.php
Executable file → Normal file
0
app/Library/getid3/getid3/module.misc.par2.php
Executable file → Normal file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue