コード例 #1
0
ファイル: SongsController.php プロジェクト: Lavoaster/PVLive
 public function newAction()
 {
     $new_threshold = strtotime('-2 weeks');
     $song_adapters = Song::getExternalAdapters();
     $new_songs_raw = $this->em->createQuery('SELECT s, ex_eqbeats, ex_btunes, ex_pfm
         FROM Entity\\Song s
         LEFT JOIN s.external_eqbeats AS ex_eqbeats
         LEFT JOIN s.external_bronytunes AS ex_btunes
         LEFT JOIN s.external_ponyfm AS ex_pfm
         WHERE (ex_eqbeats.created >= :threshold OR ex_btunes.created >= :threshold OR ex_pfm.created >= :threshold)')->setParameter('threshold', $new_threshold)->getArrayResult();
     $new_songs = array();
     foreach ($new_songs_raw as $song) {
         $timestamps = array();
         foreach ($song_adapters as $adapter_key => $adapter_class) {
             $local_key = 'external_' . $adapter_key;
             if (!empty($song[$local_key])) {
                 $timestamps[] = $song[$local_key]['created'];
             }
         }
         $song['created'] = max($timestamps);
         $song['filename'] = $song['artist'] . ' - ' . $song['title'];
         $new_songs[] = $song;
     }
     $new_songs = Utilities::irsort($new_songs, 'created');
     $this->view->new_songs = $new_songs;
 }
コード例 #2
0
ファイル: IndexController.php プロジェクト: Lavoaster/PVLive
 public function indexAction()
 {
     $this->forceInsecure();
     // Pull podcasts.
     $podcasts = Podcast::fetchLatest();
     $this->view->podcasts = $podcasts;
     // Pull large photos and news for rotator.
     $network_news = NetworkNews::fetchFeatured();
     $this->view->network_news = $network_news;
     // Pull stations and calendar events.
     $this->_initStations();
     $this->_initEvents();
     // Pull conventions.
     $conventions = Convention::getAllConventions();
     $this->view->conventions_upcoming = $conventions['upcoming'];
     $this->view->conventions_archived = $conventions['archived'];
     /*
     // Pull rotators.
     $rotators = Rotator::fetch();
     $this->view->rotators = $rotators;
     */
     // Special event flagging and special formatting.
     $special_event = \PVL\Utilities::showSpecialEventsMode();
     $this->view->special_event = $special_event;
     if ($special_event) {
         $autoplay_station = Settings::getSetting('special_event_station_id', 0);
         if ($autoplay_station != 0) {
             $this->view->station_id = $autoplay_station;
             $this->view->autoplay = true;
         }
         $this->view->special_event_embed = trim(Settings::getSetting('special_event_embed_code'));
         $this->view->special_chat_embed = trim(Settings::getSetting('special_event_chat_code'));
     }
     $this->view->autoplay = (bool) $this->getParam('autoplay', true);
 }
コード例 #3
0
ファイル: LiveStream.php プロジェクト: Lavoaster/PVLive
 public static function getAccount($url)
 {
     $url_parts = \PVL\Utilities::parseUrl($url);
     $url_components = explode('/', $url_parts['path']);
     $url_last_element = array_pop($url_components);
     $account = trim($url_last_element);
     return $account;
 }
コード例 #4
0
ファイル: AnalyticsManager.php プロジェクト: Lavoaster/PVLive
 public static function addTracking($url, $utm_data = array())
 {
     $utm_defaults = array('source' => 'pvlive', 'medium' => 'direct', 'campaign' => 'pvlive', 'term' => NULL, 'content' => NULL);
     $utm_data = array_merge($utm_defaults, $utm_data);
     $url_parts = Utilities::parseUrl($url);
     $url_params = (array) $url_parts['query_arr'];
     foreach ($utm_data as $utm_key => $utm_val) {
         if (!empty($utm_val)) {
             $url_params['utm_' . $utm_key] = $utm_val;
         }
     }
     $url_parts['query'] = http_build_query($url_params);
     return Utilities::buildUrl($url_parts);
 }
コード例 #5
0
ファイル: YouTube.php プロジェクト: Lavoaster/PVLive
 public static function getAccount($url)
 {
     if (stristr($url, 'youtube.com') !== FALSE) {
         $url_parts = \PVL\Utilities::parseUrl($url);
         if ($url_parts['path_clean'] == 'playlist') {
             return array('type' => 'playlist', 'id' => $url_parts['query_arr']['list']);
         } else {
             $url_components = explode('/', $url_parts['path']);
             $url_last_element = array_pop($url_components);
             $account = trim($url_last_element);
             return array('type' => 'user', 'id' => $account);
         }
     } else {
         return array('type' => 'user', 'id' => trim($url));
     }
 }
コード例 #6
0
 /**
  * Static Functions
  */
 public static function processRemote($result)
 {
     return array('id' => $result['id'], 'created' => Utilities::gstrtotime($result['published_at']['date']), 'updated' => time(), 'artist' => $result['user']['name'], 'title' => $result['title'], 'description' => $result['description'], 'lyrics' => $result['lyrics'], 'web_url' => $result['url'], 'image_url' => $result['covers']['normal'], 'download_url' => str_replace('stream.mp3', 'dl.mp3', $result['streams']['mp3']), 'is_vocal' => (int) $result['is_vocal'], 'is_explicit' => (int) $result['is_explicit'], 'duration' => (double) $result['duration']);
 }
コード例 #7
0
ファイル: Curl.php プロジェクト: Lavoaster/PVLive
 /**
  * Submit a URL request with a specified cache lifetime.
  *
  * @param null $c_opts
  * @param int $cache_time
  * @return string
  */
 public static function request($c_opts = null)
 {
     // Compose cURL configuration array.
     if (is_null($c_opts)) {
         $c_opts = array();
     } elseif (!is_array($c_opts)) {
         $c_opts = array('url' => $c_opts);
     }
     $c_defaults = array('method' => 'GET', 'useragent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2', 'timeout' => 10);
     $c_opts = array_merge($c_defaults, $c_opts);
     Debug::log('cURL Outgoing Request: ' . $c_opts['url']);
     Debug::startTimer('Make cURL Request');
     $postfields = false;
     if (!empty($c_opts['params'])) {
         if (strtoupper($c_opts['method']) == 'POST') {
             $postfields = $c_opts['params'];
         } else {
             $c_opts['url'] = $c_opts['url'] . '?' . http_build_query($c_opts['params']);
         }
     }
     // Start cURL request.
     $curl = curl_init($c_opts['url']);
     // Handle POST support.
     if (strtoupper($c_opts['method']) == 'POST') {
         curl_setopt($curl, CURLOPT_POST, true);
     }
     if (!empty($c_opts['referer'])) {
         curl_setopt($curl, CURLOPT_REFERER, $c_opts['referer']);
     }
     if ($postfields) {
         curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);
     }
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
     curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $c_opts['timeout']);
     curl_setopt($curl, CURLOPT_TIMEOUT, $c_opts['timeout']);
     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
     curl_setopt($curl, CURLOPT_USERAGENT, $c_opts['useragent']);
     curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
     curl_setopt($curl, CURLOPT_MAXREDIRS, 3);
     // Custom DNS management.
     curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
     curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT, 600);
     // Set custom HTTP headers.
     if (!empty($c_opts['headers'])) {
         curl_setopt($curl, CURLOPT_HTTPHEADER, $c_opts['headers']);
     }
     $return_raw = Utilities::curl_exec_utf8($curl);
     // End cURL request.
     Debug::endTimer('Make cURL Request');
     // Log more detailed information to screen about resolution times.
     $conn_info = curl_getinfo($curl);
     $important_conn_info = array('url', 'http_code', 'total_time', 'namelookup_time', 'connect_time', 'pretransfer_time', 'starttransfer_time', 'redirect_time');
     $debug_conn_info = array();
     foreach ($important_conn_info as $conn_param) {
         $debug_conn_info[$conn_param] = $conn_info[$conn_param];
     }
     Debug::print_r($debug_conn_info);
     $error = curl_error($curl);
     if ($error) {
         Debug::log("Curl error: " . $error);
     }
     return trim($return_raw);
 }
