Plugin Directory

Changeset 3415875


Ignore:
Timestamp:
12/09/2025 11:21:08 PM (4 months ago)
Author:
razorfrog
Message:

Spinitron Player v1.0.9

Location:
spinitron-player
Files:
14 added
6 edited

Legend:

Unmodified
Added
Removed
  • spinitron-player/trunk/ajax/ajax-handler-today.php

    r3278401 r3415875  
    11<?php
    22
    3 if (!defined('ABSPATH')) exit; // Exit if accessed directly
     3if ( ! defined( 'ABSPATH' ) ) {
     4    exit; // Exit if accessed directly
     5}
    46
    57/**
     
    79 * @return void
    810 */
    9 function fetch_spinitron_show_today_callback() {
    10         // Prevent browser and server-side caching
    11         header("Expires: 0");
    12         header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
    13         header("Pragma: no-cache");
    14         header("Content-Type: text/html; charset=utf-8");
     11function spinitron_player_fetch_spinitron_show_today_callback() {
     12    // Prevent browser and server-side caching
     13    header( 'Expires: 0' );
     14    header( 'Cache-Control: no-store, no-cache, must-revalidate, max-age=0' );
     15    header( 'Pragma: no-cache' );
     16    header( 'Content-Type: text/html; charset=utf-8' );
    1517
    16         // Clear any output buffers that might interfere
    17         if (ob_get_length()) {
    18                 ob_clean();
     18    // Clear any output buffers that might interfere
     19    if ( ob_get_length() ) {
     20        ob_clean();
     21    }
     22
     23    require plugin_dir_path( __FILE__ ) . '../app/spinitron-get-client.php';
     24
     25    global $spinitron_player_client;
     26
     27    // Retrieve plugin options
     28    $options              = get_option( 'spinitron_player_options' );
     29    $separate_time_dj     = isset( $options['spinitron_player_field_separate_time_dj'] ) ? $options['spinitron_player_field_separate_time_dj'] : 0;
     30    $duplicate_show_image = isset( $options['spinitron_player_field_duplicate_show_image'] ) ? $options['spinitron_player_field_duplicate_show_image'] : 0;
     31
     32    // Ensure the fallback image is set, since it's required
     33    $fallback_image = '';
     34    if ( isset( $options['spinitron_player_field_image_fallback'] ) && ! empty( $options['spinitron_player_field_image_fallback'] ) ) {
     35        $fallback_image = esc_url( $options['spinitron_player_field_image_fallback'] );
     36    }
     37
     38    // Try to get the transient
     39    $shows = get_transient( 'spinitron_show_today' );
     40
     41    if ( false === $shows ) {
     42        // If the transient doesn't exist, fetch from API
     43        $shows = $spinitron_player_client->search(
     44            'shows',
     45            array(
     46                'count'      => 1,
     47                'cache_bust' => time(),
     48            )
     49        );
     50
     51        if ( empty( $shows['items'] ) ) {
     52            echo '<p>No shows found. Please check the Spinitron API for available shows.</p>';
     53            wp_die();
    1954        }
    2055
    21         require plugin_dir_path(__FILE__) . '../app/spinitron-get-client.php';
     56        // Calculate the number of seconds until the next multiple of 5 minutes
     57        $current_time    = time();
     58        $next_cache_time = ceil( $current_time / 300 ) * 300; // 300 seconds = 5 minutes
     59        $expiration      = $next_cache_time - $current_time;
    2260
    23         global $client;
     61        // Set the transient
     62        set_transient( 'spinitron_show_today', $shows, $expiration );
     63    }
    2464
    25         // Retrieve plugin options
    26         $options = get_option('spinitron_player_options');
    27         $separate_time_dj = isset($options['spinitron_player_field_separate_time_dj']) ? $options['spinitron_player_field_separate_time_dj'] : 0;
    28         $duplicate_show_image = isset($options['spinitron_player_field_duplicate_show_image']) ? $options['spinitron_player_field_duplicate_show_image'] : 0;
     65    ob_start();
    2966
    30         // Ensure the fallback image is set, since it's required
    31         $fallback_image = '';
    32         if (isset($options['spinitron_player_field_image_fallback']) && !empty($options['spinitron_player_field_image_fallback'])) {
    33                 $fallback_image = esc_url($options['spinitron_player_field_image_fallback']);
     67    foreach ( $shows['items'] as $show ) {
     68        $timezone    = isset( $show['timezone'] ) ? $show['timezone'] : 'America/Los_Angeles';
     69        $tz          = new DateTimeZone( $timezone );
     70        $show_title  = esc_html( $show['title'] );
     71        $show_image  = esc_url( $show['image'] );
     72        $show_start  = ( new DateTime( $show['start'] ) )->setTimezone( $tz );
     73        $show_end    = ( new DateTime( $show['end'] ) )->setTimezone( $tz );
     74        $time_now    = ( new DateTime( 'now' ) )->setTimezone( $tz );
     75        $persona_url = esc_url( $show['_links']['personas'][0]['href'] );
     76
     77        $persona_parts = explode( '/', $persona_url );
     78        $persona_id    = end( $persona_parts );
     79        $persona_array = $spinitron_player_client->fetch( 'personas', $persona_id );
     80        $show_dj       = esc_html( $persona_array['name'] );
     81
     82        // Check if the image URL is valid
     83        if ( ! empty( $show_image ) ) {
     84            $headers = @get_headers( $show_image );
     85            if ( ! $headers || false === strpos( $headers[0], '200' ) ) {
     86                $show_image = $fallback_image;
     87            }
     88        } else {
     89            $show_image = $fallback_image;
    3490        }
    3591
    36         // Try to get the transient
    37         $shows = get_transient('spinitron_show_today');
     92        $show_status = ( $show_start <= $time_now && $time_now <= $show_end ) ? 'On air' : 'Up next';
    3893
    39         if ($shows === false) {
    40                 // If the transient doesn't exist, fetch from API
    41                 $shows = $client->search('shows', array('count' => 1, 'cache_bust' => time()));
     94        echo '<div class="spinitron-player">';
    4295
    43                 if (empty($shows['items'])) {
    44                         echo '<p>No shows found. Please check the Spinitron API for available shows.</p>';
    45                         wp_die();
    46                 }
    47 
    48                 // Calculate the number of seconds until the next multiple of 5 minutes
    49                 $current_time = time();
    50                 $next_cache_time = ceil($current_time / 300) * 300; // 300 seconds = 5 minutes
    51                 $expiration = $next_cache_time - $current_time;
    52 
    53                 // Set the transient
    54                 set_transient('spinitron_show_today', $shows, $expiration);
     96        if ( $duplicate_show_image ) {
     97            echo '<img class="show-image-outter" src="' . esc_html( $show_image ) . '" alt="' . esc_attr( $show_title ) . '" />';
    5598        }
    5699
    57         ob_start();
     100        echo '<div class="show-image">
     101                    <img src="' . esc_html( $show_image ) . '" alt="' . esc_attr( $show_title ) . '" />
     102                </div>
     103                <div class="show-details">
     104                    <p class="show-status">' . esc_html( $show_status ) . '</p>
     105                    <p class="show-title">' . esc_html( $show_title ) . '</p>';
    58106
    59         foreach ($shows['items'] as $show) {
    60                 $show_title = esc_html($show['title']);
    61                 $show_image = esc_url($show['image']);
    62                 $show_start = (new DateTime($show['start']))->setTimezone(new DateTimeZone($show['timezone'] ?? 'America/Los_Angeles'));
    63                 $show_end = (new DateTime($show['end']))->setTimezone(new DateTimeZone($show['timezone'] ?? 'America/Los_Angeles'));
    64                 $time_now = (new DateTime('now'))->setTimezone(new DateTimeZone($show['timezone'] ?? 'America/Los_Angeles'));
    65 
    66                 $persona_url = esc_url($show['_links']['personas'][0]['href']);
    67                 $persona_parts = explode('/', $persona_url);
    68                 $persona_id = end($persona_parts);
    69                 $persona_array = $client->fetch('personas', $persona_id);
    70                 $show_dj = esc_html($persona_array['name']);
    71 
    72                 // Check if the image URL is valid
    73                 if (!empty($show_image)) {
    74                         $headers = @get_headers($show_image);
    75                         if (!$headers || strpos($headers[0], '200') === false) {
    76                                 $show_image = $fallback_image;
    77                         }
    78                 } else {
    79                         error_log('Show image URL is empty. Using fallback image.');
    80                         $show_image = $fallback_image;
    81                 }
    82 
    83                 $show_status = ($show_start <= $time_now && $time_now <= $show_end) ? 'On air' : 'Up next';
    84 
    85                 echo '<div class="spinitron-player">';
    86                 if ($duplicate_show_image) {
    87                         echo '<img class="show-image-outter" src="' . esc_html($show_image) . '" alt="' . esc_attr($show_title) . '" />';
    88                 }
    89 
    90                 echo '<div class="show-image">
    91                                 <img src="' . esc_html($show_image) . '" alt="' . esc_attr($show_title) . '" />
    92                             </div>
    93                             <div class="show-details">
    94                                 <p class="show-status">' . esc_html($show_status) . '</p>
    95                                 <p class="show-title">' . esc_html($show_title) . '</p>';
    96 
    97                 if ($separate_time_dj) {
    98                         echo '<p class="show-time">' . esc_html($show_start->format('g:i A')) . ' - ' . esc_html($show_end->format('g:i A')) . '</p>
    99                                     <p class="show-dj">With ' . esc_html($show_dj) . '</p>';
    100                 } else {
    101                         echo '<p class="show-time-dj">' . esc_html($show_start->format('g:i A')) . ' - ' . esc_html($show_end->format('g:i A')) . ' with ' . esc_html($show_dj) . '</p>';
    102                 }
    103 
    104                 echo '</div></div>';
     107        if ( $separate_time_dj ) {
     108            echo '<p class="show-time">' . esc_html( $show_start->format( 'g:i A' ) ) . ' - ' . esc_html( $show_end->format( 'g:i A' ) ) . '</p>
     109                        <p class="show-dj">With ' . esc_html( $show_dj ) . '</p>';
     110        } else {
     111            echo '<p class="show-time-dj">' . esc_html( $show_start->format( 'g:i A' ) ) . ' - ' . esc_html( $show_end->format( 'g:i A' ) ) . ' with ' . esc_html( $show_dj ) . '</p>';
    105112        }
    106113
    107         $output = ob_get_clean();
     114        echo '</div></div>';
     115    }
    108116
    109         echo $output;
     117    $output = ob_get_clean();
    110118
    111         wp_die(); // This is required to terminate immediately and return a proper response.
     119    // $output is composed of escaped HTML fragments above.
     120    echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     121
     122    wp_die(); // This is required to terminate immediately and return a proper response.
    112123}
    113 add_action('wp_ajax_fetch_spinitron_show_today', 'fetch_spinitron_show_today_callback');
    114 add_action('wp_ajax_nopriv_fetch_spinitron_show_today', 'fetch_spinitron_show_today_callback');
     124
     125add_action( 'wp_ajax_fetch_spinitron_show_today', 'spinitron_player_fetch_spinitron_show_today_callback' );
     126add_action( 'wp_ajax_nopriv_fetch_spinitron_show_today', 'spinitron_player_fetch_spinitron_show_today_callback' );
  • spinitron-player/trunk/app/plugin-settings.php

    r3102947 r3415875  
    88 */
    99function Spinitron_Player_Settings_init() {
    10         register_setting('spinitron_player', 'spinitron_player_options');
     10        register_setting(
     11             'spinitron_player',
     12             'spinitron_player_options',
     13             array(
     14                  'sanitize_callback' => 'spinitron_player_sanitize_options',
     15             )
     16        );
    1117
    1218        add_settings_section(
     
    8389}
    8490add_action('admin_init', 'Spinitron_Player_Settings_init');
     91
     92/**
     93 * Sanitize and validate Spinitron Player options.
     94 *
     95 * @param array $input Raw input from the settings form.
     96 * @return array Sanitized options.
     97 */
     98function spinitron_player_sanitize_options( $input ) {
     99
     100    $input   = is_array( $input ) ? $input : array();
     101    $output  = array();
     102    $options = get_option( 'spinitron_player_options', array() );
     103
     104    // API Key (text)
     105    if ( isset( $input['spinitron_player_field_api_key'] ) ) {
     106          $output['spinitron_player_field_api_key'] = sanitize_text_field(
     107                $input['spinitron_player_field_api_key']
     108          );
     109
     110          // If API key changed, clear transient cache.
     111          if (
     112                empty( $options['spinitron_player_field_api_key'] ) ||
     113                $options['spinitron_player_field_api_key'] !== $output['spinitron_player_field_api_key']
     114          ) {
     115                delete_transient( 'spinitron_show_today' );
     116          }
     117    }
     118
     119    // Image Fallback (URL)
     120    if ( isset( $input['spinitron_player_field_image_fallback'] ) ) {
     121          $output['spinitron_player_field_image_fallback'] = esc_url_raw(
     122                $input['spinitron_player_field_image_fallback']
     123          );
     124    }
     125
     126    // Stream URL (URL)
     127    if ( isset( $input['spinitron_player_field_stream_url'] ) ) {
     128          $output['spinitron_player_field_stream_url'] = esc_url_raw(
     129                $input['spinitron_player_field_stream_url']
     130          );
     131    }
     132
     133    // Separate Time & DJ (checkbox)
     134    $output['spinitron_player_field_separate_time_dj'] = ! empty( $input['spinitron_player_field_separate_time_dj'] ) ? 1 : 0;
     135
     136    // Duplicate Show Image (checkbox)
     137    $output['spinitron_player_field_duplicate_show_image'] = ! empty( $input['spinitron_player_field_duplicate_show_image'] ) ? 1 : 0;
     138
     139    return $output;
     140}
    85141
    86142/**
  • spinitron-player/trunk/app/spinitron-get-client.php

    r3102938 r3415875  
    1717 */
    1818
    19 if (!defined('ABSPATH')) exit; // Exit if accessed directly
     19if ( ! defined( 'ABSPATH' ) ) {
     20    exit; // Exit if accessed directly
     21}
    2022
    21 $spinitron_player_options = get_option('spinitron_player_options', '');
     23$spinitron_player_options = get_option( 'spinitron_player_options', '' );
    2224
    23 if (!empty($spinitron_player_options) && is_array($spinitron_player_options)) {
    24     $api_key = isset($spinitron_player_options['spinitron_player_field_api_key']) ? $spinitron_player_options['spinitron_player_field_api_key'] : '';
     25if ( ! empty( $spinitron_player_options ) && is_array( $spinitron_player_options ) ) {
    2526
    26     if (empty($api_key)) {
     27    $spinitron_api_key = isset( $spinitron_player_options['spinitron_player_field_api_key'] )
     28        ? $spinitron_player_options['spinitron_player_field_api_key']
     29        : '';
     30
     31    if ( empty( $spinitron_api_key ) ) {
    2732        echo '<p>API key is missing. Please provide a valid API key in the settings.</p>';
    2833        exit;
    2934    }
    3035
    31     if (!class_exists('SpinitronApiClient')) {
    32         include plugin_dir_path(__FILE__) . 'spinitron-api-client.php';
     36    if ( ! class_exists( 'SpinitronApiClient' ) ) {
     37        include plugin_dir_path( __FILE__ ) . 'spinitron-api-client.php';
    3338    }
    3439
    35     global $client;
    36     if (!isset($client)) {
    37         $client = new SpinitronApiClient($api_key);
     40    // Global client used throughout the plugin.
     41    global $spinitron_player_client;
     42
     43    if ( ! isset( $spinitron_player_client ) ) {
     44        $spinitron_player_client = new SpinitronApiClient( $spinitron_api_key );
    3845
    3946        // Validate API key by making a test request to the Spinitron API.
    4047        try {
    41             $test_response = $client->search('shows', array('count' => 1, 'cache_bust' => time()));
    42             if (isset($test_response['error'])) {
    43                 throw new Exception('Invalid API key');
     48            $spinitron_test_response = $spinitron_player_client->search(
     49                'shows',
     50                array(
     51                    'count'      => 1,
     52                    'cache_bust' => time(),
     53                )
     54            );
     55
     56            if ( isset( $spinitron_test_response['error'] ) ) {
     57                throw new Exception( 'Invalid API key' );
    4458            }
    45             if (empty($test_response['items'])) {
    46                 throw new Exception('No shows found');
     59
     60            if ( empty( $spinitron_test_response['items'] ) ) {
     61                throw new Exception( 'No shows found' );
    4762            }
    48         } catch (Exception $e) {
    49             if ($e->getMessage() === 'Invalid API key') {
     63        } catch ( Exception $e ) {
     64            if ( 'Invalid API key' === $e->getMessage() ) {
    5065                echo '<p>Invalid API key. Please make sure your Spinitron API key is valid.</p>';
    51             } elseif ($e->getMessage() === 'No shows found') {
     66            } elseif ( 'No shows found' === $e->getMessage() ) {
    5267                echo '<p>No shows found. Please check the Spinitron API for available shows.</p>';
    5368            } else {
  • spinitron-player/trunk/readme.txt

    r3352329 r3415875  
    22Contributors: razorfrog
    33Tags: spinitron, radio, music, player, stream
    4 Requires at least: 5.0
    5 Tested up to: 6.8.2
     4Requires at least: 5.2
     5Tested up to: 6.9
    66Requires PHP: 7.2
    7 Stable tag: 1.0.8
     7Stable tag: 1.0.9
    88License: GPLv2 or later
    9 License URI: http://www.gnu.org/licenses/gpl-2.0.html
     9License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    1111A streaming player for radio stations using Spinitron, with live data integration.
     
    4141
    4242== Changelog ==
     43
     44= 1.0.9 =
     45- Security updates
     46- Updated for WP Core compatibility
    4347
    4448= 1.0.8 =
  • spinitron-player/trunk/spinitron-player.php

    r3352329 r3415875  
    11<?php
     2
    23/**
    3  * Plugin Name: Spinitron Player
    4  * Plugin URI: https://razorfrog.com/spinitron-player/
    5  * Description: A streaming player for radio stations using Spinitron, with live data integration.
    6  * Author: Razorfrog Web Design
    7  * Version: 1.0.8
    8  * Author URI: https://razorfrog.com/
    9  * License: GPLv2 or later
    10  * Text Domain: spinitron-player
    11  * Requires at least: 6.0
    12  * Requires PHP: 7.2
    13  *
    14  * PHP version 7.2
    15  *
    16  * @category Media
    17  * @package SpinitronPlayer
     4 * Plugin Name:       Spinitron Player
     5 * Plugin URI:        https://razorfrog.com/spinitron-player/
     6 * Description:       A streaming player for radio stations using Spinitron.
     7 * Version:           1.0.9
     8 * Requires at least: 5.2
     9 * Requires PHP:      7.2
     10 * Author:            Razorfrog Web Design
     11 * Author URI:        https://razorfrog.com/
     12 * License:           GPLv2 or later
     13 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
     14 * Text Domain:       spinitron-player
    1815 */
    1916
  • spinitron-player/trunk/ui/today.php

    r3102938 r3415875  
    11<?php
    2 if (!defined('ABSPATH')) exit; // Exit if accessed directly
     2if ( ! defined( 'ABSPATH' ) ) {
     3    exit; // Exit if accessed directly
     4}
    35
    4 $options = get_option('spinitron_player_options');
    5 $fallback_image = isset($options['spinitron_player_field_image_fallback']) ? esc_url($options['spinitron_player_field_image_fallback']) : '';
    6 $separate_time_dj = isset($options['spinitron_player_field_separate_time_dj']) ? $options['spinitron_player_field_separate_time_dj'] : 0;
    7 $duplicate_show_image = isset($options['spinitron_player_field_duplicate_show_image']) ? $options['spinitron_player_field_duplicate_show_image'] : 0;
     6// Prefixed globals to satisfy coding standards.
     7$spinitron_options              = get_option( 'spinitron_player_options' );
     8$spinitron_fallback_image       = isset( $spinitron_options['spinitron_player_field_image_fallback'] ) ? $spinitron_options['spinitron_player_field_image_fallback'] : '';
     9$spinitron_separate_time_dj     = isset( $spinitron_options['spinitron_player_field_separate_time_dj'] ) ? $spinitron_options['spinitron_player_field_separate_time_dj'] : 0;
     10$spinitron_duplicate_show_image = isset( $spinitron_options['spinitron_player_field_duplicate_show_image'] ) ? $spinitron_options['spinitron_player_field_duplicate_show_image'] : 0;
    811
    912global $spinitron_instance_count;
    10 $container_id = 'spinitron-show-container-' . $spinitron_instance_count;
     13$spinitron_container_id = 'spinitron-show-container-' . $spinitron_instance_count;
    1114?>
    1215
    13 <div id="<?php echo $container_id; ?>">
    14         <div class="spinitron-player spinitron-player-loading">
    15                 <?php if ($duplicate_show_image) : ?>
    16                         <img class="show-image-outter" src="<?php echo $fallback_image; ?>" alt="Fallback radio cover image" />
    17                 <?php endif; ?>
    18                 <div class="show-image">
    19                         <img src="<?php echo $fallback_image; ?>" alt="Fallback radio cover image" />
    20                 </div>
    21                 <div class="show-details">
    22                         <p class="show-title">Loading...</p>
    23                 </div>
     16<div id="<?php echo esc_attr( $spinitron_container_id ); ?>">
     17    <div class="spinitron-player spinitron-player-loading">
     18        <?php if ( $spinitron_duplicate_show_image ) : ?>
     19            <img class="show-image-outter" src="<?php echo esc_url( $spinitron_fallback_image ); ?>" alt="Fallback radio cover image" />
     20        <?php endif; ?>
     21        <div class="show-image">
     22            <img src="<?php echo esc_url( $spinitron_fallback_image ); ?>" alt="Fallback radio cover image" />
    2423        </div>
     24        <div class="show-details">
     25            <p class="show-title">Loading...</p>
     26        </div>
     27    </div>
    2528</div>
Note: See TracChangeset for help on using the changeset viewer.