style: auto-fix linting issues
This commit is contained in:
parent
1cb17680f3
commit
3e212a7e5b
4 changed files with 190 additions and 181 deletions
|
|
@ -1493,10 +1493,12 @@
|
|||
}
|
||||
</script>
|
||||
<p style="padding-top: 50px; text-align: center; color: #8b8b93">
|
||||
We only store music data and a randomized ID to find out which Google/Email account is which.
|
||||
We only store music data and a randomized ID to find out which Google/Email account is
|
||||
which.
|
||||
<br />
|
||||
All data is anonymous. We do not store anything like emails, usernames, or anything
|
||||
sensitive. <br />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="page-donate" class="page">
|
||||
|
|
|
|||
|
|
@ -19,22 +19,22 @@ const syncManager = {
|
|||
if (this._userRecordCache && this._userRecordCache.firebase_id === uid) {
|
||||
return this._userRecordCache;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const record = await this.pb.collection('DB_users').getFirstListItem(
|
||||
`firebase_id="${uid}"`,
|
||||
{ f_id: uid }
|
||||
);
|
||||
const record = await this.pb.collection('DB_users').getFirstListItem(`firebase_id="${uid}"`, { f_id: uid });
|
||||
this._userRecordCache = record;
|
||||
return record;
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
try {
|
||||
const newRecord = await this.pb.collection('DB_users').create({
|
||||
firebase_id: uid,
|
||||
library: {},
|
||||
history: [],
|
||||
}, { f_id: uid });
|
||||
const newRecord = await this.pb.collection('DB_users').create(
|
||||
{
|
||||
firebase_id: uid,
|
||||
library: {},
|
||||
history: [],
|
||||
},
|
||||
{ f_id: uid }
|
||||
);
|
||||
this._userRecordCache = newRecord;
|
||||
return newRecord;
|
||||
} catch (createError) {
|
||||
|
|
@ -95,11 +95,7 @@ const syncManager = {
|
|||
}
|
||||
|
||||
try {
|
||||
const updated = await this.pb.collection('DB_users').update(
|
||||
record.id,
|
||||
{ [field]: data },
|
||||
{ f_id: uid }
|
||||
);
|
||||
const updated = await this.pb.collection('DB_users').update(record.id, { [field]: data }, { f_id: uid });
|
||||
this._userRecordCache = updated;
|
||||
} catch (error) {
|
||||
console.error(`Failed to sync ${field} to PocketBase:`, error);
|
||||
|
|
@ -114,13 +110,13 @@ const syncManager = {
|
|||
if (!record) return;
|
||||
|
||||
let library = record.library || {};
|
||||
|
||||
|
||||
if (typeof library === 'string') {
|
||||
try {
|
||||
library = JSON.parse(library);
|
||||
} catch (e) {
|
||||
console.error('Library field is not valid JSON', e);
|
||||
library = {};
|
||||
library = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +251,7 @@ const syncManager = {
|
|||
if (!record) return;
|
||||
|
||||
let userPlaylists = record.user_playlists || {};
|
||||
|
||||
|
||||
if (typeof userPlaylists === 'string') {
|
||||
try {
|
||||
userPlaylists = JSON.parse(userPlaylists);
|
||||
|
|
@ -272,7 +268,7 @@ const syncManager = {
|
|||
id: playlist.id,
|
||||
name: playlist.name,
|
||||
cover: playlist.cover || null,
|
||||
tracks: playlist.tracks ? playlist.tracks.map(t => this._minifyItem('track', t)) : [],
|
||||
tracks: playlist.tracks ? playlist.tracks.map((t) => this._minifyItem('track', t)) : [],
|
||||
createdAt: playlist.createdAt || Date.now(),
|
||||
updatedAt: playlist.updatedAt || Date.now(),
|
||||
numberOfTracks: playlist.tracks ? playlist.tracks.length : 0,
|
||||
|
|
@ -286,18 +282,19 @@ const syncManager = {
|
|||
|
||||
async getPublicPlaylist(uuid) {
|
||||
try {
|
||||
const record = await this.pb.collection(PUBLIC_COLLECTION).getFirstListItem(
|
||||
`uuid="${uuid}"`,
|
||||
{ p_id: uuid }
|
||||
);
|
||||
const record = await this.pb
|
||||
.collection(PUBLIC_COLLECTION)
|
||||
.getFirstListItem(`uuid="${uuid}"`, { p_id: uuid });
|
||||
|
||||
let rawCover = record.image || record.cover || record.playlist_cover || '';
|
||||
let extraData = record.data;
|
||||
|
||||
|
||||
if (typeof extraData === 'string') {
|
||||
try { extraData = JSON.parse(extraData); } catch(e) {}
|
||||
try {
|
||||
extraData = JSON.parse(extraData);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
|
||||
if (!rawCover && extraData && typeof extraData === 'object') {
|
||||
rawCover = extraData.cover || extraData.image || '';
|
||||
}
|
||||
|
|
@ -309,7 +306,7 @@ const syncManager = {
|
|||
|
||||
let images = [];
|
||||
let tracks = record.tracks || [];
|
||||
|
||||
|
||||
if (typeof tracks === 'string') {
|
||||
try {
|
||||
tracks = JSON.parse(tracks);
|
||||
|
|
@ -338,7 +335,6 @@ const syncManager = {
|
|||
finalTitle = extraData.title || extraData.name;
|
||||
}
|
||||
if (!finalTitle) finalTitle = 'Untitled Playlist';
|
||||
|
||||
|
||||
return {
|
||||
...record,
|
||||
|
|
@ -352,7 +348,7 @@ const syncManager = {
|
|||
numberOfTracks: tracks.length,
|
||||
type: 'user-playlist',
|
||||
isPublic: true,
|
||||
user: { name: 'Community Playlist' }
|
||||
user: { name: 'Community Playlist' },
|
||||
};
|
||||
} catch (error) {
|
||||
if (error.status === 404) return null;
|
||||
|
|
@ -379,14 +375,14 @@ const syncManager = {
|
|||
isPublic: true,
|
||||
data: {
|
||||
title: playlist.name,
|
||||
cover: playlist.cover
|
||||
}
|
||||
cover: playlist.cover,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const existing = await this.pb.collection(PUBLIC_COLLECTION).getList(1, 1, {
|
||||
filter: `uuid="${playlist.id}"`,
|
||||
p_id: playlist.id
|
||||
p_id: playlist.id,
|
||||
});
|
||||
|
||||
if (existing.items.length > 0) {
|
||||
|
|
@ -406,7 +402,7 @@ const syncManager = {
|
|||
try {
|
||||
const existing = await this.pb.collection('public_playlists').getList(1, 1, {
|
||||
filter: `uuid="${uuid}"`,
|
||||
p_id: uuid
|
||||
p_id: uuid,
|
||||
});
|
||||
|
||||
if (existing.items && existing.items.length > 0) {
|
||||
|
|
@ -439,24 +435,36 @@ const syncManager = {
|
|||
if (this._isSyncing) return;
|
||||
|
||||
this._isSyncing = true;
|
||||
|
||||
|
||||
try {
|
||||
const data = await this.getUserData();
|
||||
|
||||
|
||||
if (data) {
|
||||
const convertedData = {
|
||||
favorites_tracks: data.library.tracks ? Object.values(data.library.tracks).filter(t => t && typeof t === 'object') : [],
|
||||
favorites_albums: data.library.albums ? Object.values(data.library.albums).filter(a => a && typeof a === 'object') : [],
|
||||
favorites_artists: data.library.artists ? Object.values(data.library.artists).filter(a => a && typeof a === 'object') : [],
|
||||
favorites_playlists: data.library.playlists ? Object.values(data.library.playlists).filter(p => p && typeof p === 'object') : [],
|
||||
favorites_mixes: data.library.mixes ? Object.values(data.library.mixes).filter(m => m && typeof m === 'object') : [],
|
||||
favorites_tracks: data.library.tracks
|
||||
? Object.values(data.library.tracks).filter((t) => t && typeof t === 'object')
|
||||
: [],
|
||||
favorites_albums: data.library.albums
|
||||
? Object.values(data.library.albums).filter((a) => a && typeof a === 'object')
|
||||
: [],
|
||||
favorites_artists: data.library.artists
|
||||
? Object.values(data.library.artists).filter((a) => a && typeof a === 'object')
|
||||
: [],
|
||||
favorites_playlists: data.library.playlists
|
||||
? Object.values(data.library.playlists).filter((p) => p && typeof p === 'object')
|
||||
: [],
|
||||
favorites_mixes: data.library.mixes
|
||||
? Object.values(data.library.mixes).filter((m) => m && typeof m === 'object')
|
||||
: [],
|
||||
history_tracks: data.history || [],
|
||||
user_playlists: data.userPlaylists ? Object.values(data.userPlaylists).filter(p => p && typeof p === 'object') : [],
|
||||
user_playlists: data.userPlaylists
|
||||
? Object.values(data.userPlaylists).filter((p) => p && typeof p === 'object')
|
||||
: [],
|
||||
};
|
||||
|
||||
|
||||
await db.importData(convertedData);
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
|
||||
window.dispatchEvent(new CustomEvent('library-changed'));
|
||||
window.dispatchEvent(new CustomEvent('history-changed'));
|
||||
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
||||
|
|
@ -477,4 +485,4 @@ if (pb) {
|
|||
authManager.onAuthStateChanged(syncManager.onAuthStateChanged.bind(syncManager));
|
||||
}
|
||||
|
||||
export { pb, syncManager };
|
||||
export { pb, syncManager };
|
||||
|
|
|
|||
261
js/db.js
261
js/db.js
|
|
@ -141,28 +141,28 @@ export class MusicDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
async getFavorites(type) {
|
||||
const plural = type === 'mix' ? 'mixes' : `${type}s`;
|
||||
const storeName = `favorites_${plural}`;
|
||||
const db = await this.open();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(storeName, 'readonly');
|
||||
const store = transaction.objectStore(storeName);
|
||||
|
||||
const request = store.getAll();
|
||||
|
||||
request.onsuccess = () => {
|
||||
const results = request.result;
|
||||
results.sort((a, b) => {
|
||||
const aTime = a.addedAt || 0;
|
||||
const bTime = b.addedAt || 0;
|
||||
return bTime - aTime; // Newest first
|
||||
});
|
||||
resolve(results);
|
||||
};
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
async getFavorites(type) {
|
||||
const plural = type === 'mix' ? 'mixes' : `${type}s`;
|
||||
const storeName = `favorites_${plural}`;
|
||||
const db = await this.open();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(storeName, 'readonly');
|
||||
const store = transaction.objectStore(storeName);
|
||||
|
||||
const request = store.getAll();
|
||||
|
||||
request.onsuccess = () => {
|
||||
const results = request.result;
|
||||
results.sort((a, b) => {
|
||||
const aTime = a.addedAt || 0;
|
||||
const bTime = b.addedAt || 0;
|
||||
return bTime - aTime; // Newest first
|
||||
});
|
||||
resolve(results);
|
||||
};
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
|
||||
_minifyItem(type, item) {
|
||||
if (!item) return item;
|
||||
|
|
@ -281,105 +281,102 @@ export class MusicDatabase {
|
|||
return data;
|
||||
}
|
||||
|
||||
async importData(data, clear = false) {
|
||||
const db = await this.open();
|
||||
|
||||
const importStore = async (storeName, items) => {
|
||||
if (items === undefined) return false;
|
||||
|
||||
let itemsArray = Array.isArray(items) ? items : Object.values(items || {});
|
||||
|
||||
console.log(`Importing to ${storeName}: ${itemsArray.length} items`);
|
||||
|
||||
if (itemsArray.length === 0) {
|
||||
if (clear) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(storeName, 'readwrite');
|
||||
const store = transaction.objectStore(storeName);
|
||||
|
||||
const countReq = store.count();
|
||||
countReq.onsuccess = () => {
|
||||
if (countReq.result > 0) {
|
||||
store.clear();
|
||||
}
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
resolve(countReq.result > 0);
|
||||
};
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(storeName, 'readwrite');
|
||||
const store = transaction.objectStore(storeName);
|
||||
let hasChanges = false;
|
||||
|
||||
// force clear on first sync
|
||||
console.log(`Clearing ${storeName} to Make Sure Everythings Good`);
|
||||
store.clear();
|
||||
hasChanges = true;
|
||||
|
||||
itemsArray.forEach((item) => {
|
||||
if (item.id && typeof item.id === 'string' && !isNaN(item.id)) {
|
||||
item.id = parseInt(item.id, 10);
|
||||
}
|
||||
if (item.album?.id && typeof item.album.id === 'string' && !isNaN(item.album.id)) {
|
||||
item.album.id = parseInt(item.album.id, 10);
|
||||
}
|
||||
if (item.artists) {
|
||||
item.artists.forEach(artist => {
|
||||
if (artist.id && typeof artist.id === 'string' && !isNaN(artist.id)) {
|
||||
artist.id = parseInt(artist.id, 10);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`${storeName}: Adding item with ID ${item.id || item.uuid || item.timestamp}`);
|
||||
store.put(item);
|
||||
});
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
console.log(`${storeName}: Imported ${itemsArray.length} items`);
|
||||
resolve(true);
|
||||
};
|
||||
|
||||
transaction.onerror = (event) => {
|
||||
console.error(`${storeName}: Transaction error:`, event.target.error);
|
||||
reject(transaction.error);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
console.log('Starting import with data:', {
|
||||
tracks: data.favorites_tracks?.length || 0,
|
||||
albums: data.favorites_albums?.length || 0,
|
||||
artists: data.favorites_artists?.length || 0,
|
||||
playlists: data.favorites_playlists?.length || 0,
|
||||
mixes: data.favorites_mixes?.length || 0,
|
||||
history: data.history_tracks?.length || 0,
|
||||
userPlaylists: data.user_playlists?.length || 0,
|
||||
});
|
||||
|
||||
const results = await Promise.all([
|
||||
importStore('favorites_tracks', data.favorites_tracks),
|
||||
importStore('favorites_albums', data.favorites_albums),
|
||||
importStore('favorites_artists', data.favorites_artists),
|
||||
importStore('favorites_playlists', data.favorites_playlists),
|
||||
importStore('favorites_mixes', data.favorites_mixes),
|
||||
importStore('history_tracks', data.history_tracks),
|
||||
data.user_playlists ? importStore('user_playlists', data.user_playlists) : Promise.resolve(false),
|
||||
]);
|
||||
|
||||
console.log('Import results:', results);
|
||||
return results.some((r) => r);
|
||||
}
|
||||
async importData(data, clear = false) {
|
||||
const db = await this.open();
|
||||
|
||||
const importStore = async (storeName, items) => {
|
||||
if (items === undefined) return false;
|
||||
|
||||
let itemsArray = Array.isArray(items) ? items : Object.values(items || {});
|
||||
|
||||
console.log(`Importing to ${storeName}: ${itemsArray.length} items`);
|
||||
|
||||
if (itemsArray.length === 0) {
|
||||
if (clear) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(storeName, 'readwrite');
|
||||
const store = transaction.objectStore(storeName);
|
||||
|
||||
const countReq = store.count();
|
||||
countReq.onsuccess = () => {
|
||||
if (countReq.result > 0) {
|
||||
store.clear();
|
||||
}
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
resolve(countReq.result > 0);
|
||||
};
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(storeName, 'readwrite');
|
||||
const store = transaction.objectStore(storeName);
|
||||
let hasChanges = false;
|
||||
|
||||
// force clear on first sync
|
||||
console.log(`Clearing ${storeName} to Make Sure Everythings Good`);
|
||||
store.clear();
|
||||
hasChanges = true;
|
||||
|
||||
itemsArray.forEach((item) => {
|
||||
if (item.id && typeof item.id === 'string' && !isNaN(item.id)) {
|
||||
item.id = parseInt(item.id, 10);
|
||||
}
|
||||
if (item.album?.id && typeof item.album.id === 'string' && !isNaN(item.album.id)) {
|
||||
item.album.id = parseInt(item.album.id, 10);
|
||||
}
|
||||
if (item.artists) {
|
||||
item.artists.forEach((artist) => {
|
||||
if (artist.id && typeof artist.id === 'string' && !isNaN(artist.id)) {
|
||||
artist.id = parseInt(artist.id, 10);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`${storeName}: Adding item with ID ${item.id || item.uuid || item.timestamp}`);
|
||||
store.put(item);
|
||||
});
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
console.log(`${storeName}: Imported ${itemsArray.length} items`);
|
||||
resolve(true);
|
||||
};
|
||||
|
||||
transaction.onerror = (event) => {
|
||||
console.error(`${storeName}: Transaction error:`, event.target.error);
|
||||
reject(transaction.error);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
console.log('Starting import with data:', {
|
||||
tracks: data.favorites_tracks?.length || 0,
|
||||
albums: data.favorites_albums?.length || 0,
|
||||
artists: data.favorites_artists?.length || 0,
|
||||
playlists: data.favorites_playlists?.length || 0,
|
||||
mixes: data.favorites_mixes?.length || 0,
|
||||
history: data.history_tracks?.length || 0,
|
||||
userPlaylists: data.user_playlists?.length || 0,
|
||||
});
|
||||
|
||||
const results = await Promise.all([
|
||||
importStore('favorites_tracks', data.favorites_tracks),
|
||||
importStore('favorites_albums', data.favorites_albums),
|
||||
importStore('favorites_artists', data.favorites_artists),
|
||||
importStore('favorites_playlists', data.favorites_playlists),
|
||||
importStore('favorites_mixes', data.favorites_mixes),
|
||||
importStore('history_tracks', data.history_tracks),
|
||||
data.user_playlists ? importStore('user_playlists', data.user_playlists) : Promise.resolve(false),
|
||||
]);
|
||||
|
||||
console.log('Import results:', results);
|
||||
return results.some((r) => r);
|
||||
}
|
||||
|
||||
_updatePlaylistMetadata(playlist) {
|
||||
playlist.numberOfTracks = playlist.tracks ? playlist.tracks.length : 0;
|
||||
|
|
@ -402,9 +399,11 @@ export class MusicDatabase {
|
|||
}
|
||||
|
||||
_dispatchPlaylistSync(action, playlist) {
|
||||
window.dispatchEvent(new CustomEvent('sync-playlist-change', {
|
||||
detail: { action, playlist }
|
||||
}));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('sync-playlist-change', {
|
||||
detail: { action, playlist },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// User Playlists API
|
||||
|
|
@ -418,14 +417,14 @@ export class MusicDatabase {
|
|||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
numberOfTracks: tracks.length,
|
||||
images: [] // Initialize images
|
||||
images: [], // Initialize images
|
||||
};
|
||||
this._updatePlaylistMetadata(playlist);
|
||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||
|
||||
|
||||
// TRIGGER SYNC
|
||||
this._dispatchPlaylistSync('create', playlist);
|
||||
|
||||
|
||||
return playlist;
|
||||
}
|
||||
|
||||
|
|
@ -439,9 +438,9 @@ export class MusicDatabase {
|
|||
playlist.updatedAt = Date.now();
|
||||
this._updatePlaylistMetadata(playlist);
|
||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||
|
||||
|
||||
this._dispatchPlaylistSync('update', playlist);
|
||||
|
||||
|
||||
return playlist;
|
||||
}
|
||||
|
||||
|
|
@ -453,15 +452,15 @@ export class MusicDatabase {
|
|||
playlist.updatedAt = Date.now();
|
||||
this._updatePlaylistMetadata(playlist);
|
||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||
|
||||
|
||||
this._dispatchPlaylistSync('update', playlist);
|
||||
|
||||
|
||||
return playlist;
|
||||
}
|
||||
|
||||
async deletePlaylist(playlistId) {
|
||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.delete(playlistId));
|
||||
|
||||
|
||||
// TRIGGER SYNC (but for deleting)
|
||||
this._dispatchPlaylistSync('delete', { id: playlistId });
|
||||
}
|
||||
|
|
@ -474,9 +473,9 @@ export class MusicDatabase {
|
|||
playlist.updatedAt = Date.now();
|
||||
this._updatePlaylistMetadata(playlist);
|
||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||
|
||||
|
||||
this._dispatchPlaylistSync('update', playlist);
|
||||
|
||||
|
||||
return playlist;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,8 +81,8 @@ export function initializeUIInteractions(player, api) {
|
|||
const likeBtn = container.querySelector('#like-queue-btn');
|
||||
if (likeBtn) {
|
||||
likeBtn.addEventListener('click', async () => {
|
||||
const { db } = await import('./db.js'); // Already imported
|
||||
const { syncManager } = await import('./accounts/pocketbase.js');
|
||||
const { db } = await import('./db.js'); // Already imported
|
||||
const { syncManager } = await import('./accounts/pocketbase.js');
|
||||
const { showNotification } = await import('./downloads.js');
|
||||
|
||||
let addedCount = 0;
|
||||
|
|
@ -107,8 +107,8 @@ export function initializeUIInteractions(player, api) {
|
|||
const addToPlaylistBtn = container.querySelector('#add-queue-to-playlist-btn');
|
||||
if (addToPlaylistBtn) {
|
||||
addToPlaylistBtn.addEventListener('click', async () => {
|
||||
const { db } = await import('./db.js'); // Already imported
|
||||
const { syncManager } = await import('./accounts/pocketbase.js');
|
||||
const { db } = await import('./db.js'); // Already imported
|
||||
const { syncManager } = await import('./accounts/pocketbase.js');
|
||||
const { showNotification } = await import('./downloads.js');
|
||||
|
||||
const playlists = await db.getPlaylists();
|
||||
|
|
|
|||
Loading…
Reference in a new issue