Initial support for offline playback

This commit is contained in:
Shiny Nematoda 2023-06-20 15:53:45 +00:00
parent 1372d87beb
commit 4353cacead
9 changed files with 116 additions and 50 deletions

View file

@ -93,12 +93,12 @@ function parseUrl() {
function playThis(t) {
const i = data.state.urls.indexOf(t);
data.getSong(data.state.urls[i].url);
data.play(data.state.urls[i]);
}
function playList(a) {
data.state.urls = a;
data.getSong(data.state.urls[0].url);
data.play(data.state.urls[0]);
}
/* Lifestyle hooks */

View file

@ -1,3 +1,3 @@
{
"date": "2023-06-13"
"date": "2023-06-20"
}

View file

@ -75,10 +75,8 @@ const setProxy = async () => {
title: 'Local • ' + key,
items: res.urls.map(i => ({
...i,
...{
playlistId: key,
thumbnail: parseThumb(i.url, proxy.value),
},
playlistId: key,
thumbnail: parseThumb(i.url, proxy.value),
})),
});
@ -86,6 +84,23 @@ const setProxy = async () => {
} else alert('No songs to play!');
});
},
OpenOffline = async () => {
if (window.offline) {
const songs = await window.offline.list();
console.log();
results.resetItems();
results.setItem('songs', {
title: 'Hyp • Offline',
items: songs.map(i => ({
...i.appMetadata,
offlineUri: i.offlineUri,
thumbnail: parseThumb(i.appMetadata.url, proxy.value),
duration: i.duration
})),
});
nav.state.page = 'home';
}
},
List = async () => {
if (!proxy.value) await setProxy();
@ -421,6 +436,7 @@ onMounted(async () => {
<h2 v-if="list.length > 0">{{ t('playlist.local') }}</h2>
<div class="grid-3">
<AlbumItem name="Offline" :grad="useRand()" @open-album="OpenOffline()" />
<AlbumItem
v-for="i in list"
:key="i.name"

View file

@ -60,6 +60,18 @@ async function Stream() {
}
});
window.offline = new shaka.offline.Storage(audioPlayer);
window.offline.configure({
offline: {
progressCallback: (data, prog) => console.log(data, prog),
trackSelectionCallback: tracks => [
tracks
.sort((a, b) => a.bandwidth - b.bandwidth)
.find(i => i.type == 'variant'),
],
},
});
audioPlayer.configure({
preferredAudioCodecs: codecs ? codecs.split(':') : ['opus', 'mp4a'],
manifest: {
@ -171,7 +183,7 @@ onMounted(() => {
if (data.state.urls.length > 2) {
const i = data.state.urls.findIndex(s => s.url == data.state.url);
data.getSong(data.state.urls[i - 1].url);
data.play(data.state.urls[i - 1]);
}
});
@ -179,7 +191,7 @@ onMounted(() => {
if (data.state.urls.length > 2) {
const i = data.state.urls.findIndex(s => s.url == data.state.url);
data.getSong(data.state.urls[i + 1].url);
data.play(data.state.urls[i + 1]);
}
});

View file

@ -34,6 +34,9 @@ const shuffleAdd = () => {
url: i.url,
title: i.title,
thumbnails: [{ url: i.thumbnail }],
thumbnail: i.thumbnail,
offlineUri: i.offlineUri,
duration: i.duration
})),
copy = [];
@ -56,9 +59,13 @@ const shuffleAdd = () => {
url: i.url || '/watch?v=' + song.id,
title: i.title,
thumbnails: [{ url: i.thumbnail }],
thumbnail: i.thumbnail,
offlineUri: i.offlineUri,
duration: i.duration
}));
data.getSong(song.url || '/watch?v=' + song.id);
song.url = song.url || '/watch?v=' + song.id;
data.play(song);
} else {
emit('play-urls', [
{
@ -245,6 +252,9 @@ onDeactivated(() => {
url: item.url,
title: item.title,
thumbnails: [{ url: item.thumbnail }],
thumbnail: item.thumbnail,
offlineUri: item.offlineUri,
duration: item.duration
})),
)
" />
@ -313,9 +323,11 @@ onDeactivated(() => {
:key="song.url || song.id"
:index="index"
:playlistId="song.playlistId"
:author="song.uploaderName || song.subtitle"
:author="song.uploaderName || song.artist || song.subtitle"
:title="song.title || song.name"
:channel="song.uploaderUrl || '/channel/' + song.subId"
:channel="
song.uploaderUrl || song.artistUrl || '/channel/' + song.subId
"
:play="song.url || '/watch?v=' + song.id"
:art="
song.thumbnail ||

View file

@ -75,6 +75,17 @@ function Save() {
}
}
async function Offline() {
if (window.offline && data.state.url) {
window.offline.store(window.audioPlayer.getAssetUri(), {
title: data.state.title,
url: data.state.url,
artist: data.state.artist,
artistUrl: data.state.artistUrl,
});
} else console.error('no offline storage found');
}
async function Like() {
liking.value = true;
@ -279,6 +290,12 @@ async function Like() {
:data-loading="liking"
@click="Like"></button>
<button
id="dl-btn"
title="Save for Offline Playback"
class="bi bi-download clickable"
@click="Offline"></button>
<button
id="addToPlaylist"
title="Add Current Song to a Playlist"

View file

@ -39,6 +39,15 @@ export const useData = defineStore('data', () => {
await getNext(hash);
}
async function play(song) {
if (song.offlineUri) {
state.art = song.thumbnail;
player.state.duration = song.duration
for (let i of ['title', 'artist', 'artistUrl', 'url']) state[i] = song[i];
window.audioPlayer.load(song.offlineUri);
} else await getSong(song.url);
}
async function getNext(hash) {
if (
store.getItem('next') !== 'false' &&
@ -97,34 +106,34 @@ export const useData = defineStore('data', () => {
state.urls.length != 0 &&
state.urls[i + 1]
)
getSong(state.urls[i + 1].url);
play(state.urls[i + 1]);
else if (player.state.loop == 1) {
state.url = state.urls[0].url;
getSong(state.urls[0].url);
play(state.urls[0]);
} else state.urls = [];
}
function prevTrack() {
const i = state.urls.findIndex(s => s.url === state.url);
if (state.urls[i - 1]) getSong(state.urls[i - 1].url);
if (state.urls[i - 1]) play(state.urls[i - 1]);
else if (player.state.loop == 1) {
state.url = state.urls[state.urls.length - 1].url;
getSong(state.urls[state.urls.length - 1].url);
play(state.urls[state.urls.length - 1]);
} else state.urls = [];
}
function nextTrack() {
const i = state.urls.findIndex(s => s.url === state.url);
if (state.urls[i + 1]) getSong(state.urls[i + 1].url);
if (state.urls[i + 1]) play(state.urls[i + 1]);
else if (player.state.loop == 1) {
state.url = state.urls[0].url;
getSong(state.urls[0].url);
play(state.urls[0]);
} else state.urls = [];
}
return { state, getSong, playNext, prevTrack, nextTrack };
return { state, getSong, play, playNext, prevTrack, nextTrack };
});
export const usePlayer = defineStore('player', () => {