From 535ff867a9db613579f0e6443a5c7dc04956d9c9 Mon Sep 17 00:00:00 2001 From: Sander Vocke Date: Tue, 21 Jul 2020 19:48:36 +0200 Subject: [PATCH] Add GPM links. --- client/src/App.tsx | 26 ++++- client/src/api.ts | 8 +- client/src/assets/googleplaymusic_icon.svg | 109 ++++++++++++++++++ .../components/ItemListLoadedArtistItem.tsx | 7 ++ .../src/components/ItemListLoadedSongItem.tsx | 9 +- client/src/types/DisplayItem.tsx | 8 ++ scripts/gpm_retrieve/gpm_retrieve.py | 20 +++- .../endpoints/ArtistDetailsEndpointHandler.ts | 5 +- server/endpoints/CreateSongEndpointHandler.ts | 1 + .../endpoints/ModifyArtistEndpointHandler.ts | 1 + server/endpoints/ModifySongEndpointHandler.ts | 1 + .../endpoints/SongDetailsEndpointHandler.ts | 1 + server/models/album.js | 1 + server/models/artist.js | 1 + server/models/song.js | 1 + 15 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 client/src/assets/googleplaymusic_icon.svg diff --git a/client/src/App.tsx b/client/src/App.tsx index a961e86..8825d6f 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,12 +1,15 @@ import React, { useState, useEffect } from 'react'; import { Paper } from '@material-ui/core'; +import StoreIcon from '@material-ui/icons/Store'; import * as serverApi from './api'; import AppBar, { ActiveTab as AppBarActiveTab } from './components/AppBar'; import ItemList from './components/ItemList'; import ItemListItem from './components/ItemListItem'; import { SongDisplayItem, ArtistDisplayItem } from './types/DisplayItem'; +import { ReactComponent as GooglePlayIcon } from './assets/googleplaymusic_icon.svg'; + import { BrowserRouter as Router, Switch, @@ -23,6 +26,12 @@ interface ArtistItemProps { id: Number, } +const getStoreIcon = (url: String) => { + if (url.includes('play.google.com')) { + return ; + } + return ; +} function SongItem(props: SongItemProps) { const [songDisplayItem, setSongDisplayItem] = React.useState(undefined); @@ -41,7 +50,13 @@ function SongItem(props: SongItemProps) { return { title: title ? title : "Unknown", - artistNames: artistNames ? artistNames : [] + artistNames: artistNames ? artistNames : [], + storeLinks: json.storeLinks.map((url: String) => { + return { + icon: getStoreIcon(url), + url: url + } + }), }; }; @@ -88,8 +103,15 @@ function ArtistItem(props: ArtistItemProps) { const updateArtist = async () => { const response: any = await fetch(serverApi.ArtistDetailsEndpoint.replace(':id', props.id.toString())); const json: any = await response.json(); + return { - name: json.name ? json.name : "Unknown" + name: json.name ? json.name : "Unknown", + storeLinks: json.storeLinks.map((url: String) => { + return { + icon: getStoreIcon(url), + url: url + } + }), }; }; diff --git a/client/src/api.ts b/client/src/api.ts index 720f750..9322e9c 100644 --- a/client/src/api.ts +++ b/client/src/api.ts @@ -59,6 +59,7 @@ export const SongDetailsEndpoint = '/song/:id'; export interface SongDetailsRequest {} export interface SongDetailsResponse { title: String, + storeLinks: String[], artistIds: Number[], albumIds: Number[], } @@ -80,7 +81,8 @@ export function checkQueryArtistsRequest(req:any): boolean { export const ArtistDetailsEndpoint = '/artist/:id'; export interface ArtistDetailsRequest {} export interface ArtistDetailsResponse { - name: String + name: String, + storeLinks: String[], } export function checkArtistDetailsRequest(req:any): boolean { return true; @@ -92,6 +94,7 @@ export interface CreateSongRequest { title: String; artistIds?: Number[]; albumIds?: Number[]; + storeLinks?: String[]; } export interface CreateSongResponse { id: Number; @@ -107,6 +110,7 @@ export interface ModifySongRequest { title?: String; artistIds?: Number[]; albumIds?: Number[]; + storeLinks?: String[]; } export interface ModifySongResponse {} export function checkModifySongRequest(req:any): boolean { @@ -119,6 +123,7 @@ export interface CreateArtistRequest { name: String; songIds?: Number[]; albumIds?: Number[]; + storeLinks?: String[]; } export interface CreateArtistResponse { id: Number; @@ -132,6 +137,7 @@ export function checkCreateArtistRequest(req:any): boolean { export const ModifyArtistEndpoint = '/artist/:id'; export interface ModifyArtistRequest { name?: String, + storeLinks?: String[], } export interface ModifyArtistResponse {} export function checkModifyArtistRequest(req:any): boolean { diff --git a/client/src/assets/googleplaymusic_icon.svg b/client/src/assets/googleplaymusic_icon.svg new file mode 100644 index 0000000..dba5258 --- /dev/null +++ b/client/src/assets/googleplaymusic_icon.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/client/src/components/ItemListLoadedArtistItem.tsx b/client/src/components/ItemListLoadedArtistItem.tsx index e8e4d19..4d4c7a9 100644 --- a/client/src/components/ItemListLoadedArtistItem.tsx +++ b/client/src/components/ItemListLoadedArtistItem.tsx @@ -19,6 +19,13 @@ export default function ItemListLoadedArtistItem(props: IProps) { + {props.item.storeLinks.map((link: any) => { + return + + {link.icon} + + ; + })} ); } diff --git a/client/src/components/ItemListLoadedSongItem.tsx b/client/src/components/ItemListLoadedSongItem.tsx index 982a8f1..0fb5330 100644 --- a/client/src/components/ItemListLoadedSongItem.tsx +++ b/client/src/components/ItemListLoadedSongItem.tsx @@ -12,7 +12,7 @@ export interface IProps { export default function ItemListLoadedSongItem(props: IProps) { var artists = props.item.artistNames.length ? props.item.artistNames[0] : "Unknown"; - for(var i:number=1; i + {props.item.storeLinks.map((link: any) => { + return + + {link.icon} + + ; + })} ); } diff --git a/client/src/types/DisplayItem.tsx b/client/src/types/DisplayItem.tsx index b173c27..b7dd1f2 100644 --- a/client/src/types/DisplayItem.tsx +++ b/client/src/types/DisplayItem.tsx @@ -1,6 +1,10 @@ export interface SongDisplayItem { title:String, artistNames:String[], + storeLinks: { + icon: JSX.Element, + url: String, + }[] } export interface LoadingSongDisplayItem { @@ -9,6 +13,10 @@ export interface LoadingSongDisplayItem { export interface ArtistDisplayItem { name:String, + storeLinks: { + icon: JSX.Element, + url: String, + }[] } export interface LoadingArtistDisplayItem { diff --git a/scripts/gpm_retrieve/gpm_retrieve.py b/scripts/gpm_retrieve/gpm_retrieve.py index 17f7892..3ce1838 100755 --- a/scripts/gpm_retrieve/gpm_retrieve.py +++ b/scripts/gpm_retrieve/gpm_retrieve.py @@ -22,21 +22,35 @@ def transferLibrary(gpm_api, mudbase_api): # Determine all unique albums per artist artistAlbums = [ sorted(set([ song['album'] for song in songs if song['artist'] == artist ])) for artist in artists ] + # Determine store ID for all artists + def getArtistStoreIds(song): + if 'artistId' in song: + return [ song['artistId'][0] ] + return []; + artistStoreIds = [ [ getArtistStoreIds(song) for song in songs if song['artist'] == artist ][0] for artist in artists ] + # Create artists and store their mudbase Ids artistMudbaseIds = [] - for artist in artists: + for idx,artist in enumerate(artists): + print(artistStoreIds[idx]) response = requests.post(mudbase_api + '/artist', data = { - 'name': artist + 'name': artist, + 'storeLinks': [ 'https://play.google.com/music/m/' + id for id in artistStoreIds[idx] ] }).json() print(f"Created artist \"{artist}\", response: {response}") artistMudbaseIds.append(response['id']) # Create songs + def getSongStoreIds(song): + if 'storeId' in song: + return [ song['storeId'] ] + return []; for song in songs: artistMudbaseId = artistMudbaseIds[ artists.index(song['artist']) ] response = requests.post(mudbase_api + '/song', json = { 'title': song['title'], - 'artistIds': [ artistMudbaseId ] + 'artistIds': [ artistMudbaseId ], + 'storeLinks': [ 'https://play.google.com/music/m/' + id for id in getSongStoreIds(song) ], }).json() print(f"Created song \"{song['title']}\" with artist ID {artistMudbaseId}, response: {response}") diff --git a/server/endpoints/ArtistDetailsEndpointHandler.ts b/server/endpoints/ArtistDetailsEndpointHandler.ts index 81214de..47e4123 100644 --- a/server/endpoints/ArtistDetailsEndpointHandler.ts +++ b/server/endpoints/ArtistDetailsEndpointHandler.ts @@ -25,8 +25,11 @@ export const ArtistDetailsEndpointHandler: EndpointHandler = async (req: any, re throw e; } let artist = artists[0]; + const storeLinks = Array.isArray(artist.storeLinks) ? artist.storeLinks : + (artist.storeLinks ? [ artist.storeLinks ] : []); const response: api.ArtistDetailsResponse = { - name: artist.name + name: artist.name, + storeLinks: storeLinks, }; res.send(response); }) diff --git a/server/endpoints/CreateSongEndpointHandler.ts b/server/endpoints/CreateSongEndpointHandler.ts index e40cbe3..de060fb 100644 --- a/server/endpoints/CreateSongEndpointHandler.ts +++ b/server/endpoints/CreateSongEndpointHandler.ts @@ -47,6 +47,7 @@ export const CreateSongEndpointHandler: EndpointHandler = async (req: any, res: var song = models.Song.build({ title: reqObject.title, + storeLinks: reqObject.storeLinks || [], }); artists && song.addArtists(artists); albums && song.addAlbums(albums); diff --git a/server/endpoints/ModifyArtistEndpointHandler.ts b/server/endpoints/ModifyArtistEndpointHandler.ts index bb70a4a..7eb5941 100644 --- a/server/endpoints/ModifyArtistEndpointHandler.ts +++ b/server/endpoints/ModifyArtistEndpointHandler.ts @@ -25,6 +25,7 @@ export const ModifyArtistEndpointHandler: EndpointHandler = async (req: any, res } let artist = artists[0]; artist.name = reqObject.name; + if(reqObject.storeLinks) { artist.setStoreLinks(reqObject.storeLinks) }; await artist.save(); }) .then(() => { diff --git a/server/endpoints/ModifySongEndpointHandler.ts b/server/endpoints/ModifySongEndpointHandler.ts index 06150e4..a234a4e 100644 --- a/server/endpoints/ModifySongEndpointHandler.ts +++ b/server/endpoints/ModifySongEndpointHandler.ts @@ -77,6 +77,7 @@ export const ModifySongEndpointHandler: EndpointHandler = async (req: any, res: if(reqObject.artistIds) { song.setArtists(artists) }; if(reqObject.albumIds) { song.setAlbums(albums) }; if(reqObject.title) { song.setTitle(reqObject.title) }; + if(reqObject.storeLinks) { song.setStoreIds(reqObject.storeLinks) }; await song.save(); }) .then(() => { diff --git a/server/endpoints/SongDetailsEndpointHandler.ts b/server/endpoints/SongDetailsEndpointHandler.ts index 0fa5c69..9ed591f 100644 --- a/server/endpoints/SongDetailsEndpointHandler.ts +++ b/server/endpoints/SongDetailsEndpointHandler.ts @@ -30,6 +30,7 @@ export const SongDetailsEndpointHandler: EndpointHandler = async (req: any, res: title: song.title, artistIds: song.Artists.map((artist:any) => artist.id), albumIds: song.Albums.map((album:any) => album.id), + storeLinks: song.storeLinks, } res.send(response); }) diff --git a/server/models/album.js b/server/models/album.js index 92edb7e..7380aed 100644 --- a/server/models/album.js +++ b/server/models/album.js @@ -1,6 +1,7 @@ module.exports = (sequelize, DataTypes) => { var Album = sequelize.define('Album', { name: DataTypes.STRING, + storeLinks: DataTypes.JSON, }); Album.associate = function (models) { diff --git a/server/models/artist.js b/server/models/artist.js index 74bca35..4abefea 100644 --- a/server/models/artist.js +++ b/server/models/artist.js @@ -1,6 +1,7 @@ module.exports = (sequelize, DataTypes) => { var Artist = sequelize.define('Artist', { name: DataTypes.STRING, + storeLinks: DataTypes.JSON, }); Artist.associate = function (models) { diff --git a/server/models/song.js b/server/models/song.js index 6293546..8382e2f 100644 --- a/server/models/song.js +++ b/server/models/song.js @@ -1,6 +1,7 @@ module.exports = (sequelize, DataTypes) => { var Song = sequelize.define('Song', { title: DataTypes.STRING, + storeLinks: DataTypes.JSON, }); Song.associate = function (models) {