Example #1
1
 /**
  * Generate Structured NowPlaying Data
  *
  * @param Station $station
  * @return array Structured NowPlaying Data
  */
 public static function processStation(Station $station)
 {
     $em = self::getEntityManager();
     $np_old = (array) $station->nowplaying_data;
     $np = array();
     $np['status'] = 'offline';
     $np['station'] = Station::api($station);
     // Remove API-supplied 'streams' item in the wrong place.
     unset($np['station']['streams']);
     $listener_totals = array('current' => 0, 'unique' => 0, 'total' => 0);
     $np['streams'] = array();
     foreach ($station->streams as $stream) {
         if (!$stream->is_active) {
             continue;
         }
         if ($station->category == 'video') {
             $np_stream = self::processVideoStream($stream, $station);
             foreach ($listener_totals as $type => $total) {
                 $listener_totals[$type] += $np_stream['meta']['listeners'];
             }
         } else {
             $np_stream = self::processAudioStream($stream, $station);
             foreach ($np_stream['listeners'] as $type => $count) {
                 $listener_totals[$type] += $count;
             }
         }
         $np['streams'][] = $np_stream;
         $em->persist($stream);
         // Merge default info into main array for legacy purposes.
         if ($np_stream['is_default'] == true) {
             $np['status'] = $np_stream['status'];
             $np['station']['stream_url'] = $np_stream['url'];
             $np['station']['default_stream_id'] = $np_stream['id'];
             if ($station->category != 'video') {
                 $np['current_song'] = $np_stream['current_song'];
                 $np['song_history'] = $np_stream['song_history'];
             }
         }
     }
     $np['listeners'] = $listener_totals;
     // Get currently active event (cached query)
     $event_current = Schedule::getCurrentEvent($station->id);
     $event_upcoming = Schedule::getUpcomingEvent($station->id);
     $np['event'] = Schedule::api($event_current);
     $np['event_upcoming'] = Schedule::api($event_upcoming);
     if ($station->category != 'video') {
         $station->nowplaying_data = array('current_song' => $np['current_song'], 'song_history' => $np['song_history']);
         $em->persist($station);
     }
     $em->flush();
     return $np;
 }
Example #2
0
 /**
  * Send notifications for new station events.
  *
  * @param \Phalcon\DiInterface $di
  * @param bool $force
  * @throws \DF\Exception
  */
 public static function _runStationEvents(\Phalcon\DiInterface $di, $force = false)
 {
     $notify_minutes = 15;
     $em = $di->get('em');
     $start_threshold = time();
     $end_threshold = time() + 60 * $notify_minutes;
     $schedule_items = $em->createQuery('SELECT s, st FROM Entity\\Schedule s JOIN s.station st WHERE s.start_time >= :start AND s.start_time <= :end AND s.is_notified = 0')->setParameter('start', $start_threshold)->setParameter('end', $end_threshold)->setMaxResults(1)->execute();
     if ($schedule_items) {
         $schedule_item = $schedule_items[0];
         $station = $schedule_item->station;
         if ($station->twitter_url) {
             $twitter_handle = '@' . array_pop(explode('/', $station->twitter_url));
         } else {
             $twitter_handle = $station->name;
         }
         $tweet = 'Tune in to ' . $schedule_item->title . ' in ' . $notify_minutes . ' minutes on ' . $twitter_handle . '!';
         $tweet_url = $station->getShortUrl();
         PvlNode::push('schedule.event_upcoming', array('event' => Schedule::api($schedule_item), 'station' => Station::api($station)));
         $image_url = NULL;
         if ($schedule_item->banner_url) {
             $image_url = $schedule_item->banner_url;
         } else {
             if ($station->banner_url) {
                 $image_url = \PVL\Service\AmazonS3::path($station->banner_url);
             }
         }
         self::notify($tweet, $tweet_url, $image_url, $force);
         $schedule_item->is_notified = true;
         $schedule_item->save();
     }
 }
