its not like its our development token ¯\_(ツ)_/¯
This commit is contained in:
parent
c24dcced5f
commit
24155c97a5
5 changed files with 1044 additions and 269 deletions
|
@ -218,9 +218,9 @@ input[type=range].md-slider::-webkit-slider-runnable-track {
|
|||
--bs-gutter-y: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: calc(-1 * var(--bs-gutter-y));
|
||||
margin-right: calc(-0.5 * var(--bs-gutter-x));
|
||||
margin-left: calc(-0.5 * var(--bs-gutter-x));
|
||||
/*margin-top: calc(-1 * var(--bs-gutter-y));*/
|
||||
/*margin-right: calc(-0.5 * var(--bs-gutter-x));*/
|
||||
/*margin-left: calc(-0.5 * var(--bs-gutter-x));*/
|
||||
}
|
||||
|
||||
.row > * {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<link rel="manifest" href="./manifest.json?v=2">
|
||||
</head>
|
||||
|
||||
<body oncontextmenu="return false;">
|
||||
<body oncontextmenu="return false;" loading="1">
|
||||
<div id="app">
|
||||
<div id="app-main">
|
||||
<div class="app-chrome">
|
||||
|
@ -31,20 +31,27 @@
|
|||
<div class="app-title"></div>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small shuffle"></button>
|
||||
<button class="playback-button--small shuffle" v-if="mk.shuffleMode == 0"
|
||||
@click="mk.shuffleMode = 1"></button>
|
||||
<button class="playback-button--small shuffle active" v-else @click="mk.shuffleMode = 0"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button previous"></button>
|
||||
<button class="playback-button previous" @click="mk.skipToPreviousItem()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button pause" @click="mk.pause()" v-if="mk.isPlaying"></button>
|
||||
<button class="playback-button play" @click="mk.play()" v-else></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button next"></button>
|
||||
<button class="playback-button next" @click="mk.skipToNextItem()"></button>
|
||||
</div>
|
||||
<div class="app-chrome-item">
|
||||
<button class="playback-button--small repeat"></button>
|
||||
<button class="playback-button--small repeat" v-if="mk.repeatMode == 0"
|
||||
@click="mk.repeatMode = 1"></button>
|
||||
<button class="playback-button--small repeat active" @click="mk.repeatMode = 2"
|
||||
v-else-if="mk.repeatMode == 1"></button>
|
||||
<button class="playback-button--small repeat repeatOne" @click="mk.repeatMode = 0"
|
||||
v-else-if="mk.repeatMode == 2"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-chrome--center">
|
||||
|
@ -57,13 +64,14 @@
|
|||
{{ mk.nowPlayingItem["attributes"]["name"] }}
|
||||
</div>
|
||||
<div class="song-artist">
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }} - {{ mk.nowPlayingItem["attributes"]["albumName"] }}
|
||||
{{ mk.nowPlayingItem["attributes"]["artistName"] }} - {{
|
||||
mk.nowPlayingItem["attributes"]["albumName"] }}
|
||||
</div>
|
||||
<div class="song-progress">
|
||||
<input type="range" step="0.01" min="0"
|
||||
@change="mk.seekToTime($event.target.value)"
|
||||
:max="mk.currentPlaybackDuration"
|
||||
:value="mk.currentPlaybackProgress * 100">
|
||||
:value="playerLCD.playbackDuration">
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">❤️</div>
|
||||
|
@ -74,7 +82,8 @@
|
|||
</div>
|
||||
<div class="app-chrome--right">
|
||||
<div class="app-chrome-item volume display--large">
|
||||
<input type="range" class="" step="0.01" min="0" max="1" v-model="mk.volume" v-if="typeof mk.volume != 'undefined'">
|
||||
<input type="range" class="" step="0.01" min="0" max="1" v-model="mk.volume"
|
||||
v-if="typeof mk.volume != 'undefined'">
|
||||
</div>
|
||||
<div class="app-chrome-item generic">
|
||||
<button class="playback-button--small">
|
||||
|
@ -94,9 +103,9 @@
|
|||
</div>
|
||||
<div class="app-chrome-item full-height">
|
||||
<div class="window-controls">
|
||||
<div class="minimize"></div>
|
||||
<div class="minmax"></div>
|
||||
<div class="close"></div>
|
||||
<div class="minimize" onclick="ipcRenderer.send('minimize')"></div>
|
||||
<div class="minmax" onclick="ipcRenderer.send('maximize')"></div>
|
||||
<div class="close" onclick="ipcRenderer.send('close')"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,38 +115,35 @@
|
|||
<div class="app-sidebar-header">
|
||||
<div class="search-input-container">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search" placeholder="Search..." class="search-input">
|
||||
<input type="search"
|
||||
spellcheck="false"
|
||||
@click="showSearch()"
|
||||
@change="showSearch();searchQuery()"
|
||||
placeholder="Search..."
|
||||
v-model="search.term"
|
||||
class="search-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-sidebar-content">
|
||||
<!-- Think the special category could be a iframe, so we wouldn't need to update the entire site everytime-->
|
||||
<div class="app-sidebar-header-text">
|
||||
🎉Special
|
||||
</div>
|
||||
<button class="app-sidebar-item" href="https://music.apple.com/replay" target="_blank">
|
||||
<div></div>
|
||||
<div>Replay</div>
|
||||
</button>
|
||||
<div class="app-sidebar-header-text">
|
||||
Apple Music
|
||||
</div>
|
||||
<button class="app-sidebar-item">
|
||||
<div></div>
|
||||
<div>Listen Now</div>
|
||||
</button>
|
||||
<button class="app-sidebar-item active">Browse</button>
|
||||
<button class="app-sidebar-item">Radio</button>
|
||||
<sidebar-library-item name="Listen Now" page="listen_now"></sidebar-library-item>
|
||||
<sidebar-library-item name="Browse" page="browse"></sidebar-library-item>
|
||||
<sidebar-library-item name="Radio" page="radio"></sidebar-library-item>
|
||||
<div class="app-sidebar-header-text">
|
||||
Library
|
||||
</div>
|
||||
<button class="app-sidebar-item">Songs</button>
|
||||
<button class="app-sidebar-item">Albums</button>
|
||||
<button class="app-sidebar-item">Artists</button>
|
||||
<button class="app-sidebar-item">Made For You</button>
|
||||
<sidebar-library-item name="Songs" page="library-songs"></sidebar-library-item>
|
||||
<sidebar-library-item name="Albums" page="library-albums"></sidebar-library-item>
|
||||
<sidebar-library-item name="Artists" page="library-artists"></sidebar-library-item>
|
||||
<sidebar-library-item name="Made For You" page="library-madeforyou"></sidebar-library-item>
|
||||
<div class="app-sidebar-header-text">
|
||||
Playlists
|
||||
</div>
|
||||
<button class="app-sidebar-item" v-for="i in 32">Playist</button>
|
||||
<button class="app-sidebar-item" v-for="item in playlists.listing" :key="item.id" href="item.href">
|
||||
{{ item.attributes.name }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-sidebar-footer">
|
||||
<input type="range" class="display--small">
|
||||
|
@ -150,7 +156,15 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="app-content">
|
||||
<button class="md-btn md-btn-primary" @click="init()">Start MusicKit</button>
|
||||
<!-- Browse -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'browse'">
|
||||
<div class="content-inner">
|
||||
<button id="apple-music-authorize" class="md-btn md-btn-primary" @click="init()">Start MusicKit
|
||||
</button>
|
||||
<button id="apple-music-unauthorize" class="md-btn md-btn-primary" @click="unauthorize()">Stop
|
||||
MusicKit
|
||||
</button>
|
||||
<br>
|
||||
<template v-if="mk.nowPlayingItem">
|
||||
currentPlaybackProgress: {{ app.mk.currentPlaybackProgress }}
|
||||
|
@ -158,7 +172,8 @@
|
|||
currentPlaybackDuration: {{ app.mk.currentPlaybackDuration }}
|
||||
</template>
|
||||
<div><input type="text" v-model="quickPlayQuery">
|
||||
<button @click="quickPlay(quickPlayQuery)">Play</button></div>
|
||||
<button @click="quickPlay(quickPlayQuery)">Play</button>
|
||||
</div>
|
||||
<h1 class="header-text">Browse</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, urna eu tincidunt
|
||||
|
@ -177,22 +192,250 @@
|
|||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<h1 class="header-text">Listen Now</h1>
|
||||
<div class="winbox">
|
||||
<div class="fancy">990kbps</div>
|
||||
<div class="">
|
||||
<button class="md-btn md-btn-primary">Audio Quality Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="md-btn" @click="drawertest = !drawertest">Toggle Drawer</button>
|
||||
<button class="md-btn">Button</button>
|
||||
<button class="md-btn md-btn-primary">Button</button>
|
||||
Now Playing:
|
||||
<p data-apple-music-now-playing></p>
|
||||
<button data-apple-music-add-to-library="1558534271">add "never gonna give you up" to library</button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Listen Now -->
|
||||
<transition v-on:enter="getListenNow()" name="wpfade">
|
||||
<template v-if="page == 'listen_now'" @created="console.log('listennow')">
|
||||
<cider-listen-now :data="listennow"></cider-listen-now>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Radio -->
|
||||
<transition v-on:enter="getRadioStations()" name="wpfade">
|
||||
<template v-if="page == 'radio'" @created="console.log('radio')">
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">Radio</h1>
|
||||
<h3>Recent Stations</h3>
|
||||
<mediaitem-square :item="item" v-for="item in radio.personal"></mediaitem-square>
|
||||
</div>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Search -->
|
||||
<transition name="wpfade">
|
||||
<template v-if="page == 'search'">
|
||||
<cider-search :search="search"></cider-search>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- Library - Songs -->
|
||||
<transition name="wpfade" v-on:enter="getLibrarySongs()">
|
||||
<template v-if="page == 'library-songs'">
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">Songs</h1>
|
||||
<div class="search-input-container" style="width:100%;margin: 16px 0px;">
|
||||
<div class="search-input--icon"></div>
|
||||
<input type="search"
|
||||
style="width:100%;"
|
||||
spellcheck="false"
|
||||
placeholder="Search..."
|
||||
class="search-input">
|
||||
</div>
|
||||
<mediaitem-list-item :item="item"
|
||||
v-for="item in library.songs.listing"></mediaitem-list-item>
|
||||
</div>
|
||||
</template>
|
||||
</transition>
|
||||
</div>
|
||||
<div class="app-drawer" v-if="drawertest">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-artwork"></div>
|
||||
<transition name="wpfade">
|
||||
<img v-show="chrome.artworkReady"
|
||||
@load="chrome.artworkReady = true"
|
||||
class="bg-artwork"
|
||||
:src="getNowPlayingArtworkBG(32)">
|
||||
</transition>
|
||||
<transition name="wpfade">
|
||||
<div class="bg-artwork--placeholder" v-else></div>
|
||||
</transition>
|
||||
|
||||
</div>
|
||||
<script src="https://js-cdn.music.apple.com/musickit/v3/amp/musickit.js"></script>
|
||||
|
||||
<script type="text/x-template" id="cider-listen-now">
|
||||
<div class="content-inner">
|
||||
<h1 class="header-text">Listen Now</h1>
|
||||
<template v-for="recom in data.data">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ recom.attributes.title ? recom.attributes.title.stringForDisplay : ""}}</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="recom.relationships.contents.data.length >= 10">
|
||||
<button class="cd-btn-seeall">See All</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-scroller-horizontal :items="recom.relationships.contents.data.limit(10)"></mediaitem-scroller-horizontal>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-template" id="cider-search">
|
||||
<div class="content-inner">
|
||||
<div class="row">
|
||||
<div class="col-sm" style="width: auto;" v-if="getTopResult()">
|
||||
<template >
|
||||
<h3>Top Result</h3>
|
||||
<mediaitem-square :item="getTopResult()"></mediaitem-square>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col" v-if="search.results.songs">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Songs</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.results.songs.data.length >= 6">
|
||||
<button class="cd-btn-seeall">See All</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<mediaitem-list-item :item="item"
|
||||
v-for="item in search.results.songs.data.limit(6)"></mediaitem-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="search.results['meta']">
|
||||
<template v-if="search.results.albums">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Albums</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.results.albums.data.length >= 10">
|
||||
<button class="cd-btn-seeall">See All</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-scroller-horizontal :items="search.results.albums.data.limit(10)"></mediaitem-scroller-horizontal>
|
||||
</template>
|
||||
<template v-if="search.results.artists">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Artists</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.results.artists.data.length >= 5">
|
||||
<button class="cd-btn-seeall">See All</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-square :item="item"
|
||||
v-for="item in search.results.artists.data.limit(5)"></mediaitem-square>
|
||||
</template>
|
||||
<template v-if="search.results.playlists">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>Playlists</h3>
|
||||
</div>
|
||||
<div class="col-auto flex-center" v-if="search.results.playlists.data.length >= 10">
|
||||
<button class="cd-btn-seeall">See All</button>
|
||||
</div>
|
||||
</div>
|
||||
<mediaitem-square :item="item"
|
||||
v-for="item in search.results.playlists.data.limit(10)"></mediaitem-square>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="am-musiccovershelf">
|
||||
<h1>{{ component.attributes.title.stringForDisplay }}</h1>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="sidebar-library-item">
|
||||
<button class="app-sidebar-item"
|
||||
:class="$parent.getSidebarItemClass(page)"
|
||||
@click="$parent.page = page">{{ name }}
|
||||
</button>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="mediaitem-scroller-horizontal">
|
||||
<template>
|
||||
<div class="cd-hmedia-scroller">
|
||||
<mediaitem-square :item="item"
|
||||
v-for="item in items"></mediaitem-square>
|
||||
</div>
|
||||
</template>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="mediaitem-list-item">
|
||||
<template>
|
||||
<div @click="app.playMediaItemById(item.id, item.type)"
|
||||
class="cd-mediaitem-list-item">
|
||||
<div class="artwork"
|
||||
:class="{'round': item.type == 'artists'}"
|
||||
:style="{'--artwork': app.getMediaItemArtwork(item.attributes.artwork.url, 34)}
|
||||
"></div>
|
||||
<div class="info-rect">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis">
|
||||
<template v-if="item.attributes.artistName">
|
||||
{{ item.attributes.artistName }}
|
||||
<template v-if="item.attributes.albumName">
|
||||
- {{ item.attributes.albumName }}
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-rating" v-if="item.attributes.contentRating">
|
||||
{{ item.attributes.contentRating }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="mediaitem-hrect">
|
||||
<template>
|
||||
<div @click="app.playMediaItemById(item.id, item.type)"
|
||||
class="cd-mediaitem-hrect">
|
||||
<div class="artwork"
|
||||
:class="{'round': item.type == 'artists'}"
|
||||
:style="{'--artwork': app.getMediaItemArtwork(item.attributes.artwork.url, 70)}
|
||||
"></div>
|
||||
<div class="info-rect">
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis">
|
||||
{{ item.type }}
|
||||
<template v-if="item.attributes.artistName">
|
||||
∙ {{ item.attributes.artistName }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="mediaitem-square">
|
||||
<template>
|
||||
<div @click="app.playMediaItemById(item.id, item.type)"
|
||||
class="cd-mediaitem-square">
|
||||
<div class="artwork"
|
||||
:class="{'round': item.type == 'artists'}"
|
||||
:style="{'--artwork': app.getMediaItemArtwork(item.attributes.artwork.url, 128)}"></div>
|
||||
<div class="title text-overflow-elipsis">
|
||||
{{ item.attributes.name }}
|
||||
</div>
|
||||
<div class="subtitle text-overflow-elipsis" v-if="item.attributes.artistName">
|
||||
{{ item.attributes.artistName }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</script>
|
||||
|
||||
|
||||
<script src="https://js-cdn.music.apple.com/musickit/v2/amp/musickit.js"></script>
|
||||
<script src="index.js?v=1"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -1,16 +1,223 @@
|
|||
Vue.component('sidebar-library-item', {
|
||||
template: '#sidebar-library-item',
|
||||
props: ['name', 'page', 'cd-click'],
|
||||
methods: {}
|
||||
});
|
||||
|
||||
Vue.component('mediaitem-scroller-horizontal', {
|
||||
template: '#mediaitem-scroller-horizontal',
|
||||
props: ['items'],
|
||||
methods: {}
|
||||
});
|
||||
|
||||
var app = new Vue({
|
||||
Vue.component('mediaitem-square', {
|
||||
template: '#mediaitem-square',
|
||||
props: ['item'],
|
||||
methods: {}
|
||||
});
|
||||
|
||||
Vue.component('mediaitem-hrect', {
|
||||
template: '#mediaitem-hrect',
|
||||
props: ['item'],
|
||||
methods: {}
|
||||
});
|
||||
|
||||
Vue.component('mediaitem-list-item', {
|
||||
template: '#mediaitem-list-item',
|
||||
props: ['item'],
|
||||
methods: {}
|
||||
});
|
||||
|
||||
Vue.component('cider-search', {
|
||||
template: "#cider-search",
|
||||
props: ['search'],
|
||||
methods: {
|
||||
getTopResult() {
|
||||
if (this.search.results["meta"]) {
|
||||
return this.search.results[this.search.results.meta.results.order[0]]["data"][0]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Vue.component('cider-listen-now', {
|
||||
template: "#cider-listen-now",
|
||||
props: ["data"]
|
||||
})
|
||||
|
||||
const MusicKitTools = {
|
||||
getHeader() {
|
||||
return new Headers({
|
||||
Authorization: 'Bearer ' + MusicKit.getInstance().developerToken,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Music-User-Token': '' + MusicKit.getInstance().musicUserToken
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// limit an array to a certain number of items
|
||||
Array.prototype.limit = function (n) {
|
||||
return this.slice(0, n);
|
||||
};
|
||||
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
drawertest: false,
|
||||
mk: {},
|
||||
quickPlayQuery: ""
|
||||
quickPlayQuery: "",
|
||||
search: {
|
||||
term: "",
|
||||
results: {},
|
||||
limit: 10
|
||||
},
|
||||
playerLCD: {
|
||||
playbackDuration: 0
|
||||
},
|
||||
listennow: [],
|
||||
radio: {
|
||||
personal: []
|
||||
},
|
||||
library: {
|
||||
songs: {
|
||||
listing: [],
|
||||
meta: {total: 0}
|
||||
}
|
||||
},
|
||||
playlists: {
|
||||
listing: [],
|
||||
details: {}
|
||||
},
|
||||
chrome: {
|
||||
artworkReady: false
|
||||
},
|
||||
page: "browse"
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let self = this
|
||||
this.mk = MusicKit.getInstance()
|
||||
this.mk.authorize()
|
||||
this.$forceUpdate()
|
||||
|
||||
this.mk.addEventListener(MusicKit.Events.playbackTimeDidChange, (a) => {
|
||||
self.playerLCD.playbackDuration = (self.mk.currentPlaybackTime)
|
||||
})
|
||||
|
||||
this.mk.addEventListener(MusicKit.Events.nowPlayingItemDidChange, (a) => {
|
||||
self.chrome.artworkReady = false
|
||||
})
|
||||
|
||||
this.apiCall('https://api.music.apple.com/v1/me/library/playlists', res => {
|
||||
self.playlists.listing = res.data
|
||||
})
|
||||
document.body.removeAttribute("loading")
|
||||
},
|
||||
|
||||
getSidebarItemClass(page) {
|
||||
if (this.page == page) {
|
||||
return ["active"]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
async mkapi(method, library = false, term, params = {}, params2 = {}, attempts = 0) {
|
||||
if (attempts > 3) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (library) {
|
||||
return await this.mk.api.library[method](term, params, params2)
|
||||
} else {
|
||||
return await this.mk.api[method](term, params, params2)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return await this.mkapi(method, library, term, params, params2, attempts + 1)
|
||||
}
|
||||
},
|
||||
async getLibrarySongs() {
|
||||
var response = await this.mkapi("songs", true, "", {limit: 100}, {includeResponseMeta: !0})
|
||||
this.library.songs.listing = response.data
|
||||
this.library.songs.meta = response.meta
|
||||
},
|
||||
async getListenNow(attempt = 0) {
|
||||
if (attempt > 3) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
this.listennow = await this.mk.api.personalRecommendations("",
|
||||
{
|
||||
name: "listen-now",
|
||||
with: "friendsMix,library,social",
|
||||
"art[social-profiles:url]": "c",
|
||||
"art[url]": "c,f",
|
||||
"omit[resource]": "autos",
|
||||
"relate[editorial-items]": "contents",
|
||||
extend: ["editorialCard", "editorialVideo"],
|
||||
"extend[albums]": ["artistUrl"],
|
||||
"extend[library-albums]": ["artistUrl"],
|
||||
"extend[playlists]": ["artistNames", "editorialArtwork"],
|
||||
"extend[library-playlists]": ["artistNames", "editorialArtwork"],
|
||||
"extend[social-profiles]": "topGenreNames",
|
||||
"include[albums]": "artists",
|
||||
"include[songs]": "artists",
|
||||
"include[music-videos]": "artists",
|
||||
"fields[albums]": ["artistName", "artistUrl", "artwork", "contentRating", "editorialArtwork", "editorialVideo", "name", "playParams", "releaseDate", "url"],
|
||||
"fields[artists]": ["name", "url"],
|
||||
"extend[stations]": ["airDate", "supportsAirTimeUpdates"],
|
||||
"meta[stations]": "inflectionPoints",
|
||||
types: "artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-profiles,social-upsells",
|
||||
platform: "web"
|
||||
},
|
||||
{
|
||||
includeResponseMeta: !0,
|
||||
reload: !0
|
||||
});
|
||||
console.log(this.listennow)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.getListenNow(attempt + 1)
|
||||
}
|
||||
},
|
||||
async getRadioStations(attempt = 0) {
|
||||
if (attempt > 3) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
this.radio.personal = await this.mkapi("recentRadioStations", false, "",
|
||||
{
|
||||
"platform": "web",
|
||||
"art[url]": "f"
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.getRadioStations(attempt + 1)
|
||||
}
|
||||
},
|
||||
unauthorize() {
|
||||
this.mk.unauthorize()
|
||||
},
|
||||
showSearch() {
|
||||
this.page = "search"
|
||||
},
|
||||
playMediaItemById(id, kind) {
|
||||
this.mk.setQueue({[kind]: [id]}).then(function (queue) {
|
||||
MusicKit.getInstance().play()
|
||||
})
|
||||
},
|
||||
searchQuery() {
|
||||
let self = this
|
||||
this.mk.api.search(this.search.term,
|
||||
{
|
||||
types: "songs,artists,albums,playlists",
|
||||
limit: self.search.limit
|
||||
}).then(function (results) {
|
||||
self.search.results = results
|
||||
})
|
||||
},
|
||||
mkReady() {
|
||||
if (this.mk["nowPlayingItem"]) {
|
||||
|
@ -19,6 +226,19 @@ var app = new Vue({
|
|||
return false
|
||||
}
|
||||
},
|
||||
getMediaItemArtwork(url, size = 64) {
|
||||
return `url("${url.replace('{w}', size).replace('{h}', size).replace('{f}', "webp").replace('{c}', "cc")}")`;
|
||||
},
|
||||
getNowPlayingArtworkBG(size = 600) {
|
||||
if(!this.mkReady()) {
|
||||
return ""
|
||||
}
|
||||
if (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"]) {
|
||||
return `${this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"].replace('{w}', size).replace('{h}', size)}`;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
getNowPlayingArtwork(size = 600) {
|
||||
if (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"]) {
|
||||
return `url("${this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"].replace('{w}', size).replace('{h}', size)}")`;
|
||||
|
@ -36,18 +256,63 @@ var app = new Vue({
|
|||
}, 1000)
|
||||
})
|
||||
})
|
||||
},
|
||||
apiCall(url, callback) {
|
||||
const xmlHttp = new XMLHttpRequest();
|
||||
|
||||
xmlHttp.onreadystatechange = (e) => {
|
||||
if (xmlHttp.readyState !== 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (xmlHttp.status === 200) {
|
||||
console.log('SUCCESS', xmlHttp.responseText);
|
||||
callback(JSON.parse(xmlHttp.responseText));
|
||||
} else {
|
||||
console.warn('request_error');
|
||||
}
|
||||
};
|
||||
|
||||
xmlHttp.open("GET", url);
|
||||
xmlHttp.setRequestHeader("Authorization", "Bearer " + MusicKit.getInstance().developerToken);
|
||||
xmlHttp.setRequestHeader("Music-User-Token", "" + MusicKit.getInstance().musicUserToken);
|
||||
xmlHttp.setRequestHeader("Accept", "application/json");
|
||||
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
||||
xmlHttp.responseType = "text";
|
||||
xmlHttp.send();
|
||||
},
|
||||
fetchPlaylist(id, callback) {
|
||||
// id can be found in playlist.attributes.playParams.globalId
|
||||
this.mk.api.playlist(id).then(res => {
|
||||
callback(res)
|
||||
})
|
||||
|
||||
// tracks are found in relationship.data
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener('musickitloaded', function () {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
// MusicKit global is now defined
|
||||
fetch("https://beta.music.apple.com/")
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
var el = document.createElement("html");
|
||||
el.innerHTML = data;
|
||||
var u = el.querySelector(`[name="desktop-music-app/config/environment"]`)
|
||||
var amwebCFG = JSON.parse(decodeURIComponent(u.getAttribute("content")));
|
||||
console.log(amwebCFG.MEDIA_API.token)
|
||||
// eh fuck it lets just expose the token
|
||||
MusicKit.configure({
|
||||
developerToken: `${urlParams.get('auth') || ''}`,
|
||||
developerToken: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IldlYlBsYXlLaWQifQ.eyJpc3MiOiJBTVBXZWJQbGF5IiwiaWF0IjoxNjM2NTYwMjc1LCJleHAiOjE2NTIxMTIyNzV9.is4KeAN_M9FWTfuw9zMV2lgHSSdPqEV2SX-XfCuEYY4qtmjbo-NjebHCageS28z0P0erksqql9rtsoizE4hsJg",
|
||||
app: {
|
||||
name: 'My Cool Web App',
|
||||
name: 'Cider',
|
||||
build: '1978.4.1'
|
||||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
app.init()
|
||||
}, 1000)
|
||||
});
|
||||
|
||||
});
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
:root {
|
||||
--appleEase: cubic-bezier(0.42, 0, 0.58, 1);
|
||||
--mediaItemShadow-Shadow: inset 0px 0px 0px 1px rgb(200 200 200 / 16%), 0 8px 40px rgb(0 0 0 / 0.55);
|
||||
--mediaItemShadow: inset 0px 0px 0px 1px rgb(200 200 200 / 16%);
|
||||
--mediaItemRadius: 4px;
|
||||
--mediaItemRadiusRound: 100%;
|
||||
--keyColor: #fa586a;
|
||||
--keyColor-rgb: 250, 88, 106;
|
||||
--keyColor-rollover: #ff8a9c;
|
||||
|
@ -27,6 +31,12 @@ body {
|
|||
|
||||
body {
|
||||
background: transparent;
|
||||
transition: opacity .10s var(--appleEase);
|
||||
}
|
||||
|
||||
body[loading] {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
*,
|
||||
|
@ -76,6 +86,24 @@ body {
|
|||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
.bg-artwork--placeholder {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #222;
|
||||
z-index: -1;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
opacity: 0.70;
|
||||
}
|
||||
|
||||
|
||||
.bg-artwork {
|
||||
position: absolute;
|
||||
|
@ -83,10 +111,20 @@ body {
|
|||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url("artwork.jpeg");
|
||||
background: var(--artwork);
|
||||
z-index: -1;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
filter: blur(60px) saturate(180%);
|
||||
display: none;
|
||||
opacity: 0.70;
|
||||
transition: opacity .25s var(--appleEase);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
[artwork-hidden] {
|
||||
transition: opacity .25s var(--appleEase);
|
||||
opacity:0;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -145,17 +183,26 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
|||
flex-direction: column;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
#app-content {
|
||||
background-color: var(--color2);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 32px;
|
||||
overflow-y: scroll;
|
||||
overflow-y: overlay;
|
||||
overflow-x: hidden;
|
||||
border-radius: 10px 0px;
|
||||
border-left: 1px solid rgb(0 0 0 / 25%);
|
||||
border-top: 1px solid rgb(0 0 0 / 25%);
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.content-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 32px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
@ -323,8 +370,7 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
|||
|
||||
.app-chrome .app-chrome--left,
|
||||
.app-chrome .app-chrome--center,
|
||||
.app-chrome .app-chrome--right
|
||||
{
|
||||
.app-chrome .app-chrome--right {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
@ -444,9 +490,11 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
|||
height: 100%;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.app-chrome .app-chrome-item > .window-controls > div:hover {
|
||||
background: rgb(200 200 200 / 10%);
|
||||
}
|
||||
|
||||
.app-chrome .app-chrome-item > .window-controls > div.close {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -494,12 +542,19 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
|||
font-weight: 600;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-chrome .app-chrome-item > .app-playback-controls .song-artist {
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
overflow: hidden;
|
||||
/* animation: marquee 10s linear infinite; */
|
||||
}
|
||||
|
||||
.app-chrome .app-chrome-item > .app-playback-controls .song-progress {
|
||||
|
@ -508,6 +563,16 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
|||
bottom: 0px;
|
||||
left: 0px;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
@keyframes marquee {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
.app-chrome .app-chrome-item > .app-playback-controls .song-progress > input[type=range] {
|
||||
|
@ -583,11 +648,13 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
|||
.display--small {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Window is smaller <= 1023px width */
|
||||
@media only screen and (max-width: 1023px) {
|
||||
.display--small {
|
||||
display: inherit !important;
|
||||
}
|
||||
|
||||
.display--large {
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -1198,6 +1265,205 @@ input[type=range].web-slider::-webkit-slider-runnable-track {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
/* Cider */
|
||||
|
||||
.text-overflow-elipsis {
|
||||
min-width: 0px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* horizontal media scroller */
|
||||
.cd-hmedia-scroller {
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.cd-hmedia-scroller::-webkit-scrollbar-thumb{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.cd-hmedia-scroller:hover::-webkit-scrollbar-thumb{
|
||||
box-shadow: inset 0px 0px 10px 10px rgb(200 200 200 / 50%);
|
||||
}
|
||||
|
||||
/* mediaitem-list-item */
|
||||
.cd-mediaitem-list-item {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row;
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgb(200 200 200 / 10%);
|
||||
}
|
||||
|
||||
.cd-mediaitem-list-item:hover {
|
||||
background: rgb(200 200 200 / 10%);
|
||||
}
|
||||
|
||||
.cd-mediaitem-list-item .artwork {
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
background: blue;
|
||||
border-radius: var(--mediaItemRadius);
|
||||
background: var(--artwork);
|
||||
background-size: contain;
|
||||
box-shadow: var(--mediaItemShadow);
|
||||
flex: 0 0 auto;
|
||||
background-repeat: no-repeat;
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
.cd-mediaitem-list-item .artwork.round {
|
||||
border-radius: var(--mediaItemRadiusRound);
|
||||
}
|
||||
|
||||
.cd-mediaitem-list-item .info-rect {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cd-mediaitem-list-item .title {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cd-mediaitem-list-item .subtitle {
|
||||
width: 90%;
|
||||
font-size: 12px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.cd-mediaitem-list-item .content-rating {
|
||||
text-transform: uppercase;
|
||||
font-size: 10px;
|
||||
border-radius: 3px;
|
||||
background: rgb(200 200 200 / 15%);
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
margin-right: 12px;
|
||||
flex: 0 0 auto;
|
||||
font-weight: 500;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* mediaitem-hrect */
|
||||
.cd-mediaitem-hrect {
|
||||
background: rgb(255 255 255 / 18%);
|
||||
width: 264px;
|
||||
height: 100px;
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row;
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cd-mediaitem-hrect .artwork {
|
||||
height: 70px;
|
||||
width: 70px;
|
||||
background: blue;
|
||||
border-radius: var(--mediaItemRadius);
|
||||
background: var(--artwork);
|
||||
background-size: contain;
|
||||
box-shadow: var(--mediaItemShadow);
|
||||
flex: 0 0 auto;
|
||||
background-repeat: no-repeat;
|
||||
margin: 18px;
|
||||
}
|
||||
|
||||
.cd-mediaitem-hrect .artwork.round {
|
||||
border-radius: var(--mediaItemRadiusRound);
|
||||
}
|
||||
|
||||
.cd-mediaitem-hrect .info-rect {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cd-mediaitem-hrect .title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cd-mediaitem-hrect .subtitle {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
/* mediaitem-square */
|
||||
.cd-mediaitem-square {
|
||||
width: 200px;
|
||||
height: 190px;
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: column;
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cd-mediaitem-square:hover {
|
||||
background: rgb(200 200 200 / 10%);
|
||||
}
|
||||
|
||||
.cd-mediaitem-square .artwork {
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
background: blue;
|
||||
border-radius: var(--mediaItemRadius);
|
||||
background: var(--artwork);
|
||||
background-size: cover;
|
||||
box-shadow: var(--mediaItemShadow);
|
||||
flex: 0 0 auto;
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
.cd-mediaitem-square .artwork.round {
|
||||
border-radius: var(--mediaItemRadiusRound);
|
||||
}
|
||||
|
||||
.cd-mediaitem-square .title {
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cd-mediaitem-square .subtitle {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
.cd-btn-seeall {
|
||||
background: transparent;
|
||||
border: 0px;
|
||||
color: var(--keyColor);
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.cd-btn-seeall:hover {
|
||||
cursor: pointer;
|
||||
background: rgb(200 200 200 / 10%)
|
||||
}
|
||||
|
||||
/* Cider */
|
||||
|
||||
/* Transitions */
|
||||
.wpfade-enter-active,
|
||||
.wpfade-leave-active {
|
||||
|
|
|
@ -302,10 +302,11 @@ document.addEventListener('musickitloaded', function () {
|
|||
var u = el.querySelector(`[name="desktop-music-app/config/environment"]`)
|
||||
var amwebCFG = JSON.parse(decodeURIComponent(u.getAttribute("content")));
|
||||
console.log(amwebCFG.MEDIA_API.token)
|
||||
// eh fuck it lets just expose the token
|
||||
MusicKit.configure({
|
||||
developerToken: amwebCFG.MEDIA_API.token,
|
||||
developerToken: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IldlYlBsYXlLaWQifQ.eyJpc3MiOiJBTVBXZWJQbGF5IiwiaWF0IjoxNjM2NTYwMjc1LCJleHAiOjE2NTIxMTIyNzV9.is4KeAN_M9FWTfuw9zMV2lgHSSdPqEV2SX-XfCuEYY4qtmjbo-NjebHCageS28z0P0erksqql9rtsoizE4hsJg",
|
||||
app: {
|
||||
name: 'My Cool Web App',
|
||||
name: 'Cider',
|
||||
build: '1978.4.1'
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue