Пример #1
0
 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;
 }
Пример #2
0
 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));
 }
Пример #3
0
 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());
     }
 }
Пример #4
0
 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();
     }
 }
Пример #5
0
 /**
  * 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();
 }
Пример #6
0
 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('&nbsp;', $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();
 }
Пример #7
0
 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;
 }
Пример #8
0
 /**
  * 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();
     }
 }
Пример #9
0
 public static function getSocialTypes()
 {
     return Podcast::getSocialTypes();
 }
Пример #10
0
 /**
  * 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');
 }