Example #3
0
 public function promoteAction()
 {
     $event_guid = $this->getParam('event');
     $event = Schedule::getRepository()->findOneBy(array('guid' => $event_guid, 'station_id' => $this->station->id));
     if (!$event instanceof Schedule) {
         throw new \DF\Exception\DisplayOnly('Event not found!');
     }
     $banner_url = $this->station->banner_url;
     if (empty($banner_url)) {
         throw new \DF\Exception\DisplayOnly('You have not supplied a banner for your station yet! Please visit the "Edit Profile" page to supply a banner image.');
     }
     $event->is_promoted = !$event->is_promoted;
     $event->save();
     $this->alert('<b>Event promotion toggled!</b>', 'green');
     return $this->redirectFromHere(array('action' => 'index', 'event' => NULL));
 }
Example #4
0
 protected function _initEvents()
 {
     $event_info = Cache::get('pvlive_events');
     if (!$event_info) {
         $events_raw = $this->em->createQuery('SELECT s, st FROM Entity\\Schedule s JOIN s.station st WHERE (s.end_time >= :current AND s.start_time <= :future) ORDER BY s.start_time ASC')->setParameter('current', time())->setParameter('future', strtotime('+4 days'))->getArrayResult();
         $all_events = array();
         $events_by_day = array();
         for ($i = 0; $i < 6; $i++) {
             $day_timestamp = mktime(0, 0, 1, date('n'), (int) date('j') + $i);
             $day_date = date('Y-m-d', $day_timestamp);
             $is_today = $day_date == date('Y-m-d');
             $events_by_day[$day_date] = array('day_name' => $is_today ? 'Today' : date('l', $day_timestamp), 'timestamp' => $day_timestamp, 'is_today' => $is_today, 'events' => array());
         }
         foreach ($events_raw as $event) {
             $event['image_url'] = \PVL\Url::upload(Schedule::getRowImageUrl($event));
             $event['status'] = $event['start_time'] <= time() ? 'now' : 'upcoming';
             $event['range'] = Schedule::getRangeText($event['start_time'], $event['end_time'], $event['is_all_day']);
             if ($event['station_id']) {
                 $sid = $event['station_id'];
                 if (isset($this->stations[$sid])) {
                     $station = $this->stations[$sid];
                     unset($station['nowplaying_data'], $station['streams'], $station['intake_votes']);
                     $event['station'] = $station;
                 }
             }
             $all_events[] = $event;
             for ($i = $event['start_time']; $i <= $event['end_time']; $i += 86400) {
                 $event_date = date('Y-m-d', $i);
                 if (isset($events_by_day[$event_date])) {
                     $events_by_day[$event_date]['events'][] = $event;
                 }
             }
         }
         $event_info = array('all' => $all_events, 'by_day' => $events_by_day);
         Cache::save($event_info, 'pvlive_events', array(), 60);
     }
     $this->view->all_events = $event_info['all'];
     $this->view->events_by_day = $event_info['by_day'];
 }