コード例 #8
0
 /**
  * Process an individual convention archive row.
  * @param ConventionArchive $row
  */
 public static function process(ConventionArchive $row)
 {
     $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);
     $yt_client = new YouTube($gclient);
     $url = $row->web_url;
     if (empty($row->playlist_id)) {
         switch ($row->type) {
             case "yt_playlist":
                 $url_parts = \PVL\Utilities::parseUrl($url);
                 $playlist_id = $url_parts['query_arr']['list'];
                 if (!$playlist_id) {
                     break;
                 }
                 // Clear existing related items.
                 $em->createQuery('DELETE FROM Entity\\ConventionArchive ca WHERE ca.playlist_id = :id')->setParameter('id', $row->id)->execute();
                 $data = $yt_client->playlists->listPlaylists('id,snippet', array('id' => $playlist_id, 'maxResults' => 1));
                 if ($data) {
                     $playlist = $data['items'][0]['snippet'];
                     $row->name = $playlist['title'];
                     $row->description = $playlist['description'];
                     $row->thumbnail_url = YouTube::getThumbnail($playlist['thumbnails']);
                 }
                 // Get playlist contents.
                 $data = $yt_client->getPlaylistItems($playlist_id);
                 foreach ((array) $data as $item) {
                     $row_name = self::filterName($row, $item['snippet']['title']);
                     $row_thumb = YouTube::getThumbnail($item['snippet']['thumbnails']);
                     // Apply name/thumbnail filtering to sub-videos.
                     if (!empty($row_name) && !empty($row_thumb)) {
                         $child_row = new ConventionArchive();
                         $child_row->convention = $row->convention;
                         $child_row->playlist_id = $row->id;
                         $child_row->type = 'yt_video';
                         $child_row->folder = $row->folder;
                         $child_row->name = $row_name;
                         $child_row->description = $item['snippet']['description'];
                         $child_row->web_url = 'http://www.youtube.com/watch?v=' . $item['id'];
                         $child_row->thumbnail_url = $row_thumb;
                         $em->persist($child_row);
                     }
                 }
                 $row->synchronized_at = time();
                 $em->persist($row);
                 break;
             case "yt_video":
             default:
                 // Pull video ID from any URL format.
                 if (preg_match('%(?:youtube(?:-nocookie)?\\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\\.be/)([^"&?/ ]{11})%i', $url, $match)) {
                     $video_id = $match[1];
                 } else {
                     break;
                 }
                 // Reformat video URL to match standard format.
                 $row->web_url = 'http://www.youtube.com/watch?v=' . $video_id;
                 // Pull data from API.
                 $data = $yt_client->videos->listVideos('snippet,contentDetails', array('id' => $video_id, 'maxResults' => 1));
                 if ($data) {
                     $video = $data['items'][0]['snippet'];
                     $row->name = self::filterName($row, $video['title']);
                     $row->description = $video['description'];
                     $row->thumbnail_url = YouTube::getThumbnail($video['thumbnails']);
                     $row->synchronized_at = time();
                     $em->persist($row);
                 }
                 break;
         }
     }
     $em->flush();
 }
