MikeNGarrett/Play-Later

View on GitHub
all.php

Summary

Maintainability
F
5 days
Test Coverage
<?php
// This is /music-bin/
if( !defined('CHECK') )
    header( 'Location: '.APPURL.'music-bin/' );

error_reporting(E_ALL);
session_start();

include_once dirname(__FILE__).'/spotify-config.php';
$spotify = new Spotify();

include_once dirname(__FILE__).'/config.php';
$database = new Database();

include_once dirname(__FILE__).'/phpfastcache.php';
$cache = phpFastCache();

$all_user_playlists = array();

// Only start a session if we have an authorized account
$logged_in = false;

if( !empty( $_SESSION['spotify_token'] ) && !empty( $_SESSION['spotify_expires'] ) ) {
    if ( $_SESSION['spotify_expires'] < time() ) {
        if( !empty($_SESSION['spotify_refresh_token']) ) {
            $spotify->session->refreshAccessToken( $_SESSION['spotify_refresh_token'] );
            $_SESSION['spotify_token'] = $spotify->session->getAccessToken();
            $_SESSION['spotify_refresh_token'] = $spotify->session->getRefreshToken();
            $_SESSION['spotify_expires'] = $spotify->session->getTokenExpiration();

            $spotify->api->setAccessToken( $_SESSION['spotify_token'] );
        } else {
            // Kill the session
            session_unset();
        }
    } else {
        $spotify->api->setAccessToken( $_SESSION['spotify_token'] );
    }
    $me = $spotify->api->me();
    if( !isset( $_SESSION['playlist'] ) && !$cache->isExisting( $me->id.'play-later-list' ) ) {
        $test = get_playlist( $me, $spotify->api );
        if( !is_array( $test ) || empty( $test['all'] ) ) {
            //error_log( "Did not find Play Later. count:". count($all_user_playlists).PHP_EOL );
            $play_later = $spotify->api->createUserPlaylist( $me->id, array( 'name' => 'Play Later' ) );
        } else {
            if( count( $test['all'] ) > 1 ) {
                $final_form = array();
                $track_record = 0;
                foreach( $test['all'] as $user_playlist ) {
                    if( $user_playlist->tracks->total > $track_record ) {
                        $final_form = $user_playlist;
                    }
                }
                $play_later = $final_form;
            } else {
                if( isset( $test['all'][0] ) ) {
                    $play_later = $test['all'][0];
                } else {
                    //error_log( "Did not find Play Later. count:". count($all_user_playlists).PHP_EOL );
                    $play_later = $spotify->api->createUserPlaylist( $me->id, array( 'name' => 'Play Later' ) );
                }
            }
        }
        $_SESSION['playlist'] = $play_later;
        $cache->set( $me->id.'play-later-list', $play_later, 60*60*24*7); // Cache for 7 days
    } else {
        $_SESSION['playlist'] = $cache->get( $me->id.'play-later-list' );
    }

    $play_later = $_SESSION['playlist'];
    $logged_in = true;

    $playlist_limits = $spotify->api->getUserPlaylist( $me->id, $play_later->id, array( 'fields' => 'tracks(total)' ) );

    $playlist_tracks_cursor = 0;
    $playlist_tracks_total = $playlist_limits->tracks->total;

    $i = 0;
    $all_albums = array();
    while( $playlist_tracks_cursor <= $playlist_tracks_total ) {
        $i++;

        $playlist = $spotify->api->getUserPlaylistTracks( $me->id, $play_later->id, array( 'fields' => 'items(track(album(id))),limit,offset', 'limit' => 100, 'offset' => $playlist_tracks_cursor ) );
        $playlist_tracks_cursor = $playlist->offset + $playlist->limit;

        foreach( $playlist->items as $album ) {
            $all_albums[$album->track->album->id] = $album->track->album->id;
        }
        if($i > 50) {
            // Kill runaway processes, limited to 5000 track playlists.
            break;
        }
    }
}

$baseDir = dirname(realpath(__FILE__));
/* $spotifyCountries = loadCountryCodesMap($baseDir.'/ISO-3166-1-alpha-2-country-codes-spotify.tsv'); */

/*
function spotifyCountriesFilter($v) {
    global $spotifyCountries;
    return isset($spotifyCountries[strtoupper($v)]);
}

if (isset($_GET['region']) && spotifyCountriesFilter($_GET['region']))
    $region = strtolower($_GET['region']);
*/

// Get rid of these if they're empty
if( isset( $_GET['date'] ) && empty( $_GET['date'] ) ) {
    unset( $_GET['date'] );
}
if( isset( $_GET['genres'] ) && empty( $_GET['genres'] ) ) {
    unset( $_GET['genres'] );
}


function get_playlist( $me, $api, $offset = 0 ) {
    $new_all_user_playlists = array();
    $all_user_playlists_playlists = $api->getUserPlaylists( $me->id, array( 'offset' => $offset ) );
    $total = $all_user_playlists_playlists->total;
    $total_pages = $total / 20;
    for($i=0;$i<=$total_pages;$i++) {
        $offset = $i*20;
        $all_user_playlists_playlists = $api->getUserPlaylists( $me->id, array( 'offset' => $offset ) );

        foreach( $all_user_playlists_playlists->items as $playlist ) {
            if( $playlist->name == 'Play Later' ) {
                $new_all_user_playlists[] = $playlist;
            }
        }
    }
    return array( 'success' => false, 'count' => $offset.' / '.$total, 'offset' => $offset, 'all' => $new_all_user_playlists );
}

function xe($s) {
    static $u = array('&', '"', '<', '>');
    static $e = array('&#38;', '&#34;', '&#60;', '&#62;');
    return str_replace($u, $e, $s);
}


$date = date('Y-m-d');

// If it's Friday, set it to today.
if( date( 'D' ) == 'Fri' ) {
    $last_friday = time();
} else {
    $last_friday = strtotime( "last Friday" );
}
$one_week = 7 * 24 * 60 * 60;
$one_day = 24 * 60 * 60;

$from_day = $last_friday;
$to_day = time();

if( isset( $_GET['date'] ) ) {
    switch($_GET['date']) {
        case 'this-week':
        default :
            $from_day = $last_friday;
            $to_day = time();
        break;
        case 'last-week':
            $from_day = $last_friday - $one_week;
            $to_day = $last_friday - $one_day;
        break;
        case 'two-weeks':
            $from_day = $last_friday - $one_week - $one_week;
            $to_day = $last_friday - $one_week - $one_day;
        break;
    }
}
$previous_date = date( "Y-m-d", $from_day );
$next_date = date( "Y-m-d", $to_day );

$limit = 100;
$list_offset = 0;
// Required for is_numeric, that jerk
if( isset( $_GET['offset'] ) ) {
    $temp_offset = $_GET['offset'];
    if( is_numeric( $temp_offset ) ) {
        if( $temp_offset >= 0 && $temp_offset < 25000 ) {
            $list_offset = intval( $temp_offset );
        }
    }
}

$where_track_count = "";
$where_release_date = "";
$where_availability = "";
$where_genres = "";
if( isset( $_GET['genres'] ) ) {
    $get_genres = $_GET['genres'];

    // Go get synonyms
    $imp_genres = implode('|', $get_genres);
    $genre_syn = $database->prepare("SELECT mega_relation,large_relation,medium_relation,low_relation FROM genres WHERE name REGEXP ".$database->quote( $imp_genres ) );
    $genre_syn->execute();
    $syns = $genre_syn->fetchAll();

    foreach( $syns as $row ) {
        foreach( $row as $key => $syn ) {
            if( !$syn )
                continue;

            switch( $key ) {
                case "mega_relation":
                    $syn_genres = unserialize( $syn );
                    $get_genres = array_merge( $get_genres, $syn_genres );
                break;
                case "large_relation":
                    $syn_genres = unserialize( $syn );
                    $get_genres = array_merge( $get_genres, $syn_genres );
                break;
                case "medium_relation":
                    $syn_genres = unserialize( $syn );
                    $get_genres = array_merge( $get_genres, $syn_genres );
                break;
                case "mega_relation":
                    $syn_genres = unserialize( $syn );
                    $get_genres = array_merge( $get_genres, $syn_genres );
                break;
            }
        }
    }
    $get_genres = array_unique($get_genres);

    $where_genres = "(";
    foreach( $get_genres as $g ) {
        $where_genres .= ' genres LIKE '.$database->quote('%"'.$g.'"%').' OR';
    }
    $where_genres = rtrim( $where_genres, ' OR' );
    $where_genres .= ")";
} else {
    if( isset( $_GET['date'] ) ) {
        $where_release_date = "WHERE ( release_date BETWEEN :lastfriday AND :thisfriday )";
    }
}