Example #5
0
 public function indexAction()
 {
     // Get calendar name.
     $short_names = Station::getShortNameLookup();
     $station_shortcode = $this->getParam('station', 'all');
     if ($station_shortcode != "all") {
         $station = $short_names[$station_shortcode];
         $calendar_name = $station['name'];
     } else {
         $calendar_name = 'Ponyville Live!';
     }
     // Get timestamp boundaries.
     if ($this->hasParam('month')) {
         $show = $this->getParam('month');
         $calendar = new \DF\Calendar($show);
         $timestamps = $calendar->getTimestamps();
         $start_timestamp = $timestamps['start'];
         $end_timestamp = $timestamps['end'];
         $use_cache = true;
         $cache_name = 'month_' . $show;
         $calendar_name .= ' - ' . date('F Y', $timestamps['mid']);
     } elseif ($this->hasParam('start')) {
         $start_timestamp = (int) $this->getParam('start');
         $end_timestamp = (int) $this->getParam('end');
         $use_cache = false;
         $cache_name = null;
         // $cache_name = 'range_'.$start_timestamp.'_'.$end_timestamp;
         $calendar_name .= ' - ' . date('F j, Y', $start_timestamp) . ' to ' . date('F j, Y', $end_timestamp);
     } else {
         $start_timestamp = time();
         $end_timestamp = time() + 86400 * 30;
         $use_cache = true;
         $cache_name = 'upcoming';
         $calendar_name .= ' - Upcoming';
     }
     // Load from cache or regenerate.
     if ($use_cache) {
         $cache_name = 'api_sched_' . $station_shortcode . '_' . $cache_name;
         $events = \DF\Cache::get($cache_name);
     } else {
         $events = null;
     }
     if (!$events) {
         if ($station_shortcode != "all") {
             $station = $short_names[$station_shortcode];
             $events_raw = $this->em->createQuery('SELECT s FROM Entity\\Schedule s WHERE (s.station_id = :sid) AND (s.start_time <= :end AND s.end_time >= :start) ORDER BY s.start_time ASC')->setParameter('sid', $station['id'])->setParameter('start', $start_timestamp)->setParameter('end', $end_timestamp)->getArrayResult();
         } else {
             $events_raw = $this->em->createQuery('SELECT s, st FROM Entity\\Schedule s LEFT JOIN s.station st WHERE (s.start_time <= :end AND s.end_time >= :start) ORDER BY s.start_time ASC')->setParameter('start', $start_timestamp)->setParameter('end', $end_timestamp)->getArrayResult();
         }
         $events = array();
         foreach ((array) $events_raw as $event) {
             $events[] = Schedule::api($event);
         }
         if ($use_cache) {
             \DF\Cache::save($events, $cache_name, array(), 300);
         }
     }
     $format = strtolower($this->getParam('format', 'json'));
     switch ($format) {
         case "ics":
         case "ical":
             return $this->_printCalendar($events, $calendar_name, $cache_name);
             break;
         case "json":
         default:
             return $this->returnSuccess($events);
             break;
     }
 }
Example #6
0
 public function timelineAction()
 {
     $stream_id = $this->getParam('stream');
     if (!$stream_id) {
         $default_stream = $this->station->getDefaultStream();
         $stream_id = $default_stream->id;
     }
     $this->view->stream_id = $stream_id;
     $songs_played_raw = $this->_getEligibleHistory($stream_id);
     // Get current events within threshold.
     $threshold = $songs_played_raw[0]['timestamp'];
     $events = \Entity\Schedule::getEventsInRange($this->station->id, $threshold, time());
     $songs = array();
     foreach ($songs_played_raw as $i => $song_row) {
         if (!isset($songs_played_raw[$i + 1])) {
             break;
         }
         $start_timestamp = $song_row['timestamp'];
         $song_row['stat_start'] = $song_row['listeners'];
         if ($i + 1 == count($songs_played_raw)) {
             $end_timestamp = $start_timestamp;
             $song_row['stat_end'] = $song_row['stat_start'];
         } else {
             $end_timestamp = $songs_played_raw[$i + 1]['timestamp'];
             $song_row['stat_end'] = $songs_played_raw[$i + 1]['listeners'];
         }
         $song_row['stat_delta'] = $song_row['stat_end'] - $song_row['stat_start'];
         foreach ($events as $event) {
             if ($event['end_time'] >= $start_timestamp && $event['start_time'] <= $end_timestamp) {
                 $song_row['event'] = $event;
                 break;
             }
         }
         $songs[] = $song_row;
     }
     $format = $this->getParam('format', 'html');
     if ($format == 'csv') {
         $this->doNotRender();
         $export_all = array();
         $export_all[] = array('Date', 'Time', 'Listeners', 'Delta', 'Likes', 'Dislikes', 'Track', 'Artist', 'Event');
         foreach ($songs as $song_row) {
             $export_row = array(date('Y-m-d', $song_row['timestamp']), date('g:ia', $song_row['timestamp']), $song_row['stat_start'], $song_row['stat_delta'], $song_row['score_likes'], $song_row['score_dislikes'], $song_row['song']['title'] ? $song_row['song']['title'] : $song_row['song']['text'], $song_row['song']['artist'], $song_row['event'] ? $song_row['event']['title'] : '');
             $export_all[] = $export_row;
         }
         \DF\Export::csv($export_all, true, $this->station->getShortName() . '_timeline_' . date('Ymd'));
         return;
     } else {
         $songs = array_reverse($songs);
         $pager = new \DF\Paginator($songs, $this->getParam('page', 1), 50);
         $this->view->pager = $pager;
     }
 }
