是否可以保存来自 Spotify 搜索 API 的结果?
Posted
技术标签:
【中文标题】是否可以保存来自 Spotify 搜索 API 的结果?【英文标题】:Acceptable to save results from Spotify search API? 【发布时间】:2013-08-17 22:30:57 【问题描述】:阅读 Spotify Web API 的 TOS,开发人员不得在创建数据库时从 API 聚合数据。我不知道我想要完成的是否算作“聚合”。
我有一个网站,允许用户就婚礼上播放的歌曲提出建议。我让他们输入歌曲名称、艺术家和专辑名称,以便 DJ 可以轻松找到音乐。所有这些都是用户提供的。然后歌曲由新娘/新郎批准并由其他客人投票生成播放列表,DJ 将知道哪些音乐将在活动中流行。
我想提供的是一种让用户使用该信息的方式,并能够在 Spotify 上搜索前几个搜索结果,选择正确的曲目,并将 Spotify 曲目与他们的建议相关联。这让其他客人听到他们不熟悉的歌曲,并允许管理员根据新娘/新郎的口味允许或禁止歌曲。
为了避免 API 调用超过速率限制,我希望能够将搜索结果返回的 Spotify URI 与用户提供的歌曲信息一起存储,以便我可以在网站上为推荐的歌曲。
这算作聚合,还是在当前网络搜索 API 的 TOS 下允许这样做?
【问题讨论】:
我投票结束这个问题,因为它是关于服务条款和法律建议,而不是代码问题。 【参考方案1】:你在做什么听起来不错。
您要询问的 TOS 部分是为了防止人们制作在没有用户交互的情况下抓取 Spotify 目录的自动化工具。如果您正在编写“普通”应用程序并缓存来自 Spotify API 的数据,因为用户实际执行了搜索、浏览等操作,那么您没有问题。
资料来源:我在 Spotify 工作。
【讨论】:
谢谢!我很感激反馈。这就是我的想法,但我不想踩到任何脚趾。【参考方案2】:我用这个:
<?php
namespace App\Services;
use DB;
use Exception;
use App\Genre;
use App\Album;
use App\Artist;
use Illuminate\Support\Str;
class ArtistSaver
/**
* Save artist to database and return it.
*
* @param array $data
* @return Artist
*/
public function save($data)
$artist = Artist::whereName($data['mainInfo']['name'])->first();
if ( ! $artist)
$artist = Artist::create($data['mainInfo']);
else
$artist->fill($data['mainInfo'])->save();
$this->saveAlbums($data, $artist);
if (isset($data['albums']))
$this->saveTracks($data['albums'], $artist);
if (isset($data['similar']))
$this->saveSimilar($data['similar'], $artist);
if (isset($data['genres']) && ! empty($data['genres']))
$this->saveGenres($data['genres'], $artist);
return $artist;
/**
* Save and attach artist genres.
*
* @param array $genres
* @param Artist $artist
*/
public function saveGenres($genres, $artist)
$existing = Genre::whereIn('name', $genres)->get();
$ids = [];
foreach($genres as $genre)
$dbGenre = $existing->filter(function($item) use($genre) return $item->name === $genre; )->first();
//genre doesn't exist in db yet, so we need to insert it
if ( ! $dbGenre)
try
$dbGenre = Genre::create(['name' => $genre]);
catch(Exception $e)
continue;
$ids[] = $dbGenre->id;
//attach genres to artist
$artist->genres()->sync($ids, false);
/**
* Save artists similar artists to database.
*
* @param $similar
* @param $artist
* @return void
*/
public function saveSimilar($similar, $artist)
$names = array_map(function($item) return $item['name']; , $similar);
//insert similar artists that don't exist in db yet
$this->saveOrUpdate($similar, array_flatten($similar), 'artists');
//get ids in database for artist we just inserted
$ids = Artist::whereIn('name', $names)->lists('id');
//attach ids to given artist
$artist->similar()->sync($ids);
/**
* Save artist albums to database.
*
* @param array $data
* @param Artist|null $artist
* $param int|null
* @return void
*/
public function saveAlbums($data, $artist = null, $albumId = null)
if (isset($data['albums']) && count($data['albums']))
$b = $this->prepareAlbumBindings($data['albums'], $artist, $albumId);
$this->saveOrUpdate($b['values'], $b['bindings'], 'albums');
/**
* Save albums tracks to database.
*
* @param array $albums
* @param Artist|null $artist
* @param Album|null $trackAlbum
* @return void
*/
public function saveTracks($albums, $artist, $tracksAlbum = null)
if ( ! $albums || ! count($albums)) return;
$tracks = [];
foreach($albums as $album)
if ( ! isset($album['tracks']) || empty($album['tracks'])) continue;
if ($tracksAlbum)
$id = $tracksAlbum['id'];
else
$id = $this->getIdFromAlbumsArray($album['name'], $artist['albums']);
foreach($album['tracks'] as $track)
$track['album_id'] = $id;
$tracks[] = $track;
if ( ! empty($tracks))
$this->saveOrUpdate($tracks, array_flatten($tracks), 'tracks');
private function getIdFromAlbumsArray($name, $albums)
$id = false;
foreach($albums as $album)
if ($name === $album['name'])
$id = $album['id']; break;
if ( ! $id)
foreach($albums as $album)
if (Str::slug($name) == Str::slug($album['name']))
$id = $album['id']; break;
return $id;
/**
* Unset tracks key from album arrays and flatten them into single array.
*
* @param array $albums
* @param Artist|null $artist
* @param int|null $albumId
* @return array
*/
private function prepareAlbumBindings($albums, $artist = null, $albumId = null)
$flat = [];
foreach($albums as $k => $album)
if (isset($albums[$k]['tracks'])) unset($albums[$k]['tracks']);
if ( ! isset($albums[$k]['artist_id']) || ! $albums[$k]['artist_id'])
$albums[$k]['artist_id'] = $artist ? $artist->id : 0;
//can't insert null into auto incrementing id because
//mysql will increment the id instead of keeping the old one
if ($albumId)
$albums[$k]['id'] = $albumId;
foreach($albums[$k] as $name => $data)
if ($name !== 'tracks')
$flat[] = $data;
return ['values' => $albums, 'bindings' => $flat];
/**
* Compiles insert on duplicate update query for multiple inserts.
*
* @param array $values
* @param array $bindings
* @param string $table
*
* @return void
*/
public function saveOrUpdate(array $values, $bindings, $table)
if (empty($values)) return;
$first = head($values);
//count how many inserts we need to make
$amount = count($values);
//count in how many columns we're inserting
$columns = array_fill(0, count($first), '?');
$columns = '(' . implode(', ', $columns) . ') ';
//make placeholders for the amount of inserts we're doing
$placeholders = array_fill(0, $amount, $columns);
$placeholders = implode(',', $placeholders);
$updates = [];
//construct update part of the query if we're trying to insert duplicates
foreach ($first as $column => $value)
$updates[] = "$column = COALESCE(values($column), $column)";
$prefixed = DB::getTablePrefix() ? DB::getTablePrefix().$table : $table;
$query = "INSERT INTO $prefixed " . '(' . implode(',' , array_keys($first)) . ')' . ' VALUES ' . $placeholders .
'ON DUPLICATE KEY UPDATE ' . implode(', ', $updates);
DB::statement($query, $bindings);
【讨论】:
虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。以上是关于是否可以保存来自 Spotify 搜索 API 的结果?的主要内容,如果未能解决你的问题,请参考以下文章
适用于 ios 的 Spotify API:从 ios spotify api 下载、保存、访问曲目
在 iPhone 上使用 API 无需登录即可Spotify 播放歌曲