4
0
mirror of https://github.com/AzuraCast/AzuraCast.git synced 2024-06-14 21:26:37 +00:00

A new "smarter" synchronization system that can be invoked and debugged directly from the admin pages.

This commit is contained in:
Buster Neece 2014-07-26 08:37:11 -05:00
parent 5a53cce814
commit 7bc30d8bed
10 changed files with 307 additions and 179 deletions

View File

@ -0,0 +1,92 @@
<?php
namespace PVL;
use \Entity\NetworkNews;
class NewsManager
{
public static function syncNetwork()
{
$em = \Zend_Registry::get('em');
// Pull featured images.
$timestamp_threshold = strtotime('-6 weeks');
$api_params = array(
'api_key' => 'Hp1W4lpJ0dhHA7pOGih0yow02ZXAFHdiIR5bzFS67C0xlERPAZ',
'limit' => 10,
);
$api_url = 'http://api.tumblr.com/v2/blog/news.ponyvillelive.com/posts/photo?'.http_build_query($api_params);
$results_raw = @file_get_contents($api_url);
$news_items = array();
if ($results_raw)
{
$results = json_decode($results_raw, true);
$posts = $results['response']['posts'];
$network_news = array();
foreach((array)$posts as $post)
{
$image = $post['photos'][0]['original_size'];
if ($image['height'] > 250)
continue;
// Copy the image to the local static directory (for SSL and other caching support).
$image_url = $image['url'];
$image_url_basename = basename($image_url);
$local_path_base = 'rotators/'.$image_url_basename;
$local_path = DF_UPLOAD_FOLDER.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $local_path_base);
$local_url = $local_path_base;
if (!file_exists($local_path))
@copy($image_url, $local_path);
$tags = array_map('strtolower', (array)$post['tags']);
if (in_array('archive', $tags))
continue;
$description = \DF\Utilities::truncateText(strip_tags($post['caption']), 250);
if (strpos($description, ':') !== FALSE)
{
list($title, $description) = explode(':', $description, 2);
}
else
{
$title = $description;
$description = NULL;
}
$news_row = array(
'id' => 'tumblr_'.$post['id'],
'title' => trim($title),
'body' => trim($description),
'image_url' => $local_url,
'web_url' => $post['post_url'],
'timestamp' => $post['timestamp'],
);
if ($news_row['timestamp'] >= $timestamp_threshold)
$news_items[] = $news_row;
}
// Delete current rotator contents.
$em->createQuery('DELETE FROM Entity\NetworkNews nn')->execute();
foreach($news_items as $item)
{
$record = new NetworkNews;
$record->fromArray($item);
$em->persist($record);
}
$em->flush();
}
}
}

View File