$query = $database->prepare("SELECT * FROM albums " . $where_release_date ." GROUP BY(artists) ORDER BY popularity DESC LIMIT :offset, :limit");
if( !isset( $_GET['genres'] ) && isset( $_GET['date'] ) ) {
    $query->bindParam(':lastfriday', $previous_date, PDO::PARAM_STR);
    $query->bindParam(':thisfriday', $next_date, PDO::PARAM_STR);
}
$query->bindParam(':offset', $list_offset, PDO::PARAM_INT);
$query->bindParam(':limit', $limit, PDO::PARAM_INT);
$query->execute();

// Only returns 100
// TODO: grab all rows or something and actually show an accurate count
//$album_count = $query->rowCount();
$albums = $query->fetchAll();

foreach( $albums as $key => &$album ) {
    $get_artists = maybe_unserialize( $album['artists'] );

    if( !is_array( $get_artists ) ) {
        continue;
    } else {
        $album['artists'] = $get_artists;
    }


/*
    $album['artists'] = array();

    foreach( $get_artists as &$artist ) {
        $query = $database->prepare('SELECT name FROM artists WHERE id=:id');
        $query->bindParam(':id', $artist->id, PDO::PARAM_STR);
        $query->execute();
        $artist_names = $query->fetchAll();

        $album['artists'][$artist->id] = $artist_names[0];
    }
*/
}
//unset($album);

// TODO: figure out what the hell to exactly do with these currently useless genres
/*
if( $cache->isExisting("spec_all_genres") ) {
    $select_genres = $cache->get("spec_all_genres");
} else {
    $genre_query = $database->prepare("SELECT name FROM genres");
    $genre_query->execute();

    $select_genres = array();
    while ($row = $genre_query->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT)) {
        $genre = $row[0];
        $url_genres = xe($genre);
        $selected = '';
        $count_genre_query = $database->prepare("SELECT COUNT(*) FROM albums WHERE ( genres LIKE :genre ) AND ( tracks > 3 AND tracks < 25 ) AND ( release_date BETWEEN :lastfriday AND :thisfriday )");
        // A way to check for an exact match in a serialized array
        $p_genre = '%"'.$genre.'"%';
        $count_genre_query->bindParam(':genre', $p_genre, PDO::PARAM_STR);

        if( date( 'D' ) == 'Fri' ) {
            $last_friday = date( 'Y-m-d' );
        } else {
            $last_friday = date( 'Y-m-d', strtotime( "last Friday" ) );
        }
        $today = date( 'Y-m-d' );

        $count_genre_query->bindParam(':lastfriday', $last_friday, PDO::PARAM_STR);
        $count_genre_query->bindParam(':thisfriday', $today, PDO::PARAM_STR);
        $count_genre_query->execute();

        $genre_count = $count_genre_query->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT);
        $genre_count = $genre_count[0];
/* // TODO: figure out what the hell to do here
        if( isset( $_GET['genres'] ) && in_array( $genre, $_GET['genres'] ) ) {
            $selected = ' selected';
        }
end here /
        if( $genre_count > 1 ) {
            $select_genres[$genre] = '<option value="'.$url_genres.'"'.$selected.'>'.$genre.' ('.$genre_count.')</option>';
        }
    }
    asort( $select_genres );
    $cache->set("spec_all_genres", $select_genres, 60*60*12); // Cache for 12 hours
}
*/
?>
<!DOCTYPE HTML>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="title" content="The Music Bin: Save New Music Releases for Later (Page <?php echo ( $list_offset / $limit ) + 1; ?>)">
    <meta name="description" content="All new album releases published on Spotify presented similar to Rdio's new albums list, updated every New Music Friday. Never miss another new album.">
    <link rel="canonical" href="<?php echo APPURL; ?>music-bin/" />

    <meta property="og:url" content="<?php echo APPURL; ?>music-bin/"/>
    <meta property="og:title" content="The Music Bin: Save New Music Releases for Later"/>
    <meta property="og:description" content="All new album releases published on Spotify presented similar to Rdio's new albums list, updated every New Music Friday. Never miss another new album."/>

    <title>The Music Bin: Save New Music Releases for Later (Page <?php echo ( $list_offset / $limit ) + 1; ?>)</title>
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,600,600italic,800' rel='stylesheet' type='text/css'>
    <link type="text/css" href="/css/select2.min.css" rel="stylesheet" />
    <link type="text/css" href="/css/site.css" rel="stylesheet" />
  </head>

  <body>
    <header>
      <h1><a href="<?php echo APPURL; ?>music-bin/">The Music Bin</a></h1>
      <h2>Browse all new releases and save them for later</h2>
      <h3>Showing the most popular released albums on <a href="http://spotify.com/" target="_blank">Spotify</a>.</h3>
      <?php if( isset( $_GET['genres'] ) ) { ?>
        <h2>Showing the all albums in genres: <?php echo implode( ', ', $get_genres ); ?></h2>
      <?php } elseif( isset( $_GET['date'] ) ) { ?>
        <h3>Current limits: Releases since last Friday (<?php echo $previous_date; ?>).</h2>
      <?php } else { ?>
        <h3>Current limits: Releases since November 11th, 2015 (epoch of Play Later).</h2>
      <?php } ?>
      <p>Once you log in to Spotify, The Play Later buttons add the selected album to a new (or existing) playlist called &ldquo;Play Later&rdquo;</p>
      <div class="log-in-wrap">
          <?php if( !$logged_in ) { ?>
            <a href="/spotify/" class="button log-in-button">Log In to Spotify</a>
          <?php } else { ?>
            <a href="?destroy=1" class="button log-in-button">Logout</a>
          <?php } ?>
      </div>
      <form action="/music-bin/" method="get">
        <select name="date" class="date-select">
            <option value="">-- Date Range --</option>
            <option value="this-week"<?php if( isset( $_GET['date'] ) && $_GET['date'] == 'this-week' ) { echo ' selected'; } ?>>This Week</option>
            <option value="last-week"<?php if( isset( $_GET['date'] ) && $_GET['date'] == 'last-week' ) { echo ' selected'; } ?>>Last Week</option>
            <option value="two-weeks"<?php if( isset( $_GET['date'] ) && $_GET['date'] == 'two-weeks' ) { echo ' selected'; } ?>>Two Weeks Ago</option>
        </select>
        <button type="submit" class="button">Filter</button>
      </form>
