RSS_FEED_FILE_NAME = '.index.php' RSS_FEED_INFO_EXTENSION = 'info' RSS_FEED_SHOW_INDEX = 'index' def RSS_FEED_CODE(): return r'''title; $feed_description=$info->description; $feed_logo=$info->image; $feed_link=$info->link; } ?> '; // use php to output the " <?php echo $feed_name; ?> <?php echo $feed_name; ?> \n"; echo " ".$info->title."\n"; echo " ".$info->description."\n"; echo " ".$info->guid."\n"; echo " ".$base_url.$info->filename."\n"; echo " filename."\" length=\"".$info->size."\" type=\"".$info->mimetype."\" />\n"; echo " filename."\" medium=\"".$info->medium."\" duration=\"".$info->duration."\" type=\"".$info->mimetype."\" />\n"; echo " ".$info->date."\n"; echo " ".$info->duration."\n"; echo " \n"; } } } } ?> ''' def RSS_INDEX_CODE(bin_path, config_name): return r''' [options...]".PHP_EOL; echo " commands: ".implode("|",CLI_COMMANDS).PHP_EOL; die(); } $settings=read(dirname(__FILE__)."/".SETTINGS_INFO); $feeds=read(dirname(__FILE__)."/".FEEDS_INFO); $SPODCAST_CONFIG=dirname(__FILE__)."/".SPODCAST_CONFIG; $command=$argv[1]; if($command == "refresh") { foreach ($feeds as $url => ["title"=>$title,"directory"=>$directory,"max"=>$max,"keep"=>$keep]) { if ($max > 0) { $output = add_feed($url, $max, true); echo(implode(PHP_EOL, $output)); } $episodes=get_episodes($directory); if(count($episodes) > $keep) { $to_delete=array_splice($episodes, $keep); foreach ($to_delete as $episode) { system("rm -f ".escapeshellarg($directory."/".$episode['filename'])." 2>&1"); system("rm -f ".escapeshellarg($directory."/".$episode['filename']).".".INFO." 2>&1"); } } } } die(); } $feeds=get_feeds(dirname(__FILE__)); $settings=get_settings(); $ERROR_MESSAGE=null; $ERROR_DETAILS=null; function get_feeds($dir) { $spodcast_url=(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http")."://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; foreach(glob($dir."/*/".SHOW_INFO) as $show_info) { $episodes=get_episodes(dirname($show_info)); $json=file_get_contents($show_info); $info=json_decode($json); $feeds[$info->link]['title']=$info->title; $feeds[$info->link]['image']=$info->image; $feeds[$info->link]['episodes']=count($episodes); $feeds[$info->link]['last']=date("Y-m-d",strtotime($episodes[0]['date'])); $feeds[$info->link]['directory']=dirname($show_info); $feeds[$info->link]['max']=$info->max ?? 2; $feeds[$info->link]['keep']=$info->keep ?? 5; $feeds[$info->link]['feed']=$spodcast_url.basename(dirname($show_info)); } uasort($feeds, fn ($a, $b) => strnatcmp($a['title'], $b['title'])); store($feeds, FEEDS_INFO); return $feeds; } function get_episodes($dir) { foreach(glob($dir."/*.".INFO) as $episode_info) { if(basename($episode_info) == SHOW_INFO) { continue; } $json=file_get_contents($episode_info); $info=json_decode($json); $episodes[]=["filename"=>$info->filename,"date"=>$info->date,"title"=>$info->title]; } usort($episodes, fn ($a, $b) => strtotime($b["date"]) - strtotime($a["date"])); return $episodes; } function get_settings() { $settings=read(SETTINGS_INFO); $spodcast_url=(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http")."://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; $settings['spodcast_url']=$settings['spodcast_url'] ?? $spodcast_url; $settings['update_start']=$settings['update_start'] ?? 0; $settings['update_rate']=$settings['update_rate'] ?? 1; $settings['update_enabled']=$settings['update_enabled'] ?? false; store($settings, SETTINGS_INFO); return $settings; } function get(&$var, $default=null) { return isset($var) ? $var : $default; } function read($file) { if(file_exists($file)) { $json=file_get_contents($file); $info=json_decode($json, true); } else { $info=[]; } return $info; } function store($info, $file) { $f = fopen($file,'w'); fwrite($f, json_encode($info)); fclose($f); } function cron_signature($crontab, $CRON_SIGNATURE) { $index = 0; foreach ($crontab as $line) { if (strpos($line, $CRON_SIGNATURE) !== false) { return $index; } $index++; } return NOT_FOUND; } function debug($var) { ob_start(); var_dump($var); error_log(ob_get_clean()); } function submit_crontab($crontab) { $tempfile=system("mktemp"); file_put_contents($tempfile, implode(PHP_EOL,$crontab)); $command="crontab ".$tempfile; exec($command); unlink($tempfile); } function get_range($start, $rate) { for ($i=0; $i < $rate; $i++) { $arr[]=(($start%(24/$rate))+($i*(24/$rate)))%24; } return implode(",", $arr); } function update_scheduler($enable, $start, $rate) { $CRON_SIGNATURE="SPODCAST:".dirname(__FILE__); $crontab=null; $retval=null; exec("crontab -l", $crontab, $retval); if ($retval == 0) { $index=cron_signature($crontab, $CRON_SIGNATURE); if ($enable == true) { if($index !== NOT_FOUND) { array_splice($crontab, $index, 1); } $crontab[]=sprintf("%d %s * * * php %s refresh # %s".PHP_EOL, rand(5,25), get_range($start, $rate), __FILE__, $CRON_SIGNATURE); submit_crontab($crontab); } else { if ($index !== NOT_FOUND) { array_splice($crontab, $index, 1); $crontab[count($crontab)-1]=rtrim($crontab[count($crontab)-1]).PHP_EOL; submit_crontab($crontab); } } } } function login($username, $password, $return_output=false) { $output = null; $retval = null; $tempfile=system("mktemp"); $SPODCAST_CONFIG=dirname(__FILE__)."/".SPODCAST_CONFIG; file_put_contents($tempfile, "$username $password"); $command=SPODCAST." -c ".$SPODCAST_CONFIG." --log-level ".LOG_LEVEL." -l ".$tempfile." 2>&1"; exec($command, $output, $retval); unlink($tempfile); if ($retval > 0 || $return_output) { return $output; } return SUCCESS; } function add_feed($url, $max, $return_output=false) { $output = null; $retval = null; $SPODCAST_CONFIG=dirname(__FILE__)."/".SPODCAST_CONFIG; $command=SPODCAST." -c ".$SPODCAST_CONFIG." --max-episodes ".$max." ".escapeshellarg($url)." 2>&1"; exec($command, $output, $retval); if ($retval > 0 || $return_output) { return $output; } return SUCCESS; } function delete_feed($url, $return_output=false) { $output = null; $retval = null; $feeds=read(FEEDS_INFO); $feed_dir=$feeds[$url]['directory']; $command="rm -rf ".$feed_dir." 2>&1"; exec($command, $output, $retval); if ($retval > 0 || $return_output) { return $output; } return SUCCESS; } function update_show($url, $field, $value) { if (array_search($field, UPDATEABLE) === false) { return ["$field is not an updateable field"]; } else { $feeds=read(FEEDS_INFO); $show_dir=$feeds[$url]['directory']; $show=read($show_dir."/".SHOW_INFO); $show[$field]=(int) $value; store($show, $show_dir."/".SHOW_INFO); return SUCCESS; } } function show_error($message, $details) { header("Location: ./?action=error&message=".urlencode($message)."&details=".urlencode(implode(PHP_EOL,$details))); die(); } switch(get($_GET['action'])) { case 'refresh': case 'new': $url = get($_GET['url']); $result = add_feed($url, MAX_EPISODES); if ($result !== SUCCESS) { show_error("Add/refresh feed failed", $result); } header("Location: ."); die(); case 'delete': $url = get($_GET['url']); $result = delete_feed($url); if ($result !== SUCCESS) { show_error("Delete feed failed", $result); } header("Location: ."); die(); case 'update': $url = get($_GET['url']); $field = get($_GET['field']); $value = get($_GET['value']); $result=update_show($url, $field, $value); if ($result !== SUCCESS) { show_error("Update failed", $result); } header("Location: ."); die(); case 'login': $username = get($_GET['username']); $password = get($_GET['password']); $result = login($username, $password); if ($result !== SUCCESS) { show_error("Login failed",$result); } header("Location: ."); die(); case 'schedule': $enable = (get($_GET['enable']) == "true" ? true : false); $start = (int) get($_GET['start']); $rate = (int) get($_GET['rate']); $settings['update_enabled'] = $enable; $settings['update_start'] = $start; $settings['update_rate'] = $rate; store($settings, SETTINGS_INFO); update_scheduler($enable, $start, $rate); header("Location: ."); die(); case 'error': $ERROR_MESSAGE = get($_GET['message']); $ERROR_DETAILS = get($_GET['details']); default: break; } $UPDATE_ENABLED=$settings['update_enabled']; $UPDATE_START=$settings['update_start']; $UPDATE_RATE=$settings['update_rate']; ?> Spodcast feed manager
["title"=>$title,"image"=>$image,"episodes"=>$episodes,"last"=>$last,"max"=>$max,"keep"=>$keep,"feed"=>$feed]): ?>
 ()
  
sync 
keep  
delete
refresh
'''