@ -18,9 +18,9 @@ class ScheduleManager
$schedule_items = array();
$schedule_records = array();
$schedule_stations = array();
// PVL news
/*
// PVL news (retired for con center)
$schedule_items[] = array(
'name' => 'PVL Global Events',
'url' => 'https://www.google.com/calendar/feeds/lj3d00magjlucuk902rarrhhrg%40group.calendar.google.com/public/full',
@ -29,28 +29,27 @@ class ScheduleManager
'image_url' => \DF\Url::content('pvl_square.png'),
);
$schedule_stations[0] = NULL;
*/
$stations = $em->createQuery('SELECT s FROM Entity\Station s WHERE s.category IN (:types) AND s.is_active = 1')
->setParameter('types', array('audio', 'video'))
->execute();
->getArrayResult();
foreach($stations as $station)
{
if ($station->gcal_url)
if ($station['gcal_url'])
{
$schedule_stations[$station->id] = $station;
$schedule_items[] = array(
'name' => $station->name,
'url' => $station->gcal_url,
'name' => $station['name'],
'url' => $station['gcal_url'],
'type' => 'station',
'station_id' => $station->id,
'image_url' => \DF\Url::content($station->image_url),
'station_id' => $station['id'],
'image_url' => \DF\Url::content($station['image_url']),
);
}
}
\PVL\Debug::startTimer('Get Calendar Records');
Debug::startTimer('Get Calendar Records');
$time_check_start = time();
@ -80,11 +79,14 @@ class ScheduleManager
$calendar_array = json_decode($calendar_raw, true);
if (empty($calendar_array['feed']['entry']))
{
Debug::log($calendar_raw);
continue;
}
$events = (array)$calendar_array['feed']['entry'];
\PVL\Debug::print_r($calendar_array);
Debug::print_r($calendar_array);
$all_events = array();
@ -149,10 +151,16 @@ class ScheduleManager
}
}
\PVL\Debug::endTimer('Get Calendar Records');
Debug::endTimer('Get Calendar Records');
if (count($schedule_records) == 0)
{
Debug::log('Error: No calendar records loaded');
return;
}
// Add/Remove all differential records.
\PVL\Debug::startTimer('Sync DB Records');
Debug::startTimer('Sync DB Records');
$em->createQuery('DELETE FROM Entity\Schedule s WHERE s.type = :type AND s.station_id NOT IN (:station_ids)')
->setParameter('type', 'station')
@ -161,7 +169,7 @@ class ScheduleManager
foreach($schedule_records as $station_id => $station_records)
{
$station = $schedule_stations[$station_id];
$station = Station::find($station_id);
if ($station_id == 0)
{
@ -204,19 +212,20 @@ class ScheduleManager
$em->persist($record);
}
}
$em->flush();
$em->clear();
}
$em->flush();
\PVL\Debug::endTimer('Sync DB Records');
Debug::endTimer('Sync DB Records');
Settings::setSetting('schedule_manager_last_run', time());
}
public static function requestExternalUrl($url, $name = 'Calendar')
{
\PVL\Debug::startTimer('Request URL '.$name);
\PVL\Debug::log($url);
Debug::startTimer('Request URL '.$name);
Debug::log($url);
// Start cURL request.
$curl = curl_init();
@ -228,11 +237,11 @@ class ScheduleManager
$return_raw = \PVL\Utilities::curl_exec_utf8($curl);
// End cURL request.
\PVL\Debug::endTimer('Request URL '.$name);
Debug::endTimer('Request URL '.$name);
$error = curl_error($curl);
if ($error)
\PVL\Debug::log('Curl Error:'.$error);
Debug::log('Curl Error:'.$error);
return $return_raw;
}

View File

@ -0,0 +1,124 @@
<?php
namespace PVL;
use \Entity\Settings;
class SyncManager
{
public static function syncNowplaying()
{
set_time_limit(60);
ini_set('memory_limit', '256M');
// Prevent nowplaying from running on top of itself.
$last_start = Settings::getSetting('nowplaying_last_started', 0);
$last_end = Settings::getSetting('nowplaying_last_run', 0);
if ($last_start > $last_end && $last_start >= (time() - 60))
return;
// Sync schedules.
Settings::setSetting('nowplaying_last_started', time());
NowPlaying::generate();
Settings::setSetting('nowplaying_last_run', time());
}
public static function syncShort()
{
set_time_limit(60);
ini_set('memory_limit', '256M');
// Send notifications related to schedules (high priority).
NotificationManager::run();
Settings::setSetting('sync_fast_last_run', time());
}
public static function syncMedium()
{
set_time_limit(300);
ini_set('memory_limit', '256M');
// Pull the homepage news.
NewsManager::syncNetwork();
// Sync schedules (highest priority).
ScheduleManager::run(!DF_IS_COMMAND_LINE);
// Sync show episodes and artist news (high priority).
PodcastManager::run();
// Sync CentovaCast song data.
try
{
CentovaCast::sync();
}
catch(\Exception $e)
{
echo "Error syncing CentovaCast:\n";
echo $e->getMessage()."\n";
}
// Generate cache files.
CacheManager::generateSlimPlayer();
Settings::setSetting('sync_last_run', time());
}
public static function syncLong()
{
set_time_limit(1800);
ini_set('memory_limit', '256M');
// Sync analytical and statistical data (long running).
AnalyticsManager::run();
// Update convention archives.
ConventionManager::run();
// Sync the BronyTunes library.
Service\BronyTunes::load();
// Sync the Pony.fm library.
Service\PonyFm::load();
// Sync the EqBeats library.
Service\EqBeats::load();
Settings::setSetting('sync_slow_last_run', time());
}
public static function getSyncTimes()
{
$syncs = array(
'nowplaying' => array(
'name' => 'Now Playing Data',
'latest' => Settings::getSetting('nowplaying_last_run', 0),
),
'short' => array(
'name' => '1-Minute Sync',
'latest' => Settings::getSetting('sync_fast_last_run', 0),
),
'medium' => array(
'name' => '5-Minute Sync',
'latest' => Settings::getSetting('sync_last_run', 0),
),
'long' => array(
'name' => '1-Hour Sync',
'latest' => Settings::getSetting('sync_slow_last_run', 0),
),
);
foreach($syncs as $sync_key => $sync_info)
{
$sync_latest = $sync_info['latest'];
$syncs[$sync_key]['diff'] = time()-$sync_latest;
$syncs[$sync_key]['diff_text'] = \DF\Utilities::timeDifferenceText($sync_latest, time());
}
return $syncs;
}
}

View File

@ -58,89 +58,4 @@ class NetworkNews extends \DF\Doctrine\Entity
return $network_news;
}
public static function load()
{
$em = self::getEntityManager();
// Pull featured images.
$timestamp_threshold = strtotime('-6 weeks');
$api_params = array(
'api_key' => 'Hp1W4lpJ0dhHA7pOGih0yow02ZXAFHdiIR5bzFS67C0xlERPAZ',
'limit' => 10,
);
$api_url = 'http://api.tumblr.com/v2/blog/news.ponyvillelive.com/posts/photo?'.http_build_query($api_params);
$results_raw = @file_get_contents($api_url);
$news_items = array();
if ($results_raw)
{
$results = json_decode($results_raw, true);
$posts = $results['response']['posts'];
$network_news = array();
foreach((array)$posts as $post)
{
$image = $post['photos'][0]['original_size'];
if ($image['height'] > 250)
continue;
// Copy the image to the local static directory (for SSL and other caching support).
$image_url = $image['url'];
$image_url_basename = basename($image_url);
$local_path_base = 'rotators/'.$image_url_basename;
$local_path = DF_UPLOAD_FOLDER.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $local_path_base);
$local_url = $local_path_base;
if (!file_exists($local_path))
@copy($image_url, $local_path);
$tags = array_map('strtolower', (array)$post['tags']);
if (in_array('archive', $tags))
continue;
$description = \DF\Utilities::truncateText(strip_tags($post['caption']), 250);
if (strpos($description, ':') !== FALSE)
{
list($title, $description) = explode(':', $description, 2);
}
else
{
$title = $description;
$description = NULL;
}
$news_row = array(
'id' => 'tumblr_'.$post['id'],
'title' => trim($title),
'body' => trim($description),
'image_url' => $local_url,
'web_url' => $post['post_url'],
'timestamp' => $post['timestamp'],
);
if ($news_row['timestamp'] >= $timestamp_threshold)
$news_items[] = $news_row;
}
// Delete current rotator contents.
$em->createQuery('DELETE FROM '.__CLASS__.' nn')->execute();
foreach($news_items as $item)
{
$record = new self;
$record->fromArray($item);
$em->persist($record);
}
$em->flush();
}
}
}

View File

@ -96,5 +96,43 @@ class Admin_IndexController extends \DF\Controller\Action
$this->view->network_metrics = json_encode($network_metrics);
$this->view->station_metrics = json_encode($station_metrics);
// Synchronization statuses
if ($this->acl->isAllowed('administer all'))
$this->view->sync_times = \PVL\SyncManager::getSyncTimes();
}
public function syncAction()
{
$this->acl->checkPermission('administer all');
$this->doNotRender();
\PVL\Debug::setEchoMode(TRUE);
\PVL\Debug::startTimer('sync_task');
$type = $this->getParam('type', 'nowplaying');
switch($type)
{
case "long":
\PVL\SyncManager::syncLong();
break;
case "medium":
\PVL\SyncManager::syncMedium();
break;
case "short":
\PVL\SyncManager::syncShort();
break;
case "nowplaying":
default:
\PVL\SyncManager::syncNowplaying();
break;
}
\PVL\Debug::endTimer('sync_task');
\PVL\Debug::log('Sync task complete. See log above.');
}
}

