Merge branch 'master' of git.darkou.fr:dbroqua/MusicTopus into develop

This commit is contained in:
Damien Broqua 2024-01-28 17:27:50 +01:00
commit 5a7d9d707f
24 changed files with 18815 additions and 336 deletions

133
views/components/album.ejs Normal file
View file

@ -0,0 +1,133 @@
<div class="grid md:grid-cols-3 gap-16">
<div>
<template v-for="album in tracklist">
<strong v-if="album.title">{{album.title}}</strong>
<ul>
<li v-for="(track, index) in album.tracks" class="ml-4">
{{track.position || (index+1)}} - {{ track.title }} <template v-if="track.duration">({{track.duration}})</template>
<ul v-if="track.artists && track.artists.length > 0" class="sm-hidden">
<li v-for="extra in track.artists" class=" ml-4">
<small>{{extra.name}}</small>
</li>
</ul>
<ul v-if="track.extraartists && track.extraartists.length > 0" class="sm-hidden">
<li v-for="extra in track.extraartists" class=" ml-4">
<small>{{extra.role}} : {{extra.name}}</small>
</li>
</ul>
</li>
</ul>
</template>
</div>
<div class="md:col-span-2">
<div class="grid grid-cols-2 gap-10">
<div>
<strong>Genres</strong>
<br />
<template v-for="(genre, index) in item.genres">
{{genre}}<template v-if="index < item.genres.length - 1">, </template>
</template>
</div>
<div>
<strong>Styles</strong>
<br />
<span v-for="(style, index) in item.styles">
{{style}}<template v-if="index < item.styles.length - 1">, </template>
</span>
</div>
</div>
<hr />
<div class="grid grid-cols-3 gap-10">
<div>
<strong>Pays</strong>
<br />
<span>{{item.country}}</span>
</div>
<div>
<strong>Année</strong>
<br />
<span>{{item.year}}</span>
</div>
<div>
<strong>Date de sortie</strong>
<br />
<span>{{item.released}}</span>
</div>
</div>
<hr />
<div class="grid gap-10">
<div>
<strong>Format<template v-if="item.formats.length > 1">s</template></strong>
<ul class="ml-4">
<li v-for="(format) in item.formats">
{{format.name}}
<template v-if="format.text">
- <i>{{format.text}}</i>
</template>
<template v-if="format.descriptions && format.descriptions.length > 0">
(<span v-for="(description, index) in format.descriptions">
{{description}}<template v-if="index < format.descriptions.length - 1">, </template>
</span>)
</template>
</li>
</ul>
</div>
</div>
<hr />
<div class="grid grid-cols-1 md:grid-cols-2 gap-10">
<div>
<strong id="identifiers">Code<template v-if="item.identifiers.length > 1">s</template> barre<template v-if="item.identifiers.length > 1">s</template></strong>
<ol class="ml-4">
<li v-for="identifier in identifiers">
{{identifier.value}} ({{identifier.type}})
</li>
</ol>
<template v-if="item.identifiers.length > identifiersPreviewLength">
<button type="button" class="button is-link" v-if="identifiersMode === 'preview'" @click="showAllIdentifiers">
Voir la suite
</button>
<button type="button" class="button is-link" v-if="identifiersMode === 'all'" @click="showLessIdentifiers">
Voir moins
</button>
</template>
</div>
<div>
<strong>Label<template v-if="item.labels.length > 1">s</template></strong>
<ol class="ml-4">
<li v-for="label in item.labels">
{{label.name}} {{label.catno}}
</li>
</ol>
<strong>Société<template v-if="item.companies.length > 1">s</template></strong>
<ol class="ml-4">
<li v-for="company in item.companies">
<strong>{{company.entity_type_name}}</strong> {{company.name}}
</li>
</ol>
</div>
</div>
<hr />
<div class="grid gap-10">
<div>
<strong>Note</strong>
<div v-html="(item.notes || '').replaceAll('\n', '<br />')"></div>
</div>
</div>
<hr />
<div class="grid gap-10">
<div>
<strong>Vidéos</strong>
<dl>
<template v-for="video in item.videos">
<dt>
<a :href="video.uri" target="_blank" rel="noopener noreferrer">{{video.title}}</a>
</dt>
<dd>
{{video.description}}
</dd>
</template>
</dl>
</div>
</div>
</div>
</div>

