* SAAS-1084 - initial work on publishing API backend
* More work on automatic ingest * Add automatic_ingest_timestamp column to ImportedPodcast
This commit is contained in:
parent
3a791ef9b5
commit
0b1df6baf3
|
@ -42,6 +42,10 @@ require_once "MediaType.php";
|
|||
/* Interfaces */
|
||||
require_once "OAuth2.php";
|
||||
require_once "OAuth2Controller.php";
|
||||
require_once "Publish.php";
|
||||
/* Factories */
|
||||
require_once __DIR__.'/services/CeleryServiceFactory.php';
|
||||
require_once __DIR__.'/services/PublishServiceFactory.php';
|
||||
|
||||
require_once __DIR__.'/forms/helpers/ValidationTypes.php';
|
||||
require_once __DIR__.'/forms/helpers/CustomDecorators.php';
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<?php
|
||||
|
||||
require_once "CeleryServiceFactory.php";
|
||||
|
||||
class CeleryManager {
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,23 +28,43 @@ class PodcastManager {
|
|||
public static function downloadNewestEpisodes() {
|
||||
$autoIngestPodcasts = static::_getAutoIngestPodcasts();
|
||||
$service = new Application_Service_PodcastEpisodeService();
|
||||
$episodes = array();
|
||||
foreach ($autoIngestPodcasts as $podcast) {
|
||||
/** @var ImportedPodcast $podcast */
|
||||
$podcastArray = Application_Service_PodcastService::getPodcastById($podcast->getDbPodcastId());
|
||||
// A bit hacky... sort the episodes by publication date to get the most recent
|
||||
usort($podcastArray["episodes"], array(static::class, "_sortByEpisodePubDate"));
|
||||
$episodeData = $podcastArray["episodes"][0];
|
||||
$episodes = static::_findUningestedEpisodes($podcast, $service);
|
||||
$podcast->setDbAutoIngestTimestamp(date('r'))->save();
|
||||
$service->downloadEpisodes($episodes);
|
||||
}
|
||||
|
||||
Application_Model_Preference::setPodcastPollLock(microtime(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an ImportedPodcast, find all uningested episodes since the last automatic ingest,
|
||||
* and add them to a given episodes array
|
||||
*
|
||||
* @param ImportedPodcast $podcast the podcast to search
|
||||
* @param Application_Service_PodcastEpisodeService $service podcast episode service object
|
||||
*
|
||||
* @return array array of episodes to append be downloaded
|
||||
*/
|
||||
protected static function _findUningestedEpisodes($podcast, $service) {
|
||||
$podcastArray = Application_Service_PodcastService::getPodcastById($podcast->getDbPodcastId());
|
||||
$episodeList = $podcastArray["episodes"];
|
||||
$episodes = array();
|
||||
// A bit hacky... sort the episodes by publication date to get the most recent
|
||||
usort($episodeList, array(static::class, "_sortByEpisodePubDate"));
|
||||
for ($i = 0; $i < sizeof($episodeList); $i++) {
|
||||
$episodeData = $episodeList[$i];
|
||||
// If the publication date of this episode is before the ingest timestamp, we don't need to ingest it
|
||||
// Since we're sorting by publication date, we can break
|
||||
if ($episodeData["pub_date"] < $podcast->getDbAutoIngestTimestamp()) break;
|
||||
$episode = PodcastEpisodesQuery::create()->findOneByDbEpisodeGuid($episodeData["guid"]);
|
||||
// Make sure there's no existing episode placeholder or import, and that the data is non-empty
|
||||
if (empty($episode) && !empty($episodeData)) {
|
||||
$placeholder = $service->addPodcastEpisodePlaceholder($podcast->getDbPodcastId(), $episodeData);
|
||||
$placeholder = $service->addPlaceholder($podcast->getDbPodcastId(), $episodeData);
|
||||
array_push($episodes, $placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
$service->downloadEpisodes($episodes);
|
||||
Application_Model_Preference::setPodcastPollLock(microtime(true));
|
||||
return $episodes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
interface Publish {
|
||||
|
||||
/**
|
||||
* Publish the file with the given file ID
|
||||
*
|
||||
* @param int $fileId ID of the file to be published
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function publish($fileId);
|
||||
|
||||
/**
|
||||
* Unpublish the file with the given file ID
|
||||
*
|
||||
* @param int $fileId ID of the file to be unpublished
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unpublish($fileId);
|
||||
|
||||
}
|
|
@ -126,6 +126,9 @@ define('CELERY_FAILED_STATUS', 'FAILED');
|
|||
define('SOUNDCLOUD_SERVICE_NAME', 'soundcloud');
|
||||
define('PODCAST_SERVICE_NAME', 'podcast');
|
||||
|
||||
// Publish Services
|
||||
define('STATION_PODCAST_SERVICE_NAME', 'station_podcast');
|
||||
|
||||
// Podcast Types
|
||||
//define('STATION_PODCAST', 0);
|
||||
//define('IMPORTED_PODCAST', 1);
|
||||
|
|
|
@ -21,7 +21,7 @@ class SoundcloudController extends ThirdPartyController implements OAuth2Control
|
|||
}
|
||||
|
||||
/**
|
||||
* Upload the file with the given id to a third-party service
|
||||
* Upload the file with the given id to SoundCloud
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
|
@ -34,7 +34,7 @@ class SoundcloudController extends ThirdPartyController implements OAuth2Control
|
|||
}
|
||||
|
||||
/**
|
||||
* Download the file with the given id from a third-party service
|
||||
* Download the file with the given id from SoundCloud
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
|
@ -47,7 +47,7 @@ class SoundcloudController extends ThirdPartyController implements OAuth2Control
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete the file with the given id from a third-party service
|
||||
* Delete the file with the given id from SoundCloud
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
|
|
|
@ -223,7 +223,7 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
|
|||
}
|
||||
|
||||
private function verifyAuth() {
|
||||
if ($this->verifyAPIKey()) {
|
||||
if ($this->isVerifiedDownload() || $this->verifyAPIKey()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,32 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the requested file can be downloaded.
|
||||
* It should satisfy the following requirements:
|
||||
* * request path is /rest/media/:id/download
|
||||
* * download key is correct
|
||||
* * requested file belongs to the station podcast
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isVerifiedDownload() {
|
||||
$request = $this->getRequest();
|
||||
$fileId = $request->getParam("id");
|
||||
$key = $request->getParam("download_key");
|
||||
$module = $request->getModuleName();
|
||||
$controller = $request->getControllerName();
|
||||
$action = $request->getActionName();
|
||||
$stationPodcast = StationPodcastQuery::create()
|
||||
->findOneByDbPodcastId(Application_Model_Preference::getStationPodcastId());
|
||||
return $module == "rest"
|
||||
&& $controller == "media"
|
||||
&& $action == "download"
|
||||
&& $key === Application_Model_Preference::getStationPodcastDownloadKey()
|
||||
&& $stationPodcast->hasEpisodeForFile($fileId);
|
||||
}
|
||||
|
||||
private function verifyCSRFToken($token) {
|
||||
return SecurityHelper::verifyCSRFToken($token);
|
||||
}
|
||||
|
|
|
@ -157,6 +157,7 @@ class PageLayoutInitPlugin extends Zend_Controller_Plugin_Abstract
|
|||
|
||||
$view->headScript()->appendFile($baseUrl . 'js/libs/jquery-1.8.3.min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript')
|
||||
->appendFile($baseUrl . 'js/libs/jquery-ui-1.8.24.min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript')
|
||||
->appendFile($baseUrl . 'js/libs/angular.min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript')
|
||||
->appendFile($baseUrl . 'js/bootstrap/bootstrap.js?' . $CC_CONFIG['airtime_version'], 'text/javascript')
|
||||
->appendFile($baseUrl . 'js/libs/underscore-min.js?' . $CC_CONFIG['airtime_version'], 'text/javascript')
|
||||
|
||||
|
|
|
@ -1525,4 +1525,13 @@ class Application_Model_Preference
|
|||
{
|
||||
self::setValue("station_podcast_id", $value);
|
||||
}
|
||||
|
||||
public static function getStationPodcastDownloadKey() {
|
||||
return self::getValue("station_podcast_download_key");
|
||||
}
|
||||
|
||||
public static function setStationPodcastDownloadKey($value = null) {
|
||||
$value = empty($value) ? (new Application_Model_Auth())->generateRandomString() : $value;
|
||||
self::setValue("station_podcast_download_key", $value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,4 +15,26 @@
|
|||
*/
|
||||
class PodcastEpisodes extends BasePodcastEpisodes
|
||||
{
|
||||
|
||||
/**
|
||||
* @override
|
||||
* We need to override this function in order to provide the rotating
|
||||
* download key for the station podcast.
|
||||
*
|
||||
* Get the [download_url] column value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDbDownloadUrl() {
|
||||
$podcastId = $this->getDbPodcastId();
|
||||
// We may have more station podcasts later, so use this instead of checking the id stored in Preference
|
||||
$podcast = StationPodcastQuery::create()->findOneByDbPodcastId($podcastId);
|
||||
if ($podcast) {
|
||||
$fileId = $this->getDbFileId();
|
||||
$key = Application_Model_Preference::getStationPodcastDownloadKey();
|
||||
return Application_Common_HTTPHelper::getStationUrl()."rest/media/$fileId/download?download_key=$key";
|
||||
}
|
||||
return parent::getDbDownloadUrl();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,4 +15,24 @@
|
|||
*/
|
||||
class StationPodcast extends BaseStationPodcast
|
||||
{
|
||||
|
||||
/**
|
||||
* Utility function to check whether an episode for the file with the given ID
|
||||
* is contained within the station podcast
|
||||
*
|
||||
* @param int $fileId the file ID to check for
|
||||
*
|
||||
* @return bool true if the station podcast contains an episode with
|
||||
* the given file ID, otherwise false
|
||||
*/
|
||||
public function hasEpisodeForFile($fileId) {
|
||||
$episodes = PodcastEpisodesQuery::create()
|
||||
->filterByDbPodcastId($this->getDbPodcastId())
|
||||
->find();
|
||||
foreach ($episodes as $e) {
|
||||
if ($e->getDbFileId() == $fileId) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ class ImportedPodcastTableMap extends TableMap
|
|||
// columns
|
||||
$this->addPrimaryKey('id', 'DbId', 'INTEGER', true, null, null);
|
||||
$this->addColumn('auto_ingest', 'DbAutoIngest', 'BOOLEAN', true, null, false);
|
||||
$this->addColumn('auto_ingest_timestamp', 'DbAutoIngestTimestamp', 'TIMESTAMP', false, null, null);
|
||||
$this->addForeignKey('podcast_id', 'DbPodcastId', 'INTEGER', 'podcast', 'id', true, null, null);
|
||||
// validators
|
||||
} // initialize()
|
||||
|
|
|
@ -42,6 +42,12 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
*/
|
||||
protected $auto_ingest;
|
||||
|
||||
/**
|
||||
* The value for the auto_ingest_timestamp field.
|
||||
* @var string
|
||||
*/
|
||||
protected $auto_ingest_timestamp;
|
||||
|
||||
/**
|
||||
* The value for the podcast_id field.
|
||||
* @var int
|
||||
|
@ -116,6 +122,41 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
return $this->auto_ingest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [optionally formatted] temporal [auto_ingest_timestamp] column value.
|
||||
*
|
||||
*
|
||||
* @param string $format The date/time format string (either date()-style or strftime()-style).
|
||||
* If format is null, then the raw DateTime object will be returned.
|
||||
* @return mixed Formatted date/time value as string or DateTime object (if format is null), null if column is null
|
||||
* @throws PropelException - if unable to parse/validate the date/time value.
|
||||
*/
|
||||
public function getDbAutoIngestTimestamp($format = 'Y-m-d H:i:s')
|
||||
{
|
||||
if ($this->auto_ingest_timestamp === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
$dt = new DateTime($this->auto_ingest_timestamp);
|
||||
} catch (Exception $x) {
|
||||
throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->auto_ingest_timestamp, true), $x);
|
||||
}
|
||||
|
||||
if ($format === null) {
|
||||
// Because propel.useDateTimeClass is true, we return a DateTime object.
|
||||
return $dt;
|
||||
}
|
||||
|
||||
if (strpos($format, '%') !== false) {
|
||||
return strftime($format, $dt->format('U'));
|
||||
}
|
||||
|
||||
return $dt->format($format);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [podcast_id] column value.
|
||||
*
|
||||
|
@ -177,6 +218,29 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
return $this;
|
||||
} // setDbAutoIngest()
|
||||
|
||||
/**
|
||||
* Sets the value of [auto_ingest_timestamp] column to a normalized version of the date/time value specified.
|
||||
*
|
||||
* @param mixed $v string, integer (timestamp), or DateTime value.
|
||||
* Empty strings are treated as null.
|
||||
* @return ImportedPodcast The current object (for fluent API support)
|
||||
*/
|
||||
public function setDbAutoIngestTimestamp($v)
|
||||
{
|
||||
$dt = PropelDateTime::newInstance($v, null, 'DateTime');
|
||||
if ($this->auto_ingest_timestamp !== null || $dt !== null) {
|
||||
$currentDateAsString = ($this->auto_ingest_timestamp !== null && $tmpDt = new DateTime($this->auto_ingest_timestamp)) ? $tmpDt->format('Y-m-d H:i:s') : null;
|
||||
$newDateAsString = $dt ? $dt->format('Y-m-d H:i:s') : null;
|
||||
if ($currentDateAsString !== $newDateAsString) {
|
||||
$this->auto_ingest_timestamp = $newDateAsString;
|
||||
$this->modifiedColumns[] = ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP;
|
||||
}
|
||||
} // if either are not null
|
||||
|
||||
|
||||
return $this;
|
||||
} // setDbAutoIngestTimestamp()
|
||||
|
||||
/**
|
||||
* Set the value of [podcast_id] column.
|
||||
*
|
||||
|
@ -240,7 +304,8 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
|
||||
$this->id = ($row[$startcol + 0] !== null) ? (int) $row[$startcol + 0] : null;
|
||||
$this->auto_ingest = ($row[$startcol + 1] !== null) ? (boolean) $row[$startcol + 1] : null;
|
||||
$this->podcast_id = ($row[$startcol + 2] !== null) ? (int) $row[$startcol + 2] : null;
|
||||
$this->auto_ingest_timestamp = ($row[$startcol + 2] !== null) ? (string) $row[$startcol + 2] : null;
|
||||
$this->podcast_id = ($row[$startcol + 3] !== null) ? (int) $row[$startcol + 3] : null;
|
||||
$this->resetModified();
|
||||
|
||||
$this->setNew(false);
|
||||
|
@ -250,7 +315,7 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
}
|
||||
$this->postHydrate($row, $startcol, $rehydrate);
|
||||
|
||||
return $startcol + 3; // 3 = ImportedPodcastPeer::NUM_HYDRATE_COLUMNS.
|
||||
return $startcol + 4; // 4 = ImportedPodcastPeer::NUM_HYDRATE_COLUMNS.
|
||||
|
||||
} catch (Exception $e) {
|
||||
throw new PropelException("Error populating ImportedPodcast object", $e);
|
||||
|
@ -494,6 +559,9 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
if ($this->isColumnModified(ImportedPodcastPeer::AUTO_INGEST)) {
|
||||
$modifiedColumns[':p' . $index++] = '"auto_ingest"';
|
||||
}
|
||||
if ($this->isColumnModified(ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP)) {
|
||||
$modifiedColumns[':p' . $index++] = '"auto_ingest_timestamp"';
|
||||
}
|
||||
if ($this->isColumnModified(ImportedPodcastPeer::PODCAST_ID)) {
|
||||
$modifiedColumns[':p' . $index++] = '"podcast_id"';
|
||||
}
|
||||
|
@ -514,6 +582,9 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
case '"auto_ingest"':
|
||||
$stmt->bindValue($identifier, $this->auto_ingest, PDO::PARAM_BOOL);
|
||||
break;
|
||||
case '"auto_ingest_timestamp"':
|
||||
$stmt->bindValue($identifier, $this->auto_ingest_timestamp, PDO::PARAM_STR);
|
||||
break;
|
||||
case '"podcast_id"':
|
||||
$stmt->bindValue($identifier, $this->podcast_id, PDO::PARAM_INT);
|
||||
break;
|
||||
|
@ -663,6 +734,9 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
return $this->getDbAutoIngest();
|
||||
break;
|
||||
case 2:
|
||||
return $this->getDbAutoIngestTimestamp();
|
||||
break;
|
||||
case 3:
|
||||
return $this->getDbPodcastId();
|
||||
break;
|
||||
default:
|
||||
|
@ -696,7 +770,8 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
$result = array(
|
||||
$keys[0] => $this->getDbId(),
|
||||
$keys[1] => $this->getDbAutoIngest(),
|
||||
$keys[2] => $this->getDbPodcastId(),
|
||||
$keys[2] => $this->getDbAutoIngestTimestamp(),
|
||||
$keys[3] => $this->getDbPodcastId(),
|
||||
);
|
||||
$virtualColumns = $this->virtualColumns;
|
||||
foreach ($virtualColumns as $key => $virtualColumn) {
|
||||
|
@ -748,6 +823,9 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
$this->setDbAutoIngest($value);
|
||||
break;
|
||||
case 2:
|
||||
$this->setDbAutoIngestTimestamp($value);
|
||||
break;
|
||||
case 3:
|
||||
$this->setDbPodcastId($value);
|
||||
break;
|
||||
} // switch()
|
||||
|
@ -776,7 +854,8 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
|
||||
if (array_key_exists($keys[0], $arr)) $this->setDbId($arr[$keys[0]]);
|
||||
if (array_key_exists($keys[1], $arr)) $this->setDbAutoIngest($arr[$keys[1]]);
|
||||
if (array_key_exists($keys[2], $arr)) $this->setDbPodcastId($arr[$keys[2]]);
|
||||
if (array_key_exists($keys[2], $arr)) $this->setDbAutoIngestTimestamp($arr[$keys[2]]);
|
||||
if (array_key_exists($keys[3], $arr)) $this->setDbPodcastId($arr[$keys[3]]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -790,6 +869,7 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
|
||||
if ($this->isColumnModified(ImportedPodcastPeer::ID)) $criteria->add(ImportedPodcastPeer::ID, $this->id);
|
||||
if ($this->isColumnModified(ImportedPodcastPeer::AUTO_INGEST)) $criteria->add(ImportedPodcastPeer::AUTO_INGEST, $this->auto_ingest);
|
||||
if ($this->isColumnModified(ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP)) $criteria->add(ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP, $this->auto_ingest_timestamp);
|
||||
if ($this->isColumnModified(ImportedPodcastPeer::PODCAST_ID)) $criteria->add(ImportedPodcastPeer::PODCAST_ID, $this->podcast_id);
|
||||
|
||||
return $criteria;
|
||||
|
@ -855,6 +935,7 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
public function copyInto($copyObj, $deepCopy = false, $makeNew = true)
|
||||
{
|
||||
$copyObj->setDbAutoIngest($this->getDbAutoIngest());
|
||||
$copyObj->setDbAutoIngestTimestamp($this->getDbAutoIngestTimestamp());
|
||||
$copyObj->setDbPodcastId($this->getDbPodcastId());
|
||||
|
||||
if ($deepCopy && !$this->startCopy) {
|
||||
|
@ -973,6 +1054,7 @@ abstract class BaseImportedPodcast extends BaseObject implements Persistent
|
|||
{
|
||||
$this->id = null;
|
||||
$this->auto_ingest = null;
|
||||
$this->auto_ingest_timestamp = null;
|
||||
$this->podcast_id = null;
|
||||
$this->alreadyInSave = false;
|
||||
$this->alreadyInValidation = false;
|
||||
|
|
|
@ -24,13 +24,13 @@ abstract class BaseImportedPodcastPeer
|
|||
const TM_CLASS = 'ImportedPodcastTableMap';
|
||||
|
||||
/** The total number of columns. */
|
||||
const NUM_COLUMNS = 3;
|
||||
const NUM_COLUMNS = 4;
|
||||
|
||||
/** The number of lazy-loaded columns. */
|
||||
const NUM_LAZY_LOAD_COLUMNS = 0;
|
||||
|
||||
/** The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */
|
||||
const NUM_HYDRATE_COLUMNS = 3;
|
||||
const NUM_HYDRATE_COLUMNS = 4;
|
||||
|
||||
/** the column name for the id field */
|
||||
const ID = 'imported_podcast.id';
|
||||
|
@ -38,6 +38,9 @@ abstract class BaseImportedPodcastPeer
|
|||
/** the column name for the auto_ingest field */
|
||||
const AUTO_INGEST = 'imported_podcast.auto_ingest';
|
||||
|
||||
/** the column name for the auto_ingest_timestamp field */
|
||||
const AUTO_INGEST_TIMESTAMP = 'imported_podcast.auto_ingest_timestamp';
|
||||
|
||||
/** the column name for the podcast_id field */
|
||||
const PODCAST_ID = 'imported_podcast.podcast_id';
|
||||
|
||||
|
@ -60,12 +63,12 @@ abstract class BaseImportedPodcastPeer
|
|||
* e.g. ImportedPodcastPeer::$fieldNames[ImportedPodcastPeer::TYPE_PHPNAME][0] = 'Id'
|
||||
*/
|
||||
protected static $fieldNames = array (
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbAutoIngest', 'DbPodcastId', ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbAutoIngest', 'dbPodcastId', ),
|
||||
BasePeer::TYPE_COLNAME => array (ImportedPodcastPeer::ID, ImportedPodcastPeer::AUTO_INGEST, ImportedPodcastPeer::PODCAST_ID, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'AUTO_INGEST', 'PODCAST_ID', ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id', 'auto_ingest', 'podcast_id', ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, )
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbAutoIngest', 'DbAutoIngestTimestamp', 'DbPodcastId', ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbAutoIngest', 'dbAutoIngestTimestamp', 'dbPodcastId', ),
|
||||
BasePeer::TYPE_COLNAME => array (ImportedPodcastPeer::ID, ImportedPodcastPeer::AUTO_INGEST, ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP, ImportedPodcastPeer::PODCAST_ID, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'AUTO_INGEST', 'AUTO_INGEST_TIMESTAMP', 'PODCAST_ID', ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id', 'auto_ingest', 'auto_ingest_timestamp', 'podcast_id', ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -75,12 +78,12 @@ abstract class BaseImportedPodcastPeer
|
|||
* e.g. ImportedPodcastPeer::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0
|
||||
*/
|
||||
protected static $fieldKeys = array (
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbAutoIngest' => 1, 'DbPodcastId' => 2, ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbAutoIngest' => 1, 'dbPodcastId' => 2, ),
|
||||
BasePeer::TYPE_COLNAME => array (ImportedPodcastPeer::ID => 0, ImportedPodcastPeer::AUTO_INGEST => 1, ImportedPodcastPeer::PODCAST_ID => 2, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'AUTO_INGEST' => 1, 'PODCAST_ID' => 2, ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'auto_ingest' => 1, 'podcast_id' => 2, ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, )
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbAutoIngest' => 1, 'DbAutoIngestTimestamp' => 2, 'DbPodcastId' => 3, ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbAutoIngest' => 1, 'dbAutoIngestTimestamp' => 2, 'dbPodcastId' => 3, ),
|
||||
BasePeer::TYPE_COLNAME => array (ImportedPodcastPeer::ID => 0, ImportedPodcastPeer::AUTO_INGEST => 1, ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP => 2, ImportedPodcastPeer::PODCAST_ID => 3, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'AUTO_INGEST' => 1, 'AUTO_INGEST_TIMESTAMP' => 2, 'PODCAST_ID' => 3, ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'auto_ingest' => 1, 'auto_ingest_timestamp' => 2, 'podcast_id' => 3, ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -156,10 +159,12 @@ abstract class BaseImportedPodcastPeer
|
|||
if (null === $alias) {
|
||||
$criteria->addSelectColumn(ImportedPodcastPeer::ID);
|
||||
$criteria->addSelectColumn(ImportedPodcastPeer::AUTO_INGEST);
|
||||
$criteria->addSelectColumn(ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP);
|
||||
$criteria->addSelectColumn(ImportedPodcastPeer::PODCAST_ID);
|
||||
} else {
|
||||
$criteria->addSelectColumn($alias . '.id');
|
||||
$criteria->addSelectColumn($alias . '.auto_ingest');
|
||||
$criteria->addSelectColumn($alias . '.auto_ingest_timestamp');
|
||||
$criteria->addSelectColumn($alias . '.podcast_id');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
*
|
||||
* @method ImportedPodcastQuery orderByDbId($order = Criteria::ASC) Order by the id column
|
||||
* @method ImportedPodcastQuery orderByDbAutoIngest($order = Criteria::ASC) Order by the auto_ingest column
|
||||
* @method ImportedPodcastQuery orderByDbAutoIngestTimestamp($order = Criteria::ASC) Order by the auto_ingest_timestamp column
|
||||
* @method ImportedPodcastQuery orderByDbPodcastId($order = Criteria::ASC) Order by the podcast_id column
|
||||
*
|
||||
* @method ImportedPodcastQuery groupByDbId() Group by the id column
|
||||
* @method ImportedPodcastQuery groupByDbAutoIngest() Group by the auto_ingest column
|
||||
* @method ImportedPodcastQuery groupByDbAutoIngestTimestamp() Group by the auto_ingest_timestamp column
|
||||
* @method ImportedPodcastQuery groupByDbPodcastId() Group by the podcast_id column
|
||||
*
|
||||
* @method ImportedPodcastQuery leftJoin($relation) Adds a LEFT JOIN clause to the query
|
||||
|
@ -26,10 +28,12 @@
|
|||
* @method ImportedPodcast findOneOrCreate(PropelPDO $con = null) Return the first ImportedPodcast matching the query, or a new ImportedPodcast object populated from the query conditions when no match is found
|
||||
*
|
||||
* @method ImportedPodcast findOneByDbAutoIngest(boolean $auto_ingest) Return the first ImportedPodcast filtered by the auto_ingest column
|
||||
* @method ImportedPodcast findOneByDbAutoIngestTimestamp(string $auto_ingest_timestamp) Return the first ImportedPodcast filtered by the auto_ingest_timestamp column
|
||||
* @method ImportedPodcast findOneByDbPodcastId(int $podcast_id) Return the first ImportedPodcast filtered by the podcast_id column
|
||||
*
|
||||
* @method array findByDbId(int $id) Return ImportedPodcast objects filtered by the id column
|
||||
* @method array findByDbAutoIngest(boolean $auto_ingest) Return ImportedPodcast objects filtered by the auto_ingest column
|
||||
* @method array findByDbAutoIngestTimestamp(string $auto_ingest_timestamp) Return ImportedPodcast objects filtered by the auto_ingest_timestamp column
|
||||
* @method array findByDbPodcastId(int $podcast_id) Return ImportedPodcast objects filtered by the podcast_id column
|
||||
*
|
||||
* @package propel.generator.airtime.om
|
||||
|
@ -138,7 +142,7 @@ abstract class BaseImportedPodcastQuery extends ModelCriteria
|
|||
*/
|
||||
protected function findPkSimple($key, $con)
|
||||
{
|
||||
$sql = 'SELECT "id", "auto_ingest", "podcast_id" FROM "imported_podcast" WHERE "id" = :p0';
|
||||
$sql = 'SELECT "id", "auto_ingest", "auto_ingest_timestamp", "podcast_id" FROM "imported_podcast" WHERE "id" = :p0';
|
||||
try {
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindValue(':p0', $key, PDO::PARAM_INT);
|
||||
|
@ -296,6 +300,49 @@ abstract class BaseImportedPodcastQuery extends ModelCriteria
|
|||
return $this->addUsingAlias(ImportedPodcastPeer::AUTO_INGEST, $dbAutoIngest, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query on the auto_ingest_timestamp column
|
||||
*
|
||||
* Example usage:
|
||||
* <code>
|
||||
* $query->filterByDbAutoIngestTimestamp('2011-03-14'); // WHERE auto_ingest_timestamp = '2011-03-14'
|
||||
* $query->filterByDbAutoIngestTimestamp('now'); // WHERE auto_ingest_timestamp = '2011-03-14'
|
||||
* $query->filterByDbAutoIngestTimestamp(array('max' => 'yesterday')); // WHERE auto_ingest_timestamp < '2011-03-13'
|
||||
* </code>
|
||||
*
|
||||
* @param mixed $dbAutoIngestTimestamp The value to use as filter.
|
||||
* Values can be integers (unix timestamps), DateTime objects, or strings.
|
||||
* Empty strings are treated as NULL.
|
||||
* Use scalar values for equality.
|
||||
* Use array values for in_array() equivalent.
|
||||
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
|
||||
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
|
||||
*
|
||||
* @return ImportedPodcastQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByDbAutoIngestTimestamp($dbAutoIngestTimestamp = null, $comparison = null)
|
||||
{
|
||||
if (is_array($dbAutoIngestTimestamp)) {
|
||||
$useMinMax = false;
|
||||
if (isset($dbAutoIngestTimestamp['min'])) {
|
||||
$this->addUsingAlias(ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP, $dbAutoIngestTimestamp['min'], Criteria::GREATER_EQUAL);
|
||||
$useMinMax = true;
|
||||
}
|
||||
if (isset($dbAutoIngestTimestamp['max'])) {
|
||||
$this->addUsingAlias(ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP, $dbAutoIngestTimestamp['max'], Criteria::LESS_EQUAL);
|
||||
$useMinMax = true;
|
||||
}
|
||||
if ($useMinMax) {
|
||||
return $this;
|
||||
}
|
||||
if (null === $comparison) {
|
||||
$comparison = Criteria::IN;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->addUsingAlias(ImportedPodcastPeer::AUTO_INGEST_TIMESTAMP, $dbAutoIngestTimestamp, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query on the podcast_id column
|
||||
*
|
||||
|
|
|
@ -71,5 +71,18 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap
|
|||
)
|
||||
);
|
||||
$router->addRoute('clear', $clearLibraryRoute);
|
||||
|
||||
$publishRoute = new Zend_Controller_Router_Route(
|
||||
'rest/media/:id/publish',
|
||||
array(
|
||||
'controller' => 'media',
|
||||
'action' => 'publish',
|
||||
'module' => 'rest'
|
||||
),
|
||||
array(
|
||||
'id' => '\d+'
|
||||
)
|
||||
);
|
||||
$router->addRoute('publish', $publishRoute);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,6 +185,23 @@ class Rest_MediaController extends Zend_Rest_Controller
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish endpoint for individual media items
|
||||
*/
|
||||
public function publishAction() {
|
||||
$id = $this->getId();
|
||||
try {
|
||||
// Is there a better way to do this?
|
||||
$data = json_decode($this->getRequest()->getRawBody(), true)["sources"];
|
||||
Application_Service_MediaService::publish($id, $data);
|
||||
$this->getResponse()
|
||||
->setHttpResponseCode(200);
|
||||
} catch (Exception $e) {
|
||||
$this->unknownErrorResponse();
|
||||
Logging::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function getId()
|
||||
{
|
||||
if (!$id = $this->_getParam('id', false)) {
|
||||
|
|
|
@ -111,9 +111,19 @@ class Application_Service_MediaService
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Publish or remove the file with the given file ID from the services
|
||||
* specified in the request data (ie. SoundCloud, the station podcast)
|
||||
*
|
||||
* @param int $fileId ID of the file to be published
|
||||
* @param array $data request data containing what services to publish to
|
||||
*/
|
||||
public static function publish($fileId, $data) {
|
||||
foreach ($data as $k => $v) {
|
||||
$service = PublishServiceFactory::getService($k);
|
||||
$service->$v($fileId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
class Application_Service_PodcastEpisodeService extends Application_Service_ThirdPartyCeleryService
|
||||
class Application_Service_PodcastEpisodeService extends Application_Service_ThirdPartyCeleryService implements Publish
|
||||
{
|
||||
/**
|
||||
* Arbitrary constant identifiers for the internal tasks array
|
||||
|
@ -22,7 +22,7 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
|||
* @var array map of constant identifiers to Celery task names
|
||||
*/
|
||||
protected static $_CELERY_TASKS = [
|
||||
self::DOWNLOAD => 'podcast-download' // TODO: rename this to ingest?
|
||||
self::DOWNLOAD => 'podcast-download'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
|||
public function addPodcastEpisodePlaceholders($podcastId, $episodes) {
|
||||
$storedEpisodes = array();
|
||||
foreach ($episodes as $episode) {
|
||||
$e = $this->addPodcastEpisodePlaceholder($podcastId, $episode);
|
||||
$e = $this->addPlaceholder($podcastId, $episode);
|
||||
array_push($storedEpisodes, $e);
|
||||
}
|
||||
return $storedEpisodes;
|
||||
|
@ -52,19 +52,33 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
|||
*
|
||||
* @return PodcastEpisodes the stored PodcastEpisodes object
|
||||
*/
|
||||
public function addPodcastEpisodePlaceholder($podcastId, $episode) {
|
||||
public function addPlaceholder($podcastId, $episode) {
|
||||
// We need to check whether the array is parsed directly from the SimplePie
|
||||
// feed object, or whether it's passed in as json
|
||||
if ($episode["enclosure"] instanceof SimplePie_Enclosure) {
|
||||
$url = $episode["enclosure"]->get_link();
|
||||
} else {
|
||||
$url = $episode["enclosure"]["link"];
|
||||
}
|
||||
$enclosure = $episode["enclosure"];
|
||||
$url = $enclosure instanceof SimplePie_Enclosure ? $enclosure->get_link() : $enclosure["link"];
|
||||
return $this->_buildEpisode($podcastId, $url, $episode["guid"], $episode["pub_date"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given episode parameters, construct and store a basic PodcastEpisodes object
|
||||
*
|
||||
* @param int $podcastId the podcast the episode belongs to
|
||||
* @param string $url the download URL for the episode
|
||||
* @param string $guid the unique id for the episode. Often the same as the download URL
|
||||
* @param string $publicationDate the publication date of the episode
|
||||
*
|
||||
* @return PodcastEpisodes the newly created PodcastEpisodes object
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws PropelException
|
||||
*/
|
||||
private function _buildEpisode($podcastId, $url, $guid, $publicationDate) {
|
||||
$e = new PodcastEpisodes();
|
||||
$e->setDbPodcastId($podcastId);
|
||||
$e->setDbDownloadUrl($url);
|
||||
$e->setDbEpisodeGuid($episode["guid"]);
|
||||
$e->setDbPublicationDate($episode["pub_date"]);
|
||||
$e->setDbEpisodeGuid($guid);
|
||||
$e->setDbPublicationDate($publicationDate);
|
||||
$e->save();
|
||||
return $e;
|
||||
}
|
||||
|
@ -75,25 +89,24 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
|||
* @param array $episodes array of podcast episodes
|
||||
*/
|
||||
public function downloadEpisodes($episodes) {
|
||||
$episodeUrls = array();
|
||||
/** @var PodcastEpisodes $episode */
|
||||
foreach($episodes as $episode) {
|
||||
array_push($episodeUrls, array("id" => $episode->getDbId(),
|
||||
"url" => $episode->getDbDownloadUrl()));
|
||||
$this->_download($episode->getDbId(), $episode->getDbDownloadUrl());
|
||||
}
|
||||
if (empty($episodeUrls)) return;
|
||||
$this->_download($episodeUrls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of download URLs, download RSS feed tracks
|
||||
* Given an episode ID and a download URL, send a Celery task
|
||||
* to download an RSS feed track
|
||||
*
|
||||
* @param array $episodes array of episodes containing download URLs and IDs to send to Celery
|
||||
* @param int $id episode unique ID
|
||||
* @param string $url download url for the episode
|
||||
*/
|
||||
private function _download($episodes) {
|
||||
private function _download($id, $url) {
|
||||
$CC_CONFIG = Config::getConfig();
|
||||
$data = array(
|
||||
'episodes' => $episodes,
|
||||
'id' => $id,
|
||||
'url' => $url,
|
||||
'callback_url' => Application_Common_HTTPHelper::getStationUrl() . '/rest/media',
|
||||
'api_key' => $apiKey = $CC_CONFIG["apiKey"][0],
|
||||
);
|
||||
|
@ -105,7 +118,7 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
|||
*
|
||||
* @param $task CeleryTasks the completed CeleryTasks object
|
||||
* @param $episodeId int PodcastEpisodes identifier
|
||||
* @param $episodes array array containing Podcast episode information
|
||||
* @param $episode stdClass simple object containing Podcast episode information
|
||||
* @param $status string Celery task status
|
||||
*
|
||||
* @return ThirdPartyTrackReferences the updated ThirdPartyTrackReferences object
|
||||
|
@ -113,26 +126,44 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
|||
* @throws Exception
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function updateTrackReference($task, $episodeId, $episodes, $status) {
|
||||
$ref = parent::updateTrackReference($task, $episodeId, $episodes, $status);
|
||||
public function updateTrackReference($task, $episodeId, $episode, $status) {
|
||||
$ref = parent::updateTrackReference($task, $episodeId, $episode, $status);
|
||||
|
||||
if ($status == CELERY_SUCCESS_STATUS) {
|
||||
foreach ($episodes as $episode) {
|
||||
// Since we process episode downloads as a batch, individual downloads can fail
|
||||
// even if the task itself succeeds
|
||||
$dbEpisode = PodcastEpisodesQuery::create()
|
||||
->findOneByDbId($episode->episodeid);
|
||||
if ($episode->status) {
|
||||
$dbEpisode->setDbFileId($episode->fileid)
|
||||
->save();
|
||||
} else {
|
||||
Logging::warn("Celery task $task episode $episode->episodeid unsuccessful with status $episode->status");
|
||||
$dbEpisode->delete();
|
||||
}
|
||||
}
|
||||
$dbEpisode = PodcastEpisodesQuery::create()
|
||||
->findOneByDbId($episode->episodeid);
|
||||
// Even if the task itself succeeds, the download could have failed, so check the status
|
||||
if ($status == CELERY_SUCCESS_STATUS && $episode->status) {
|
||||
$dbEpisode->setDbFileId($episode->fileid)->save();
|
||||
} else {
|
||||
Logging::warn("Celery task $task episode $episode->episodeid unsuccessful with status $episode->status");
|
||||
$dbEpisode->delete();
|
||||
}
|
||||
// TODO: do we need a broader fail condition here?
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the file with the given file ID to the station podcast
|
||||
*
|
||||
* @param int $fileId ID of the file to be published
|
||||
*/
|
||||
public function publish($fileId) {
|
||||
$id = Application_Model_Preference::getStationPodcastId();
|
||||
$url = $guid = Application_Common_HTTPHelper::getStationUrl()."rest/media/$fileId/download";
|
||||
$e = $this->_buildEpisode($id, $url, $guid, date('r'));
|
||||
$e->setDbFileId($fileId)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpublish the file with the given file ID from the station podcast
|
||||
*
|
||||
* @param int $fileId ID of the file to be unpublished
|
||||
*/
|
||||
public function unpublish($fileId) {
|
||||
$id = Application_Model_Preference::getStationPodcastId();
|
||||
PodcastEpisodesQuery::create()
|
||||
->filterByDbPodcastId($id)
|
||||
->findOneByDbFileId($fileId)
|
||||
->delete();
|
||||
}
|
||||
}
|
|
@ -158,7 +158,9 @@ class Application_Service_PodcastService
|
|||
$stationPodcast->save();
|
||||
|
||||
Application_Model_Preference::setStationPodcastId($podcast->getDbId());
|
||||
|
||||
// Set the download key when we create the station podcast
|
||||
// The value is randomly generated in the setter
|
||||
Application_Model_Preference::setStationPodcastDownloadKey();
|
||||
}
|
||||
|
||||
//TODO move this somewhere where it makes sense
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
class PublishServiceFactory {
|
||||
|
||||
/**
|
||||
* Given an identifying string, get a PublishService object of that type
|
||||
*
|
||||
* @param $serviceName string the name of the service to create
|
||||
*
|
||||
* @return Publish|null
|
||||
*/
|
||||
public static function getService($serviceName) {
|
||||
switch($serviceName) {
|
||||
case SOUNDCLOUD_SERVICE_NAME:
|
||||
return new Application_Service_SoundcloudService();
|
||||
case STATION_PODCAST_SERVICE_NAME:
|
||||
return new Application_Service_PodcastEpisodeService();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,7 @@ require_once "ThirdPartyCeleryService.php";
|
|||
*
|
||||
* Class Application_Service_SoundcloudService
|
||||
*/
|
||||
class Application_Service_SoundcloudService extends Application_Service_ThirdPartyCeleryService implements OAuth2 {
|
||||
class Application_Service_SoundcloudService extends Application_Service_ThirdPartyCeleryService implements OAuth2, Publish {
|
||||
|
||||
/**
|
||||
* Arbitrary constant identifiers for the internal tasks array
|
||||
|
@ -145,7 +145,7 @@ class Application_Service_SoundcloudService extends Application_Service_ThirdPar
|
|||
public function download($trackId = null) {
|
||||
$CC_CONFIG = Config::getConfig();
|
||||
$data = array(
|
||||
'callback_url' => Application_Common_HTTPHelper::getStationUrl() . '/rest/media',
|
||||
'callback_url' => Application_Common_HTTPHelper::getStationUrl() . 'rest/media',
|
||||
'api_key' => $apiKey = $CC_CONFIG["apiKey"][0],
|
||||
'token' => $this->_accessToken,
|
||||
'track_id' => $trackId
|
||||
|
@ -287,4 +287,25 @@ class Application_Service_SoundcloudService extends Application_Service_ThirdPar
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the file with the given file ID to SoundCloud
|
||||
*
|
||||
* @param int $fileId ID of the file to be published
|
||||
*/
|
||||
public function publish($fileId) {
|
||||
$this->upload($fileId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpublish the file with the given file ID from SoundCloud
|
||||
*
|
||||
* @param int $fileId ID of the file to be unpublished
|
||||
*
|
||||
* @throws ServiceNotFoundException when a $fileId with no corresponding
|
||||
* service identifier is given
|
||||
*/
|
||||
public function unpublish($fileId) {
|
||||
$this->delete($fileId);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,8 +16,10 @@
|
|||
</label>
|
||||
<fieldset>
|
||||
<legend><?php echo _("Publish to:"); ?></legend>
|
||||
<input type="checkbox" name="publish_sources" id="station_podcast" value="station_podcast"><label for="station_podcast"><?php echo(_("My Station Podcast"));?></label><br/>
|
||||
<input type="checkbox" name="publish_sources" id="soundcloud" value="soundcloud"><label for="soundcloud">SoundCloud</label>
|
||||
<input ng-model="publishSources.station_podcast" type="checkbox" name="publish_sources" id="station_podcast" value="station_podcast">
|
||||
<label for="station_podcast"><?php echo(_("My Station Podcast"));?></label><br/>
|
||||
<input ng-model="publishSources.soundcloud" type="checkbox" name="publish_sources" id="soundcloud" value="soundcloud">
|
||||
<label for="soundcloud">SoundCloud</label>
|
||||
</fieldset>
|
||||
|
||||
</form>
|
||||
|
|
|
@ -598,6 +598,7 @@
|
|||
<table name="imported_podcast" phpName="ImportedPodcast">
|
||||
<column name="id" phpName="DbId" required="true" primaryKey="true" autoIncrement="true" type="INTEGER"/>
|
||||
<column name="auto_ingest" phpName="DbAutoIngest" type="BOOLEAN" required="true" defaultValue="false"/>
|
||||
<column name="auto_ingest_timestamp" phpName="DbAutoIngestTimestamp" type="TIMESTAMP" required="false" />
|
||||
<column name="podcast_id" phpName="DbPodcastId" required="true" type="INTEGER"/>
|
||||
<foreign-key foreignTable="podcast" name="podcast_id_fkey" onDelete="CASCADE">
|
||||
<reference local="podcast_id" foreign="id" />
|
||||
|
|
|
@ -756,6 +756,7 @@ CREATE TABLE "imported_podcast"
|
|||
(
|
||||
"id" serial NOT NULL,
|
||||
"auto_ingest" BOOLEAN DEFAULT 'f' NOT NULL,
|
||||
"auto_ingest_timestamp" TIMESTAMP,
|
||||
"podcast_id" INTEGER NOT NULL,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
|
|
@ -17,6 +17,8 @@ var AIRTIME = (function (AIRTIME) {
|
|||
var publishApp = angular.module(PUBLISH_APP_NAME, [])
|
||||
.controller('RestController', function($scope, $http, mediaId, tab) {
|
||||
|
||||
$scope.publishSources = {};
|
||||
|
||||
$http.get(endpoint + mediaId, { csrf_token: jQuery("#csrf").val() })
|
||||
.success(function(json) {
|
||||
console.log(json);
|
||||
|
@ -24,8 +26,12 @@ var AIRTIME = (function (AIRTIME) {
|
|||
tab.setName($scope.media.track_title);
|
||||
});
|
||||
|
||||
$scope.save = function() {
|
||||
$http.put(endpoint + $scope.media.id, { csrf_token: jQuery("#csrf").val(), media: $scope.media })
|
||||
$scope.publish = function() {
|
||||
var sources = {};
|
||||
$.each($scope.publishSources, function(k, v) {
|
||||
if (v) sources[k] = 'publish'; // Tentative TODO: decide on a robust implementation
|
||||
});
|
||||
$http.put(endpoint + $scope.media.id + '/publish', { csrf_token: jQuery("#csrf").val(), sources: sources })
|
||||
.success(function() {
|
||||
// TODO
|
||||
});
|
||||
|
|
|
@ -86,35 +86,32 @@ def soundcloud_delete(token, track_id):
|
|||
|
||||
|
||||
@celery.task(name='podcast-download', acks_late=True)
|
||||
def podcast_download(episodes, callback_url, api_key):
|
||||
def podcast_download(id, url, callback_url, api_key):
|
||||
"""
|
||||
Download a batch of podcast episodes
|
||||
|
||||
:param episodes: array of episodes containing download URLs and IDs
|
||||
:param id: episode unique ID
|
||||
:param url: download url for the episode
|
||||
:param callback_url: callback URL to send the downloaded file to
|
||||
:param api_key: API key for callback authentication
|
||||
:rtype: None
|
||||
"""
|
||||
response = []
|
||||
for episode in episodes:
|
||||
logger.info(episode)
|
||||
# Object to store file IDs, episode IDs, and download status
|
||||
# (important if there's an error before the file is posted)
|
||||
obj = { 'episodeid': episode['id'] }
|
||||
try:
|
||||
re = None
|
||||
with closing(requests.get(episode['url'], stream=True)) as r:
|
||||
filename = get_filename(r)
|
||||
re = requests.post(callback_url, files={'file': (filename, r.content)}, auth=requests.auth.HTTPBasicAuth(api_key, ''))
|
||||
re.raise_for_status()
|
||||
f = json.loads(re.content) # Read the response from the media API to get the file id
|
||||
obj['fileid'] = f['id']
|
||||
obj['status'] = 1
|
||||
except Exception as e:
|
||||
logger.info('Error during file download: {0}'.format(e.message))
|
||||
obj['status'] = 0
|
||||
response.append(obj)
|
||||
return json.dumps(response)
|
||||
# Object to store file IDs, episode IDs, and download status
|
||||
# (important if there's an error before the file is posted)
|
||||
obj = { 'episodeid': id }
|
||||
try:
|
||||
re = None
|
||||
with closing(requests.get(url, stream=True)) as r:
|
||||
filename = get_filename(r)
|
||||
re = requests.post(callback_url, files={'file': (filename, r.content)}, auth=requests.auth.HTTPBasicAuth(api_key, ''))
|
||||
re.raise_for_status()
|
||||
f = json.loads(re.content) # Read the response from the media API to get the file id
|
||||
obj['fileid'] = f['id']
|
||||
obj['status'] = 1
|
||||
except Exception as e:
|
||||
logger.info('Error during file download: {0}'.format(e.message))
|
||||
obj['status'] = 0
|
||||
return json.dumps(obj)
|
||||
|
||||
|
||||
def get_filename(r):
|
||||
|
|
Loading…
Reference in New Issue