Commit e1f65cd3 authored by Benjamin Bellamy's avatar Benjamin Bellamy 💬
Browse files

feat(episodes): replace all audio file URL parameters with base64 encoded data

parent 391c349d
Loading
Loading
Loading
Loading
Loading
+5 −8
Original line number Diff line number Diff line
@@ -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}');

/**
 * --------------------------------------------------------------------
@@ -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');
+14 −14
Original line number Diff line number Diff line
@@ -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));
+3 −2
Original line number Diff line number Diff line
@@ -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
@@ -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) 
+28 −16
Original line number Diff line number Diff line
@@ -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
@@ -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']
            )
        );
+21 −1
Original line number Diff line number Diff line
@@ -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
 */
@@ -245,6 +261,7 @@ function podcast_hit(
    $bytesThreshold,
    $fileSize,
    $duration,
    $publicationDate,
    $serviceName
) {
    $session = \Config\Services::session();
@@ -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_' .
@@ -337,7 +356,7 @@ function podcast_hit(
                cache()->save($listenerHashId, $downloadsByUser, $midnightTTL);

                $db->query(
                    "CALL $procedureName(?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
                    "CALL $procedureName(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
                    [
                        $podcastId,
                        $episodeId,
@@ -352,6 +371,7 @@ function podcast_hit(
                        $session->get('player')['bot'],
                        $fileSize,
                        $duration,
                        $age,
                        $newListener,
                    ]
                );