Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Track.artist and Track.extraArtists with Track.artists #1681

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5923449
Replace `Track.artist` and `Track.extraArtists` with `Track.artists`
Lucki Aug 22, 2024
e7b2e90
Read autoradio artist into new artists array
Lucki Aug 22, 2024
dfca722
Copy old format history DB entries to new array
Lucki Aug 22, 2024
bac2ba3
[Spotify] Adapt to new `artists`
Lucki Aug 20, 2024
5075fe7
[MusicBrainz] Adapt to new `artists`
Lucki Aug 20, 2024
ab6e0c8
[Discogs] Adapt to new `artists`
Lucki Aug 20, 2024
ddf6d61
Display artists in TrackRow when deviating from album artist
Lucki Aug 20, 2024
6479d6f
Adjust reading the config into the new format
Lucki Aug 21, 2024
ca09d7c
[WIP] fixup! Adjust reading the config into the new format
Lucki Aug 26, 2024
129ee02
[WIP] Adjust `NuclearMeta`
Lucki Aug 26, 2024
0ecdce9
Reset xesam:artist to an array
nukeop Oct 15, 2024
a67de60
Merge branch 'master' into fix/1668
nukeop Oct 15, 2024
a9906b3
Adapt GridTrackTable to multiple artists per track
nukeop Oct 16, 2024
2a4e2c8
Avoid mutation when converting a playlist to the new format
nukeop Oct 16, 2024
8efdb52
Avoid mutation when remapping downloads and favorites
nukeop Oct 16, 2024
6a214c5
Use new artist format in GridTrackTable tests
nukeop Oct 16, 2024
dd1fd00
Use new metadata format in linux system api (mpris)
nukeop Oct 16, 2024
37a607a
Favorites multi-artist support, snapshot update
nukeop Oct 20, 2024
97d2488
Fix add to favorites action
nukeop Oct 21, 2024
84b7216
Update grid track table snapshots
nukeop Oct 21, 2024
d558aee
Rewrite SoundContainer in Typescript
nukeop Oct 28, 2024
4dcbd58
Update last.fm action types
nukeop Oct 29, 2024
e2805bb
Replace failing playlist
nukeop Oct 29, 2024
3580b36
Merge branch 'master' of github.com:nukeop/nuclear into fix/1668
nukeop Oct 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/app/app/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import PlayerBarContainer from './containers/PlayerBarContainer';
import MiniPlayerContainer from './containers/MiniPlayerContainer';

import IpcContainer from './containers/IpcContainer';
import SoundContainer from './containers/SoundContainer';
import { SoundContainer } from './containers/SoundContainer';
import ToastContainer from './containers/ToastContainer';
import ShortcutsContainer from './containers/ShortcutsContainer';
import ErrorBoundary from './containers/ErrorBoundary';
Expand Down Expand Up @@ -78,7 +78,7 @@ class App extends React.PureComponent {
if (e.button === 1) {
e.preventDefault();
}
}
}
updateConnectivityStatus = (isConnected) => {
this.props.actions.changeConnectivity(isConnected);
}
Expand Down
38 changes: 26 additions & 12 deletions packages/app/app/actions/downloads.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import _ from 'lodash';
import { isEqual } from 'lodash';
import { store, StreamProvider } from '@nuclear/core';
import { getTrackItem } from '@nuclear/ui';
import { safeAddUuid } from './helpers';
import { rewriteTrackArtists, safeAddUuid } from './helpers';
import { Download, DownloadStatus, Track, TrackItem } from '@nuclear/ui/lib/types';
import { createStandardAction } from 'typesafe-actions';
import { Download as DownloadActionTypes } from './actionTypes';
Expand All @@ -24,19 +25,19 @@ const changePropertyForItem = ({downloads, uuid, propertyName='status', value}:C

export const readDownloads = createStandardAction(DownloadActionTypes.READ_DOWNLOADS).map(
() => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();
return { payload: downloads };
}
);

