*/ protected $helpers = ['analytics']; protected Podcast $podcast; protected Episode $episode; protected Analytics $analyticsConfig; /** * Constructor. */ public function initController( RequestInterface $request, ResponseInterface $response, LoggerInterface $logger ): void { // Do Not Edit This Line parent::initController($request, $response, $logger); set_user_session_deny_list_ip(); set_user_session_location(); set_user_session_player(); $this->analyticsConfig = config('Analytics'); } public function _remap(string $method, string ...$params): mixed { if (count($params) < 2) { throw PageNotFoundException::forPageNotFound(); } if ( ! ($podcast = (new PodcastModel())->getPodcastByHandle($params[0])) instanceof Podcast ) { throw PageNotFoundException::forPageNotFound(); } $this->podcast = $podcast; if ( ! ($episode = (new EpisodeModel())->getEpisodeBySlug($params[0], $params[1])) instanceof Episode ) { throw PageNotFoundException::forPageNotFound(); } $this->episode = $episode; unset($params[1]); unset($params[0]); return $this->{$method}(...$params); } public function index(): RedirectResponse | ResponseInterface { // check if episode is premium? $subscription = null; // check if podcast is already unlocked before any token validation if ($this->episode->is_premium && ! ($subscription = service('premium_podcasts')->subscription( $this->episode->podcast->handle )) instanceof Subscription) { // look for token as GET parameter if (($token = $this->request->getGet('token')) === null) { return $this->response->setStatusCode(401) ->setJSON([ 'errors' => [ 'status' => 401, 'title' => 'Unauthorized', 'detail' => 'Episode is premium, you must provide a token to unlock it.', ], ]); } // check if there's a valid subscription for the provided token if (! ($subscription = (new SubscriptionModel())->validateSubscription( $this->episode->podcast->handle, $token )) instanceof Subscription) { return $this->response->setStatusCode(401, 'Invalid token!') ->setJSON([ 'errors' => [ 'status' => 401, 'title' => 'Unauthorized', 'detail' => 'Invalid token!', ], ]); } } $session = Services::session(); $serviceName = ''; if ($this->request->getGet('_from')) { $serviceName = $this->request->getGet('_from'); } elseif ($session->get('embed_domain') !== null) { $serviceName = $session->get('embed_domain'); } elseif ($session->get('referer') !== null && $session->get('referer') !== '- Direct -') { $serviceName = parse_url((string) $session->get('referer'), PHP_URL_HOST); } $audioFileSize = $this->episode->audio->file_size; $audioFileHeaderSize = $this->episode->audio->header_size; $audioDuration = $this->episode->audio->duration; // bytes_threshold: number of bytes that must be downloaded for an episode to be counted in download analytics // - if audio is less than or equal to 60s, then take the audio file_size // - if audio is more than 60s, then take the audio file_header_size + 60s $bytesThreshold = $audioDuration <= 60 ? $audioFileSize : $audioFileHeaderSize + (int) floor((($audioFileSize - $audioFileHeaderSize) / $audioDuration) * 60); podcast_hit( $this->episode->podcast_id, $this->episode->id, $bytesThreshold, $audioFileSize, $audioDuration, $this->episode->published_at->getTimestamp(), $serviceName, $subscription instanceof Subscription ? $subscription->id : null ); $audioFileURI = new URI(service('file_manager')->getUrl($this->episode->audio->file_key)); $queryParams = []; foreach ($this->request->getGet() as $key => $value) { // do not include token in query params if ($key !== 'token') { $queryParams[$key] = $value; } } $audioFileURI->setQueryArray($queryParams); return redirect()->to((string) $audioFileURI); } }