Compare commits
No commits in common. "58a096db29e5e848f3a3d0bae50b1bc74d925714" and "e4c5806974757a347e025354e89dce799791e349" have entirely different histories.
58a096db29
...
e4c5806974
@ -28,8 +28,6 @@ export SONG_LIBRARY=/path/to/library
|
|||||||
|
|
||||||
**A web-based UI to browse the song library.** It supports searching by title and artist, and allows to mark and unmark favorites on the client side (using local storage).
|
**A web-based UI to browse the song library.** It supports searching by title and artist, and allows to mark and unmark favorites on the client side (using local storage).
|
||||||
|
|
||||||
The UI was developed in a different repository, available for historic reasons at https://gitlab.cl.uni-heidelberg.de/moser/karaokatalog-ui.
|
|
||||||
|
|
||||||
#### Serve
|
#### Serve
|
||||||
|
|
||||||
**Launch a server for the catalogue UI** on localhost. Mostly useful for development purposes.
|
**Launch a server for the catalogue UI** on localhost. Mostly useful for development purposes.
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
import "./lib/mithril.min.js"
|
|
||||||
|
|
||||||
import All from "./components/pages/All.js"
|
|
||||||
import Favorites from "./components/pages/Favorites.js"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We leave the default routing strategy (https://mithril.js.org/route.html#routing-strategies), i.e.,
|
|
||||||
* with a #! prefix, and do not change m.route.prefix.
|
|
||||||
*
|
|
||||||
* This is to make it easier to deploy this app on servers without changing the configuration.
|
|
||||||
*/
|
|
||||||
m.route(document.body, "/all", {
|
|
||||||
"/all": All,
|
|
||||||
"/favorites": Favorites,
|
|
||||||
})
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
function toMap(objs) {
|
|
||||||
return new Map(objs.map(obj => [obj.id || obj.uuid, obj]))
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Base {
|
|
||||||
/**
|
|
||||||
* A Map mapping ids to instances of `Base`.
|
|
||||||
* Must be treated as private.
|
|
||||||
*/
|
|
||||||
static _byId = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A list of all instances of `Base`
|
|
||||||
*/
|
|
||||||
static get all() {
|
|
||||||
return this._byId ? Array.from(this._byId.values()) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {str} id A id
|
|
||||||
* @returns The instance with the given id, if it exists
|
|
||||||
*/
|
|
||||||
static get(id) {
|
|
||||||
return this._byId ? this._byId.get(id) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the objects from the API, unless the objects have already been loaded.
|
|
||||||
* They are then stored in `this.byUid`.
|
|
||||||
*
|
|
||||||
* @returns Nothing.
|
|
||||||
*/
|
|
||||||
static async load() {
|
|
||||||
if (!this._byId) {
|
|
||||||
const objects = await this.forceLoad()
|
|
||||||
// Hack: We get plain JSON objects from the server, however, we'd like
|
|
||||||
// them to actually be instances of the classes we define. So, we first create a new empty
|
|
||||||
// instance of whatever subclass of `Base` we are currently in using `new this()`,
|
|
||||||
// and then copy all properties from the plain object over to the instance
|
|
||||||
// using `Object.assign`.
|
|
||||||
const instances = objects.map(obj => Object.assign(new this(), obj))
|
|
||||||
this._byId = toMap(instances)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the objects were already loaded, forget them and load them again.
|
|
||||||
* If the objects were not yet loaded, don't do anything.
|
|
||||||
*/
|
|
||||||
static refresh() {
|
|
||||||
if (this._byId) {
|
|
||||||
this._byId = null
|
|
||||||
this.load()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the objects from the API and return them.
|
|
||||||
* Abstract method, must be overriden in child classes.
|
|
||||||
*
|
|
||||||
* @returns A list of instances.
|
|
||||||
*/
|
|
||||||
static async forceLoad() {}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { Base } from "./Base.js"
|
|
||||||
import { getFavoriteIds, addFavorite, removeFavorite } from "./favorites.js"
|
|
||||||
|
|
||||||
export default class Song extends Base {
|
|
||||||
static async forceLoad() {
|
|
||||||
return await m.request({ url: "/songs.json" })
|
|
||||||
}
|
|
||||||
|
|
||||||
get favorite() {
|
|
||||||
return getFavoriteIds().has(this.id || this.uuid)
|
|
||||||
}
|
|
||||||
|
|
||||||
set favorite(isFavorite) {
|
|
||||||
if (isFavorite) {
|
|
||||||
addFavorite(this.id || this.uuid)
|
|
||||||
} else {
|
|
||||||
removeFavorite(this.id || this.uuid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleFavorite() {
|
|
||||||
this.favorite = !this.favorite
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
const FAVORITES_STORAGE_KEY = "songAppFavorites"
|
|
||||||
|
|
||||||
let favoriteIds = null
|
|
||||||
|
|
||||||
export function getFavoriteIds() {
|
|
||||||
if (favoriteIds === null) {
|
|
||||||
favoriteIds = new Set(
|
|
||||||
JSON.parse(localStorage.getItem(FAVORITES_STORAGE_KEY)) || [],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return favoriteIds
|
|
||||||
}
|
|
||||||
|
|
||||||
function setFavoriteIds(favs) {
|
|
||||||
localStorage.setItem(
|
|
||||||
FAVORITES_STORAGE_KEY,
|
|
||||||
JSON.stringify(Array.from(favs)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addFavorite(id) {
|
|
||||||
const favs = getFavoriteIds()
|
|
||||||
favs.add(id)
|
|
||||||
setFavoriteIds(favs)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeFavorite(id) {
|
|
||||||
const favs = getFavoriteIds()
|
|
||||||
favs.delete(id)
|
|
||||||
setFavoriteIds(favs)
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
export default {
|
|
||||||
query: null,
|
|
||||||
|
|
||||||
apply(songs) {
|
|
||||||
const normalizedQuery = this.query?.trim()?.toLowerCase()
|
|
||||||
return normalizedQuery ? songs?.filter(
|
|
||||||
song => song.title?.toLowerCase()?.includes(normalizedQuery) || song.artist?.toLowerCase()?.includes(normalizedQuery)
|
|
||||||
) : songs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user