export const addToDownloads = createStandardAction(DownloadActionTypes.ADD_TO_DOWNLOADS).map(
(_:StreamProvider[], track: Track) => {
const clonedTrack: TrackItem = safeAddUuid(getTrackItem(track));
let downloads: Download[] = store.get('downloads');
let downloads: Download[] = getDownloadsBackwardsCompatible();

const existingTrack = downloads.find(({track}) => {
const {name, artist} = track;
return artist === clonedTrack.artist && name === clonedTrack.name;
const {name, artists} = track;
return isEqual(artists, clonedTrack.artists) && name === clonedTrack.name;
});

if (!existingTrack ){
Expand All @@ -61,7 +62,7 @@ export const addToDownloads = createStandardAction(DownloadActionTypes.ADD_TO_DO

export const onDownloadStarted = createStandardAction(DownloadActionTypes.DOWNLOAD_STARTED).map(
(uuid: string) => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();
const payload = changePropertyForItem({
downloads,
uuid,
Expand All @@ -74,7 +75,7 @@ export const onDownloadStarted = createStandardAction(DownloadActionTypes.DOWNLO

export const onDownloadPause = createStandardAction(DownloadActionTypes.DOWNLOAD_PAUSED).map(
(uuid: string) => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();
const payload = changePropertyForItem({
downloads,
uuid,
Expand All @@ -87,7 +88,7 @@ export const onDownloadPause = createStandardAction(DownloadActionTypes.DOWNLOA

export const onDownloadResume = createStandardAction(DownloadActionTypes.DOWNLOAD_RESUMED).map(
(uuid: string) => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();
const payload = changePropertyForItem({
downloads,
uuid,
Expand Down Expand Up @@ -132,7 +133,7 @@ export const onDownloadProgress = createStandardAction(DownloadActionTypes.DOWNL

export const onDownloadError = createStandardAction(DownloadActionTypes.DOWNLOAD_ERROR).map(
(uuid: string) => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();
const payload = changePropertyForItem({
downloads,
uuid,
Expand All @@ -147,7 +148,7 @@ export const onDownloadError = createStandardAction(DownloadActionTypes.DOWNLOAD

export const onDownloadRemoved = createStandardAction(DownloadActionTypes.DOWNLOAD_REMOVED).map(
(uuid: string) => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();
const filteredTracks = downloads.filter(item => item.track.uuid !== uuid);
return {
payload: filteredTracks
Expand All @@ -156,7 +157,7 @@ export const onDownloadRemoved = createStandardAction(DownloadActionTypes.DOWNLO

export const onDownloadFinished = createStandardAction(DownloadActionTypes.DOWNLOAD_FINISHED).map(
(uuid: string) => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();
const payload = changePropertyForItem({
downloads,
uuid,
Expand All @@ -170,7 +171,7 @@ export const onDownloadFinished = createStandardAction(DownloadActionTypes.DOWNL

export const clearFinishedDownloads = createStandardAction(DownloadActionTypes.CLEAR_FINISHED_DOWNLOADS).map(
() => {
const downloads: Download[] = store.get('downloads');
const downloads: Download[] = getDownloadsBackwardsCompatible();

const filteredTracks = downloads.filter(( item ) =>
item.status !== DownloadStatus.FINISHED && item.status !== DownloadStatus.ERROR
Expand All @@ -181,6 +182,19 @@ export const clearFinishedDownloads = createStandardAction(DownloadActionTypes.C
};
});

/**
* Helper function to read the old track format into the new format.
*
* `Track.artist` and `Track.extraArtists` are written into {@link Track.artists}
*/
function getDownloadsBackwardsCompatible(): Download[] {
const downloads: Download[] = store.get('downloads');
return downloads.map(download => ({
...download,
track: rewriteTrackArtists(download.track)
}));
}

export const resumeDownloads = createStandardAction(DownloadActionTypes.RESUME_DOWNLOADS).map(
() => {
const downloads: Download[] = store.get('downloads');
Expand Down
53 changes: 39 additions & 14 deletions packages/app/app/actions/favorites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ import _, { flow, omit, unionWith } from 'lodash';
import { store, Track } from '@nuclear/core';
import { areTracksEqualByName, getTrackItem } from '@nuclear/ui';

import { safeAddUuid } from './helpers';
import { rewriteTrackArtists, safeAddUuid } from './helpers';
import { createStandardAction } from 'typesafe-actions';
import { addToDownloads } from './downloads';
import StreamProviderPlugin from '@nuclear/core/src/plugins/streamProvider';

export type FavoriteArtist = {
id: string;
name: string;
source: string;
coverImage: string;
thumb: string;
}

export const READ_FAVORITES = 'READ_FAVORITES';
export const ADD_FAVORITE_TRACK = 'ADD_FAVORITE_TRACK';
export const REMOVE_FAVORITE_TRACK = 'REMOVE_FAVORITE_TRACK';
Expand All @@ -19,7 +27,7 @@ export const ADD_FAVORITE_ARTIST = 'ADD_FAVORITE_ARTIST';
export const REMOVE_FAVORITE_ARTIST = 'REMOVE_FAVORITE_ARTIST';

export function readFavorites() {
const favorites = store.get('favorites');
const favorites = getFavoritesBackwardsCompatible();
return {
type: READ_FAVORITES,
payload: favorites
Expand All @@ -29,10 +37,10 @@ export function readFavorites() {
export function addFavoriteTrack(track) {
const clonedTrack = flow(safeAddUuid, getTrackItem)(track);

const favorites = store.get('favorites');
const favorites = getFavoritesBackwardsCompatible();
const filteredTracks = favorites.tracks.filter(t => !areTracksEqualByName(t, track));
favorites.tracks = [...filteredTracks, omit(clonedTrack, 'streams')];

favorites.tracks = [...filteredTracks, omit(clonedTrack, 'streams')];
store.set('favorites', favorites);

const settings = store.get('settings');
Expand All @@ -50,18 +58,18 @@ export function addFavoriteTrack(track) {
};
}

const bulkAddFavoriteTracksAction = createStandardAction(BULK_ADD_FAVORITE_TRACKS)<Track[]>();
const bulkAddFavoriteTracksAction = createStandardAction(BULK_ADD_FAVORITE_TRACKS)<ReturnType<typeof getFavoritesBackwardsCompatible>>();

export const bulkAddFavoriteTracks = (tracks: Track[]) => {
const favorites = store.get('favorites');
const favorites = getFavoritesBackwardsCompatible();
favorites.tracks = unionWith(favorites.tracks, tracks, areTracksEqualByName);
store.set('favorites', favorites);

return bulkAddFavoriteTracksAction(favorites);
};

export function removeFavoriteTrack(track) {
const favorites = store.get('favorites');
const favorites = getFavoritesBackwardsCompatible();
favorites.tracks = favorites.tracks.filter(t => !areTracksEqualByName(t, track));

store.set('favorites', favorites);
Expand All @@ -73,7 +81,7 @@ export function removeFavoriteTrack(track) {
}

export function addFavoriteAlbum(album) {
const favorites = store.get('favorites');
const favorites = getFavoritesBackwardsCompatible();
favorites.albums = _.concat(favorites.albums, album);
store.set('favorites', favorites);

Expand All @@ -84,7 +92,7 @@ export function addFavoriteAlbum(album) {
}

export function removeFavoriteAlbum(album) {
const favorites = store.get('favorites');
const favorites = getFavoritesBackwardsCompatible();
_.remove(favorites.albums, {
artist: album.artist,
title: album.title
Expand All @@ -97,9 +105,8 @@ export function removeFavoriteAlbum(album) {
};
}

export function addFavoriteArtist(artist) {

const favorites = store.get('favorites');
export function addFavoriteArtist(artist: FavoriteArtist) {
const favorites = getFavoritesBackwardsCompatible();
const savedArtist = {
id: artist.id,
name: artist.name,
Expand All @@ -108,7 +115,7 @@ export function addFavoriteArtist(artist) {
thumb: artist.thumb
};

favorites.artists = _.concat(favorites.artists || [], savedArtist);
favorites.artists = [...(favorites.artists ?? []), savedArtist];
store.set('favorites', favorites);

return {
Expand All @@ -118,7 +125,7 @@ export function addFavoriteArtist(artist) {
}

export function removeFavoriteArtist(artist) {
const favorites = store.get('favorites');
const favorites = getFavoritesBackwardsCompatible();
_.remove(favorites.artists, {
id: artist.id,
name: artist.name
Expand All @@ -130,3 +137,21 @@ export function removeFavoriteArtist(artist) {
payload: favorites
};
}

/**
* Helper function to read the old track format into the new format.
*
* `Track.artist` and `Track.extraArtists` are written into {@link Track.artists}
*/
function getFavoritesBackwardsCompatible() {
const favorites = store.get('favorites');

return {
...favorites,
tracks: favorites.tracks?.map(rewriteTrackArtists),
albums: favorites.albums?.map(album => ({
...album,
tracklist: album.tracklist?.map(rewriteTrackArtists)
}))
};
}
18 changes: 18 additions & 0 deletions packages/app/app/actions/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { v4 } from 'uuid';
import _ from 'lodash';
import { createAction } from 'redux-actions';
import { PlaylistTrack, Track } from '@nuclear/core';
import { TrackItem } from '@nuclear/ui/lib/types';

type ActionsBasicType = {
[k: string]: (...payload: any) => any;
Expand All @@ -22,3 +24,19 @@ export const safeAddUuid = track => {

return clonedTrack;
};

export function rewriteTrackArtists<T extends PlaylistTrack | Track | TrackItem>(track: T): T {
const clonedTrack = _.cloneDeep(track);

// @ts-expect-error For backwards compatibility we're trying to parse an invalid field
if (clonedTrack.artists || !clonedTrack.artist) {
return clonedTrack;
}

// @ts-expect-error For backwards compatibility we're trying to parse an invalid field
clonedTrack.artists = _.isString(clonedTrack.artist) ? [clonedTrack.artist] : [clonedTrack.artist.name];
// @ts-expect-error For backwards compatibility we're trying to parse an invalid field
clonedTrack.artists = clonedTrack.artists.concat(clonedTrack.extraArtists?.map(artist));

return clonedTrack;
}
2 changes: 1 addition & 1 deletion packages/app/app/actions/lyrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function lyricsSearch(track: Track) {
const selectedProvider = getState().plugin.selected.lyricsProviders;
const lyricsProvider = _.find(providers, {sourceName: selectedProvider});

lyricsProvider.search(track.artist, track.name)
lyricsProvider.search(track.artists?.[0], track.name)
.then(result => {
dispatch(lyricsSearchSuccess(result));
})
Expand Down
22 changes: 19 additions & 3 deletions packages/app/app/actions/playlists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { v4 } from 'uuid';
import { remote } from 'electron';
import { createAsyncAction, createStandardAction } from 'typesafe-actions';

import { store, PlaylistHelper, Playlist, PlaylistTrack, rest } from '@nuclear/core';
import { store, PlaylistHelper, Playlist, PlaylistTrack, Track, rest } from '@nuclear/core';
import { GetPlaylistsByUserIdResponseBody } from '@nuclear/core/src/rest/Nuclear/Playlists.types';
import { ErrorBody } from '@nuclear/core/src/rest/Nuclear/types';

Expand All @@ -18,6 +18,7 @@ import { success, error } from './toasts';
import { IdentityStore } from '../reducers/nuclear/identity';
import { PlaylistsStore } from '../reducers/playlists';
import { isEmpty } from 'lodash';
import { rewriteTrackArtists } from './helpers';

export const updatePlaylistsAction = createStandardAction(Playlists.UPDATE_LOCAL_PLAYLISTS)<PlaylistsStore['localPlaylists']['data']>();

Expand Down Expand Up @@ -55,7 +56,7 @@ export const loadLocalPlaylists = () => dispatch => {
dispatch(loadLocalPlaylistsAction.request());

try {
const playlists: Playlist[] = store.get('playlists');
const playlists: Playlist[] = getPlaylistsBackwardsCompatible();
dispatch(loadLocalPlaylistsAction.success(isEmpty(playlists) ? [] : playlists));
} catch (error) {
dispatch(loadLocalPlaylistsAction.failure());
Expand Down Expand Up @@ -147,7 +148,7 @@ export function addPlaylistFromFile(filePath, t) {
throw new Error('missing tracks or name');
}

let playlists = store.get('playlists') || [];
let playlists = getPlaylistsBackwardsCompatible() || [];
const playlist = PlaylistHelper.formatPlaylistForStorage(name, tracks, v4(), source);

if (!(tracks?.length > 0)) {
Expand All @@ -167,3 +168,18 @@ export function addPlaylistFromFile(filePath, t) {
});
};
}

/**
* Helper function to read the old track format into the new format.
*
* `Track.artist` and `Track.extraArtists` are written into {@link Track.artists}
*/
function getPlaylistsBackwardsCompatible(): Playlist[] {
const playlists: Playlist[] = store.get('playlists');
return playlists.map(playlist => {
return {
...playlist,
tracks: playlist.tracks?.map(rewriteTrackArtists)
};
});
}
2 changes: 1 addition & 1 deletion packages/app/app/actions/queue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('Queue actions tests', () => {
const trackIndex = 123;
const queueItems: QueueItem[] = [];
queueItems[trackIndex] = {
artist: 'Artist Name',
artists: ['Artist Name'],
name: 'Track Name',
local: false,
streams: null
Expand Down
Loading
Loading