今年一月,我写了一篇回顾性文章,回顾了我在2016年喜欢听的音乐。由于我几乎只使用Spotify,因此我为自己喜欢的歌曲制作了一个播放列表,并编写了一个Perl脚本,可以从Spotify下载所有专辑封面并进行拼接蒙太奇。 脚本是为满足我的特定需求而急着编写的,但由于其他人对此有兴趣,因此我决定对其进行完善,然后在github上发布:
https://github.com/deepakg/spotify
本文的其余部分注释了脚本中有趣的部分。
在使用脚本之前,您需要在Spotify上设置一个应用程序。 这将为您提供一个client_id和client_secret。 对于个人脚本,我会将其硬编码到脚本中,但是对于打算在github上发布的内容,我宁愿不要这样做,因为我会无意间最终将其推送到某天。 因此,我在主目录中创建了一个.ini文件,并将其存储在.api_keys中:
[发现]
client_id =
client_secret =
我们使用CPAN的Config::INI::Reader
模块将.ini文件的全部内容解析为字典:
我的$ config = $ ENV {HOME}。 '/.api_keys';
我的$ config_hash = Config :: INI :: Reader-> read_file($ config);
现在可以通过以下方式访问client_id和client_secret: $config_hash->{spotify}{client_id}
和$config_hash->{spotify}{client_secret}
我们不能直接使用客户端ID和客户端密钥来进行API调用。 相反,我们需要将它们交换为可用于进行API调用的“承载者令牌”。 get_bearer_token
子例程正是这样做的。 与客户端ID和客户端机密不同,承载令牌将过期并且必须更新。 由于它通常持续一个小时,因此我们不需要在此脚本中对其进行续订(并且保持简单,也不会尝试在两次脚本运行之间重用该承载令牌)。
获得了承载令牌后,下一步就是使用它来调用Spotify的播放列表API,以检索有关该播放列表中所有曲目的元数据(包括专辑封面网址)。 但是,哪个播放列表? 该脚本包括一个带有8首歌曲的硬编码播放列表作为演示,但是您可以通过将其通过--playlist
命令行参数传递来要求它使用自己的播放列表。

在Spotify桌面客户端中右键单击播放列表,然后从菜单中选择“复制播放列表链接”选项。 该链接是--playlist
参数所期望的:
perl spotify-collage.pl-播放列表https://open.spotify.com/user/deepak.gulati/playlist/6VIJPqtY1rsRH9uxEj0c0o
该脚本从该URL中提取用户和播放列表ID,并使用它调用Spotify的播放列表跟踪API:
我的($ user_id,$ playlist_id)= $ playlist_url =〜m | ^ https:// open \ .spotify \ .com / user /(。*?)/ playlist /(。*)$ |;
我的$ api_url =“ https://api.spotify.com/v1/users/$user_id/playlists/$playlist_id/tracks”; #这是我们称为的端点
该调用返回很多元数据,包括有关曲目所来自专辑的信息。 专辑部分还包含一个数组,其中包含三种尺寸(640×640、300×300和64×64)的专辑封面网址。 我们将640×640图像的网址收集到一个数组中,然后提取唯一的网址。 我们这样做是因为播放列表中可能有同一张专辑中的多首曲目,并且我们不想在拼贴中重复专辑封面。
下一步是将图像下载到临时目录。 我没有使用/ tmp来对文件夹进行硬编码,而是使用File::Temp
的tempdir
函数来执行正确的操作。 另外,您可以告诉函数在脚本完成后自动清除目录。 HTTP::Tiny
的mirror
方法使将URL下载到本地文件变得非常简单。
子download_images {
我的$ images =移动;
我的$ dir = tempdir(
CLEANUP => 1,
DIR => File :: Spec-> tmpdir,
模板=>'spotify-montage-XXXX',
);
说STDERR $ dir;
我的$ count = 1;
我的$ total =标量(@ $ images);
我的$ ua = HTTP :: Tiny-> new;
为我的$ image(@ $ images){
#$ image是完整的网址-在'/'上分割它并获取名称
文件数
我的$ file = $ count。 '-' (将m | / |分割成$ image)[-1]。 '.jpg';
#下载文件
说STDERR“正在下载$ count的$ total”;
$ ua-> mirror($ image,$ dir。“ /”。$ file);
$ count ++;
}
返回$ dir;
}
曲目数据的返回顺序与添加到播放列表中的顺序相同。 专辑封面网址不透明。 因此,尽管我们可以使用$images
arrayref跟踪顺序,但我还是决定在文件前添加一个数字以捕获文件的下载顺序。
蒙太奇图像的创建工作由Imager::Montage
处理,从而大大简化了工作。 它所需要的只是文件路径的列表以及我们在网格中所需的行数和列数。 它还可以在将图像放入网格之前调整图像的大小。 在将其排列在网格中之前,我们使用640×640的大小并将其大小减小到200×200。 没有 行和列的数量是根据我们拥有的图像数量动态生成的。 我们尝试将图像调整为4:3的比例网格,这可能会排除某些相册。 您始终可以修改脚本以接受命令行中的行数和列数。
就这样。