View File

@ -47,6 +47,24 @@ if ($skin == "dark")
<div id="network_listeners_by_day" style="height: 250px;"></div>
<div id="station_listeners_by_day" style="height: 450px;"></div>
</div>
<div class="well no-margin">
<h2>Synchronization Status</h2>
<div class="row-fluid">
<? foreach($this->sync_times as $sync_key => $sync_info): ?>
<div class="span3">
<h4><?=$sync_info['name'] ?></h4>
<p><?=date('F j, Y g:ia', $sync_info['latest']) ?><br><small><?=$sync_info['diff_text'] ?> ago</small></p>
<?=$this->button(array(
'type' => 'small',
'href' => $this->routeFromHere(array('action' => 'sync', 'type' => $sync_key)),
'text' => 'Run Manually',
'target' => '_blank',
)) ?>
</div>
<? endforeach; ?>
</div>
</div>
</div>
</div>

View File

@ -6,22 +6,4 @@
require_once dirname(__FILE__) . '/../app/bootstrap.php';
$application->bootstrap();
if (DF_APPLICATION_ENV != 'production')
\PVL\Debug::setEchoMode(TRUE);
set_time_limit(60);
ini_set('memory_limit', '256M');
// Prevent nowplaying from running on top of itself.
$last_start = \Entity\Settings::getSetting('nowplaying_last_started', 0);
$last_end = \Entity\Settings::getSetting('nowplaying_last_run', 0);
if ($last_start > $last_end && $last_start >= (time() - 60))
exit;
// Sync schedules.
\Entity\Settings::setSetting('nowplaying_last_started', time());
\PVL\NowPlaying::generate();
\Entity\Settings::setSetting('nowplaying_last_run', time());
\PVL\SyncManager::syncNowplaying();

View File

@ -6,27 +6,4 @@
require_once dirname(__FILE__) . '/../app/bootstrap.php';
$application->bootstrap();
set_time_limit(300);
ini_set('memory_limit', '256M');
// Generate cache files.
\PVL\CacheManager::generateSlimPlayer();
// Sync schedules (highest priority).
\PVL\ScheduleManager::run();
// Sync show episodes and artist news (high priority).
\PVL\PodcastManager::run();
// Sync CentovaCast song data.
try
{
\PVL\CentovaCast::sync();
}
catch(\Exception $e)
{
echo "Error syncing CentovaCast:\n";
echo $e->getMessage()."\n";
}
\Entity\Settings::setSetting('sync_last_run', time());
\PVL\SyncManager::syncMedium();

View File

@ -6,13 +6,4 @@
require_once dirname(__FILE__) . '/../app/bootstrap.php';
$application->bootstrap();
set_time_limit(60);
ini_set('memory_limit', '256M');
// Pull the homepage news.
\Entity\NetworkNews::load();
// Send notifications related to schedules (high priority).
\PVL\NotificationManager::run();
\Entity\Settings::setSetting('sync_fast_last_run', time());
\PVL\SyncManager::syncShort();

View File

@ -6,22 +6,4 @@
require_once dirname(__FILE__) . '/../app/bootstrap.php';
$application->bootstrap();
set_time_limit(1800);
ini_set('memory_limit', '256M');
// Sync analytical and statistical data (long running).
\PVL\AnalyticsManager::run();
// Update convention archives.
\PVL\ConventionManager::run();
// Sync the BronyTunes library.
\PVL\Service\BronyTunes::load();
// Sync the Pony.fm library.
\PVL\Service\PonyFm::load();
// Sync the EqBeats library.
\PVL\Service\EqBeats::load();
\Entity\Settings::setSetting('sync_slow_last_run', time());
\PVL\SyncManager::syncLong();