Loading app/Config/Routes.php +5 −8 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ $routes->setAutoRoute(false); $routes->addPlaceholder('podcastName', '[a-zA-Z0-9\_]{1,191}'); $routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,191}'); $routes->addPlaceholder('base64', '[A-Za-z0-9\.\_]+\-{0,2}'); /** * -------------------------------------------------------------------- Loading Loading @@ -59,14 +60,10 @@ $routes->group(config('App')->installGateway, function ($routes) { ]); }); // Route for podcast audio file analytics (/audio/podcast_id/episode_id/bytes_threshold/filesize/duration/podcast_folder/filename.mp3) $routes->add( 'audio/(:num)/(:num)/(:num)/(:num)/(:num)/(:any)', 'Analytics::hit/$1/$2/$3/$4/$5/$6', [ // Route for podcast audio file analytics (/audio/pack(podcast_id,episode_id,bytes_threshold,filesize,duration,date)/podcast_folder/filename.mp3) $routes->add('audio/(:base64)/(:any)', 'Analytics::hit/$1/$2', [ 'as' => 'analytics_hit', ] ); ]); // Show the Unknown UserAgents $routes->get('.well-known/unknown-useragents', 'UnknownUserAgents'); Loading app/Controllers/Analytics.php +14 −14 Original line number Diff line number Diff line Loading @@ -46,24 +46,24 @@ class Analytics extends Controller } // Add one hit to this episode: public function hit( $podcastId, $episodeId, $bytesThreshold, $fileSize, $duration, ...$filename ) { helper('media'); public function hit($base64EpisodeData, ...$filename) { helper('media', 'analytics'); $serviceName = isset($_GET['_from']) ? $_GET['_from'] : ''; $episodeData = unpack( 'IpodcastId/IepisodeId/IbytesThreshold/IfileSize/Iduration/IpublicationDate', base64_url_decode($base64EpisodeData) ); podcast_hit( $podcastId, $episodeId, $bytesThreshold, $fileSize, $duration, $episodeData['podcastId'], $episodeData['episodeId'], $episodeData['bytesThreshold'], $episodeData['fileSize'], $episodeData['duration'], $episodeData['publicationDate'], $serviceName ); return redirect()->to(media_base_url($filename)); Loading app/Database/Migrations/2020-06-11-210000_add_analytics_podcasts_procedure.php +3 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ CREATE PROCEDURE `{$prefix}analytics_podcasts` ( IN `p_bot` TINYINT(1) UNSIGNED, IN `p_filesize` INT UNSIGNED, IN `p_duration` INT UNSIGNED, IN `p_age` INT UNSIGNED, IN `p_new_listener` TINYINT(1) UNSIGNED ) MODIFIES SQL DATA DETERMINISTIC Loading @@ -58,7 +59,7 @@ IF NOT `p_bot` THEN VALUES (p_podcast_id, @current_date, @current_hour) ON DUPLICATE KEY UPDATE `hits`=`hits`+1; INSERT INTO `{$prefix}analytics_podcasts_by_episode`(`podcast_id`, `episode_id`, `date`, `age`) SELECT p_podcast_id, p_episode_id, @current_date, datediff(@current_datetime,`published_at`) FROM `{$prefix}episodes` WHERE `id`= p_episode_id VALUES (p_podcast_id, p_episode_id, @current_date, p_age) ON DUPLICATE KEY UPDATE `hits`=`hits`+1; INSERT INTO `{$prefix}analytics_podcasts_by_country`(`podcast_id`, `country_code`, `date`) VALUES (p_podcast_id, p_country_code, @current_date) Loading app/Entities/Episode.php +28 −16 Original line number Diff line number Diff line Loading @@ -179,9 +179,14 @@ class Episode extends Entity public function getEnclosureUrl() { helper('analytics'); return base_url( route_to( 'analytics_hit', base64_url_encode( pack( 'I*', $this->attributes['podcast_id'], $this->attributes['id'], // bytes_threshold: number of bytes that must be downloaded for an episode to be counted in download analytics Loading @@ -192,12 +197,19 @@ class Episode extends Entity : $this->attributes['enclosure_headersize'] + floor( (($this->attributes['enclosure_filesize'] - $this->attributes['enclosure_headersize']) / $this->attributes['enclosure_duration']) * $this->attributes[ 'enclosure_headersize' ]) / $this->attributes[ 'enclosure_duration' ]) * 60 ), $this->attributes['enclosure_filesize'], $this->attributes['enclosure_duration'], strtotime($this->attributes['published_at']) ) ), $this->attributes['enclosure_uri'] ) ); Loading app/Helpers/analytics_helper.php +21 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,22 @@ if (!function_exists('getallheaders')) { } } /** * Encode Base64 for URLs */ function base64_url_encode($input) { return strtr(base64_encode($input), '+/=', '._-'); } /** * Decode Base64 from URL */ function base64_url_decode($input) { return base64_decode(strtr($input, '._-', '+/=')); } /** * Set user country in session variable, for analytics purpose */ Loading Loading @@ -245,6 +261,7 @@ function podcast_hit( $bytesThreshold, $fileSize, $duration, $publicationDate, $serviceName ) { $session = \Config\Services::session(); Loading Loading @@ -311,6 +328,8 @@ function podcast_hit( $db = \Config\Database::connect(); $procedureName = $db->prefixTable('analytics_podcasts'); $age = intdiv(time() - $publicationDate, 86400); // We create a sha1 hash for this IP_Address+User_Agent+Podcast_ID (used to count unique listeners): $listenerHashId = '_IpUaPo_' . Loading @@ -337,7 +356,7 @@ function podcast_hit( cache()->save($listenerHashId, $downloadsByUser, $midnightTTL); $db->query( "CALL $procedureName(?,?,?,?,?,?,?,?,?,?,?,?,?,?);", "CALL $procedureName(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", [ $podcastId, $episodeId, Loading @@ -352,6 +371,7 @@ function podcast_hit( $session->get('player')['bot'], $fileSize, $duration, $age, $newListener, ] ); Loading Loading
app/Config/Routes.php +5 −8 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ $routes->setAutoRoute(false); $routes->addPlaceholder('podcastName', '[a-zA-Z0-9\_]{1,191}'); $routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,191}'); $routes->addPlaceholder('base64', '[A-Za-z0-9\.\_]+\-{0,2}'); /** * -------------------------------------------------------------------- Loading Loading @@ -59,14 +60,10 @@ $routes->group(config('App')->installGateway, function ($routes) { ]); }); // Route for podcast audio file analytics (/audio/podcast_id/episode_id/bytes_threshold/filesize/duration/podcast_folder/filename.mp3) $routes->add( 'audio/(:num)/(:num)/(:num)/(:num)/(:num)/(:any)', 'Analytics::hit/$1/$2/$3/$4/$5/$6', [ // Route for podcast audio file analytics (/audio/pack(podcast_id,episode_id,bytes_threshold,filesize,duration,date)/podcast_folder/filename.mp3) $routes->add('audio/(:base64)/(:any)', 'Analytics::hit/$1/$2', [ 'as' => 'analytics_hit', ] ); ]); // Show the Unknown UserAgents $routes->get('.well-known/unknown-useragents', 'UnknownUserAgents'); Loading
app/Controllers/Analytics.php +14 −14 Original line number Diff line number Diff line Loading @@ -46,24 +46,24 @@ class Analytics extends Controller } // Add one hit to this episode: public function hit( $podcastId, $episodeId, $bytesThreshold, $fileSize, $duration, ...$filename ) { helper('media'); public function hit($base64EpisodeData, ...$filename) { helper('media', 'analytics'); $serviceName = isset($_GET['_from']) ? $_GET['_from'] : ''; $episodeData = unpack( 'IpodcastId/IepisodeId/IbytesThreshold/IfileSize/Iduration/IpublicationDate', base64_url_decode($base64EpisodeData) ); podcast_hit( $podcastId, $episodeId, $bytesThreshold, $fileSize, $duration, $episodeData['podcastId'], $episodeData['episodeId'], $episodeData['bytesThreshold'], $episodeData['fileSize'], $episodeData['duration'], $episodeData['publicationDate'], $serviceName ); return redirect()->to(media_base_url($filename)); Loading
app/Database/Migrations/2020-06-11-210000_add_analytics_podcasts_procedure.php +3 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ CREATE PROCEDURE `{$prefix}analytics_podcasts` ( IN `p_bot` TINYINT(1) UNSIGNED, IN `p_filesize` INT UNSIGNED, IN `p_duration` INT UNSIGNED, IN `p_age` INT UNSIGNED, IN `p_new_listener` TINYINT(1) UNSIGNED ) MODIFIES SQL DATA DETERMINISTIC Loading @@ -58,7 +59,7 @@ IF NOT `p_bot` THEN VALUES (p_podcast_id, @current_date, @current_hour) ON DUPLICATE KEY UPDATE `hits`=`hits`+1; INSERT INTO `{$prefix}analytics_podcasts_by_episode`(`podcast_id`, `episode_id`, `date`, `age`) SELECT p_podcast_id, p_episode_id, @current_date, datediff(@current_datetime,`published_at`) FROM `{$prefix}episodes` WHERE `id`= p_episode_id VALUES (p_podcast_id, p_episode_id, @current_date, p_age) ON DUPLICATE KEY UPDATE `hits`=`hits`+1; INSERT INTO `{$prefix}analytics_podcasts_by_country`(`podcast_id`, `country_code`, `date`) VALUES (p_podcast_id, p_country_code, @current_date) Loading
app/Entities/Episode.php +28 −16 Original line number Diff line number Diff line Loading @@ -179,9 +179,14 @@ class Episode extends Entity public function getEnclosureUrl() { helper('analytics'); return base_url( route_to( 'analytics_hit', base64_url_encode( pack( 'I*', $this->attributes['podcast_id'], $this->attributes['id'], // bytes_threshold: number of bytes that must be downloaded for an episode to be counted in download analytics Loading @@ -192,12 +197,19 @@ class Episode extends Entity : $this->attributes['enclosure_headersize'] + floor( (($this->attributes['enclosure_filesize'] - $this->attributes['enclosure_headersize']) / $this->attributes['enclosure_duration']) * $this->attributes[ 'enclosure_headersize' ]) / $this->attributes[ 'enclosure_duration' ]) * 60 ), $this->attributes['enclosure_filesize'], $this->attributes['enclosure_duration'], strtotime($this->attributes['published_at']) ) ), $this->attributes['enclosure_uri'] ) ); Loading
app/Helpers/analytics_helper.php +21 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,22 @@ if (!function_exists('getallheaders')) { } } /** * Encode Base64 for URLs */ function base64_url_encode($input) { return strtr(base64_encode($input), '+/=', '._-'); } /** * Decode Base64 from URL */ function base64_url_decode($input) { return base64_decode(strtr($input, '._-', '+/=')); } /** * Set user country in session variable, for analytics purpose */ Loading Loading @@ -245,6 +261,7 @@ function podcast_hit( $bytesThreshold, $fileSize, $duration, $publicationDate, $serviceName ) { $session = \Config\Services::session(); Loading Loading @@ -311,6 +328,8 @@ function podcast_hit( $db = \Config\Database::connect(); $procedureName = $db->prefixTable('analytics_podcasts'); $age = intdiv(time() - $publicationDate, 86400); // We create a sha1 hash for this IP_Address+User_Agent+Podcast_ID (used to count unique listeners): $listenerHashId = '_IpUaPo_' . Loading @@ -337,7 +356,7 @@ function podcast_hit( cache()->save($listenerHashId, $downloadsByUser, $midnightTTL); $db->query( "CALL $procedureName(?,?,?,?,?,?,?,?,?,?,?,?,?,?);", "CALL $procedureName(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", [ $podcastId, $episodeId, Loading @@ -352,6 +371,7 @@ function podcast_hit( $session->get('player')['bot'], $fileSize, $duration, $age, $newListener, ] ); Loading