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; }
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); }
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; }
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); }
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)); } }
/** * 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']); }
/** * 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); }
/** * 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(); }
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; }
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; }
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; }
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()); }
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'); }
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; }
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'); }