Skip to content

Commit

Permalink
Merge pull request #33 from akashrchandran/develop
Browse files Browse the repository at this point in the history
Merge develop to main for release v2.1.0
  • Loading branch information
akashrchandran authored Jan 18, 2024
2 parents 7ea8b5f + 0aefe85 commit 9f6e4c6
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 69 deletions.
2 changes: 1 addition & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
web: vendor/bin/heroku-php-apache2 public/
web: vendor/bin/heroku-php-apache2 api/
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ __Heroku__

[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://dashboard.heroku.com/new?template=https://github.com/akashrchandran/spotify-lyrics-api)

__Vercel__


[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/project?template=https://github.com/akashrchandran/spotify-lyrics-api)

__Run locally__

> use git to clone the repo to your local machine or you can download the latest [zip](https://github.com/akashrchandran/spotify-lyrics-api/archive/refs/heads/main.zip) file and extract it.
Expand All @@ -232,7 +237,7 @@ export SP_DC=[token here and remove the square brackets]

__Start the server__
```
php -S localhost:8000
php -S localhost:8000 api/index.php
```
now open your browser and type `localhost:8080` and you should see the program running.
# Credits
Expand Down
2 changes: 1 addition & 1 deletion public/index.php → api/index.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

require('../vendor/autoload.php');
require_once __DIR__ . '/../vendor/autoload.php';

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
Expand Down
6 changes: 0 additions & 6 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,5 @@
"description": "SP_DC cookie token from spotify"
}
},
"formation": {
"web": {
"quantity": 1,
"size": "free"
}
},
"image": "heroku/php"
}
4 changes: 2 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 70 additions & 58 deletions src/Spotify.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,100 @@

namespace SpotifyLyricsApi;

/**
* Class Spotify
*
* This class is responsible for interacting with the Spotify API.
*/
class Spotify
{
private $token_url = 'https://open.spotify.com/get_access_token?reason=transport&productType=web_player';
private $lyrics_url = 'https://spclient.wg.spotify.com/color-lyrics/v2/track/';

private $sp_dc;
private $cache_file;

/**
* Spotify constructor.
*
* @param string $sp_dc The Spotify Data Controller (sp_dc) cookie value.
*/
function __construct($sp_dc)
{
$this -> sp_dc = $sp_dc;
$this->cache_file = sys_get_temp_dir() . '/spotify_token.json';
$this->sp_dc = $sp_dc;
}

/**
* Retrieves an access token from the Spotify and stores it in a file.
* The file is stored in the working directory.
*/
* Retrieves an access token from the Spotify and stores it in a file.
* The file is stored in the working directory.
*/
function getToken(): void
{
$sp_dc = $this -> sp_dc;
if ( !$sp_dc )
throw new SpotifyException( 'Please set SP_DC as a environmental variable.' );
$sp_dc = $this->sp_dc;
if (!$sp_dc)
throw new SpotifyException('Please set SP_DC as a environmental variable.');
$ch = curl_init();
curl_setopt( $ch, CURLOPT_TIMEOUT, 600 );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
curl_setopt( $ch, CURLOPT_VERBOSE, 0 );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_HEADER, 0 );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, false );
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'GET' );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
curl_setopt($ch, CURLOPT_TIMEOUT, 600);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36',
'App-platform: WebPlayer',
'content-type: text/html; charset=utf-8',
"cookie: sp_dc=$sp_dc;"
) );
));
curl_setopt($ch, CURLOPT_URL, $this->token_url);
$result = curl_exec( $ch );
$token_json = json_decode( $result, true );
if ( !$token_json || $token_json[ 'isAnonymous' ] )
throw new SpotifyException('The SP_DC set seems to be invalid, please correct it!' );
$token_file = fopen('.cache', 'w' ) or die( 'Unable to open file!' );
;
fwrite( $token_file, $result );
$result = curl_exec($ch);
$token_json = json_decode($result, true);
if (!$token_json || $token_json['isAnonymous'])
throw new SpotifyException('The SP_DC set seems to be invalid, please correct it!');
$token_file = fopen($this -> cache_file, 'w') or die('Unable to open file!');;
fwrite($token_file, $result);
}

