mirror of
https://github.com/koel/koel
synced 2024-11-24 13:13:05 +00:00
Add iTunes integration
This commit is contained in:
parent
27793adefd
commit
86ca8d40f6
19 changed files with 386 additions and 51 deletions
13
app/Facades/iTunes.php
Normal file
13
app/Facades/iTunes.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Facades;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
|
class iTunes extends Facade
|
||||||
|
{
|
||||||
|
protected static function getFacadeAccessor()
|
||||||
|
{
|
||||||
|
return 'iTunes';
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ use App\Models\Interaction;
|
||||||
use App\Models\Playlist;
|
use App\Models\Playlist;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use iTunes;
|
||||||
use Lastfm;
|
use Lastfm;
|
||||||
use YouTube;
|
use YouTube;
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ class DataController extends Controller
|
||||||
'currentUser' => auth()->user(),
|
'currentUser' => auth()->user(),
|
||||||
'useLastfm' => Lastfm::used(),
|
'useLastfm' => Lastfm::used(),
|
||||||
'useYouTube' => YouTube::enabled(),
|
'useYouTube' => YouTube::enabled(),
|
||||||
|
'useiTunes' => iTunes::used(),
|
||||||
'allowDownload' => config('koel.download.allow'),
|
'allowDownload' => config('koel.download.allow'),
|
||||||
'cdnUrl' => app()->staticUrl(),
|
'cdnUrl' => app()->staticUrl(),
|
||||||
'currentVersion' => Application::KOEL_VERSION,
|
'currentVersion' => Application::KOEL_VERSION,
|
||||||
|
|
28
app/Http/Controllers/API/iTunesController.php
Normal file
28
app/Http/Controllers/API/iTunesController.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Http\Requests\API\ViewSongRequest;
|
||||||
|
use App\Models\Album;
|
||||||
|
use iTunes;
|
||||||
|
|
||||||
|
class iTunesController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* View a song on iTunes store.
|
||||||
|
*
|
||||||
|
* @param ViewSongRequest $request
|
||||||
|
* @param Album $album
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function viewSong(ViewSongRequest $request, Album $album)
|
||||||
|
{
|
||||||
|
$url = iTunes::getTrackUrl($request->q, $album->name, $album->artist->name);
|
||||||
|
if ($url) {
|
||||||
|
return redirect($url);
|
||||||
|
} else {
|
||||||
|
abort(404, "Koel can't find such a song on iTunes Store.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
app/Http/Requests/API/ViewSongRequest.php
Normal file
33
app/Http/Requests/API/ViewSongRequest.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\API;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property string q
|
||||||
|
*/
|
||||||
|
class ViewSongRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'q' => 'required',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
31
app/Providers/iTunesServiceProvider.php
Normal file
31
app/Providers/iTunesServiceProvider.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Services\iTunes;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class iTunesServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap the application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
app()->singleton('iTunes', function () {
|
||||||
|
return new iTunes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
75
app/Services/iTunes.php
Normal file
75
app/Services/iTunes.php
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
|
||||||
|
class iTunes
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Client
|
||||||
|
*/
|
||||||
|
protected $client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $endPoint = 'https://itunes.apple.com/search';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iTunes constructor.
|
||||||
|
*
|
||||||
|
* @param Client|null $client
|
||||||
|
*/
|
||||||
|
public function __construct(Client $client = null)
|
||||||
|
{
|
||||||
|
$this->client = $client ?: new Client();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether to use iTunes services.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function used()
|
||||||
|
{
|
||||||
|
return (bool) config('koel.itunes.enabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a track on iTunes Store with the given information and get its URL.
|
||||||
|
*
|
||||||
|
* @param $term string The main query string (should be the track's name)
|
||||||
|
* @param $album string The album's name, if available
|
||||||
|
* @param $artist string The artist's name, if available
|
||||||
|
*
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
public function getTrackUrl($term, $album = '', $artist = '')
|
||||||
|
{
|
||||||
|
$params = [
|
||||||
|
'term' => $term.($album ? ' '.$album : '').($artist ? ' '.$artist : ''),
|
||||||
|
'media' => 'music',
|
||||||
|
'entity' => 'song',
|
||||||
|
'limit' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = (string) $this->client->get($this->endPoint, ['query' => $params])->getBody();
|
||||||
|
$response = json_decode($response);
|
||||||
|
|
||||||
|
if (!$response->resultCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trackUrl = $response->results[0]->trackViewUrl;
|
||||||
|
|
||||||
|
// Returns a string if the URL has parameters or NULL if not
|
||||||
|
if (parse_url($trackUrl, PHP_URL_QUERY)) {
|
||||||
|
$trackUrl .= '&at='.config('koel.itunes.affiliate_id');
|
||||||
|
} else {
|
||||||
|
$trackUrl .= '?at='.config('koel.itunes.affiliate_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $trackUrl;
|
||||||
|
}
|
||||||
|
}
|
|
@ -157,6 +157,7 @@ return [
|
||||||
App\Providers\YouTubeServiceProvider::class,
|
App\Providers\YouTubeServiceProvider::class,
|
||||||
App\Providers\DownloadServiceProvider::class,
|
App\Providers\DownloadServiceProvider::class,
|
||||||
App\Providers\BroadcastServiceProvider::class,
|
App\Providers\BroadcastServiceProvider::class,
|
||||||
|
App\Providers\iTunesServiceProvider::class,
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -214,6 +215,7 @@ return [
|
||||||
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
|
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
|
||||||
'AWS' => Aws\Laravel\AwsFacade::class,
|
'AWS' => Aws\Laravel\AwsFacade::class,
|
||||||
'Sentry' => Sentry\SentryLaravel\SentryFacade::class,
|
'Sentry' => Sentry\SentryLaravel\SentryFacade::class,
|
||||||
|
'iTunes' => App\Facades\iTunes::class,
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -110,4 +110,9 @@ return [
|
||||||
*/
|
*/
|
||||||
'ignore_dot_files' => env('IGNORE_DOT_FILES', true),
|
'ignore_dot_files' => env('IGNORE_DOT_FILES', true),
|
||||||
|
|
||||||
|
'itunes' => [
|
||||||
|
'enabled' => env('USE_ITUNES', true),
|
||||||
|
'affiliate_id' => '1000lsGu',
|
||||||
|
]
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
20
resources/assets/img/itunes.svg
Executable file
20
resources/assets/img/itunes.svg
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="176px" height="177px" viewBox="0 0 176 177" enable-background="new 0 0 176 177" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#fff" d="M88,0.5c-48.602,0-88,39.399-88,88c0,48.601,39.398,88,88,88c48.601,0,88-39.399,88-88
|
||||||
|
C176,39.899,136.601,0.5,88,0.5z M88,169.108c-44.52,0-80.608-36.09-80.608-80.608C7.392,43.981,43.48,7.892,88,7.892
|
||||||
|
c44.519,0,80.608,36.089,80.608,80.608C168.608,133.019,132.519,169.108,88,169.108z M126.254,31.462
|
||||||
|
c-1.221-1.033-3.796-0.399-3.796-0.399L70.117,41.451c0,0-2.253,0.057-3.795,1.998c-1.083,1.363-0.999,3.796-0.999,3.796v62.129
|
||||||
|
c0,0,0.188,2.209-1.398,3.796c-1.843,1.842-6.479,2.14-10.588,3.196c-6.84,1.76-13.585,4.634-13.585,12.985
|
||||||
|
c0,5.86,2.965,13.186,13.186,13.186c12.313,0,18.578-6.789,18.578-15.982c0-5.952,0-7.392,0-7.392l0.2-47.346
|
||||||
|
c0,0-0.299-2.608,0.6-3.596c1.264-1.389,3.995-1.598,3.995-1.598l40.354-8.19c0,0,2.452-0.845,3.596,0
|
||||||
|
c1.154,0.853,0.999,3.396,0.999,3.396v36.159c0,0,0.219,2.379-0.999,3.596c-2.288,2.289-6.141,2.242-9.988,3.196
|
||||||
|
c-7.225,1.792-14.783,4.386-14.783,13.785c0,9.929,9.67,12.785,12.785,12.785c13.62,0,19.378-7.352,19.378-16.182V35.458
|
||||||
|
C127.652,35.458,127.622,32.62,126.254,31.462z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -38,7 +38,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { playback } from '../../../services'
|
import { sharedStore } from '../../../stores'
|
||||||
|
import { playback, ls } from '../../../services'
|
||||||
import trackListItem from '../../shared/track-list-item.vue'
|
import trackListItem from '../../shared/track-list-item.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -47,7 +48,8 @@ export default {
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
showingFullWiki: false
|
showingFullWiki: false,
|
||||||
|
useiTunes: sharedStore.state.useiTunes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -64,6 +66,10 @@ export default {
|
||||||
|
|
||||||
showFull () {
|
showFull () {
|
||||||
return this.mode === 'full' || this.showingFullWiki
|
return this.mode === 'full' || this.showingFullWiki
|
||||||
|
},
|
||||||
|
|
||||||
|
iTunesUrl () {
|
||||||
|
return `/api/itunes/album/${this.album.id}&jwt-token=${ls.get('jwt-token')}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,33 @@
|
||||||
<li :class="{ available: correspondingSong }" :title="tooltip" @click="play">
|
<li :class="{ available: correspondingSong }" :title="tooltip" @click="play">
|
||||||
<span class="no">{{ index + 1 }}</span>
|
<span class="no">{{ index + 1 }}</span>
|
||||||
<span class="title">{{ track.title }}</span>
|
<span class="title">{{ track.title }}</span>
|
||||||
|
<a
|
||||||
|
:href="iTunesUrl"
|
||||||
|
v-if="useiTunes && !correspondingSong"
|
||||||
|
target="_blank"
|
||||||
|
class="view-on-itunes"
|
||||||
|
title="View on iTunes"
|
||||||
|
>
|
||||||
|
iTunes
|
||||||
|
</a>
|
||||||
<span class="length">{{ track.fmtLength }}</span>
|
<span class="length">{{ track.fmtLength }}</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { songStore, queueStore } from '../../stores'
|
import { songStore, queueStore, sharedStore } from '../../stores'
|
||||||
import { playback } from '../../services'
|
import { ls, playback } from '../../services'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'shared--track-list-item',
|
name: 'shared--track-list-item',
|
||||||
props: ['album', 'track', 'index'],
|
props: ['album', 'track', 'index'],
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
useiTunes: sharedStore.state.useiTunes
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
correspondingSong () {
|
correspondingSong () {
|
||||||
return songStore.guess(this.track.title, this.album)
|
return songStore.guess(this.track.title, this.album)
|
||||||
|
@ -21,6 +36,10 @@ export default {
|
||||||
|
|
||||||
tooltip () {
|
tooltip () {
|
||||||
return this.correspondingSong ? 'Click to play' : ''
|
return this.correspondingSong ? 'Click to play' : ''
|
||||||
|
},
|
||||||
|
|
||||||
|
iTunesUrl () {
|
||||||
|
return `/api/itunes/song/${this.album.id}?q=${encodeURIComponent(this.track.title)}&jwt-token=${ls.get('jwt-token')}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -37,3 +56,25 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
a.view-on-itunes {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: .8rem;
|
||||||
|
padding: 0 5px;
|
||||||
|
color: #fff;
|
||||||
|
background: rgba(255, 255, 255, .1);
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(27deg, #fe5c52 0%,#c74bd5 50%,#2daaff 100%);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
box-shadow: inset 0px 5px 5px -5px #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
@input="filter"
|
@input="filter"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
v-model="q"
|
v-model="q"
|
||||||
v-koel-focus="showing">
|
v-koel-focus
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ export const sharedStore = {
|
||||||
playlists: [],
|
playlists: [],
|
||||||
useLastfm: false,
|
useLastfm: false,
|
||||||
useYouTube: false,
|
useYouTube: false,
|
||||||
|
useiTunes: true,
|
||||||
allowDownload: false,
|
allowDownload: false,
|
||||||
currentVersion: '',
|
currentVersion: '',
|
||||||
latestVersion: '',
|
latestVersion: '',
|
||||||
|
@ -71,6 +72,8 @@ export const sharedStore = {
|
||||||
this.state.currentUser = null
|
this.state.currentUser = null
|
||||||
this.state.playlists = []
|
this.state.playlists = []
|
||||||
this.state.useLastfm = false
|
this.state.useLastfm = false
|
||||||
|
this.state.useYouTube = false
|
||||||
|
this.state.useiTunes = true
|
||||||
this.state.allowDownload = false
|
this.state.allowDownload = false
|
||||||
this.state.currentVersion = ''
|
this.state.currentVersion = ''
|
||||||
this.state.latestVersion = ''
|
this.state.latestVersion = ''
|
||||||
|
|
4
resources/views/errors/404.blade.php
Normal file
4
resources/views/errors/404.blade.php
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
@extends('errors.template')
|
||||||
|
|
||||||
|
@section('title', 'Not Found')
|
||||||
|
@section('details', $exception->getMessage())
|
|
@ -1,47 +1,4 @@
|
||||||
<!DOCTYPE html>
|
@extends('errors.template')
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Be right back.</title>
|
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css">
|
@section('title', 'Service Unavailable')
|
||||||
|
@section('details', 'Koel will be right back.')
|
||||||
<style>
|
|
||||||
html, body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
color: #B0BEC5;
|
|
||||||
display: table;
|
|
||||||
font-weight: 100;
|
|
||||||
font-family: 'Lato';
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
text-align: center;
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
text-align: center;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 72px;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="content">
|
|
||||||
<div class="title">Be right back.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
46
resources/views/errors/template.blade.php
Normal file
46
resources/views/errors/template.blade.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>@yield('title')</title>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: #181818;
|
||||||
|
display: table;
|
||||||
|
font-size: 24px;
|
||||||
|
font-family: system, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
color: #a0a0a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 76px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: 100;
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="title">@yield('title')</div>
|
||||||
|
<div class="details">@yield('details')</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -62,6 +62,11 @@ Route::group(['namespace' => 'API'], function () {
|
||||||
Route::get('album/{album}/info', 'AlbumController@getInfo');
|
Route::get('album/{album}/info', 'AlbumController@getInfo');
|
||||||
Route::get('artist/{artist}/info', 'ArtistController@getInfo');
|
Route::get('artist/{artist}/info', 'ArtistController@getInfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// iTunes routes
|
||||||
|
if (iTunes::used()) {
|
||||||
|
Route::get('itunes/song/{album}', 'iTunesController@viewSong');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['middleware' => 'os.auth', 'prefix' => 'os', 'namespace' => 'ObjectStorage'], function () {
|
Route::group(['middleware' => 'os.auth', 'prefix' => 'os', 'namespace' => 'ObjectStorage'], function () {
|
||||||
|
|
38
tests/blobs/itunes/track.json
Normal file
38
tests/blobs/itunes/track.json
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"resultCount": 1,
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"wrapperType": "track",
|
||||||
|
"kind": "song",
|
||||||
|
"artistId": 163805,
|
||||||
|
"collectionId": 265611220,
|
||||||
|
"trackId": 265611396,
|
||||||
|
"artistName": "Skid Row",
|
||||||
|
"collectionName": "40 Seasons - The Best of Skid Row",
|
||||||
|
"trackName": "I Remember You",
|
||||||
|
"collectionCensoredName": "40 Seasons - The Best of Skid Row",
|
||||||
|
"trackCensoredName": "I Remember You",
|
||||||
|
"artistViewUrl": "https://itunes.apple.com/us/artist/skid-row/id163805?uo=4",
|
||||||
|
"collectionViewUrl": "https://itunes.apple.com/us/album/i-remember-you/id265611220?i=265611396&uo=4",
|
||||||
|
"trackViewUrl": "https://itunes.apple.com/us/album/i-remember-you/id265611220?i=265611396&uo=4",
|
||||||
|
"previewUrl": "http://audio.itunes.apple.com/apple-assets-us-std-000001/AudioPreview71/v4/fb/72/5d/fb725d9b-371f-1fe2-ba47-798f6058d4e0/mzaf_5805178457647444594.plus.aac.p.m4a",
|
||||||
|
"artworkUrl30": "http://is3.mzstatic.com/image/thumb/Music/v4/b3/5e/28/b35e28a2-2485-3124-721c-1948a9b99220/source/30x30bb.jpg",
|
||||||
|
"artworkUrl60": "http://is3.mzstatic.com/image/thumb/Music/v4/b3/5e/28/b35e28a2-2485-3124-721c-1948a9b99220/source/60x60bb.jpg",
|
||||||
|
"artworkUrl100": "http://is3.mzstatic.com/image/thumb/Music/v4/b3/5e/28/b35e28a2-2485-3124-721c-1948a9b99220/source/100x100bb.jpg",
|
||||||
|
"collectionPrice": 11.99,
|
||||||
|
"trackPrice": 1.29,
|
||||||
|
"releaseDate": "1998-11-03T08:00:00Z",
|
||||||
|
"collectionExplicitness": "notExplicit",
|
||||||
|
"trackExplicitness": "notExplicit",
|
||||||
|
"discCount": 1,
|
||||||
|
"discNumber": 1,
|
||||||
|
"trackCount": 16,
|
||||||
|
"trackNumber": 4,
|
||||||
|
"trackTimeMillis": 314027,
|
||||||
|
"country": "USA",
|
||||||
|
"currency": "USD",
|
||||||
|
"primaryGenreName": "Rock",
|
||||||
|
"isStreamable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
25
tests/iTunesTest.php
Normal file
25
tests/iTunesTest.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Services\iTunes;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Psr7\Response;
|
||||||
|
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||||
|
use Mockery as m;
|
||||||
|
|
||||||
|
class iTunesTest extends TestCase
|
||||||
|
{
|
||||||
|
use WithoutMiddleware;
|
||||||
|
|
||||||
|
public function testGetTrackUrl()
|
||||||
|
{
|
||||||
|
$client = m::mock(Client::class, [
|
||||||
|
'get' => new Response(200, [], file_get_contents(__DIR__.'/blobs/itunes/track.json')),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$api = new iTunes($client);
|
||||||
|
self::assertEquals(
|
||||||
|
'https://itunes.apple.com/us/album/i-remember-you/id265611220?i=265611396&uo=4&at=1000lsGu',
|
||||||
|
$api->getTrackUrl('Foo Bar')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue