From cd475051c8b786647672b0440c7696ca0447dfa3 Mon Sep 17 00:00:00 2001 From: Moahmed-Ismail MEJRI Date: Tue, 21 Jun 2022 17:38:19 +0200 Subject: [PATCH 1/6] Add radio stream info from stream using php and rest api --- appinfo/routes.php | 2 + js/app/controllers/playercontroller.js | 43 +++++++++- lib/Controller/RadioApiController.php | 46 +++++++++++ lib/Utility/RadioMetadata.php | 106 +++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 lib/Utility/RadioMetadata.php diff --git a/appinfo/routes.php b/appinfo/routes.php index f1dfcc07a..f312265ba 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -85,6 +85,8 @@ ['name' => 'radioApi#exportAllToFile', 'url' => '/api/radio/export', 'verb' => 'POST'], ['name' => 'radioApi#importFromFile', 'url' => '/api/radio/import', 'verb' => 'POST'], ['name' => 'radioApi#resetAll', 'url' => '/api/radio/reset', 'verb' => 'POST'], + ['name' => 'radioApi#getRadioURLData', 'url' => '/api/radiometadata/url/{id}', 'verb' => 'GET'], + ['name' => 'radioApi#getRadioStreamData', 'url' => '/api/radiometadata/stream/{id}', 'verb' => 'GET'], // podcast API ['name' => 'podcastApi#getAll', 'url' => '/api/podcasts', 'verb' => 'GET'], diff --git a/js/app/controllers/playercontroller.js b/js/app/controllers/playercontroller.js index 8da7d566d..23f9fc047 100644 --- a/js/app/controllers/playercontroller.js +++ b/js/app/controllers/playercontroller.js @@ -32,6 +32,7 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula total: 0 }; var scrobblePending = false; + var timeoutId = 0; // shuffle and repeat may be overridden with URL parameters if ($location.search().shuffle !== undefined) { @@ -104,6 +105,13 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula }); onPlayerEvent('play', function() { $rootScope.playing = true; + if (timeoutId != 0) { + clearTimeout(timeoutId); + timeoutId = 0; + } + if (currentTrackIsStream()) { + $scope.getStreamTitle(); + } }); onPlayerEvent('pause', function() { $rootScope.playing = false; @@ -438,7 +446,7 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula }; $scope.secondaryTitle = function() { - return $scope.currentTrack?.artistName ?? $scope.currentTrack?.channel?.title ?? $scope.currentTrack?.stream_url ?? null; + return $scope.currentTrack?.artistName ?? $scope.currentTrack?.channel?.title ?? $scope.currentTrack?.currentTitle ?? $scope.currentTrack?.stream_url ?? null; }; $scope.coverArt = function() { @@ -498,6 +506,37 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula return command + ' (' + cmdScope + ')'; }; + $scope.onMetadata = function(streamTitle) { + console.log('MetaData recieved: ' + streamTitle); + if ((streamTitle) && $scope.currentTrack.currentTitle !== streamTitle) { + $scope.currentTrack.currentTitle = streamTitle; + } + }; + + $scope.getStreamTitle = function() { + if ($rootScope.playing) { + //console.log('MetaData play'); + var currentTrackId = $scope.currentTrack.id; + Restangular.one('radiometadata').one('stream', $scope.currentTrack.id).get().then( + function(_result) { + if ($scope.currentTrack && $scope.currentTrack.id == currentTrackId) { + $scope.onMetadata(_result); + } + }, + function(_error) { + // error handling + if ($scope.currentTrack && $scope.currentTrack.id == currentTrackId) { + $scope.onMetadata(_error); + } + } + ); + timeoutId = setTimeout(() => $scope.getStreamTitle(), 32000); + } else { + //console.log('MetaData pause'); + timeoutId = 0; + } + }; + /** * The coverArtToken is used to enable loading the cover art in the mediaSession of Firefox. There, * the loading happens in a context where the normal session cookies are not available. Hence, for the @@ -539,7 +578,7 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula if (track.type === 'radio') { navigator.mediaSession.metadata = new MediaMetadata({ title: track.name, - artist: track.stream_url, + artist: track.currentTitle ?? track.stream_url, artwork: [{ sizes: '190x190', src: radioIconPath, diff --git a/lib/Controller/RadioApiController.php b/lib/Controller/RadioApiController.php index f6670169e..68e7d70a2 100644 --- a/lib/Controller/RadioApiController.php +++ b/lib/Controller/RadioApiController.php @@ -25,6 +25,7 @@ use OCA\Music\Http\ErrorResponse; use OCA\Music\Utility\PlaylistFileService; use OCA\Music\Utility\Util; +use OCA\Music\Utility\RadioMetadata; class RadioApiController extends Controller { private $businessLayer; @@ -201,4 +202,49 @@ public function resetAll() { $this->businessLayer->deleteAll($this->userId); return new JSONResponse(['success' => true]); } + + /** + * get radio metadata from url + * + * @NoAdminRequired + * @NoCSRFRequired + */ + + public function getRadioURLData(int $id) { + try { + $response = ""; + $station = $this->businessLayer->find($id, $this->userId); + $stapi = $station->toAPI(); + if (isset($stapi['stream_url'])) { + $parse_url = parse_url($stapi['stream_url']); + $response = RadioMetadata::fetchUrlData($parse_url['scheme'] . '://' . $parse_url['host'] . ':' . $parse_url['port'] . '/7.html'); + } + return new JSONResponse($response); + + } catch (BusinessLayerException $ex) { + return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage()); + } + } + + /** + * get radio metadata from stream + * + * @NoAdminRequired + * @NoCSRFRequired + */ + + public function getRadioStreamData(int $id) { + try { + $response = ""; + $station = $this->businessLayer->find($id, $this->userId); + $stapi = $station->toAPI(); + if (isset($stapi['stream_url'])) { + $response = RadioMetadata::fetchStreamData($stapi['stream_url'], 1, 1); + } + return new JSONResponse($response); + + } catch (BusinessLayerException $ex) { + return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage()); + } + } } diff --git a/lib/Utility/RadioMetadata.php b/lib/Utility/RadioMetadata.php new file mode 100644 index 000000000..38749780c --- /dev/null +++ b/lib/Utility/RadioMetadata.php @@ -0,0 +1,106 @@ + + * @copyright Moahmed-Ismail MEJRI 2022 + */ + +namespace OCA\Music\Utility; + +/** + * MetaData radio utility functions + */ +class RadioMetadata { + + public static function fetchUrlData($url) : array { + $content = \file_get_contents($url); + list($version, $status_code, $msg) = explode(' ', $http_response_header[0], 3); + return [$content, $status_code, $msg]; + } + + public static function fetchStreamData($url, $maxattempts, $maxredirect) { + $parse_url = parse_url($url); + $port = 80; + if (isset($parse_url['port'])) { + $port = $parse_url['port']; + } else if ($parse_url['scheme'] == "https") { + $port = 443; + } + $hostname = $parse_url['host']; + $pathname = $parse_url['path']; + if (isset($parse_url['query'])) { + $pathname .= "?" . $parse_url['query']; + } + if ($parse_url['scheme'] == "https") { + $sockadd = "ssl://" . $hostname; + } else { + $sockadd = $hostname; + } + $streamTitle = ""; + if (($sockadd)&&($port)) { + $fp = fsockopen($sockadd, $port, $errno, $errstr, 15); + if ($fp != false) { + $out = "GET " . $pathname . " HTTP/1.1\r\n"; + $out .= "Host: ". $hostname . "\r\n"; + $out .= "Accept: */*\r\n"; /* test */ + $out .= "User-Agent: OCMusic/1.52\r\n"; + $out .= "Icy-MetaData: 1\r\n"; + $out .= "Connection: Close\r\n\r\n"; + fwrite($fp, $out); + + $header = fread($fp, 1024); + $headers = array(); + $headers = explode("\n", $header); + + if (strstr($headers[0], "200 OK") !== false) { + $interval = 0; + foreach ($headers as $value) { + if (strstr($value, "icy-metaint:") !== false) { + $val = explode(':', $value); + $interval = trim($val[1]); + break; + } + } + + if (($interval)&&($interval<64001)) { + $attempts = 0; + while ($attempts < $maxattempts) { + for ($j = 0; $j < $interval; $j++) { + fread($fp, 1); + } + + $meta_length = ord(fread($fp, 1)) * 16; + if ($meta_length) { + $metadatas = explode(';', fread($fp, $meta_length)); + foreach ($metadatas as $metadata) { + if (strstr($metadata, "StreamTitle") !== false) { + $streamTitle = trim(explode('=', $metadata)[1], "'"); + break; + } + } + } + $attempts++; + } + } + } else if (($maxredirect>0)&&(strstr($headers[0], "302 Found") !== false)) { + foreach ($headers as $value) { + $val = strstr($value, "Location:"); + if ($val) { + $location = trim(substr($val, 10), "\r"); + $streamTitle = RadioMetadata::fetchStreamData($location, $maxattempts, $maxredirect-1); + break; + } + } + } + fclose($fp); + } + } + return $streamTitle; + } + +} From d865bc18b463a97a62731609acedfb1cdedcd9bd Mon Sep 17 00:00:00 2001 From: Moahmed-Ismail MEJRI Date: Sun, 26 Jun 2022 20:12:07 +0200 Subject: [PATCH 2/6] Push back stream url in error case --- js/app/controllers/playercontroller.js | 5 ++++- lib/Utility/RadioMetadata.php | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/js/app/controllers/playercontroller.js b/js/app/controllers/playercontroller.js index 23f9fc047..e8c2844d7 100644 --- a/js/app/controllers/playercontroller.js +++ b/js/app/controllers/playercontroller.js @@ -510,6 +510,9 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula console.log('MetaData recieved: ' + streamTitle); if ((streamTitle) && $scope.currentTrack.currentTitle !== streamTitle) { $scope.currentTrack.currentTitle = streamTitle; + if (('mediaSession' in navigator)&&(navigator.mediaSession.metadata !== null)) { + navigator.mediaSession.metadata.artist = streamTitle; + } } }; @@ -526,7 +529,7 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula function(_error) { // error handling if ($scope.currentTrack && $scope.currentTrack.id == currentTrackId) { - $scope.onMetadata(_error); + $scope.onMetadata($scope.currentTrack.stream_url); } } ); diff --git a/lib/Utility/RadioMetadata.php b/lib/Utility/RadioMetadata.php index 38749780c..57fff7517 100644 --- a/lib/Utility/RadioMetadata.php +++ b/lib/Utility/RadioMetadata.php @@ -25,6 +25,7 @@ public static function fetchUrlData($url) : array { public static function fetchStreamData($url, $maxattempts, $maxredirect) { $parse_url = parse_url($url); + $timeout = 10; $port = 80; if (isset($parse_url['port'])) { $port = $parse_url['port']; @@ -43,7 +44,7 @@ public static function fetchStreamData($url, $maxattempts, $maxredirect) { } $streamTitle = ""; if (($sockadd)&&($port)) { - $fp = fsockopen($sockadd, $port, $errno, $errstr, 15); + $fp = fsockopen($sockadd, $port, $errno, $errstr, $timeout); if ($fp != false) { $out = "GET " . $pathname . " HTTP/1.1\r\n"; $out .= "Host: ". $hostname . "\r\n"; @@ -52,6 +53,7 @@ public static function fetchStreamData($url, $maxattempts, $maxredirect) { $out .= "Icy-MetaData: 1\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); + stream_set_timeout($fp, $timeout); $header = fread($fp, 1024); $headers = array(); @@ -80,6 +82,9 @@ public static function fetchStreamData($url, $maxattempts, $maxredirect) { foreach ($metadatas as $metadata) { if (strstr($metadata, "StreamTitle") !== false) { $streamTitle = trim(explode('=', $metadata)[1], "'"); + if (strlen($streamTitle) > 120) { + $streamTitle = ""; + } break; } } From 328003986659c60964b83c8261f64bc7535a6e64 Mon Sep 17 00:00:00 2001 From: Moahmed-Ismail MEJRI Date: Mon, 27 Jun 2022 20:53:29 +0200 Subject: [PATCH 3/6] Optimise RadioMetadata class and delete unused array, Correct Radio Api response from JSON to DATA --- lib/Controller/RadioApiController.php | 5 +- lib/Utility/RadioMetadata.php | 96 ++++++++++++++++----------- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/lib/Controller/RadioApiController.php b/lib/Controller/RadioApiController.php index 68e7d70a2..4dd78c471 100644 --- a/lib/Controller/RadioApiController.php +++ b/lib/Controller/RadioApiController.php @@ -15,6 +15,7 @@ use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\DataResponse; use OCP\Files\Folder; use OCP\IRequest; @@ -219,7 +220,7 @@ public function getRadioURLData(int $id) { $parse_url = parse_url($stapi['stream_url']); $response = RadioMetadata::fetchUrlData($parse_url['scheme'] . '://' . $parse_url['host'] . ':' . $parse_url['port'] . '/7.html'); } - return new JSONResponse($response); + return new DataResponse($response); } catch (BusinessLayerException $ex) { return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage()); @@ -241,7 +242,7 @@ public function getRadioStreamData(int $id) { if (isset($stapi['stream_url'])) { $response = RadioMetadata::fetchStreamData($stapi['stream_url'], 1, 1); } - return new JSONResponse($response); + return new DataResponse($response); } catch (BusinessLayerException $ex) { return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage()); diff --git a/lib/Utility/RadioMetadata.php b/lib/Utility/RadioMetadata.php index 57fff7517..c59972e99 100644 --- a/lib/Utility/RadioMetadata.php +++ b/lib/Utility/RadioMetadata.php @@ -17,37 +17,61 @@ */ class RadioMetadata { - public static function fetchUrlData($url) : array { - $content = \file_get_contents($url); - list($version, $status_code, $msg) = explode(' ', $http_response_header[0], 3); - return [$content, $status_code, $msg]; + private static function findStr($data, $str) { + $ret = ""; + foreach ($data as $value) { + $find = strstr($value, $str); + if ($find !== false) { + $ret = $find; + break; + } + } + return $ret; } - public static function fetchStreamData($url, $maxattempts, $maxredirect) { + private static function parseStreamUrl($url) { + $parse_url = parse_url($url); - $timeout = 10; - $port = 80; + + $ret['port'] = 80; if (isset($parse_url['port'])) { - $port = $parse_url['port']; + $ret['port'] = $parse_url['port']; } else if ($parse_url['scheme'] == "https") { - $port = 443; + $ret['port'] = 443; } - $hostname = $parse_url['host']; - $pathname = $parse_url['path']; + + $ret['hostname'] = $parse_url['host']; + $ret['pathname'] = $parse_url['path']; + if (isset($parse_url['query'])) { - $pathname .= "?" . $parse_url['query']; + $ret['pathname'] .= "?" . $parse_url['query']; } + if ($parse_url['scheme'] == "https") { - $sockadd = "ssl://" . $hostname; + $ret['sockadd'] = "ssl://" . $ret['hostname']; } else { - $sockadd = $hostname; + $ret['sockadd'] = $ret['hostname']; } + + return $ret; + } + + + public static function fetchUrlData($url) : array { + $content = \file_get_contents($url); + list($version, $status_code, $msg) = explode(' ', $http_response_header[0], 3); + return [$content, $status_code, $msg]; + } + + public static function fetchStreamData($url, $maxattempts, $maxredirect) { + $timeout = 10; $streamTitle = ""; - if (($sockadd)&&($port)) { - $fp = fsockopen($sockadd, $port, $errno, $errstr, $timeout); + $pUrl = self::parseStreamUrl($url); + if (($pUrl['sockadd']) && ($pUrl['port'])) { + $fp = fsockopen($pUrl['sockadd'], $pUrl['port'], $errno, $errstr, $timeout); if ($fp != false) { - $out = "GET " . $pathname . " HTTP/1.1\r\n"; - $out .= "Host: ". $hostname . "\r\n"; + $out = "GET " . $pUrl['pathname'] . " HTTP/1.1\r\n"; + $out .= "Host: ". $pUrl['hostname'] . "\r\n"; $out .= "Accept: */*\r\n"; /* test */ $out .= "User-Agent: OCMusic/1.52\r\n"; $out .= "Icy-MetaData: 1\r\n"; @@ -56,17 +80,13 @@ public static function fetchStreamData($url, $maxattempts, $maxredirect) { stream_set_timeout($fp, $timeout); $header = fread($fp, 1024); - $headers = array(); $headers = explode("\n", $header); if (strstr($headers[0], "200 OK") !== false) { $interval = 0; - foreach ($headers as $value) { - if (strstr($value, "icy-metaint:") !== false) { - $val = explode(':', $value); - $interval = trim($val[1]); - break; - } + $line = self::findStr($headers, "icy-metaint:"); + if ($line) { + $interval = trim(explode(':', $line)[1]); } if (($interval)&&($interval<64001)) { @@ -79,27 +99,23 @@ public static function fetchStreamData($url, $maxattempts, $maxredirect) { $meta_length = ord(fread($fp, 1)) * 16; if ($meta_length) { $metadatas = explode(';', fread($fp, $meta_length)); - foreach ($metadatas as $metadata) { - if (strstr($metadata, "StreamTitle") !== false) { - $streamTitle = trim(explode('=', $metadata)[1], "'"); - if (strlen($streamTitle) > 120) { - $streamTitle = ""; - } - break; - } + $metadata = self::findStr($metadatas, "StreamTitle"); + if ($metadata) { + $streamTitle = trim(explode('=', $metadata)[1], "'"); + if (strlen($streamTitle) > 256) { + $streamTitle = ""; + } + break; } } $attempts++; } } } else if (($maxredirect>0)&&(strstr($headers[0], "302 Found") !== false)) { - foreach ($headers as $value) { - $val = strstr($value, "Location:"); - if ($val) { - $location = trim(substr($val, 10), "\r"); - $streamTitle = RadioMetadata::fetchStreamData($location, $maxattempts, $maxredirect-1); - break; - } + $value = self::findStr($headers, "Location:"); + if ($value) { + $location = trim(substr($value, 10), "\r"); + $streamTitle = RadioMetadata::fetchStreamData($location, $maxattempts, $maxredirect-1); } } fclose($fp); From 49e9c42b7607e2dd85bbbb598d3297e354b86fd3 Mon Sep 17 00:00:00 2001 From: Moahmed-Ismail MEJRI Date: Mon, 27 Jun 2022 21:20:27 +0200 Subject: [PATCH 4/6] Add return init in RadioMetadata::parseStreamUrl --- lib/Utility/RadioMetadata.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Utility/RadioMetadata.php b/lib/Utility/RadioMetadata.php index c59972e99..63cac5375 100644 --- a/lib/Utility/RadioMetadata.php +++ b/lib/Utility/RadioMetadata.php @@ -31,6 +31,7 @@ private static function findStr($data, $str) { private static function parseStreamUrl($url) { + $ret = array(); $parse_url = parse_url($url); $ret['port'] = 80; From e8699f73ca97d4bdc7014e54c6958c4352ee2cc6 Mon Sep 17 00:00:00 2001 From: Moahmed-Ismail MEJRI Date: Tue, 28 Jun 2022 16:51:57 +0200 Subject: [PATCH 5/6] Update recommandation for clean code in radio metadata --- appinfo/routes.php | 3 +-- js/app/controllers/playercontroller.js | 15 +++++-------- lib/Controller/RadioApiController.php | 25 +-------------------- lib/Utility/RadioMetadata.php | 31 ++++++++++++++++---------- 4 files changed, 26 insertions(+), 48 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index f312265ba..28d4cd326 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -85,8 +85,7 @@ ['name' => 'radioApi#exportAllToFile', 'url' => '/api/radio/export', 'verb' => 'POST'], ['name' => 'radioApi#importFromFile', 'url' => '/api/radio/import', 'verb' => 'POST'], ['name' => 'radioApi#resetAll', 'url' => '/api/radio/reset', 'verb' => 'POST'], - ['name' => 'radioApi#getRadioURLData', 'url' => '/api/radiometadata/url/{id}', 'verb' => 'GET'], - ['name' => 'radioApi#getRadioStreamData', 'url' => '/api/radiometadata/stream/{id}', 'verb' => 'GET'], + ['name' => 'radioApi#getRadioStreamData', 'url' => '/api/radio/{id}/info', 'verb' => 'GET'], // podcast API ['name' => 'podcastApi#getAll', 'url' => '/api/podcasts', 'verb' => 'GET'], diff --git a/js/app/controllers/playercontroller.js b/js/app/controllers/playercontroller.js index e8c2844d7..fcabb43a1 100644 --- a/js/app/controllers/playercontroller.js +++ b/js/app/controllers/playercontroller.js @@ -510,20 +510,16 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula console.log('MetaData recieved: ' + streamTitle); if ((streamTitle) && $scope.currentTrack.currentTitle !== streamTitle) { $scope.currentTrack.currentTitle = streamTitle; - if (('mediaSession' in navigator)&&(navigator.mediaSession.metadata !== null)) { - navigator.mediaSession.metadata.artist = streamTitle; - } } }; $scope.getStreamTitle = function() { if ($rootScope.playing) { - //console.log('MetaData play'); var currentTrackId = $scope.currentTrack.id; - Restangular.one('radiometadata').one('stream', $scope.currentTrack.id).get().then( - function(_result) { + Restangular.one('radio', $scope.currentTrack.id).one('info').get().then( + function(response) { if ($scope.currentTrack && $scope.currentTrack.id == currentTrackId) { - $scope.onMetadata(_result); + $scope.onMetadata(response.title); } }, function(_error) { @@ -535,7 +531,6 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula ); timeoutId = setTimeout(() => $scope.getStreamTitle(), 32000); } else { - //console.log('MetaData pause'); timeoutId = 0; } }; @@ -602,7 +597,7 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula }); } } - }); + }, true); } /** @@ -648,6 +643,6 @@ function ($scope, $rootScope, playlistService, Audio, gettextCatalog, Restangula notification = null; } } - }); + }, true); } }]); diff --git a/lib/Controller/RadioApiController.php b/lib/Controller/RadioApiController.php index 4dd78c471..f8ffca6a5 100644 --- a/lib/Controller/RadioApiController.php +++ b/lib/Controller/RadioApiController.php @@ -204,29 +204,6 @@ public function resetAll() { return new JSONResponse(['success' => true]); } - /** - * get radio metadata from url - * - * @NoAdminRequired - * @NoCSRFRequired - */ - - public function getRadioURLData(int $id) { - try { - $response = ""; - $station = $this->businessLayer->find($id, $this->userId); - $stapi = $station->toAPI(); - if (isset($stapi['stream_url'])) { - $parse_url = parse_url($stapi['stream_url']); - $response = RadioMetadata::fetchUrlData($parse_url['scheme'] . '://' . $parse_url['host'] . ':' . $parse_url['port'] . '/7.html'); - } - return new DataResponse($response); - - } catch (BusinessLayerException $ex) { - return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage()); - } - } - /** * get radio metadata from stream * @@ -242,7 +219,7 @@ public function getRadioStreamData(int $id) { if (isset($stapi['stream_url'])) { $response = RadioMetadata::fetchStreamData($stapi['stream_url'], 1, 1); } - return new DataResponse($response); + return new DataResponse([ 'title' => $response ]); } catch (BusinessLayerException $ex) { return new ErrorResponse(Http::STATUS_NOT_FOUND, $ex->getMessage()); diff --git a/lib/Utility/RadioMetadata.php b/lib/Utility/RadioMetadata.php index 63cac5375..8aa24ac76 100644 --- a/lib/Utility/RadioMetadata.php +++ b/lib/Utility/RadioMetadata.php @@ -12,6 +12,8 @@ namespace OCA\Music\Utility; +use OCA\Music\Utility\Util; + /** * MetaData radio utility functions */ @@ -41,6 +43,7 @@ private static function parseStreamUrl($url) { $ret['port'] = 443; } + $ret['scheme'] = $parse_url['scheme']; $ret['hostname'] = $parse_url['host']; $ret['pathname'] = $parse_url['path']; @@ -49,9 +52,9 @@ private static function parseStreamUrl($url) { } if ($parse_url['scheme'] == "https") { - $ret['sockadd'] = "ssl://" . $ret['hostname']; + $ret['sockAddress'] = "ssl://" . $ret['hostname']; } else { - $ret['sockadd'] = $ret['hostname']; + $ret['sockAddress'] = $ret['hostname']; } return $ret; @@ -59,21 +62,26 @@ private static function parseStreamUrl($url) { public static function fetchUrlData($url) : array { + $title = ""; $content = \file_get_contents($url); list($version, $status_code, $msg) = explode(' ', $http_response_header[0], 3); - return [$content, $status_code, $msg]; + if ($status_code == 200) { + $data = explode(',', $content); + $title = $data[6]; + } + return $title; } public static function fetchStreamData($url, $maxattempts, $maxredirect) { $timeout = 10; $streamTitle = ""; $pUrl = self::parseStreamUrl($url); - if (($pUrl['sockadd']) && ($pUrl['port'])) { - $fp = fsockopen($pUrl['sockadd'], $pUrl['port'], $errno, $errstr, $timeout); + if (($pUrl['sockAddress']) && ($pUrl['port'])) { + $fp = fsockopen($pUrl['sockAddress'], $pUrl['port'], $errno, $errstr, $timeout); if ($fp != false) { $out = "GET " . $pUrl['pathname'] . " HTTP/1.1\r\n"; $out .= "Host: ". $pUrl['hostname'] . "\r\n"; - $out .= "Accept: */*\r\n"; /* test */ + $out .= "Accept: */*\r\n"; $out .= "User-Agent: OCMusic/1.52\r\n"; $out .= "Icy-MetaData: 1\r\n"; $out .= "Connection: Close\r\n\r\n"; @@ -83,7 +91,7 @@ public static function fetchStreamData($url, $maxattempts, $maxredirect) { $header = fread($fp, 1024); $headers = explode("\n", $header); - if (strstr($headers[0], "200 OK") !== false) { + if (strpos($headers[0], "200 OK") !== false) { $interval = 0; $line = self::findStr($headers, "icy-metaint:"); if ($line) { @@ -102,17 +110,16 @@ public static function fetchStreamData($url, $maxattempts, $maxredirect) { $metadatas = explode(';', fread($fp, $meta_length)); $metadata = self::findStr($metadatas, "StreamTitle"); if ($metadata) { - $streamTitle = trim(explode('=', $metadata)[1], "'"); - if (strlen($streamTitle) > 256) { - $streamTitle = ""; - } + $streamTitle = Util::truncate(trim(explode('=', $metadata)[1], "'"), 256); break; } } $attempts++; } + } else { + $streamTitle = RadioMetadata::fetchUrlData($pUrl['scheme'] . '://' . $pUrl['hostname'] . ':' . $pUrl['port'] . '/7.html'); } - } else if (($maxredirect>0)&&(strstr($headers[0], "302 Found") !== false)) { + } else if (($maxredirect>0)&&(strpos($headers[0], "302 Found") !== false)) { $value = self::findStr($headers, "Location:"); if ($value) { $location = trim(substr($value, 10), "\r"); From a9b160ed78a477a43fd1c3eae6b935b30355ba97 Mon Sep 17 00:00:00 2001 From: Moahmed-Ismail MEJRI Date: Tue, 28 Jun 2022 19:32:14 +0200 Subject: [PATCH 6/6] Update small change for return format and get stream url --- lib/Controller/RadioApiController.php | 5 +---- lib/Utility/RadioMetadata.php | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/Controller/RadioApiController.php b/lib/Controller/RadioApiController.php index f8ffca6a5..0cffa430b 100644 --- a/lib/Controller/RadioApiController.php +++ b/lib/Controller/RadioApiController.php @@ -215,10 +215,7 @@ public function getRadioStreamData(int $id) { try { $response = ""; $station = $this->businessLayer->find($id, $this->userId); - $stapi = $station->toAPI(); - if (isset($stapi['stream_url'])) { - $response = RadioMetadata::fetchStreamData($stapi['stream_url'], 1, 1); - } + $response = RadioMetadata::fetchStreamData($station->getStreamUrl(), 1, 1); return new DataResponse([ 'title' => $response ]); } catch (BusinessLayerException $ex) { diff --git a/lib/Utility/RadioMetadata.php b/lib/Utility/RadioMetadata.php index 8aa24ac76..5893deedb 100644 --- a/lib/Utility/RadioMetadata.php +++ b/lib/Utility/RadioMetadata.php @@ -61,7 +61,7 @@ private static function parseStreamUrl($url) { } - public static function fetchUrlData($url) : array { + public static function fetchUrlData($url) { $title = ""; $content = \file_get_contents($url); list($version, $status_code, $msg) = explode(' ', $http_response_header[0], 3);