Skip to content

Commit

Permalink
Merge pull request #40 from KIMB-technologies/categories-31
Browse files Browse the repository at this point in the history
Categories (Issue #31)
  • Loading branch information
kimbtech authored Dec 23, 2023
2 parents 43fc914 + 5057aec commit 1b29508
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 53 deletions.
57 changes: 35 additions & 22 deletions php/classes/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public function __construct(int $id, bool $preload = false ){
$this->redis = new Cache('radios_podcasts.' . $this->id );
$this->own_streams = new OwnStreams();

if( !$this->redis->keyExists( 'categories' ) || $preload ){
if( !$this->redis->keyExists( 'types' ) || $preload ){
$this->preloadAll();
if( !$this->redis->keyExists( 'categories' ) ){
if( !$this->redis->keyExists( 'types' ) ){
$this->constructTable();
}
}
Expand Down Expand Up @@ -72,61 +72,74 @@ private function constructTable() : void {

// generate Table
$this->table = array();
$this->table['categories'] = array(
$this->table['types'] = array(
1 => 'Radio',
3 => 'Podcast'
);
$this->table['items'] = array();

// add radio, podcasts
$this->addCategoryToTable( 1, $this->radio );
$this->addCategoryToTable( 3, $this->podcasts );
$this->addTypeToTable( 1, $this->radio );
$this->addTypeToTable( 3, $this->podcasts );

// add "own streams"
if( Config::STREAM_JSON ){
$this->table['categories'][2] = 'Stream';
$this->addCategoryToTable( 2, $this->own_streams->getStreams() );
$this->table['types'][2] = 'Stream';
$this->addTypeToTable( 2, $this->own_streams->getStreams() );
}

// save in redis
// if using own stream, we need to give a ttl, else the system won't reload the list of own streams
$this->redis->arraySet( 'categories', $this->table['categories'], Config::STREAM_JSON ? Config::CACHE_EXPIRE : 0 );
$this->redis->arraySet( 'types', $this->table['types'], Config::STREAM_JSON ? Config::CACHE_EXPIRE : 0 );
$this->redis->arraySet( 'items', $this->table['items'], Config::STREAM_JSON ? Config::CACHE_EXPIRE : 0 );
}

/**
* Add a category to table
* Add a type to table
* Helper for constructTable
*/
private function addCategoryToTable( int $cid, array $data ) : void{
private function addTypeToTable( int $tid, array $data ) : void{
foreach( $data as $id => $d ){
$idd = $id + 1000 * $cid;
$idd = $id + 1000 * $tid;
$this->table['items'][$idd] = $d;
$this->table['items'][$idd]['cid'] = $cid;
if( $id >= 999 ){ // only 999 per cat!!
$this->table['items'][$idd]['tid'] = $tid;
if( $id >= 999 ){ // only 999 per type!!
break;
}
}
}

/**
* Returns List of category, indexed by catID
* Returns List of type, indexed by typeID
*/
public function getCategories() : array {
return $this->redis->arrayGet('categories');
public function getTypes() : array {
return $this->redis->arrayGet('types');
}

/**
* Returns list of items in this cat, indexed by id!
* Returns List of categories for a typeID
*/
public function getListOfItems( int $cid ) : array {
return array_filter( $this->redis->arrayGet('items'), function($i) use (&$cid){
return $cid == $i['cid'];
});
public function getCategories(int $tid) : array {
$cats = array_filter(
$this->redis->arrayGet('items'),
fn($i) => $tid == $i['tid'] && !empty($i["category"])
);
return array_unique(array_map(fn($i) => $i["category"], $cats));
}

/**
* Returns list of items in this type, indexed by id!
* Filter for a category or set "null" to return all categories
*/
public function getListOfItems( int $tid, ?string $cat = null ) : array {
return array_filter(
$this->redis->arrayGet('items'),
fn($i) => $tid == $i['tid'] && ( (is_null($cat) && empty($i['category'])) || $cat == $i['category'])
);
}

/**
* Get data of one item by his id.
* Get data of one item by its id.
*/
public function getById( int $id ) : array {
if( !$this->redis->arrayKeyExists('items', $id) ){
Expand Down
3 changes: 3 additions & 0 deletions php/classes/ImExport.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ private function validateList(array $content) : bool {
case "desc":
$ok &= Inner::filterName($v) === $v;
break;
case "category":
$ok &= ($v === "" || Inner::filterCategory($v) === $v);
break;
case "logo":
case "url":
$ok &= Inner::filterURL($v) === $v;
Expand Down
36 changes: 35 additions & 1 deletion php/classes/Inner.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function checkPost() : void {
'desc' => self::filterName( $_POST['desc'][$id] ),
'proxy' => isset($_POST['proxy'][$id]) && $_POST['proxy'][$id] == 'yes',
'type' => !empty($_POST['type'][$id]) && $_POST['type'][$id] == 'nc' ? 'nc' : 'radio',
'category' => $this->getCategory($id)
);
}
}
Expand All @@ -56,7 +57,8 @@ public function checkPost() : void {
'url' => self::filterURL( $_POST['url'][$id] ),
'finalurl' => isset($_POST['finalurl'][$id]) && $_POST['finalurl'][$id] == 'yes',
'proxy' => isset($_POST['proxy'][$id]) && $_POST['proxy'][$id] == 'yes',
'type' => isset($_POST['type'][$id]) && $_POST['type'][$id] == 'nc' ? 'nc' : 'rss'
'type' => isset($_POST['type'][$id]) && $_POST['type'][$id] == 'nc' ? 'nc' : 'rss',
'category' => $this->getCategory($id)
);
}
}
Expand All @@ -65,6 +67,7 @@ public function checkPost() : void {
}

public function radioForm() : void {
$categories = array_filter(array_unique(array_column($this->radios, 'category')));
$radios = array();
$count = 0;
foreach($this->radios as $key => $radio ){
Expand All @@ -81,15 +84,22 @@ public function radioForm() : void {
"TYPE_NC" => $radio['type'] == 'nc' ? 'checked="checked"' : '',
"LOGO" => $radio['logo'],
"DESC" => $radio['desc'],
"CAT_OPTIONS" => array_reduce(
$categories,
fn($c, $i) => $c.'<option value="'.$i.'" '.($i === $radio['category'] ? 'selected' : '').'>'.$i.'</option>',
''
)
);

$count++;
}
$this->template->setMultipleContent('RadioStations', $radios);
$this->template->setContent('RADIO_COUNT', $count);
$this->template->setContent('RADIO_OPTIONS', array_reduce($categories, fn($c, $i) => $c.'<option value="'.$i.'">'.$i.'</option>', '' ));
}

public function podcastForm() : void {
$categories = array_filter(array_unique(array_column($this->podcasts, 'category')));
$podcasts = array();
$count = 0;
foreach($this->podcasts as $key => $pod ){
Expand All @@ -106,12 +116,18 @@ public function podcastForm() : void {
"ENDURL_NO" => !$pod['finalurl'] ? 'checked="checked"' : '',
"PROXY_YES" => $pod['proxy'] ? 'checked="checked"' : '',
"PROXY_NO" => !$pod['proxy'] ? 'checked="checked"' : '',
"CAT_OPTIONS" => array_reduce(
$categories,
fn($c, $i) => $c.'<option value="'.$i.'" '.($i === $pod['category'] ? 'selected' : '').'>'.$i.'</option>',
''
)
);

$count++;
}
$this->template->setMultipleContent('Podcasts', $podcasts);
$this->template->setContent('PODCAST_COUNT', $count);
$this->template->setContent('PODCAST_OPTIONS', array_reduce($categories, fn($c, $i) => $c.'<option value="'.$i.'">'.$i.'</option>', '' ));
}

public function outputMessages() : void {
Expand All @@ -130,5 +146,23 @@ public static function filterName(string $name): string{
$name = substr( preg_replace( '/[^0-9A-Za-z \.\-\_\,\&\;\/\(\)]/', '', $name ), 0, 200 );
return empty($name) ? 'empty' : $name;
}

public static function filterCategory(string $cat) : string{
$cat = self::filterName($cat);
$cat = preg_replace( '/[^0-9A-Za-z \-\,]/', '', $cat );
return empty($cat) ? 'empty' : $cat;
}

private function getCategory(int $post_id): string {
if($_POST['cat'][$post_id] === '*root') {
return "";
}
else {
return self::filterCategory(
$_POST['cat'][$post_id] === '*new' ?
$_POST['new_cat'][$post_id] : $_POST['cat'][$post_id]
);
}
}
}
?>
4 changes: 2 additions & 2 deletions php/classes/PodcastLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public static function getPodcastByUrl( string $url, bool $nextcloud ) : array {
*/
public static function getEpisodeData( int $id, int $eid, Data $data ) : array{
$pod = $data->getById( $id );
if( $pod['cid'] !== 3 ){
if( $pod['tid'] !== 3 ){
return array();
}
$poddata = self::getPodcastByUrl( $pod['url'], !empty($pod['type']) && $pod['type'] == 'nc' );
Expand All @@ -167,7 +167,7 @@ public static function getEpisodeData( int $id, int $eid, Data $data ) : array{
*/
public static function getPodcastDataById( int $id, Data $data ) : array {
$pod = $data->getById( $id );
if( $pod['cid'] !== 3 ){
if( $pod['tid'] !== 3 ){
return array();
}
return self::getPodcastByUrl( $pod['url'], !empty($pod['type']) && $pod['type'] == 'nc' );
Expand Down
74 changes: 49 additions & 25 deletions php/classes/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,33 @@ public function handleGet(string $uri) : void {
else if( !empty($_GET['toggleUnRead']) && is_string($_GET['toggleUnRead']) ){
$this->out->addDir('TOGGLE-UN-READ-' . $this->unread->toggleById($_GET['toggleUnRead'], $this->data), '');
}
// list of stations or podcasts depending on category
else if( $uri == '/cat' && !empty( $_GET['cid'] ) ){
// list of stations or podcasts (= the type) and possibly selecting a category
else if( $uri == '/list' && !empty( $_GET['tid'] ) ){
$this->out->prevUrl(Config::RADIO_DOMAIN . '?go=initial');

$cid = $_GET['cid'];
if( is_numeric($cid) && array_key_exists($cid, $this->data->getCategories()) ){
if( $cid == 3 && isset($_GET['id']) && preg_match('/^\d+$/', $_GET['id']) === 1 ){
$tid = $_GET['tid'];
if( is_numeric($tid) && array_key_exists($tid, $this->data->getTypes()) ){
// list a single podcast
if( $tid == 3 && isset($_GET['id']) && preg_match('/^\d+$/', $_GET['id']) === 1 ){
$this->listPodcast(intval($_GET['id']));
}
// list items of type, possibly filter by category
else{
$this->listDirectory(intval($cid));
$this->listDirectory(
intval($tid),
isset($_GET['cat']) && preg_match( '/^[0-9A-Za-z \-\,]{0,200}$/', $_GET['cat'] ) === 1 ? $_GET['cat'] : null
);
}
}
else {
$this->out->addDir( 'No item found for this cID!', Config::RADIO_DOMAIN . '?go=initial');
$this->out->addDir( 'No item found for this tID!', Config::RADIO_DOMAIN . '?go=initial');
}
}
// list of categories (startpage)
// list of types (startpage)
else{
// add local categories
foreach( $this->data->getCategories() as $cid => $name ){
$this->out->addDir( $name, Config::RADIO_DOMAIN . 'cat?cid=' . $cid );
// add local types
foreach( $this->data->getTypes() as $tid => $name ){
$this->out->addDir( $name, Config::RADIO_DOMAIN . 'list?tid=' . $tid );
}
// add RadioBrowser
$this->out->addDir( 'Radio-Browser', Config::RADIO_DOMAIN . 'radio-browser?by=none&term=none' );
Expand All @@ -107,8 +112,8 @@ public function handleGet(string $uri) : void {
}
}

private function listPodcastEpisode(int $id, int $eid, int $cid = 3) : void {
$this->out->prevUrl(Config::RADIO_DOMAIN . 'cat?cid='.$cid.'&id='.$id);
private function listPodcastEpisode(int $id, int $eid, int $tid = 3) : void {
$this->out->prevUrl(Config::RADIO_DOMAIN . 'list?tid='.$tid.'&id='.$id);

$ed = PodcastLoader::getEpisodeData( $id, $eid, $this->data );
if( $ed != array() ){
Expand All @@ -124,10 +129,14 @@ private function listPodcastEpisode(int $id, int $eid, int $cid = 3) : void {
}
}

private function listPlayItem(int $id, int $cid = 1) : void {
$this->out->prevUrl(Config::RADIO_DOMAIN . 'cat?cid=' . $cid );

private function listPlayItem(int $id, int $tid = 1) : void {
$sta = $this->data->getById( $id );

$this->out->prevUrl(
Config::RADIO_DOMAIN . 'list?tid=' . $tid .
(empty($sta['category']) ? '' : '&cat=' . rawurlencode($sta['category']))
);

if( $sta !== array() ){
// radio station or stream with "live" == true
if( !isset($sta["live"]) || $sta["live"] ){
Expand All @@ -153,11 +162,16 @@ private function listPlayItem(int $id, int $cid = 1) : void {
}

private function listPodcast(int $id) : void {
$this->out->prevUrl(Config::RADIO_DOMAIN . 'cat?cid=3');
$this->unread->searchItem($id);

$pod = $this->data->getById($id);
$this->out->prevUrl(
Config::RADIO_DOMAIN . 'list?tid=3' .
(empty($pod['category']) ? '' : '&cat=' . rawurlencode($pod['category']))
);

$pd = PodcastLoader::getPodcastDataById( $id, $this->data );

foreach( $pd['episodes'] as $eid => $e ){
$this->out->addEpisode(
$id, $eid,
Expand All @@ -171,31 +185,41 @@ private function listPodcast(int $id) : void {

}

private function listDirectory(int $cid) : void {
foreach( $this->data->getListOfItems( $cid ) as $id => $item ){
if($item['cid'] == 1 || ($item['cid'] == 2 && $item['live'])){ // radio station, or live "own stream"
private function listDirectory(int $tid, ?string $cat = null) : void {
// first add categories if in "root" folder of type
if(is_null($cat)){
foreach( $this->data->getCategories( $tid ) as $category ){
$this->out->addDir( $category, Config::RADIO_DOMAIN . 'list?tid=' . $tid . '&cat=' . rawurlencode($category) );
}
}
else{
$this->out->prevUrl(Config::RADIO_DOMAIN . 'list?tid=' . $tid);
}

// then add items
foreach( $this->data->getListOfItems( $tid, $cat ) as $id => $item ){
if($item['tid'] == 1 || ($item['tid'] == 2 && $item['live'])){ // radio station, or live "own stream"
$this->out->addStation(
$id,
$item['name'],
$this->data->getStationURL($id, $this->radioid->getMac()),
true
);
}
else if($item['cid'] == 3){ // podcast
else if($item['tid'] == 3){ // podcast
$this->out->addPodcast(
$id,
$item['name'],
Config::RADIO_DOMAIN . 'cat?cid=' . $cid . '&id=' . $id
Config::RADIO_DOMAIN . 'list?tid=' . $tid . '&id=' . $id
);
}
else if ($item['cid'] == 2 && !$item['live']) { // file based "own stream"
else if ($item['tid'] == 2 && !$item['live']) { // file based "own stream"
$this->out->addEpisode(
$id, null,
$item['name'], $item['name'],
$this->data->getStationURL($id, $this->radioid->getMac())
);
}

}
}
}
Expand Down
8 changes: 6 additions & 2 deletions php/classes/templates/list.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"%%LOGIN_CODE%%" : "",
"%%RADIO_COUNT%%" : "",
"%%PODCAST_COUNT%%" : "",
"%%RADIO_OPTIONS%%" : "",
"%%PODCAST_OPTIONS%%" : "",
"multiples" : {
"RadioStations" : {
"%%ID%%" : "",
Expand All @@ -16,7 +18,8 @@
"%%TYPE_RADIO%%" : "",
"%%TYPE_NC%%" : "",
"%%LOGO%%" : "",
"%%DESC%%" : ""
"%%DESC%%" : "",
"%%CAT_OPTIONS%%" : ""
},
"Podcasts" : {
"%%ID%%" : "",
Expand All @@ -28,7 +31,8 @@
"%%ENDURL_YES%%" : "",
"%%ENDURL_NO%%" : "",
"%%PROXY_YES%%" : "",
"%%PROXY_NO%%" : ""
"%%PROXY_NO%%" : "",
"%%CAT_OPTIONS%%" : ""
}
}
}
Loading

0 comments on commit 1b29508

Please sign in to comment.