/**
* Checks if the access token is expired and retrieves a new one if it is.
* The function invokes getToken if the token is expired or the cache file is not found.
*/
* Checks if the access token is expired and retrieves a new one if it is.
* The function invokes getToken if the token is expired or the cache file is not found.
*/
function checkTokenExpire(): void
{
$check = file_exists( '.cache' );
if ( $check ) {
$json = file_get_contents( '.cache' );
$timeleft = json_decode( $json, true )[ 'accessTokenExpirationTimestampMs' ];
$timenow = round( microtime( true ) * 1000 );
$check = file_exists($this->cache_file);
if ($check) {
$json = file_get_contents($this->cache_file);
$timeleft = json_decode($json, true)['accessTokenExpirationTimestampMs'];
$timenow = round(microtime(true) * 1000);
}
if ( !$check || $timeleft < $timenow ) {
if (!$check || $timeleft < $timenow) {
$this->getToken();
}
}

/**
* Retrieves the lyrics of a track from the Spotify.
* @param string $track_id The Spotify track id.
* @return string The lyrics of the track in JSON format.
*/
function getLyrics( $track_id ): string
* Retrieves the lyrics of a track from the Spotify.
* @param string $track_id The Spotify track id.
* @return string The lyrics of the track in JSON format.
*/
function getLyrics($track_id): string
{
$json = file_get_contents( '.cache' );
$token = json_decode( $json, true )[ 'accessToken' ];
$json = file_get_contents($this -> cache_file);
$token = json_decode($json, true)['accessToken'];
$formated_url = $this->lyrics_url . $track_id . '?format=json&market=from_token';

$ch = curl_init();
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'GET' );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36',
'App-platform: WebPlayer',
"authorization: Bearer $token"
) );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );
curl_setopt( $ch, CURLOPT_URL, $formated_url );
$result = curl_exec( $ch );
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_URL, $formated_url);
$result = curl_exec($ch);
return $result;
}

Expand All @@ -92,24 +104,24 @@ function getLyrics( $track_id ): string
* @param array $lyrics The lyrics of the track in JSON format.
* @return array The lyrics of the track in LRC format.
*/
function getLrcLyrics( $lyrics ): array
function getLrcLyrics($lyrics): array
{
$lrc = array();
foreach ( $lyrics as $lines ) {
$lrctime = $this -> formatMS( $lines[ 'startTimeMs' ] );
array_push( $lrc, [ 'timeTag' => $lrctime, 'words' => $lines[ 'words' ] ] );
foreach ($lyrics as $lines) {
$lrctime = $this->formatMS($lines['startTimeMs']);
array_push($lrc, ['timeTag' => $lrctime, 'words' => $lines['words']]);
}
return $lrc;
}

/**
* Helper fucntion for getLrcLyrics to change miliseconds to [mm:ss.xx]
* @param int $milliseconds The time in miliseconds.
* @return string The time in [mm:ss.xx] format.
*/
function formatMS( $milliseconds ): string
* Helper fucntion for getLrcLyrics to change miliseconds to [mm:ss.xx]
* @param int $milliseconds The time in miliseconds.
* @return string The time in [mm:ss.xx] format.
*/
function formatMS($milliseconds): string
{
$lrc_timetag = sprintf( '%02d:%02d.%02d', ( $milliseconds / 1000 ) / 60, ( $milliseconds / 1000 ) % 60, ( $milliseconds % 1000 ) / 10 );
$lrc_timetag = sprintf('%02d:%02d.%02d', ($milliseconds / 1000) / 60, ($milliseconds / 1000) % 60, ($milliseconds % 1000) / 10);
return $lrc_timetag;
}
}
8 changes: 8 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"functions": {
"api/**/*.php": {
"runtime": "[email protected]"
}
},
"routes": [{ "src": "/(.*)", "dest": "/api/index.php" }]
}

0 comments on commit 9f6e4c6

Please sign in to comment.