Merge pull request #326 from lsmda/feature/add-strict-album-match-toggle-on-playlist-creation
feat(playlists): add strict album match toggle on CSV tab import
This commit is contained in:
commit
7b70e55895
3 changed files with 25 additions and 10 deletions
17
index.html
17
index.html
|
|
@ -528,7 +528,6 @@
|
|||
color: var(--foreground);
|
||||
cursor: pointer;
|
||||
padding: 0.25rem 0.5rem;
|
||||
opacity: 0.7;
|
||||
"
|
||||
>
|
||||
CSV
|
||||
|
|
@ -669,6 +668,22 @@
|
|||
Make sure its headers are in English.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="setting-item"
|
||||
style="margin-top: 1rem; margin-bottom: 1rem; background: transparent"
|
||||
>
|
||||
<div class="info">
|
||||
<span style="font-size: 0.9rem; font-weight: 600">Strict Album Matching</span>
|
||||
<span style="font-size: 0.8rem; max-width: 14rem">
|
||||
Album name should strictly match CSV metadata. Disable for better discovery.
|
||||
</span>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="strict-album-match-toggle" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="jspf-import-panel" class="import-panel" style="display: none">
|
||||
|
|
|
|||
|
|
@ -1265,6 +1265,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
let name = document.getElementById('playlist-name-input').value.trim();
|
||||
let description = document.getElementById('playlist-description-input').value.trim();
|
||||
const isPublic = document.getElementById('playlist-public-toggle')?.checked;
|
||||
const isStrictAlbumMatch = document.getElementById('strict-album-match-toggle')?.checked;
|
||||
|
||||
if (name) {
|
||||
const modal = document.getElementById('playlist-modal');
|
||||
|
|
@ -1317,7 +1318,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
const xmlFileInput = document.getElementById('xml-file-input');
|
||||
const m3uFileInput = document.getElementById('m3u-file-input');
|
||||
|
||||
const importOptions = { strictArtistMatch: true, albumMatch: true };
|
||||
const importOptions = { strictArtistMatch: true, strictAlbumMatch: isStrictAlbumMatch };
|
||||
|
||||
let tracks = [];
|
||||
let importSource = 'manual';
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ function isFuzzyMatch(str1, str2) {
|
|||
return s1.includes(s2) || s2.includes(s1);
|
||||
}
|
||||
|
||||
function findBestMatch(items, targetArtist, targetAlbum, options) {
|
||||
function findBestMatch(items, targetArtist, targetAlbum, importOptions) {
|
||||
if (!items || items.length === 0) return null;
|
||||
if (!options?.strictArtistMatch && !options?.albumMatch) return items[0];
|
||||
if (!importOptions?.strictArtistMatch && !importOptions?.strictAlbumMatch) return items[0];
|
||||
|
||||
return (
|
||||
items.find((item) => {
|
||||
let artistOk = true;
|
||||
let albumOk = true;
|
||||
|
||||
if (options.strictArtistMatch && targetArtist) {
|
||||
if (importOptions.strictArtistMatch && targetArtist) {
|
||||
const itemArtist = item.artist?.name || item.artists?.[0]?.name;
|
||||
if (!isFuzzyMatch(itemArtist, targetArtist)) artistOk = false;
|
||||
}
|
||||
|
||||
if (options.albumMatch && targetAlbum) {
|
||||
if (importOptions.strictAlbumMatch && targetAlbum) {
|
||||
const itemAlbum = item.album?.title;
|
||||
if (itemAlbum && !isFuzzyMatch(itemAlbum, targetAlbum)) albumOk = false;
|
||||
}
|
||||
|
|
@ -294,8 +294,7 @@ export async function parseDynamicCSV(csvText, api, onProgress, options = {}) {
|
|||
const albumName = mappedHeaders.album !== undefined ? values[mappedHeaders.album] : '';
|
||||
const isrc = mappedHeaders.isrc !== undefined ? values[mappedHeaders.isrc] : '';
|
||||
const playlistName = mappedHeaders.playlistName !== undefined ? values[mappedHeaders.playlistName] : '';
|
||||
const typeValue =
|
||||
mappedHeaders.type !== undefined ? values[mappedHeaders.type]?.toLowerCase().trim() : '';
|
||||
const typeValue = mappedHeaders.type !== undefined ? values[mappedHeaders.type]?.toLowerCase().trim() : '';
|
||||
const isFavorite = typeValue.includes('favorite');
|
||||
|
||||
if (onProgress) {
|
||||
|
|
@ -497,7 +496,7 @@ export async function importToLibrary(csvResult, db, onProgress, options = {}) {
|
|||
return results;
|
||||
}
|
||||
|
||||
export async function parseCSV(csvText, api, onProgress, options = {}) {
|
||||
export async function parseCSV(csvText, api, onProgress, importOptions = {}) {
|
||||
const lines = csvText.trim().split('\n');
|
||||
if (lines.length < 2) return { tracks: [], missingTracks: [] };
|
||||
|
||||
|
|
@ -583,7 +582,7 @@ export async function parseCSV(csvText, api, onProgress, options = {}) {
|
|||
const searchResult = await api.searchTracks(searchQuery);
|
||||
|
||||
if (searchResult.items && searchResult.items.length > 0) {
|
||||
const match = findBestMatch(searchResult.items, artistNames, albumName, options);
|
||||
const match = findBestMatch(searchResult.items, artistNames, albumName, importOptions);
|
||||
if (match) tracks.push(match);
|
||||
else missingTracks.push({ title: trackTitle, artist: artistNames, album: albumName });
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue