public function indexAction() { $this->view->social_types = Podcast::getSocialTypes(); // Paginate episodes. $query = $this->em->createQuery('SELECT pe FROM Entity\\PodcastEpisode pe WHERE pe.podcast_id = :podcast ORDER BY pe.timestamp DESC')->setParameter('podcast', $this->podcast->id); $this->view->pager = new \DF\Paginator\Doctrine($query, $this->getParam('page', 1), 25); // Generate traffic metrics. $influx = $this->di->get('influx'); $raw_analytics = $influx->setDatabase('pvlive_analytics')->query('SELECT * FROM /^1(d|h).podcast.' . $this->podcast->id . '.*/ WHERE time > now() - 180d', 'm'); $analytic_totals = array(); foreach ($raw_analytics as $row_schema => $row_entries) { $schema_parts = explode('.', $row_schema); $duration = $schema_parts[0]; foreach ($row_entries as $row_entry) { $time = $row_entry['time']; if (!isset($analytic_totals[$duration][$time])) { $analytic_totals[$duration][$time] = 0; } $analytic_totals[$duration][$time] += $row_entry['count']; } } @ksort($analytic_totals['1d']); @ksort($analytic_totals['1h']); $chart_data = array('1d' => '[]', '1h' => '[]'); foreach ($analytic_totals as $total_duration => $total_entries) { $new_chart_data = array(); foreach ($total_entries as $entry_timestamp => $entry_value) { $new_chart_data[] = array($entry_timestamp, $entry_value); } $chart_data[$total_duration] = json_encode($new_chart_data); } $this->view->chart_data = $chart_data; }
public function deleteAction() { $record = Record::find($this->getParam('id')); if ($record) { $record->delete(); } $this->alert('Record deleted.', 'green'); $this->redirectFromHere(array('action' => 'index', 'id' => NULL, 'csrf' => NULL)); }
public function latestAction() { try { $latest_shows = Podcast::fetchLatest(); $return = array(); foreach ((array) $latest_shows as $show_info) { $return_row = Podcast::api($show_info['record'], FALSE); foreach ((array) $show_info['episodes'] as $ep_row) { $return_row['episodes'][] = PodcastEpisode::api($ep_row); } $return[] = $return_row; } return $this->returnSuccess($return); } catch (\Exception $e) { return $this->returnError($e->getMessage()); } }
protected function preDispatch() { parent::preDispatch(); $this->forceSecure(); $user = $this->auth->getLoggedInUser(); // Compile list of visible stations. $all_podcasts = Podcast::fetchAll(); $podcasts = array(); foreach ($all_podcasts as $podcast) { if ($podcast->canManage($user)) { $podcasts[$podcast->id] = $podcast; } } $this->podcasts = $podcasts; $this->view->podcasts = $podcasts; // Assign a station if one is selected. if ($this->hasParam('podcast')) { $podcast_id = (int) $this->getParam('podcast'); if (isset($podcasts[$podcast_id])) { $this->podcast = $podcasts[$podcast_id]; $this->view->podcast = $this->podcast; $this->view->hide_title = true; } else { throw new \DF\Exception\PermissionDenied(); } } else { if (count($this->podcasts) == 1) { // Convenience auto-redirect for single-station admins. $this->redirectFromHere(array('podcast' => key($this->podcasts))); return false; } } // Force a redirect to the "Select" page if no station ID is specified. if (!$this->podcast) { throw new \DF\Exception\PermissionDenied(); } }
/** * Main display. */ public function indexAction() { // Inject all stations. $stations = \Entity\Station::fetchAll(); $this->view->stations = $stations; // Inject all podcasts. $podcasts = \Entity\Podcast::fetchAll(); $this->view->podcasts = $podcasts; // Pull cached statistic charts if available. $metrics = \DF\Cache::get('admin_metrics'); if (!$metrics) { // Statistics by day. $influx = $this->di->get('influx'); $station_averages = array(); $network_data = array('PVL Network' => array('ranges' => array(), 'averages' => array())); $daily_stats = $influx->setDatabase('pvlive_stations')->query('SELECT * FROM /1d.*/ WHERE time > now() - 180d', 'm'); foreach ($daily_stats as $stat_series => $stat_rows) { $series_split = explode('.', $stat_series); if ($series_split[1] == 'all') { $network_name = 'PVL Network'; foreach ($stat_rows as $stat_row) { $network_data[$network_name]['ranges'][$stat_row['time']] = array($stat_row['time'], $stat_row['min'], $stat_row['max']); $network_data[$network_name]['averages'][$stat_row['time']] = array($stat_row['time'], round($stat_row['value'], 2)); } } else { $station_id = $series_split[2]; foreach ($stat_rows as $stat_row) { $station_averages[$station_id][$stat_row['time']] = array($stat_row['time'], round($stat_row['value'], 2)); } } } $network_metrics = array(); foreach ($network_data as $network_name => $data_charts) { if (isset($data_charts['ranges'])) { $metric_row = new \stdClass(); $metric_row->name = $network_name . ' Listener Range'; $metric_row->type = 'arearange'; ksort($data_charts['ranges']); $metric_row->data = array_values($data_charts['ranges']); $network_metrics[] = $metric_row; } if (isset($data_charts['averages'])) { $metric_row = new \stdClass(); $metric_row->name = $network_name . ' Daily Average'; $metric_row->type = 'spline'; ksort($data_charts['averages']); $metric_row->data = array_values($data_charts['averages']); $network_metrics[] = $metric_row; } } $station_metrics = array(); foreach ($stations as $station) { $station_id = $station['id']; if (isset($station_averages[$station_id])) { $series_obj = new \stdClass(); $series_obj->name = $station['name']; $series_obj->type = 'spline'; ksort($station_averages[$station_id]); $series_obj->data = array_values($station_averages[$station_id]); $station_metrics[] = $series_obj; } } // Podcast and API Call Metrics $analytics_raw = $influx->setDatabase('pvlive_analytics')->query('SELECT * FROM /1h.*/', 'm'); $raw_metrics = array(); foreach ($analytics_raw as $series_name => $series_stats) { $series_parts = explode('.', $series_name); if ($series_parts[1] == 'api_calls') { $metric_section = 'api'; } else { $metric_section = 'podcast'; } foreach ($series_stats as $stat_row) { if (!isset($raw_metrics[$metric_section][$stat_row['time']])) { $raw_metrics[$metric_section][$stat_row['time']] = 0; } $raw_metrics[$metric_section][$stat_row['time']] += $stat_row['count']; } } // Reformat for highcharts. $refined_metrics = array(); foreach ($raw_metrics as $metric_type => $metric_rows) { ksort($metric_rows); foreach ($metric_rows as $row_timestamp => $row_value) { $refined_metrics[$metric_type][] = array($row_timestamp, $row_value); } } // API call object $series_obj = new \stdClass(); $series_obj->name = 'API Calls'; $series_obj->type = 'spline'; $series_obj->data = $refined_metrics['api']; $api_metrics = array($series_obj); // Podcast object $series_obj = new \stdClass(); $series_obj->name = 'Podcast Clicks'; $series_obj->type = 'spline'; $series_obj->data = $refined_metrics['podcast']; $podcast_metrics = array($series_obj); $metrics = array('network' => json_encode($network_metrics), 'station' => json_encode($station_metrics), 'api' => json_encode($api_metrics), 'podcast' => json_encode($podcast_metrics)); \DF\Cache::save($metrics, 'admin_metrics', array(), 600); } $this->view->metrics = $metrics; // Synchronization statuses if ($this->acl->isAllowed('administer all')) { $this->view->sync_times = \PVL\SyncManager::getSyncTimes(); } // PVLNode service stats. $this->view->pvlnode_stats = \PVL\Service\PvlNode::fetch(); }
public function contactAction() { $all_categories = Station::getStationsInCategories(); $audio_stations = \DF\Utilities::columns($all_categories['audio']['stations'], 2); $video_stations = $all_categories['video']['stations']; $this->view->station_columns = array(array('<i class="icon ' . $all_categories['audio']['icon'] . '"></i> ' . $all_categories['audio']['name'], $audio_stations[0]), array(' ', $audio_stations[1]), array('<i class="icon ' . $all_categories['video']['icon'] . '"></i> ' . $all_categories['video']['name'], $video_stations)); $active_podcasts = array_filter(Podcast::fetchArray('name'), function ($row) { return $row['is_approved']; }); $this->view->podcasts = \DF\Utilities::columns($active_podcasts, 3); $this->view->podcast_social_types = Podcast::getSocialTypes(); }
public function feedAction() { $this->doNotRender(); if ($this->hasParam('id')) { $id = (int) $this->getParam('id'); $record = Podcast::find($id); if (!$record instanceof Podcast) { throw new \DF\Exception\DisplayOnly('Show record not found!'); } $feed_title = $record->name; $feed_desc = $record->description ? $record->description : 'A Ponyville Live! Show.'; $cache_name = 'podcasts_' . $id . '_feed'; $q = $this->em->createQuery('SELECT pe, p FROM Entity\\PodcastEpisode pe JOIN pe.podcast p WHERE p.is_approved = 1 AND p.id = :id ORDER BY pe.timestamp DESC')->setParameter('id', $id); } else { $feed_title = 'Ponyville Live! Shows'; $feed_desc = 'The partner shows of the Ponyville Live! network, including commentary, interviews, episode reviews, convention coverage, and more.'; $cache_name = 'podcasts_all_feed'; $q = $this->em->createQuery('SELECT pe, p FROM Entity\\PodcastEpisode pe JOIN pe.podcast p WHERE p.is_approved = 1 AND pe.timestamp >= :threshold ORDER BY pe.timestamp DESC')->setParameter('threshold', strtotime('-3 months')); } $rss = \DF\Cache::get($cache_name); if (!$rss) { $records = $q->getArrayResult(); // Initial RSS feed setup. $feed = new \Zend\Feed\Writer\Feed(); $feed->setTitle($feed_title); $feed->setLink('http://ponyvillelive.com/'); $feed->setDescription($feed_desc); $feed->addAuthor(array('name' => 'Ponyville Live!', 'email' => '*****@*****.**', 'uri' => 'http://ponyvillelive.com')); $feed->setDateModified(time()); foreach ((array) $records as $episode) { try { $podcast = $episode['podcast']; $title = $episode['title']; // Check for podcast name preceding episode name. if (substr($title, 0, strlen($podcast['name'])) == $podcast['name']) { $title = substr($title, strlen($podcast['name'])); } $title = trim($title, " :-\t\n\r\v"); $title = $podcast['name'] . ' - ' . $title; // Create record. $entry = $feed->createEntry(); $entry->setTitle($title); $entry->setLink($episode['web_url']); $entry->addAuthor(array('name' => $podcast['name'], 'uri' => $podcast['web_url'])); $entry->setDateModified($episode['timestamp']); $entry->setDateCreated($episode['timestamp']); if ($podcast['description']) { $entry->setDescription($podcast['description']); } if ($episode['body']) { $entry->setContent($episode['body']); } $feed->addEntry($entry); } catch (\Exception $e) { } } // Export feed. $rss = $feed->export('rss'); \DF\Cache::set($rss, $cache_name, array(), 60 * 15); } header("Content-Type: application/rss+xml"); echo $rss; }
/** * Send notifications for new podcast episodes. * * @param \Phalcon\DiInterface $di * @throws \DF\Exception */ public static function _runPodcastEpisodes(\Phalcon\DiInterface $di, $force = false) { $em = $di->get('em'); $start_threshold = time() - 86400 * 7; $end_threshold = time(); $podcast_episodes = $em->createQuery('SELECT pe, p FROM Entity\\PodcastEpisode pe JOIN pe.podcast p WHERE pe.timestamp BETWEEN :start AND :end AND pe.is_notified = 0 AND pe.is_active = 1 AND p.is_approved = 1 ORDER BY pe.timestamp DESC')->setParameter('start', $start_threshold)->setParameter('end', $end_threshold)->setMaxResults(1)->execute(); if ($podcast_episodes) { $episode = $podcast_episodes[0]; $podcast = $episode->podcast; $podcast_name = $podcast->name; if ($podcast->is_adult) { $podcast_name = '[18+] ' . $podcast_name; } $title = \DF\Utilities::truncateText($episode->title, 110 - strlen($podcast_name) - 6); $tweet = $podcast_name . ': "' . $title . '"'; PvlNode::push('podcast.new_episode', array('episode' => PodcastEpisode::api($episode), 'podcast' => Podcast::api($podcast, false))); $image_url = NULL; if ($podcast->banner_url) { $image_url = \PVL\Service\AmazonS3::path($podcast->banner_url); } // Special handling of podcast YT videos. if (stristr($episode->web_url, 'youtube.com') !== false) { $image_url = NULL; } self::notify($tweet, $episode->getLocalUrl('twitter'), $image_url); // Set all episodes of the same podcast to be notified, to prevent spam. $em->createQuery('UPDATE Entity\\PodcastEpisode pe SET pe.is_notified=1 WHERE pe.podcast_id = :podcast_id')->setParameter('podcast_id', $podcast->id)->execute(); } }
public static function getSocialTypes() { return Podcast::getSocialTypes(); }
/** * Submit a new show/podcast. * * @throws \DF\Exception */ public function showAction() { $this->em->getFilters()->disable('softdelete'); $user = $this->auth->getLoggedInUser(); // Check for existing submissions. $existing_submissions = $this->em->createQuery('SELECT p, u FROM Entity\\Podcast p JOIN p.managers u WHERE (p.deleted_at IS NULL OR p.deleted_at IS NOT NULL) AND u.id = :user_id')->setParameter('user_id', $user->id)->getArrayResult(); if ($existing_submissions) { $message = '<b>You have already submitted the following shows to the system:</b>'; $message .= '<ul>'; foreach ($existing_submissions as $podcast) { if ($podcast['deleted_at']) { $status = 'Declined'; } elseif ($podcast['is_approved']) { $status = 'Approved'; } else { $status = 'Pending Review'; } $message .= '<li><b>' . $podcast['name'] . ':</b> ' . $status . '</li>'; } $message .= '</ul>'; $message .= 'Please contact the PVL team for questions related to these shows, and do not resubmit them!'; $this->flash($message, 'info'); } // Initialize the form. $form = new \DF\Form($this->current_module_config->forms->submit_show); if ($_POST && $form->isValid($_POST)) { $data = $form->getValues(); $files = $form->processFiles('podcasts'); foreach ($files as $file_field => $file_paths) { $data[$file_field] = $file_paths[1]; } // Check for existing podcast by name. $existing_podcast = Podcast::getRepository()->findOneBy(array('name' => $data['name'])); if ($existing_podcast instanceof Podcast) { throw new \DF\Exception('A podcast with this name already exists! Please do not submit duplicate stations.'); } // Set up initial station record. $record = new Podcast(); $record->fromArray($data); $record->is_approved = false; $record->contact_email = $user->email; $record->save(); // Make the current user an administrator of the new podcast. if (!$this->acl->isAllowed('administer all')) { $user->podcasts->add($record); $user->save(); } // Notify all existing managers. $network_administrators = Action::getUsersWithAction('administer all'); $email_to = Utilities::ipull($network_administrators, 'email'); if ($email_to) { \DF\Messenger::send(array('to' => $email_to, 'subject' => 'New Podcast/Show Submitted For Review', 'template' => 'newshow', 'vars' => array('form' => $form->populate($_POST)))); } $this->alert('Your show has been submitted. Thank you! We will contact you with any questions or additional information.', 'green'); $this->redirectHome(); return; } $this->renderForm($form, 'edit', 'Submit Your Show'); }