Example #7
0
 public static function _runScheduleItems(\Phalcon\DiInterface $di)
 {
     $news_items = array();
     $em = $di->get('em');
     // Pull promoted schedule items.
     $events_raw = $em->createQuery('SELECT st, s FROM \\Entity\\Schedule s
         JOIN s.station st
         WHERE (s.end_time >= :current AND s.start_time <= :future)
         AND (st.banner_url != \'\' AND st.banner_url IS NOT NULL)
         AND s.is_promoted = 1
         ORDER BY s.start_time ASC')->setParameter('current', time())->setParameter('future', strtotime('+1 week'))->getArrayResult();
     $promoted_stations = array();
     foreach ($events_raw as $event) {
         $station_id = $event['station_id'];
         if (isset($promoted_stations[$station_id])) {
             continue;
         } else {
             $promoted_stations[$station_id] = true;
         }
         $range = Schedule::getRangeText($event['start_time'], $event['end_time'], $event['is_all_day']);
         $description = array();
         $description[] = 'Coming up on ' . $event['station']['name'];
         $description[] = $range;
         if (!empty($event['body'])) {
             $description[] = $event['body'];
         }
         // Manually adjust the sorting timestamp for the event if it is in the future.
         $sort_timestamp = $event['start_time'];
         if ($sort_timestamp >= time()) {
             $sort_timestamp = time() - ($sort_timestamp - time());
         }
         $news_items[] = array('id' => 'schedule_' . $event['guid'], 'title' => trim($event['title']), 'source' => 'station', 'body' => implode('<br>', $description), 'image_url' => \PVL\Url::upload($event['station']['banner_url']), 'web_url' => $event['station']['web_url'], 'layout' => 'vertical', 'tags' => array($event['station']['name'], 'Events'), 'sort_timestamp' => $sort_timestamp, 'display_timestamp' => $event['start_time']);
         break;
     }
     return $news_items;
 }
Example #8
0
 public static function run($force_run = false)
 {
     $di = \Phalcon\Di::getDefault();
     $em = $di->get('em');
     $config = $di->get('config');
     // Set up Google Client.
     $gclient_api_key = $config->apis->google_apis_key;
     $gclient_app_name = $config->application->name;
     if (empty($gclient_api_key)) {
         return null;
     }
     $gclient = new \Google_Client();
     $gclient->setApplicationName($gclient_app_name);
     $gclient->setDeveloperKey($gclient_api_key);
     $gcal = new \Google_Service_Calendar($gclient);
     // Prevent running repeatedly in too short of a time (avoid API limits).
     $last_run = Settings::getSetting('schedule_manager_last_run', 0);
     if ($last_run > time() - 60 && !$force_run) {
         return null;
     }
     $schedule_items = array();
     $schedule_records = array();
     $stations = $em->createQuery('SELECT s FROM Entity\\Station s WHERE (s.gcal_url IS NOT NULL AND s.gcal_url != \'\') AND s.is_active = 1')->getArrayResult();
     $active_stations = Utilities::ipull($stations, 'id');
     // Clear all invalid station records.
     $em->createQuery('DELETE FROM Entity\\Schedule s WHERE (s.station_id IS NOT NULL) AND (s.station_id NOT IN (:station_ids))')->setParameter('station_ids', $active_stations)->execute();
     foreach ($stations as $station) {
         if ($station['gcal_url']) {
             $schedule_items[] = array('name' => $station['name'], 'url' => $station['gcal_url'], 'type' => 'station', 'station_id' => $station['id'], 'image_url' => \DF\Url::content($station['image_url']));
         }
     }
     Debug::startTimer('Get Calendar Records');
     // Time boundaries for calendar entries.
     $threshold_start = date(\DateTime::RFC3339, strtotime('-1 week'));
     $threshold_end = date(\DateTime::RFC3339, strtotime('+1 year'));
     foreach ($schedule_items as $item) {
         // Get the "calendar_id" from the URL provided by the user.
         $orig_url_parts = parse_url($item['url']);
         $url_path_parts = explode('/', $orig_url_parts['path']);
         $calendar_id = urldecode($url_path_parts[3]);
         if (empty($calendar_id)) {
             continue;
         }
         // Call the external Google Calendar client.
         try {
             $all_events = $gcal->events->listEvents($calendar_id, array('timeMin' => $threshold_start, 'timeMax' => $threshold_end, 'singleEvents' => 'true', 'orderBy' => 'startTime', 'maxResults' => '300'));
         } catch (\Exception $e) {
             continue;
         }
         // Process each individual event.
         foreach ($all_events as $event_orig) {
             $title = $event_orig->summary;
             $body = $event_orig->description;
             $location = $event_orig->location;
             $web_url = $event_orig->htmlLink;
             $banner_url = null;
             $is_all_day = false;
             $start_time_obj = $event_orig->start;
             if ($start_time_obj->date) {
                 $is_all_day = true;
                 $start_time = strtotime($start_time_obj->date . ' 00:00:00');
             } else {
                 $start_time = strtotime($start_time_obj->dateTime);
             }
             $end_time_obj = $event_orig->end;
             if ($end_time_obj->date) {
                 $is_all_day = true;
                 $end_time = strtotime($end_time_obj->date . ' 00:00:00');
             } elseif ($end_time_obj) {
                 $end_time = strtotime($end_time_obj->dateTime);
             } else {
                 $end_time = $start_time;
             }
             // Detect URLs for link.
             if ($body && !$web_url) {
                 preg_match('@((https?://)?([-\\w]+\\.[-\\w\\.]+)+\\w(:\\d+)?(/([-\\w/_\\.]*(\\?\\S+)?)?)*)@', $body, $urls);
                 if (count($urls) > 0) {
                     $web_url = $urls[0];
                 }
             }
             // Detect URLs for photo.
             if ($location) {
                 preg_match('@((https?://)?([-\\w]+\\.[-\\w\\.]+)+\\w(:\\d+)?(/([-\\w/_\\.]*(\\?\\S+)?)?)*)@', $location, $urls);
                 if (count($urls) > 0) {
                     $banner_url = $urls[0];
                 }
             }
             $guid = md5(implode('|', array($event_orig->id, $start_time, $end_time, $title, $location)));
             $schedule_record = array('guid' => $guid, 'type' => $item['type'], 'start_time' => $start_time, 'end_time' => $end_time, 'is_all_day' => $is_all_day, 'title' => $title, 'location' => $location, 'body' => \DF\Utilities::truncateText(strip_tags($body), 300), 'banner_url' => $banner_url, 'web_url' => $web_url);
             \PVL\Debug::print_r($schedule_record);
             $schedule_records[$item['station_id']][$guid] = $schedule_record;
         }
     }
     Debug::endTimer('Get Calendar Records');
     if (count($schedule_records) == 0) {
         Debug::log('Error: No calendar records loaded');
         return;
     }
     // Add/Remove all differential records.
     Debug::startTimer('Sync DB Records');
     foreach ($schedule_records as $station_id => $station_records) {
         $station = Station::find($station_id);
         if ($station_id == 0) {
             $existing_guids_raw = $em->createQuery('SELECT s.guid FROM Entity\\Schedule s WHERE s.station_id IS NULL')->getArrayResult();
         } else {
             $existing_guids_raw = $em->createQuery('SELECT s.guid FROM Entity\\Schedule s WHERE s.station_id = :sid')->setParameter('sid', $station_id)->getArrayResult();
         }
         $existing_guids = array();
         foreach ($existing_guids_raw as $i) {
             $existing_guids[] = $i['guid'];
         }
         $new_guids = array_keys($station_records);
         $guids_to_delete = array_diff($existing_guids, $new_guids);
         if ($guids_to_delete) {
             $em->createQuery('DELETE FROM Entity\\Schedule s WHERE s.guid IN (:guids)')->setParameter('guids', $guids_to_delete)->execute();
         }
         $guids_to_add = array_diff($new_guids, $existing_guids);
         if ($guids_to_add) {
             foreach ($guids_to_add as $guid) {
                 $schedule_record = $station_records[$guid];
                 $record = new Schedule();
                 $record->station = $station;
                 $record->fromArray($schedule_record);
                 $em->persist($record);
             }
         }
         $em->flush();
         $em->clear();
     }
     Debug::endTimer('Sync DB Records');
     Settings::setSetting('schedule_manager_last_run', time());
 }