コード例 #9
0
ファイル: IndexController.php プロジェクト: Lavoaster/PVLive
 public function votesAction()
 {
     $threshold = strtotime('-2 weeks');
     $votes_raw = $this->em->createQuery('SELECT sv.song_id, SUM(sv.vote) AS vote_total FROM Entity\\SongVote sv WHERE sv.station_id = :station_id AND sv.timestamp >= :threshold GROUP BY sv.song_id')->setParameter('station_id', $this->station->id)->setParameter('threshold', $threshold)->getArrayResult();
     $ignored_songs = $this->_getIgnoredSongs();
     $votes_raw = array_filter($votes_raw, function ($value) use($ignored_songs) {
         return !isset($ignored_songs[$value['song_id']]);
     });
     \PVL\Utilities::orderBy($votes_raw, 'vote_total DESC');
     $votes = array();
     foreach ($votes_raw as $row) {
         $row['song'] = Song::find($row['song_id']);
         $votes[] = $row;
     }
     $this->view->votes = $votes;
 }
コード例 #10
0
ファイル: SongsController.php プロジェクト: Lavoaster/PVLive
 public function votesAction()
 {
     $threshold = strtotime('-1 week');
     $votes_raw = $this->em->createQuery('SELECT sv.song_id, SUM(sv.vote) AS vote_total FROM Entity\\SongVote sv WHERE sv.timestamp >= :threshold GROUP BY sv.song_id')->setParameter('threshold', $threshold)->getArrayResult();
     Utilities::orderBy($votes_raw, 'vote_total DESC');
     $votes = array();
     foreach ($votes_raw as $row) {
         $row['song'] = Song::find($row['song_id']);
         $votes[] = $row;
     }
     $this->view->votes = $votes;
 }
