2015-02-19 21:10:01 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
class Application_Service_MediaService
|
|
|
|
{
|
2021-10-11 16:10:47 +02:00
|
|
|
public const PENDING_FILE_TIMEOUT_SECONDS = 3600;
|
2015-10-29 16:03:28 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array store an internal array of the pending files so we don't have
|
|
|
|
* to go to the database twice
|
|
|
|
*/
|
|
|
|
private static $_pendingFiles;
|
|
|
|
|
2015-02-20 22:36:36 +01:00
|
|
|
/** Move (or copy) a file to the stor/organize directory and send it off to the
|
2021-10-11 16:10:47 +02:00
|
|
|
* analyzer to be processed.
|
|
|
|
*
|
2023-02-10 22:55:54 +01:00
|
|
|
* @param mixed $fileId
|
|
|
|
* @param mixed $fileOwnerId The ID of the user that will own the file inside Airtime
|
|
|
|
* @param mixed $fileTrackTypeId
|
|
|
|
* @param string $fileOriginalFilename The original filename, if you want it to be preserved after import
|
|
|
|
* @param string $filePath Path to the local file to import to the library
|
|
|
|
* @param bool $copyFile True if you want to copy the file to the "organize" directory, false if you want to move it (default)
|
2021-10-11 16:10:47 +02:00
|
|
|
*
|
|
|
|
* @return Ambigous
|
2022-09-12 13:16:14 +02:00
|
|
|
*
|
|
|
|
* @throws Exception
|
2015-02-20 22:36:36 +01:00
|
|
|
*/
|
2023-02-10 22:55:54 +01:00
|
|
|
public static function importFileToLibrary(
|
|
|
|
$fileId,
|
|
|
|
$fileOwnerId,
|
|
|
|
$fileTrackTypeId,
|
|
|
|
$fileOriginalFilename,
|
|
|
|
$filePath,
|
|
|
|
$copyFile
|
|
|
|
) {
|
|
|
|
$importedStorageDirectory = Config::getStoragePath() . '/imported/' . $fileOwnerId;
|
2015-02-19 21:10:01 +01:00
|
|
|
|
2022-03-14 11:15:04 +01:00
|
|
|
// Copy the temporary file over to the "organize" folder so that it's off our webserver
|
|
|
|
// and accessible by libretime-analyzer which could be running on a different machine.
|
2023-02-10 22:55:54 +01:00
|
|
|
$newTempFilePath = Application_Model_StoredFile::moveFileToStor(
|
|
|
|
$filePath,
|
|
|
|
$fileId,
|
|
|
|
$fileOriginalFilename,
|
|
|
|
$copyFile
|
|
|
|
);
|
2015-02-19 21:10:01 +01:00
|
|
|
|
2022-03-14 11:15:04 +01:00
|
|
|
// Dispatch a message to libretime-analyzer through RabbitMQ,
|
|
|
|
// notifying it that there's a new upload to process!
|
2021-10-11 16:10:47 +02:00
|
|
|
Application_Model_RabbitMq::SendMessageToAnalyzer(
|
|
|
|
$newTempFilePath,
|
|
|
|
$importedStorageDirectory,
|
2023-02-10 22:55:54 +01:00
|
|
|
basename($fileOriginalFilename),
|
|
|
|
$fileId,
|
|
|
|
$fileTrackTypeId
|
2021-10-11 16:10:47 +02:00
|
|
|
);
|
2015-02-20 22:36:36 +01:00
|
|
|
|
|
|
|
return $newTempFilePath;
|
2015-02-20 20:01:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-10-12 17:02:14 +02:00
|
|
|
* @param bool $inline Set the Content-Disposition header to inline to prevent a download dialog from popping up (or attachment if false)
|
|
|
|
* @param mixed $fileId
|
2021-10-11 16:10:47 +02:00
|
|
|
*
|
2015-02-20 20:01:06 +01:00
|
|
|
* @throws Exception
|
2017-02-20 21:47:53 +01:00
|
|
|
* @throws LibreTimeFileNotFoundException
|
2015-02-20 20:01:06 +01:00
|
|
|
*/
|
2021-10-11 16:10:47 +02:00
|
|
|
public static function streamFileDownload($fileId, $inline = false)
|
2015-02-20 20:01:06 +01:00
|
|
|
{
|
|
|
|
$media = Application_Model_StoredFile::RecallById($fileId);
|
|
|
|
if ($media == null) {
|
2017-02-20 21:47:53 +01:00
|
|
|
throw new LibreTimeFileNotFoundException();
|
2015-02-20 20:01:06 +01:00
|
|
|
}
|
2015-03-30 17:31:07 +02:00
|
|
|
// Make sure we don't have some wrong result because of caching
|
2015-02-20 20:01:06 +01:00
|
|
|
clearstatcache();
|
|
|
|
|
2021-10-11 16:10:47 +02:00
|
|
|
$filePath = '';
|
2015-03-30 17:31:07 +02:00
|
|
|
|
2015-02-20 20:01:06 +01:00
|
|
|
if ($media->getPropelOrm()->isValidPhysicalFile()) {
|
|
|
|
$filename = $media->getPropelOrm()->getFilename();
|
2015-07-15 19:12:56 +02:00
|
|
|
|
2022-03-14 11:15:04 +01:00
|
|
|
// Download user left clicks a track and selects Download.
|
2015-02-20 20:01:06 +01:00
|
|
|
if (!$inline) {
|
2022-03-14 11:15:04 +01:00
|
|
|
// We are using Content-Disposition to specify
|
|
|
|
// to the browser what name the file should be saved as.
|
2015-02-20 20:01:06 +01:00
|
|
|
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
|
|
|
} else {
|
2022-03-14 11:15:04 +01:00
|
|
|
// user clicks play button for track and downloads it.
|
2015-02-20 20:01:06 +01:00
|
|
|
header('Content-Disposition: inline; filename="' . $filename . '"');
|
|
|
|
}
|
|
|
|
|
2015-03-30 17:31:07 +02:00
|
|
|
/*
|
|
|
|
In this block of code below, we're getting the list of download URLs for a track
|
|
|
|
and then streaming the file as the response. A file can be stored in more than one location,
|
|
|
|
with the alternate locations used as a fallback, so that's why we're looping until we
|
|
|
|
are able to actually send the file.
|
|
|
|
|
|
|
|
This mechanism is used to try fetching our file from our internal S3 caching proxy server first.
|
|
|
|
If the file isn't found there (or the cache is down), then we attempt to download the file
|
|
|
|
directly from Amazon S3. We do this to save bandwidth costs!
|
|
|
|
*/
|
|
|
|
|
|
|
|
$filePaths = $media->getFilePaths();
|
|
|
|
assert(is_array($filePaths));
|
|
|
|
|
|
|
|
do {
|
2022-03-14 11:15:04 +01:00
|
|
|
// Read from $filePath and stream it to the browser.
|
2015-03-30 17:31:07 +02:00
|
|
|
$filePath = array_shift($filePaths);
|
2021-10-11 16:10:47 +02:00
|
|
|
|
2015-03-30 17:31:07 +02:00
|
|
|
try {
|
2021-10-11 16:10:47 +02:00
|
|
|
$size = $media->getFileSize();
|
2015-03-30 17:31:07 +02:00
|
|
|
$mimeType = $media->getPropelOrm()->getDbMime();
|
|
|
|
Application_Common_FileIO::smartReadFile($filePath, $size, $mimeType);
|
2021-10-11 16:10:47 +02:00
|
|
|
|
2022-03-14 11:15:04 +01:00
|
|
|
break; // Break out of the loop if we successfully read the file!
|
2017-02-20 21:47:53 +01:00
|
|
|
} catch (LibreTimeFileNotFoundException $e) {
|
2022-03-14 11:15:04 +01:00
|
|
|
// If we have no alternate filepaths left, then let the exception bubble up.
|
Feature: Support php7.4 (#1354)
* Run CI tests against php 7.4
* Sort composer dependencies
* Remove unused Aws S3 php library
* Pin simplepie dependency to ^1.5
* Pin getid3 dependency to ^1.9
* Pin composer semver to ^3.2
* Pin php-amqplib to ^2.12
* Drop sentry logging support
* Update composer dependencies
* Move propel regenerate to Makefile
* Regenerate propel files with v1.7.0
* Pin propel orm to ^1.7
* Regenerate propel files with v1.7.2
* fix: generator_version in airtime-conf-production.php
* Replace propel/propel1 with jooola/propel1
* Regenerate propel files with v1.7.3-dev
* Fix php7.4 compatibility
Using php-cs-fixer:
'@PhpCsFixer' => true,
'concat_space' => ['spacing' => 'one'],
'ordered_class_elements' => false,
'yoda_style' => false,
'@PHP74Migration' => true,
'assign_null_coalescing_to_coalesce_equal' => false,
'ternary_to_null_coalescing' => false,
'heredoc_indentation' => false,
'@PHP74Migration:risky' => true,
'declare_strict_types' => false,
'void_return' => false,
'use_arrow_functions' => false,
* Fix pre-commit
2021-10-17 17:19:53 +02:00
|
|
|
if (count($filePaths) == 0) {
|
2015-03-30 17:31:07 +02:00
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
}
|
2022-03-14 11:15:04 +01:00
|
|
|
// Retry with the next alternate filepath in the list
|
Feature: Support php7.4 (#1354)
* Run CI tests against php 7.4
* Sort composer dependencies
* Remove unused Aws S3 php library
* Pin simplepie dependency to ^1.5
* Pin getid3 dependency to ^1.9
* Pin composer semver to ^3.2
* Pin php-amqplib to ^2.12
* Drop sentry logging support
* Update composer dependencies
* Move propel regenerate to Makefile
* Regenerate propel files with v1.7.0
* Pin propel orm to ^1.7
* Regenerate propel files with v1.7.2
* fix: generator_version in airtime-conf-production.php
* Replace propel/propel1 with jooola/propel1
* Regenerate propel files with v1.7.3-dev
* Fix php7.4 compatibility
Using php-cs-fixer:
'@PhpCsFixer' => true,
'concat_space' => ['spacing' => 'one'],
'ordered_class_elements' => false,
'yoda_style' => false,
'@PHP74Migration' => true,
'assign_null_coalescing_to_coalesce_equal' => false,
'ternary_to_null_coalescing' => false,
'heredoc_indentation' => false,
'@PHP74Migration:risky' => true,
'declare_strict_types' => false,
'void_return' => false,
'use_arrow_functions' => false,
* Fix pre-commit
2021-10-17 17:19:53 +02:00
|
|
|
} while (count($filePaths) > 0);
|
2015-03-30 17:31:07 +02:00
|
|
|
|
2015-02-20 20:01:06 +01:00
|
|
|
exit;
|
|
|
|
}
|
2021-10-11 16:10:47 +02:00
|
|
|
|
|
|
|
throw new LibreTimeFileNotFoundException($filePath);
|
2015-02-19 21:10:01 +01:00
|
|
|
}
|
2015-02-20 20:01:06 +01:00
|
|
|
|
2015-10-29 16:03:28 +01:00
|
|
|
/**
|
|
|
|
* Check if there are any files that have been stuck
|
2021-10-11 16:10:47 +02:00
|
|
|
* in Pending status for over an hour.
|
2015-10-29 16:03:28 +01:00
|
|
|
*
|
|
|
|
* @return bool true if there are any files stuck pending,
|
|
|
|
* otherwise false
|
|
|
|
*/
|
2021-10-11 16:10:47 +02:00
|
|
|
public static function areFilesStuckInPending()
|
|
|
|
{
|
2022-07-11 17:07:30 +02:00
|
|
|
$oneHourAgo = gmdate(DEFAULT_TIMESTAMP_FORMAT, microtime(true) - self::PENDING_FILE_TIMEOUT_SECONDS);
|
2015-10-29 16:03:28 +01:00
|
|
|
self::$_pendingFiles = CcFilesQuery::create()
|
|
|
|
->filterByDbImportStatus(CcFiles::IMPORT_STATUS_PENDING)
|
|
|
|
->filterByDbUtime($oneHourAgo, Criteria::LESS_EQUAL)
|
2022-01-23 19:15:55 +01:00
|
|
|
->find();
|
2015-11-18 22:20:29 +01:00
|
|
|
$pendingEpisodes = Application_Service_PodcastEpisodeService::getStuckPendingImports();
|
2021-10-11 16:10:47 +02:00
|
|
|
|
2015-11-26 21:25:38 +01:00
|
|
|
return !self::$_pendingFiles->isEmpty() || !empty($pendingEpisodes);
|
2015-10-29 16:03:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-10-11 16:10:47 +02:00
|
|
|
* Clean up stuck imports by changing their import status to Failed.
|
2015-10-29 16:03:28 +01:00
|
|
|
*/
|
2021-10-11 16:10:47 +02:00
|
|
|
public static function clearStuckPendingImports()
|
|
|
|
{
|
2015-11-18 22:20:29 +01:00
|
|
|
$pendingEpisodes = Application_Service_PodcastEpisodeService::getStuckPendingImports();
|
|
|
|
foreach (self::$_pendingFiles as $file) {
|
2021-10-11 16:10:47 +02:00
|
|
|
// @var $file CcFiles
|
2015-10-29 16:03:28 +01:00
|
|
|
$file->setDbImportStatus(CcFiles::IMPORT_STATUS_FAILED)->save();
|
|
|
|
}
|
2015-11-18 22:20:29 +01:00
|
|
|
foreach ($pendingEpisodes as $episode) {
|
2021-10-11 16:10:47 +02:00
|
|
|
// @var $episode PodcastEpisodes
|
2015-11-18 22:20:29 +01:00
|
|
|
$episode->delete();
|
|
|
|
}
|
2015-10-29 16:03:28 +01:00
|
|
|
}
|
2015-02-20 20:01:06 +01:00
|
|
|
}
|