Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Commit

Permalink
✨ +MixesDB example
Browse files Browse the repository at this point in the history
  • Loading branch information
codemasher committed Aug 30, 2023
1 parent 29b94f0 commit 4d9dfb5
Show file tree
Hide file tree
Showing 4 changed files with 302 additions and 0 deletions.
138 changes: 138 additions & 0 deletions examples/Providers/Spotify/MixesDBTrackSearch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php
/**
* Class MixesDBTrackSearch
*
* @created 30.08.2023
* @author smiley <[email protected]>
* @copyright 2023 smiley
* @license MIT
*/

namespace chillerlan\OAuthExamples\Providers\Spotify;

use chillerlan\HTTP\Utils\MessageUtil;
use function array_column;
use function array_map;
use function array_merge;
use function explode;
use function file_get_contents;
use function implode;
use function json_decode;
use function preg_replace;
use function sprintf;
use function str_replace;
use function strtotime;
use function trim;
use function usleep;

/**
*
*/
class MixesDBTrackSearch extends SpotifyClient{

/**
* search tracks on spotify from the given mixesdb track lists
*/
public function getTracks(
string $clubnightsJSON,
int $since,
int $until,
array $find = [],
int $limit = 5,
bool $playlistPerSet = false,
):void{
$clubnights = json_decode(file_get_contents($clubnightsJSON), true);
$tracks = [];

foreach($clubnights as $date => $sets){
$date = strtotime($date);
// skip by date
if($date < $since || $date > $until){
continue;
}

foreach($sets as $name => $set){
// skip by inclusion list
if($this->setContains($name, $find)){
continue;
}

$this->logger->info($name);
$setTracks = [];

foreach($set as $track){
$track = $this->cleanTrack($track);

if(empty($track)){
continue;
}

$this->logger->info(sprintf('search: %s', $track));

$response = $this->spotify->request('/v1/search', [
'q' => $this->getSearchTerm($track),
'type' => 'track',
'limit' => $limit,
'market' => $this->market,
]);

usleep(self::sleepTimer);

if($response->getStatusCode() !== 200){
continue;
}

$data = MessageUtil::decodeJSON($response);

foreach($data->tracks->items as $i => $item){
$setTracks[$item->id] = $item->id;

$this->logger->info(sprintf('found: [%s][%s] %s - %s', ++$i, $item->id, implode(', ', array_column($item->artists, 'name')), $item->name));
}

}

if($playlistPerSet){
$playlistID = $this->createPlaylist($name, '');
$this->addTracks($playlistID, $setTracks);
}

$tracks = array_merge($tracks, $setTracks);
}

}

$playlistID = $this->createPlaylist('mixesdb search result', '');
$this->addTracks($playlistID, $tracks);
}

/**
* check a string for the occurence of any in the given array of needles
*/
protected function setContains(string $haystack, array $needles):bool{
$haystack = mb_strtolower($haystack);

return !empty($needles) && str_replace(array_map('mb_strtolower', $needles), '', $haystack) === $haystack;
}

/**
* clean any unwanted symbols/strings from the track name
*/
protected function cleanTrack(string $track):string{
// strip time codes [01:23] and record IDs [EYE Q - 001] from name
return trim(preg_replace(['/^\[[\d:?]+\] /', '/ \[[^]]+\]/'], '', $track), ' -?');
}

/**
* prepare the spotify search term
*/
protected function getSearchTerm(string $track):string{
$at = explode(' - ', $track, 2); // artist - track

return match (count($at)){
1 => sprintf('artist:%1$s track:%1$s', $at[0]),
2 => sprintf('artist:%s track:%s', $at[0], $at[1]),
};
}

}
2 changes: 2 additions & 0 deletions examples/Providers/Spotify/SpotifyClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ protected function addTracks(string $playlistID, array $trackIDs):void{
headers: ['Content-Type' => 'application/json'],
);

usleep(self::sleepTimer);

if($playlistAddTracks->getStatusCode() === 201){
$json = MessageUtil::decodeJSON($playlistAddTracks);

Expand Down
120 changes: 120 additions & 0 deletions examples/Providers/Spotify/mixesdb-scrape.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
/**
* mixesdb-scrape.php
*
* Not an actual OAuth API example, just a helper script
*
* Unfortunately, mixesdb doesn't have the mediawiki API activated, so we gotta scrape the data manually.
*
* @see https://www.mixesdb.com/w/Category:Clubnight
*
* @created 28.03.2023
* @author smiley <[email protected]>
* @copyright 2023 smiley
* @license MIT
*
* @noinspection PhpComposerExtensionStubsInspection
*/

namespace chillerlan\OAuthExamples\Providers\Spotify;

use chillerlan\HTTP\Utils\MessageUtil;
use DOMDocument;
use function file_put_contents;
use function json_encode;
use function libxml_use_internal_errors;
use function preg_match;
use function trim;
use function usleep;
use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;
use const XML_ELEMENT_NODE;

/**
* @var \Psr\Http\Client\ClientInterface $http
* @var \Psr\Http\Message\RequestFactoryInterface $requestFactory
* @var \Psr\Log\LoggerInterface $logger
* @var string $file
*/
require_once __DIR__.'/spotify-common.php';

$file ??= __DIR__.'/mixesdb-data.json';
$baseURL = 'https://www.mixesdb.com';
$catPath = '/db/index.php?title=Category:Clubnight';
$tracklist = [];

// suppress html parse errors
libxml_use_internal_errors(true);

do{
$logger->info($catPath);

// fetch the category page
$catRequest = $requestFactory->createRequest('GET', $baseURL.$catPath);
$catResponse = $http->sendRequest($catRequest);

if($catResponse->getStatusCode() !== 200){
break;
}

$catDOM = new DOMDocument('1.0', 'UTF-8');
$catDOM->loadHTML(MessageUtil::getContents($catResponse));

// get the pages from the category list
foreach($catDOM->getElementById('catMixesList')->childNodes as $node){

if($node->nodeType !== XML_ELEMENT_NODE){
continue;
}

$page = $node->childNodes[0]->attributes->getNamedItem('href')->nodeValue;

// get the date string
preg_match('#\d{4}-\d{2}-\d{2}#', $page, $match);

if(!isset($match[0])){
continue;
}

// fetch the page
$pageRequest = $requestFactory->createRequest('GET', $baseURL.$page);
$pageResponse = $http->sendRequest($pageRequest);

if($pageResponse->getStatusCode() !== 200){
continue;
}

$pageDOM = new DOMDocument('1.0', 'UTF-8');
$pageDOM->loadHTML(MessageUtil::getContents($pageResponse));

$name = $pageDOM->getElementById('firstHeading')->nodeValue;

$logger->info($name);

// get the tracklist
foreach($pageDOM->getElementsByTagName('ol') as $li){
foreach($li->childNodes as $e){
$tracklist[$match[0]][$name][] = trim($e->nodeValue);
}
}

// try not to hammer
usleep(500000);
}

// get the next page from the category navigation
$catPath = null;

foreach($catDOM->getElementById('catcount')->getElementsByTagName('a') as $node){
if($node->textContent === 'next 200'){
$catPath = $node->attributes->getNamedItem('href')->nodeValue;

break;
}
}

}
while(!empty($catPath));

file_put_contents($file, json_encode($tracklist, (JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)));
42 changes: 42 additions & 0 deletions examples/Providers/Spotify/mixesdb-track-search.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/**
* search-tracks.php
*
* @see https://de.wikipedia.org/wiki/Hr3_Clubnight
* @see https://www.fr.de/kultur/letzten-rille-11671177.html
*
* @created 26.03.2023
* @author smiley <[email protected]>
* @copyright 2023 smiley
* @license MIT
*/

namespace chillerlan\OAuthExamples\Providers\Spotify;

use function file_exists;
use function strtotime;

/**
* @var \chillerlan\OAuth\Providers\Spotify $spotify
* @var \Psr\Http\Message\RequestFactoryInterface $requestFactory
* @var \Psr\Log\LoggerInterface $logger
* @var string $CFGDIR
*/
require_once __DIR__.'/spotify-common.php';

$file = __DIR__.'/clubnights.json';
$since = strtotime('1990-05-05'); // first clubnight: 1990-05-05
$until = strtotime('2000-01-01'); // last clubnight: 2014-06-07 (studio), 2014-06-14 (live)
$find = ['Dag', 'Fenslau', 'Pascal' /* F.E.O.S. */, 'Talla', 'Taucher', 'Tom Wax', 'Ulli Brenner', 'Väth'];
$limit = 5;
$playlistPerSet = false;

if(!file_exists($file)){
include __DIR__.'/mixesdb-scrape.php';
}

$client = new MixesDBTrackSearch($spotify, $logger);

$client->getTracks($file, $since, $until, $find, $limit, $playlistPerSet);

exit;

0 comments on commit 4d9dfb5

Please sign in to comment.