View file

@ -35,86 +35,94 @@
<% } %>
</head>
<body>
<nav class="navbar" aria-label="Navigation principale">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/img/logo.png" alt="Logo MusicTopus">
<span>MusicTopus</span>
</a>
<a role="button" class="navbar-burger" aria-label="Afficher le menu" aria-expanded="false" data-target="navbar">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbar" class="navbar-menu">
<% if ( user ) { %>
<div class="navbar-start">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary" href="/ajouter-un-album">
<i class="icon-plus"></i>
<span>
Ajouter un album
</span>
</a>
</div>
</div>
</div>
<% } %>
<div class="navbar-end">
<a class="navbar-item" href="/nous-contacter">
Nous contacter
<nav class="navbar">
<nav class="navbar container" aria-label="Navigation principale">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/img/logo.png" alt="Logo MusicTopus">
<span>MusicTopus</span>
</a>
<% if ( user ) { %>
<div class="navbar-item has-dropdown">
<a class="navbar-link">
<i class="icon-user"></i>
<span>
<%= user.username %>
</span>
</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="/mon-compte">
Mon compte
</a>
<hr />
<a class="navbar-item" href="/ma-collection">
Ma collection
</a>
<a class="navbar-item" href="/ma-collection/exporter">
Exporter ma collection
</a>
<a role="button" class="navbar-burger" aria-label="Afficher le menu" aria-expanded="false" data-target="navbar">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbar" class="navbar-menu">
<% if ( user ) { %>
<div class="navbar-start">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary" href="/ajouter-un-album">
<i class="icon-plus"></i>
<span>
Ajouter un album
</span>
</a>
</div>
</div>
</div>
<% } %>
<div class="navbar-item apparence">
<div class="theme-switch-wrapper">
<label class="theme-switch" for="checkbox" aria-label="Passer du thème clair au thème sombre et inversement">
<input type="checkbox" id="checkbox" />
<div class="slider round"></div>
</label>
</div>
</div>
<div class="navbar-item">
<div class="buttons">
<% if ( !user ) { %>
<a class="button is-primary" href="/connexion">
<strong>Connexion</strong>
<div class="navbar-end">
<a class="navbar-item" href="/nous-contacter">
Nous contacter
</a>
<% if ( user ) { %>
<div class="navbar-item has-dropdown">
<a class="navbar-link">
<i class="icon-user"></i>
<span>
<%= user.username %>
</span>
</a>
<% } else { %>
<a class="button is-danger" href="/se-deconnecter">
Déconnexion
</a>
<% } %>
<div class="navbar-dropdown">
<a class="navbar-item" href="/mon-compte">
Mon compte
</a>
<hr />
<a class="navbar-item" href="/ma-collection">
Ma collection
</a>
<a class="navbar-item" href="/ma-collection/on-air">
On air
</a>
<a class="navbar-item" href="/ma-collection/exporter">
Exporter ma collection
</a>
<a class="navbar-item" href="/ma-collection/importer">
Importer une collection
</a>
<hr />
<a class="navbar-item is-danger" href="/se-deconnecter">
Déconnexion
</a>
</div>
</div>
<% } %>
<div class="navbar-item apparence">
<div class="theme-switch-wrapper">
<label class="theme-switch" for="checkbox" aria-label="Passer du thème clair au thème sombre et inversement">
<input type="checkbox" id="checkbox" />
<div class="slider round"></div>
</label>
</div>
</div>
<% if ( !user ) { %>
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary" href="/connexion">
<strong>Connexion</strong>
</a>
</div>
</div>
<% } %>
</div>
</div>
</div>
</nav>
</nav>
<div id="toastr">
@ -171,7 +179,7 @@
<footer class="footer layout-hero">
<p>
<strong title="Merci Brunus ! 😜">MusicTopus</strong> par <a href="https://www.darkou.fr" target="_blank" rel="noopener noreferrer">Damien Broqua <i class="icon-link"></i></a>.
<strong title="Merci Brunus ! 😜">MusicTopus</strong> par <a href="https://www.darkou.link" target="_blank" rel="noopener noreferrer">Damien Broqua <i class="icon-link"></i></a>.
Logo réalisé par Brunus avec <a href="https://inkscape.org/fr/" target="_blank" rel="noopener noreferrer">Inkscape <i class="icon-link"></i></a>.
<br />
Le code source est sous licence <a href="https://www.gnu.org/licenses/gpl-3.0-standalone.html" target="_blank" rel="noopener noreferrer">GNU GPL-3.0-or-later <i class="icon-link"></i></a> et disponible sur <a href="https://git.darkou.fr/dbroqua/MusicTopus" target="_blank">git.darkou.fr <i class="icon-link"></i></a>.

View file

@ -79,7 +79,7 @@
<button aria-label="Fermer" class="close" @click="toggleModal"></button>
</header>
<section>
<div class="grid grid-cols-2 gap-16">
<div class="grid grid-cols-1 md:grid-cols-3 gap-16">
<div>
<div class="text-center">
<img :src="details.thumb %>" :alt="`Miniature pour l'album ${details.title}`" />
@ -87,56 +87,57 @@
<img v-for="image in details.images" :src="image.uri150" :alt="`Miniature de type ${image.type}`" style="max-width: 60px;" />
<hr />
</div>
<ol class="ml-4">
<li v-for="track in details.tracklist">
{{ track.title }} ({{track.duration}})
<ul v-if="track.artists && track.artists.length > 0" class="sm-hidden">
<li v-for="extra in track.artists" class=" ml-4">
<small>{{extra.role}} : {{extra.name}}</small>
</li>
</ul>
<ul class="is-unstyled">
<li v-for="track in details.tracklist" :class="{'ml-4': track.type_ === 'track'}">
<strong v-if="track.type_ === 'heading'">
{{track.title}}
</strong>
<template v-else>
{{ track.position }}
{{ track.title }} <span v-if="track.duration">({{track.duration}})</span>
<ul v-if="track.artists && track.artists.length > 0" class="sm-hidden">
<li v-for="extra in track.artists" class=" ml-4">
<small>{{extra.role}} : {{extra.name}}</small>
</li>
</ul>
</template>
</li>
</ol>
</ul>
</div>
<div>
<div class="grid grid-cols-2 gap-10">
<div>
<div class="md:col-span-2">
<div class="grid grid-cols-1 md:grid-cols-2 gap-10">
<div class="grid grid-cols-1">
<strong>Genres</strong>
<br />
<template v-for="(genre, index) in details.genres">
{{genre}}<template v-if="index < details.genres.length - 1">, </template>
</template>
</div>
<div>
<div class="grid grid-cols-1">
<strong>Styles</strong>
<br />
<span v-for="(style, index) in details.styles">
{{style}}<template v-if="index < details.styles.length - 1">, </template>
</span>
</div>
</div>
<hr />
<div class="grid grid-cols-3 gap-10">
<div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-10">
<div class="grid grid-cols-2 md:grid-cols-1">
<strong>Pays</strong>
<br />
<span>{{details.country}}</span>
</div>
<div>
<div class="grid grid-cols-2 md:grid-cols-1">
<strong>Année</strong>
<br />
<span>{{details.year}}</span>
</div>
<div>
<div class="grid grid-cols-2 md:grid-cols-1">
<strong>Date de sortie</strong>
<br />
<span>{{details.released}}</span>
</div>
</div>
<hr />
<div class="grid grid-cols-2 gap-10">
<div class="grid grid-cols-1 gap-10">
<div>
<strong>Format</strong>
<strong>Format<template v-if="details?.formats?.length > 1">s</template></strong>
<ul class="ml-4">
<li v-for="(format) in details.formats">
{{format.name}}
@ -153,25 +154,26 @@
</div>
</div>
<hr />
<div class="grid grid-cols-2 gap-10">
<div class="grid grid-cols-1 md:grid-cols-2 gap-10">
<div>
<strong>Codes barres</strong>
<ol>
<strong>Code<template v-if="details?.identifiers?.length > 1">s</template> barre<template v-if="details?.identifiers?.length > 1">s</template></strong>
<ol class="ml-4">
<li v-for="identifier in details.identifiers">
{{identifier.value}} ({{identifier.type}})
</li>
</ol>
</div>
<div>
<strong>Label</strong>
<ol>
<strong>Label<template v-if="details?.labels?.length > 1">s</template></strong>
<ol class="ml-4">
<li v-for="label in details.labels">
{{label.name}}
</li>
</ol>
<strong>Société</strong>
<ol>
<li v-for="company in details.companie">
<strong>Société<template v-if="details?.companies?.length > 1">s</template></strong>
<ol class="ml-4">
<li v-for="company in details.companies">
<strong>{{company.entity_type_name}}</strong>
{{company.name}}
</li>
</ol>
@ -181,9 +183,21 @@
</div>
</section>
<footer>
<% if ( user.mastodon && user.mastodon.publish ) { %>
<div class="field">
<label for="share">Partager sur le fédiverse</label>
<span>
<input type="checkbox" id="share" name="share" v-model="share">
</span>
</div>
<% } %>
<button :class="['button is-primary', submitting ? 'is-disabled' : '']" @click="add">Ajouter</button>
<button class="button" @click="toggleModal">Annuler</button>
</footer>
</div>
</div>
</main>
</main>
<script>
const canPublish = <%- (user.mastodon && user.mastodon.publish) || false %>;
</script>

View file

@ -21,152 +21,22 @@
</div>
</div>
<hr />
<div class="grid md:grid-cols-3 gap-16">
<div>
<template v-for="album in tracklist">
<strong v-if="album.title">{{album.title}}</strong>
<ul>
<li v-for="(track, index) in album.tracks" class="ml-4">
{{track.position || (index+1)}} - {{ track.title }} <template v-if="track.duration">({{track.duration}})</template>
<ul v-if="track.artists && track.artists.length > 0" class="sm-hidden">
<li v-for="extra in track.artists" class=" ml-4">
<small>{{extra.name}}</small>
</li>
</ul>
<ul v-if="track.extraartists && track.extraartists.length > 0" class="sm-hidden">
<li v-for="extra in track.extraartists" class=" ml-4">
<small>{{extra.role}} : {{extra.name}}</small>
</li>
</ul>
</li>
</ul>
</template>
</div>
<div class="md:col-span-2">
<div class="grid grid-cols-2 gap-10">
<div>
<strong>Genres</strong>
<br />
<template v-for="(genre, index) in item.genres">
{{genre}}<template v-if="index < item.genres.length - 1">, </template>
</template>
</div>
<div>
<strong>Styles</strong>
<br />
<span v-for="(style, index) in item.styles">
{{style}}<template v-if="index < item.styles.length - 1">, </template>
</span>
</div>
</div>
<hr />
<div class="grid grid-cols-3 gap-10">
<div>
<strong>Pays</strong>
<br />
<span>{{item.country}}</span>
</div>
<div>
<strong>Année</strong>
<br />
<span>{{item.year}}</span>
</div>
<div>
<strong>Date de sortie</strong>
<br />
<span>{{item.released}}</span>
</div>
</div>
<hr />
<div class="grid gap-10">
<div>
<strong>Format</strong>
<ul class="ml-4">
<li v-for="(format) in item.formats">
{{format.name}}
<template v-if="format.text">
- <i>{{format.text}}</i>
</template>
<template v-if="format.descriptions && format.descriptions.length > 0">
(<span v-for="(description, index) in format.descriptions">
{{description}}<template v-if="index < format.descriptions.length - 1">, </template>
</span>)
</template>
</li>
</ul>
</div>
</div>
<hr />
<div class="grid grid-cols-2 gap-10">
<div>
<strong id="identifiers">Codes barres</strong>
<ol class="ml-4">
<li v-for="identifier in identifiers">
{{identifier.value}} ({{identifier.type}})
</li>
</ol>
<template v-if="item.identifiers.length > identifiersPreviewLength">
<button type="button" class="button is-link" v-if="identifiersMode === 'preview'" @click="showAllIdentifiers">
Voir la suite
</button>
<button type="button" class="button is-link" v-if="identifiersMode === 'all'" @click="showLessIdentifiers">
Voir moins
</button>
</template>
</div>
<div>
<strong>Label</strong>
<br />
<template v-for="label in item.labels">
{{label.name}} {{label.catno}}
<br />
</template>
<hr />
<strong>Sociétés</strong>
<br />
<template v-for="company in item.companies">
<strong>{{company.entity_type_name}}</strong> : {{company.name}}
<br />
</template>
</div>
</div>
<hr />
<div class="grid gap-10">
<div>
<strong>Note</strong>
<div v-html="(item.notes || '').replaceAll('\n', '<br />')"></div>
</div>
</div>
<hr />
<div class="grid gap-10">
<div>
<strong>Vidéos</strong>
<dl>
<template v-for="video in item.videos">
<dt>
<a :href="video.uri" target="_blank" rel="noopener noreferrer">{{video.title}}</a>
</dt>
<dd>
{{video.description}}
</dd>
</template>
</dl>
</div>
</div>
</div>
</div>
<%- include('../../../components/album.ejs') %>
<div class="modal" :class="{'is-visible': modalIsVisible}">
<div class="modal-background"></div>
<button type="button" aria-label="Fermer" class="close" @click="toggleModal"></button>
<button type="button" aria-label="Image précédente" class="navigation previous" @click="previous" v-if="index > 0">
<i class="icon-left-open"></i>
</button>
<button type="button" aria-label="Image suivante" class="navigation next" @click="next" v-if="index + 1 < item.images.length">
<i class="icon-right-open"></i>
</button>
<div class="modal-card">
<img :src="preview" />
<div class="carousel">
<button type="button" aria-label="Image précédente" class="navigation previous" @click="previous">
<i class="icon-left-open"></i>
</button>
<div class="text-center">
<img :src="preview" />
</div>
<button type="button" aria-label="Image suivante" class="navigation next" @click="next">
<i class="icon-right-open"></i>
</button>
</div>
</div>

View file

@ -0,0 +1,43 @@
<main class="layout-maxed" id="importer">
<h1>Importer une collection</h1>
<p>
Il est actuellement possible d'importer une collection provenant de discogs.
<br />
Vous devez dans un premier temps vous rendre sur la page <a href="https://www.discogs.com/fr/users/export" target="_blank" rel="noopener noreferrer">Exporter</a> de discogs.
<br />
Une fois exporter vous recevrez un mail de Discogs avec un lien de téléchargement. Une fois le fichier .zip téléchargé vous devez en extraire le fichier .csv afin de l'importer dans MusicTopus.
</p>
<p>
D'autres formats d'imports seront ajoutés par la suite, comme l'import entre 2 instances MusicTopus.
</p>
<div class="flash info">
<div class="header">
Information
</div>
<div class="body">
Si un album est déjà présent en base celui-ci sera ignoré.
</div>
</div>
<form @submit="importCollection">
<div class="field">
<label for="file">Fichier .csv</label>
<input type="file" name="file" id="file" @change="handleFileUpload( $event )" accept=".csv">
</div>
<div class="field">
<span>
Albums à impoter : <strong>{{content.length}}</strong>
</span>
</div>
<button type="submit" class="button is-primary my-16" :disabled="disabled">
<i v-if="['parse', 'submit'].includes(state)" class="icon-spin animate-spin"></i>
<span v-if="state === 'default'">Importer</span>
<span v-if="state === 'parse'">Analyse en cours...</span>
<span v-if="state === 'submit'">Importation en cours... ({{imported}}/{{content.length}})</span>
<span v-if="state === 'done'">Importatation terminée</span>
</button>
</form>
</main>