<?php
/*
      <p>
        <img width="600" height="225" src="days.php" alt="8 latest release days" />
        <img width="600" height="225" src="months.php" alt="4 latest release months" />
      </p>
*/
?>
    </header>

    <section>
      <ol class="albums">
        <?php foreach ($albums as $album): ?>
          <?php
            $album_genres = array();
            if( isset($album['genres']) ) {
                $album_genres = maybe_unserialize( $album['genres'] );
            }
            if( isset( $_GET['genres'] ) && !empty( $_GET['genres'] ) ) {
                $passed_genres = $_GET['genres'];
                if( empty( $album['genres'] ) || empty( array_intersect( $passed_genres, $album_genres ) ) ) {
                    continue;
                }
            }
          ?>
          <li class="album <?php echo $album['availability']; ?>">
              <p>
                  <a class="album-cover" href="spotify:album:<?php echo $album['id']; ?>">
                      <img src="<?php echo $album['image']; ?>" alt="<?php echo $album['name']; ?>"/>
                </a>
            </p>
            <?php /* <p class="no"><?php echo $no+1?></p> */ ?>
            <?php if( $logged_in ) { ?>
                <?php if( !array_search( $album['id'], $all_albums ) ) { ?>
                <a href="/spotify/add-tracks/<?php echo $album['id']; ?>/" data-album="<?php echo $album['id']; ?>" class="button play-later" target="_blank">Play Later</a>
                <?php } else { ?>
                    <p class="status">Album already in playlist</p>
                <?php } ?>
            <?php } ?>
            <h3>
              <a class="name" href="spotify:album:<?php echo $album['id']; ?>" title="Album Availability: <?php echo $album['availability']; ?>">
                  <?php echo $album['name']; ?>
              </a>
            </h3>
            <h4>
            <?php
                $buf=array();
                if( isset( $album['artists'] ) && !empty( $album['artists'] ) && !is_serialized( $album['artists'] ) ) {
                    foreach ($album['artists'] as $artist) {
                        $buf[] = '<a class="artist" href="'.$artist->uri.'">'.$artist->name.'</a>';
                    }
                    echo implode(', ', $buf);
                } else {
                    echo '<p class="artist">No Artist Data Available</p>';
                }
            ?>
            </h4>
            <?php
            if( isset($album['genres']) && isset( $album_genres ) && is_array( $album_genres ) && !empty($album_genres) ) {
                echo '<p class="genre"><strong>Genres:</strong> ';
                echo implode(", ", $album_genres);
                echo '</p>';
            }
            ?>
            <?php if( isset( $album['tracks'] ) && $album['tracks'] ) {
                echo '<p class="track-count">'.$album['tracks'].' tracks</p>';
            } ?>
            <?php if( isset( $album['release_date'] ) && $album['release_date'] ) {
                echo '<p class="release-date"><strong>Release date:</strong> '. date( 'M j, Y', strtotime( $album['release_date'] ) ) .'</p>';
            } ?>
            <p><small><a href="<?php echo APPURL; ?>album/<?php echo $album['id']; ?>/" target="_blank"><?php echo $album['name']; ?> details</a></small></p>

