A music player that connects to your cloud/distributed storage.
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: play from browser

+80 -19
+1 -1
src/component/engine/queue/worker.js
··· 138 138 const n = $now.value; 139 139 const f = future ?? $future.value; 140 140 141 + $now.value = f[0] ?? null; 141 142 if (n) $past.value = [...$past.value, n]; 142 143 $future.value = fill(f.slice(1)); 143 - $now.value = f[0] ?? null; 144 144 }
+12 -6
src/theme/webamp/browser/element.js
··· 20 20 21 21 /** @type {import("@component/engine/queue/element.js").CLASS} */ 22 22 this.queue = query(this, "queue-selector"); 23 + 24 + /** @type {import("../webamp.js").CLASS} */ 25 + this.amp = query(this, "webamp-selector"); 23 26 } 24 27 25 28 // LIFECYCLE ··· 65 68 */ 66 69 playTrack(track) { 67 70 console.log("Play track", track); 68 - this.queue.add({ 69 - inFront: true, 70 - items: [ 71 - { ...track, manualEntry: true }, 72 - ], 73 - }); 71 + // this.queue.add({ 72 + // inFront: true, 73 + // items: [ 74 + // { ...track, manualEntry: true }, 75 + // ], 76 + // }); 77 + 78 + this.amp.addTrack(track); 79 + this.amp.amp.setCurrentTrack(this.amp.amp.getPlaylistTracks().length - 1); 74 80 } 75 81 76 82 // RENDER
+13 -12
src/theme/webamp/index.js
··· 68 68 */ 69 69 amp.store.subscribe(() => { 70 70 const state = amp.store.getState(); 71 - if (state.playlist.currentTrack !== null) { 72 - $currTrack.value = state.playlist.currentTrack; 71 + 72 + if ( 73 + state.playlist.currentTrack !== null && 74 + state.playlist.currentTrack - currBase > 0 75 + ) { 76 + $currTrack.value = state.playlist.currentTrack - currBase; 73 77 } 74 78 }); 75 79 ··· 77 81 * Whenever the queue changes update the playlist. 78 82 */ 79 83 effect(() => { 80 - const now = queue.now(); 84 + const now = untracked(queue.now); 81 85 const past = untracked(queue.past); 82 86 const future = queue.future(); 83 87 ··· 92 96 JSON.stringify(untracked($playlist.get).map((i) => i.id)), 93 97 ); 94 98 95 - console.log(hashNew, hashOld); 96 99 if (hashNew === hashOld) return; 97 100 98 - const webampTracks = playlist.map((item) => { 101 + const webampTracks = playlist.map((item, idx) => { 99 102 /** @type {URLTrack} */ 100 103 const urlTrack = { 101 104 url: item.uri, ··· 107 110 duration: item.stats?.duration, 108 111 }; 109 112 113 + if (item.stats?.duration == undefined) { 114 + throw new Error("TODO: Fetch duration"); 115 + } 110 116 return urlTrack; 111 117 }); 112 118 113 - currBase = untracked($playlist.get).length; 114 - 115 - amp.setTracksToPlay([]); 116 - amp.appendTracks(webampTracks); 117 - 118 - console.log("SET CURR", currBase + past.length); 119 - amp.setCurrentTrack(currBase + past.length); 119 + // currBase = currBase + amp.getPlaylistTracks().length; 120 + // amp.setCurrentTrack(currBase + (untracked($currTrack.get) ?? 0)); 120 121 121 122 $playlist.value = playlist; 122 123 });
+1
src/theme/webamp/index.vto
··· 33 33 input-selector="di-opensubsonic" 34 34 output-selector="do-indexed-db" 35 35 queue-selector="de-queue" 36 + webamp-selector="dtw-webamp" 36 37 ></dtw-browser> 37 38 </dtw-window> 38 39 </dtw-window-manager>
+53
src/theme/webamp/webamp.js
··· 1 1 import Webamp from "webamp/lazy"; 2 2 3 + /** 4 + * @import {Track} from "@component/core/types.d.ts" 5 + */ 3 6 class WebampElement extends HTMLElement { 4 7 constructor() { 5 8 super(); ··· 29 32 }); 30 33 } 31 34 35 + // LIFECYCLE 36 + 32 37 connectedCallback() { 33 38 this.attachShadow({ mode: "open" }); 34 39 35 40 // Custom webamp rendering 36 41 this.renderWebamp(); 37 42 } 43 + 44 + // ACTIONS 45 + 46 + /** 47 + * @param {Track} track 48 + * @param {number} [idx] 49 + */ 50 + addTrack(track, idx) { 51 + idx = idx ?? (this.amp.getPlaylistTracks().length); 52 + 53 + this.amp.store.dispatch( 54 + /** 55 + * @param {any} dispatch 56 + */ 57 + (dispatch) => { 58 + dispatch({ 59 + type: "ADD_TRACK_FROM_URL", 60 + url: track.uri, 61 + duration: track.stats?.duration, 62 + defaultName: undefined, 63 + id: idx, 64 + atIndex: idx, 65 + }); 66 + 67 + dispatch({ 68 + type: "SET_MEDIA_DURATION", 69 + duration: track.stats?.duration, 70 + id: idx, 71 + }); 72 + 73 + dispatch({ 74 + type: "SET_MEDIA_TAGS", 75 + artist: track.tags?.artist, 76 + title: track.tags?.title, 77 + album: track.tags?.album, 78 + // For now, we lie about these next three things. 79 + // TODO: Ideally we would leave these as null and force a media data 80 + // fetch when the user starts playing. 81 + sampleRate: 44000, 82 + bitrate: 192000, 83 + numberOfChannels: 2, 84 + id: idx, 85 + }); 86 + }, 87 + ); 88 + } 89 + 90 + // RENDER 38 91 39 92 async renderWebamp() { 40 93 // Ideally this would render in the shadow root,