コード例 #11
0
ファイル: NewsManager.php プロジェクト: Lavoaster/PVLive
 public static function _runTumblrNews(\Phalcon\DiInterface $di)
 {
     $news_items = array();
     $config = $di->get('config');
     // Pull featured images.
     $timestamp_threshold = strtotime('-6 weeks');
     $api_params = array('api_key' => $config->apis->tumblr->key, '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);
     if ($results_raw) {
         $results = json_decode($results_raw, true);
         $posts = $results['response']['posts'];
         foreach ((array) $posts as $post) {
             if ($post['timestamp'] < $timestamp_threshold) {
                 continue;
             }
             $image = null;
             $post_style = 'vertical';
             $image_is_valid = false;
             foreach ((array) $post['photos'] as $photo) {
                 $image = $photo['original_size'];
                 if ($image['width'] == 600 && $image['height'] == 300) {
                     $image_is_valid = true;
                     $post_style = 'vertical';
                     break;
                 } elseif ($image['width'] == 1150 && $image['height'] == 200) {
                     $image_is_valid = true;
                     $post_style = 'horizontal';
                     break;
                 }
             }
             if (!$image_is_valid) {
                 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_url = $local_path_base;
             $local_path = DF_INCLUDE_TEMP . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $local_path_base);
             $s3_path = Service\AmazonS3::path($local_url);
             if (!file_exists($s3_path)) {
                 @mkdir(dirname($local_path));
                 @copy($image_url, $local_path);
                 // Optimize image for fast display.
                 Image::resizeImage($local_path, $local_path, $image['width'], $image['height']);
                 Service\AmazonS3::upload($local_path, $local_path_base);
             }
             $tags = array_map('strtolower', (array) $post['tags']);
             if (in_array('archive', $tags)) {
                 continue;
             }
             $description = strip_tags($post['caption']);
             if (strpos($description, ':') === FALSE) {
                 break;
             }
             list($title, $description) = explode(':', $description, 2);
             $description = Utilities::truncateText($description, self::DESCRIPTION_LENGTH);
             $news_items[] = array('id' => 'tumblr_' . $post['id'], 'title' => trim($title), 'source' => 'tumblr', 'body' => trim($description), 'image_url' => \PVL\Url::upload($local_url), 'web_url' => $post['post_url'], 'layout' => $post_style, 'tags' => (array) $post['tags'], 'sort_timestamp' => $post['timestamp'], 'display_timestamp' => $post['timestamp']);
         }
     }
     return $news_items;
 }
コード例 #12
0
ファイル: ScheduleManager.php プロジェクト: Lavoaster/PVLive
 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());
 }
コード例 #13
0
ファイル: Song.php プロジェクト: Lavoaster/PVLive
 public static function getIds()
 {
     $em = self::getEntityManager();
     $ids_raw = $em->createQuery('SELECT s.id FROM ' . __CLASS__ . ' s')->getArrayResult();
     return \PVL\Utilities::ipull($ids_raw, 'id');
 }
コード例 #14
0
ファイル: CentovaCast.php プロジェクト: Lavoaster/PVLive
 public static function request(Station $station, $track_id)
 {
     if (DF_APPLICATION_ENV !== 'production') {
         return false;
     }
     $db = self::getDatabase();
     $em = self::getEntityManager();
     $settings = self::getSettings();
     // Forbid web crawlers from using this feature.
     if (\PVL\Utilities::isCrawler()) {
         throw new \DF\Exception('Search engine crawlers are not permitted to use this feature.');
     }
     // Verify that the station supports CentovaCast requests.
     $station_id = self::getStationID($station);
     if (!$station_id) {
         throw new \DF\Exception('This radio station is not capable of handling requests at this time.');
     }
     // Verify that Track ID exists with station.
     $media_item = StationMedia::getRepository()->findOneBy(array('id' => $track_id, 'station_id' => $station->id));
     if (!$media_item instanceof StationMedia) {
         throw new \DF\Exception('The song ID you specified could not be found in the station playlist.');
     }
     // Check the most recent song history.
     try {
         $last_play_time = $em->createQuery('SELECT sh.timestamp FROM Entity\\SongHistory sh WHERE sh.song_id = :song_id AND sh.station_id = :station_id ORDER BY sh.timestamp DESC')->setParameter('song_id', $media_item->song_id)->setParameter('station_id', $station->id)->setMaxResults(1)->getSingleScalarResult();
     } catch (\Exception $e) {
         $last_play_time = 0;
     }
     if ($last_play_time && $last_play_time > time() - 60 * 30) {
         throw new \DF\Exception('This song has been played too recently on the station.');
     }
     // Get or create a "requests" playlist for the station.
     $request_playlist_raw = $db->fetchAssoc('SELECT p.id FROM playlists AS p WHERE p.type = ? AND p.accountid = ?', array('request', $station_id));
     if ($request_playlist_raw) {
         $playlist_id = $request_playlist_raw['id'];
     } else {
         $new_playlist = array('title' => 'Automated Song Requests', 'type' => 'request', 'scheduled_repeat' => 'never', 'scheduled_monthdays' => 'date', 'interval_type' => 'songs', 'interval_length' => '0', 'general_weight' => '0', 'status' => 'disabled', 'general_order' => 'random', 'interval_style' => 'playall', 'stateid' => '0', 'accountid' => $station_id, 'scheduled_interruptible' => '0', 'scheduled_duration' => '0', 'scheduled_style' => 'sequential', 'general_starttime' => '00:00:00', 'general_endtime' => '00:00:00', 'track_interruptible' => '0');
         $db->insert('playlists', $new_playlist);
         $playlist_id = $db->lastInsertId('playlists');
     }
     // Check for an existing request from this user.
     $user_ip = $_SERVER['REMOTE_ADDR'];
     $existing_request = $db->fetchAll('SELECT ptr.* FROM playlist_tracks_requests AS ptr WHERE ptr.playlistid = ? AND ptr.senderip = ?', array($playlist_id, $user_ip));
     if (count($existing_request) > 0) {
         throw new \DF\Exception('You already have a pending request with this station! Please try again later.');
     }
     // Check for any request (on any station) within 5 minutes.
     $recent_threshold = time() - 60 * 5;
     $recent_requests = $em->createQuery('SELECT sr FROM Entity\\StationRequest sr WHERE sr.ip = :user_ip AND sr.timestamp >= :threshold')->setParameter('user_ip', $user_ip)->setParameter('threshold', $recent_threshold)->getArrayResult();
     if (count($recent_requests) > 0) {
         throw new \DF\Exception('You have submitted a request too recently! Please wait a while before submitting another one.');
     }
     // Enable the "Automated Song Requests" playlist.
     $db->update('playlists', array('status' => 'enabled'), array('id' => $playlist_id));
     $requesttime = new \DateTime('NOW');
     $requesttime->setTimezone(new \DateTimeZone($settings['timezone']));
     // Create a new request if all other checks pass.
     $new_request = array('playlistid' => $playlist_id, 'trackid' => $track_id, 'requesttime' => $requesttime->format('Y-m-d h:i:s'), 'sendername' => 'Ponyville Live!', 'senderemail' => '*****@*****.**', 'dedication' => '', 'senderip' => $user_ip);
     $db->insert('playlist_tracks_requests', $new_request);
     $request_id = $db->lastInsertId('playlist_tracks_requests');
     $media_item->logRequest();
     $media_item->save();
     return $request_id;
 }
コード例 #15
0
ファイル: SubmitController.php プロジェクト: Lavoaster/PVLive
 public function songconfirmAction()
 {
     // Handle files submitted directly to page.
     $ignore_files = (int) $this->getParam('ignore_files');
     $request = $this->di->get('request');
     if ($request->hasFiles() && !$ignore_files) {
         $this->_processSongUpload();
     }
     // Validate song identifier token.
     $token = $this->_getSongHashToken();
     if (!$this->_validateSongHash($token)) {
         return $this->redirectFromHere(array('action' => 'song'));
     }
     // Check that any stations were selected
     if (!$this->hasParam('stations')) {
         throw new \DF\Exception\DisplayOnly('You did not specify any stations!');
     }
     // Check for uploaded songs.
     $temp_dir_name = 'song_uploads';
     $temp_dir = DF_INCLUDE_TEMP . DIRECTORY_SEPARATOR . $temp_dir_name;
     $all_files = glob($temp_dir . DIRECTORY_SEPARATOR . $token . '*.mp3');
     if (empty($all_files)) {
         throw new \DF\Exception\DisplayOnly('No files were uploaded!');
     }
     $songs = array();
     $getId3 = new GetId3();
     $getId3->encoding = 'UTF-8';
     foreach ($all_files as $song_file_base) {
         $song_file_path = $temp_dir . DIRECTORY_SEPARATOR . basename($song_file_base);
         // Attempt to analyze the MP3.
         $audio = $getId3->analyze($song_file_path);
         if (isset($audio['error'])) {
             @unlink($song_file_path);
             throw new \DF\Exception\DisplayOnly(sprintf('Error at reading audio properties with GetId3: %s.', $audio['error'][0]));
         }
         if (isset($audio['tags']['id3v1']['title'])) {
             $song_data = array('title' => $audio['tags']['id3v1']['title'][0], 'artist' => $audio['tags']['id3v1']['artist'][0]);
         } elseif (isset($audio['tags']['id3v2']['title'])) {
             $song_data = array('title' => $audio['tags']['id3v2']['title'][0], 'artist' => $audio['tags']['id3v2']['artist'][0]);
         } else {
             @unlink($song_file_path);
             continue;
         }
         // Check if existing submission exists.
         $song = Song::getOrCreate($song_data);
         $existing_submission = SongSubmission::getRepository()->findOneBy(array('hash' => $song->id));
         if ($existing_submission instanceof SongSubmission) {
             @unlink($song_file_path);
             continue;
         }
         // Create record in database.
         $metadata = array('File Format' => strtoupper($audio['fileformat']), 'Play Time' => $audio['playtime_string'], 'Bitrate' => round($audio['audio']['bitrate'] / 1024) . 'kbps', 'Bitrate Mode' => strtoupper($audio['audio']['bitrate_mode']), 'Channels' => $audio['audio']['channels'], 'Sample Rate' => $audio['audio']['sample_rate']);
         $record = new SongSubmission();
         $record->song = $song;
         $auth = $this->di->get('auth');
         $record->user = $auth->getLoggedInUser();
         $record->title = $song_data['title'];
         $record->artist = $song_data['artist'];
         $record->song_metadata = $metadata;
         $record->stations = $this->getParam('stations');
         $song_download_url = $record->uploadSong($song_file_path);
         $record->save();
         // Append information to e-mail to stations.
         $song_row = array('Download URL' => '<a href="' . $song_download_url . '" target="_blank">' . $song_download_url . '</a>', 'Title' => $song_data['title'], 'Artist' => $song_data['artist']) + $metadata;
         $songs[] = $song_row;
     }
     if (!empty($songs)) {
         // Notify all existing managers.
         $network_administrators = Action::getUsersWithAction('administer all');
         $email_to = Utilities::ipull($network_administrators, 'email');
         // Pull list of station managers for the specified stations.
         $station_managers = array();
         $short_names = Station::getShortNameLookup();
         foreach ($this->getParam('stations') as $station_key) {
             if (isset($short_names[$station_key])) {
                 $station_id = $short_names[$station_key]['id'];
                 $station = Station::find($station_id);
                 foreach ($station->managers as $manager) {
                     $station_managers[] = $manager->email;
                 }
             }
         }
         $email_to = array_merge($email_to, $station_managers);
         // Trigger e-mail notice.
         if (!empty($email_to)) {
             \DF\Messenger::send(array('to' => $email_to, 'subject' => 'New Song(s) Submitted to Station', 'template' => 'newsong', 'vars' => array('songs' => $songs)));
         }
     }
     // Have to manually call view because a view was already rendered (e-mail was sent).
     // TODO: Fix this. It's dumb.
     $this->view->songs = $songs;
     return $this->view->render('submit', 'songconfirm');
 }