<?php // add in ability to follow artist from here ?>
          </li>
        <?php endforeach; ?>
      </ol>
      <?php
          $query_args = '';
          if ( !empty($_GET) ) {
            foreach ($_GET as $parameter => $value) {
              if( $parameter == 'offset' || $parameter == 'q' ) continue;
              if( is_array( $value ) ) {
                foreach( $value as $v ) {
                    $query_args .= "&" . $parameter . "%5B%5D=" . urlencode($v);
                }
              } else {
                  $query_args .= "&" . $parameter . "=" . urlencode($value);
              }
            }
          }

          if( ( $list_offset - $limit ) >= 0 ) { ?>
          <a href="?offset=<?php echo $list_offset - $limit; echo $query_args; ?>" class="button offset prev">Previous <?php echo $limit; ?></a>

      <?php } elseif ( $list_offset !== 0 ) { ?>
          <a href="?offset=0" class="button offset prev">Back to the Start</a>
      <?php } ?>
      <?php // I would have an upward bound here, but who cares? ?>
          <span class="page-number">Page <?php echo ( $list_offset / $limit ) + 1; ?></span>
          <a href="?offset=<?php echo $list_offset + $limit; echo $query_args; ?>" class="button offset next">Next <?php echo $limit; ?></a>
    </section>

    <footer>
      <h2>Built on the open <a href="https://developer.spotify.com/web-api/">Spotify metadata API</a> and the <a href="http://www.last.fm/api">Last.fm API</a></h2>
      <p>
        DEBUG:
        <?php
        if( isset( $me ) ) {
            echo 'Logged in as <a href="'.$me->href.'">'.$me->display_name.'</a>, ';
        }
        if( isset( $all_albums ) ) {
            echo 'Ingested '.count( $all_albums ).' albums from Play Later, ';
        }
        if( isset( $_SESSION['spotify_expires'] ) ) {
            echo 'Token Expires: '.date('Y-m-d h:m:s', $_SESSION['spotify_expires']).', ';
        }

        ?>
      </p>
      <p><strong>Fork and contribute: <a href="https://github.com/MikeNGarrett/Play-Later">Play Later on Github</a></strong></p>
      <p>
    This is a simple hack built on top of the open
    <a href="https://developer.spotify.com/technologies/web-api/">Spotify metadata API</a>.
    Based on the wonderful work on <a href="http://spotifyreleases.com/">SpotifyReleases.com</a>.
      </p>
      <p>
          Other sources: <a href="http://everynoise.com/spotify_new_releases.html">EveryNoise New Releases</a>, <a href="http://swarm.fm/">Swarm.fm</a>, and <a href="http://pansentient.com/new-on-spotify/">Pansentient's New on Spotify</a>.
      </p>
      <p>
          <a href="http://everynoise.com/engenremap.html">List of all Spotify genres</a>
      </p>
      <h2>Proudly built in Alexandria, VA by <a href="http://redgarrett.com">Mike N Garrett</a>.</h2>
    </footer>
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
    <script type="text/javascript" src="/js/select2.min.js"></script>
    <script type="text/javascript" src="/js/site.js"></script>
    <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-71716026-1', 'auto');
    ga('send', 'pageview');

    </script>
  </body>
</html>