diff --git a/frontend/package-lock.json b/frontend/package-lock.json index faaaf3a..0136e12 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,6 +18,7 @@ "express-session": "^1.17.3", "ip": "^1.1.8", "jquery": "^3.7.1", + "json-beautify": "^1.1.1", "jsonwebtoken": "^9.0.2", "music-metadata": "^7.13.0", "node-fetch": "^2.7.0", @@ -8685,6 +8686,14 @@ "node": ">=4" } }, + "node_modules/json-beautify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-beautify/-/json-beautify-1.1.1.tgz", + "integrity": "sha512-17j+Hk2lado0xqKtUcyAjK0AtoHnPSIgktWRsEXgdFQFG9UnaGw6CHa0J7xsvulxRpFl6CrkDFHght1p5ZJc4A==", + "bin": { + "json-beautify": "bin/json-beautify" + } + }, "node_modules/json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.0.tgz", @@ -21622,6 +21631,11 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-beautify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-beautify/-/json-beautify-1.1.1.tgz", + "integrity": "sha512-17j+Hk2lado0xqKtUcyAjK0AtoHnPSIgktWRsEXgdFQFG9UnaGw6CHa0J7xsvulxRpFl6CrkDFHght1p5ZJc4A==" + }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 524b5ea..9fdab61 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,6 +34,7 @@ "express-session": "^1.17.3", "ip": "^1.1.8", "jquery": "^3.7.1", + "json-beautify": "^1.1.1", "jsonwebtoken": "^9.0.2", "music-metadata": "^7.13.0", "node-fetch": "^2.7.0", diff --git a/frontend/songs.json b/frontend/songs.json new file mode 100644 index 0000000..11428b0 --- /dev/null +++ b/frontend/songs.json @@ -0,0 +1,717 @@ +{ + "0": { + "artist": "Ballroom Dance Orchestra & Marc Reift", + "title": "Emperor's Dream", + "year": "2013-12-05", + "genre": [ "Easy Listening" ], + "duration": 183, + "filename": "i.b1JvdXPf09kp30", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "0", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/31/9a/e8/319ae8b2-0269-bb27-514e-200d9cf12bc0/888608304733.jpg/1200x1200bb.jpg" + }, + "1": { + "artist": "Studio Dance Band", + "title": "The Blue Danube", + "year": "2000-01-01", + "genre": [ "Pop" ], + "duration": 135, + "filename": "i.XMD6RDPH9x1ea9", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "1", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/b8/d9/1a/mzi.mkymfljn.jpg/1200x1200bb.jpg" + }, + "2": { + "artist": "Los del Río", + "title": "Macarena", + "year": "1993-12-13", + "genre": [ "Pop Latino" ], + "duration": 250, + "filename": "macarena.wav", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "2", + "origin": "disk", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/a1/2d/6a/a12d6a7b-6173-ed2e-9682-a30d245ed7fe/mzi.ndplymif.jpg/1200x1200bb.jpg" + }, + "3": { + "artist": "Spice Girls", + "title": "Wannabe", + "year": "1996-06-26", + "genre": [ "Pop" ], + "duration": 173, + "filename": "i.WmYQX3PtgOa5Wg", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "3", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/01/05/18/0105189c-9608-fb39-975c-a4dbc066da7e/21UMGIM57237.rgb.jpg/1200x1200bb.jpg" + }, + "4": { + "artist": "ABBA", + "title": "Dancing Queen", + "year": "1974-01-01", + "genre": [ "Pop" ], + "duration": 230, + "filename": "i.eoDz5v7hWx1grW", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "4", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/b5/b0/0b/b5b00b45-e209-9d03-4656-4117eec98a01/17UM1IM10690.rgb.jpg/1200x1200bb.jpg" + }, + "5": { + "artist": "Bobby Darin", + "title": "Splish Splash", + "year": "1958-09-01", + "genre": [ "Rock & Roll" ], + "duration": 132, + "filename": "i.GEG7XKkS2eOXN2", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "5", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/0c/86/fb/0c86fb9b-cb59-3b45-7d06-9c49827e541c/s05.eccxgemi.jpg/1200x1200bb.jpg" + }, + "6": { + "artist": "Bill Haley and His Comets", + "title": "See You Later, Alligator (Remastered)", + "year": "1956-06-01", + "genre": [ "Rock" ], + "duration": 164, + "filename": "i.RBrMvlofWv3A9W", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "6", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/14/24/c8/1424c885-f3a6-73d0-3fae-1bf9e4554165/5056321621139.png/1200x1200bb.jpg" + }, + "7": { + "artist": "Pedro Garcia & His Del Prado Orchestra", + "title": "Rico Vacilon", + "year": "2009-01-05", + "genre": [ "Latin" ], + "duration": 174, + "filename": "i.mmpYZ5aFkvAK9k", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "7", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/1d/c3/8a/mzi.cpscarsp.jpg/1200x1200bb.jpg" + }, + "8": { + "artist": "Rey Ruiz", + "title": "El Diablo Anda Suelto", + "year": "1999-08-11", + "genre": [ "Música tropical" ], + "duration": 254, + "filename": "i.JL1Yx2rSgGlDPg", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "8", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Features114/v4/81/f5/cf/81f5cf3e-3514-4428-affe-55d3e5f0e315/dj.ffashngb.jpg/1200x1200bb.jpg" + }, + "9": { + "artist": "Shakira", + "title": "Hips Don't Lie (feat. Wyclef Jean)", + "year": "2006-02-28", + "genre": [ "Pop" ], + "duration": 218, + "filename": "i.b1JvdpPC09kp30", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "9", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Features114/v4/2a/33/9a/2a339a01-28f3-3ddd-f9e7-30c837f046cc/dj.bvmymfoa.jpg/1200x1200bb.jpg" + }, + "10": { + "artist": "Luis Enrique", + "title": "Como Volver a Ser Feliz", + "year": "2009-05-19", + "genre": [ "Pop Latino" ], + "duration": 252, + "filename": "i.RBrMvr3TWv3A9W", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "10", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/5d/91/9a/mzi.jihxnatg.tif/1200x1200bb.jpg" + }, + "11": { + "artist": "The New 101 Strings Orchestra", + "title": "Moon River (From \"Breakfast at Tiffany's\")", + "year": "2000-01-01", + "genre": [ "Easy Listening" ], + "duration": 174, + "filename": "i.4YBelRxUdMLQOd", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "11", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/30/a3/d9/30a3d94e-1d6c-d807-fc28-58aa1759a8ac/0056775070120.jpg/1200x1200bb.jpg" + }, + "12": { + "artist": "Cat Stevens", + "title": "Morning Has Broken", + "year": "1971-10-01", + "genre": [ "Pop" ], + "duration": 201, + "filename": "i.ldDOmY9SR3XvxR", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "12", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music113/v4/3e/2e/7d/3e2e7dee-b278-7830-e286-38a815d02fa4/21UMGIM78164.rgb.jpg/1200x1200bb.jpg" + }, + "13": { + "artist": "Graham Dalby & The Grahamophones", + "title": "Jeepers Creepers (Quickstep)", + "year": "1995-01-01", + "genre": [ "Dance" ], + "duration": 179, + "filename": "i.DVEXQaPFzD5QMz", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "13", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/4e/03/33/mzi.cehftcpg.jpg/1200x1200bb.jpg" + }, + "14": { + "artist": "Britney Spears", + "title": "...Baby One More Time", + "year": "1998-09-29", + "genre": [ "Pop" ], + "duration": 211, + "filename": "i.eoDz5b8fWx1grW", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "14", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/7b/f7/0e/7bf70ecc-b16b-01d8-b14c-00ccae5062c7/dj.wvceujiz.jpg/1200x1200bb.jpg" + }, + "15": { + "artist": "Justin Timberlake", + "title": "CAN'T STOP THE FEELING! (Original Song From DreamWorks Animation's \"Trolls\")", + "year": "2016-05-06", + "genre": [ "Pop" ], + "duration": 236, + "filename": "i.XMD6R9zh9x1ea9", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "15", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/52/d0/02/52d002d7-1f7f-8d91-4791-ed04c460ec93/886445894653.jpg/1200x1200bb.jpg" + }, + "16": { + "artist": "Tommy Dorsey and His Orchestra", + "title": "Tea For Two Cha Cha (from the Isme Christmas TV advert)", + "year": "2005-01-01", + "genre": [ "Soundtrack" ], + "duration": 188, + "filename": "i.eoDz5LBcWx1grW", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "16", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/7d/05/bb/7d05bb15-2379-4bf8-ca9b-6fbf10ceaba8/nfm309.jpg/1200x1200bb.jpg" + }, + "17": { + "artist": "Rey Ruiz", + "title": "Muevelo", + "year": "2000-05-02", + "genre": [ "Música tropical" ], + "duration": 258, + "filename": "i.DVEXQE1tzD5QMz", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "17", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/58/15/0d/58150db1-0e74-dd19-f7eb-3f15e8a04b56/197187182459.jpg/1200x1200bb.jpg" + }, + "18": { + "artist": "James Brown", + "title": "I Feel Good (I Got You)", + "year": "2008-05-05", + "genre": [ "Rock" ], + "duration": 166, + "filename": "i.GEG7XLRf2eOXN2", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "18", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/a7/57/51/a7575132-3206-fb87-82d8-7b71498c4772/mzi.icplsaoj.tif/1200x1200bb.jpg" + }, + "19": { + "artist": "Elvis Presley", + "title": "Jailhouse Rock", + "year": "1957-09-24", + "genre": [ "Rock" ], + "duration": 147, + "filename": "i.WmYQXBBTgOa5Wg", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "19", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/e8/0a/4e/e80a4eb4-256d-50e8-615e-217436cf6bfb/196589185921.jpg/1200x1200bb.jpg" + }, + "20": { + "artist": "Elvis Presley", + "title": "Are You Lonesome Tonight?", + "year": "1960-11-01", + "genre": [ "Rock" ], + "duration": 187, + "filename": "i.ldDOmoESR3XvxR", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "20", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/ec/14/ea/ec14ea7c-7886-5757-5837-6ea26c0e4e7d/dj.qusytvtz.jpg/1200x1200bb.jpg" + }, + "21": { + "artist": "Span", + "title": "Louenesee", + "year": "2006-09-08", + "genre": [ "Pop" ], + "duration": 255, + "filename": "i.ldDOmEmFR3XvxR", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "21", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music112/v4/73/7e/4d/737e4dd9-c379-a078-0743-ede62a9af5f0/cover.jpg/1200x1200bb.jpg" + }, + "22": { + "artist": "Michael Bublé", + "title": "Something Stupid (feat. Reese Witherspoon)", + "year": "2013-04-15", + "genre": [ "Pop" ], + "duration": 178, + "filename": "i.RBrMvmvSWv3A9W", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "22", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/v4/27/75/f5/2775f5b3-8f62-aaf8-9743-46be49cbbc1b/093624944799.jpg/1200x1200bb.jpg" + }, + "23": { + "artist": "Bee Gees", + "title": "Stayin' Alive (From \"Saturday Night Fever\" Soundtrack)", + "year": "1977-01-01", + "genre": [ "Pop" ], + "duration": 284, + "filename": "i.ldDQRqBFR3XvxR", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "23", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music113/v4/45/db/1d/45db1dac-fe00-3681-b216-266deea6e4cc/17UM1IM26789.rgb.jpg/1200x1200bb.jpg" + }, + "24": { + "artist": "Mark Ronson", + "title": "Uptown Funk (feat. Bruno Mars)", + "year": "2015-01-13", + "genre": [ "Pop" ], + "duration": 270, + "filename": "i.JL1Yx1KUgGlDPg", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "24", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music5/v4/43/03/57/430357e0-e142-8d4d-ca56-87f4bd41e017/886444976145.jpg/1200x1200bb.jpg" + }, + "25": { + "artist": "Ballroom Orchestra & Singers", + "title": "Suelta la Cintura ( Chachacha / 32 Bpm )", + "year": "2009-09-21", + "genre": [ "Pop" ], + "duration": 155, + "filename": "i.RBrMvVgSWv3A9W", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "25", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/4c/31/28/mzi.vrcubdmd.jpg/1200x1200bb.jpg" + }, + "26": { + "artist": "Michael Bublé", + "title": "Come Dance With Me", + "year": "2013-04-15", + "genre": [ "Pop" ], + "duration": 166, + "filename": "i.DVEXQJgtzD5QMz", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "26", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/v4/27/75/f5/2775f5b3-8f62-aaf8-9743-46be49cbbc1b/093624944799.jpg/1200x1200bb.jpg" + }, + "27": { + "artist": "Sixpence None the Richer", + "title": "Kiss Me", + "year": "1989-09-01", + "genre": [ "Pop" ], + "duration": 209, + "filename": "i.XMD6R5QT9x1ea9", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "27", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music113/v4/3c/c5/b1/3cc5b1fc-828b-984a-ca75-76c139be37f6/080688702861.png/1200x1200bb.jpg" + }, + "28": { + "artist": "Surf Mesa", + "title": "ily (i love you baby) [feat. Emilee]", + "year": "2019-11-26", + "genre": [ "Dance" ], + "duration": 177, + "filename": "i.b1JvdDAF09kp30", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "28", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/00/2c/31/002c3175-9261-aee9-2e41-5af229cb2703/20UMGIM14423.rgb.jpg/1200x1200bb.jpg" + }, + "29": { + "artist": "Queen", + "title": "Crazy Little Thing Called Love", + "year": "1979-01-01", + "genre": [ "Rock" ], + "duration": 163, + "filename": "i.WmYQXZXfgOa5Wg", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "29", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/e8/f1/51/e8f151ae-0f87-a2fd-b981-807a01b24504/18UMGIM55031.rgb.jpg/1200x1200bb.jpg" + }, + "30": { + "artist": "Jerry Lee Lewis", + "title": "Great Balls Of Fire (Remastered 2022)", + "year": "1957-01-01", + "genre": [ "Rock" ], + "duration": 112, + "filename": "i.mmpYZGEHkvAK9k", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "30", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music123/v4/33/d0/88/33d0885f-0981-e55b-0983-fbc0180b332b/23UMGIM00418.rgb.jpg/1200x1200bb.jpg" + }, + "31": { + "artist": "Ritchie Valens", + "title": "La Bamba (Bonus Track)", + "year": "1958-06-25", + "genre": [ "Pop" ], + "duration": 126, + "filename": "i.4YBel4zcdMLQOd", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "31", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/52/62/27/5262275c-2998-3dd2-f226-b2ca4a08987c/cover.jpg/1200x1200bb.jpg" + }, + "32": { + "artist": "Charles Fox", + "title": "Macho", + "year": "2010-12-01", + "genre": [ "Música tropical" ], + "duration": 187, + "filename": "i.DVEXQzNFzD5QMz", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "32", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music112/v4/68/50/cf/6850cf4a-4db1-73bb-f4e6-d8d1c986970e/197187621828.jpg/1200x1200bb.jpg" + }, + "33": { + "artist": "Engelbert Humperdinck", + "title": "The Last Waltz", + "year": "1967-01-01", + "genre": [ "Pop" ], + "duration": 184, + "filename": "i.WmYQXYqigOa5Wg", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "33", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music118/v4/62/58/ff/6258ffd9-cda3-ba4d-e700-04d919a744bd/00602557548235.rgb.jpg/1200x1200bb.jpg" + }, + "34": { + "artist": "Johann Strauss Orchestra", + "title": "An Der Schönen Blauen Donau", + "year": "2007-10-01", + "genre": [ "Classical" ], + "duration": 432, + "filename": "i.eoDz5r7iWx1grW", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "34", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music/62/07/a6/mzi.aucttxtk.tif/1200x1200bb.jpg" + }, + "35": { + "artist": "Dua Lipa", + "title": "Dance The Night", + "year": "2023-05-27", + "genre": [ "Pop" ], + "duration": 177, + "filename": "i.eoDz5LPIWx1grW", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "35", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/c0/54/97/c05497aa-c19f-bf4f-de29-71edf30fbefb/075679688767.jpg/1200x1200bb.jpg" + }, + "36": { + "artist": "Justin Wellington", + "title": "Iko Iko (My Bestie) [feat. Small Jam]", + "year": "2017-03-21", + "genre": [ "Reggae" ], + "duration": 183, + "filename": "i.4YBelBNFdMLQOd", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "36", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/49/47/12/49471204-6605-e350-d4fb-9803f9105c57/886449208111.jpg/1200x1200bb.jpg" + }, + "37": { + "artist": "Michael Jackson", + "title": "Beat It", + "year": "1982-11-30", + "genre": [ "Pop" ], + "duration": 258, + "filename": "i.4YBNDgVsdMLQOd", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "37", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/32/4f/fd/324ffda2-9e51-8f6a-0c2d-c6fd2b41ac55/074643811224.jpg/1200x1200bb.jpg" + }, + "38": { + "artist": "Nicki Minaj", + "title": "Super Freaky Girl", + "year": "2022-08-12", + "genre": [ "Hip-Hop/Rap" ], + "duration": 171, + "filename": "i.JL1Yxd2HgGlDPg", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "38", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music112/v4/74/d9/a8/74d9a88e-9641-df34-401a-506b739bd824/22UMGIM87047.rgb.jpg/1200x1200bb.jpg" + }, + "39": { + "artist": "Katy Perry", + "title": "California Gurls (feat. Snoop Dogg)", + "year": "2010-05-07", + "genre": [ "Pop" ], + "duration": 235, + "filename": "i.ldDOmLEUR3XvxR", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "39", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/31/57/b3/3157b3d9-6551-e44e-46c0-488686998a05/13UABIM58339.rgb.jpg/1200x1200bb.jpg" + }, + "40": { + "artist": "Los del Río", + "title": "Macarena (Original Version)", + "year": "1993-12-13", + "genre": [ "Pop Latino" ], + "duration": 250, + "filename": "i.4YBepzRFdMLQOd", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "40", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/a1/2d/6a/a12d6a7b-6173-ed2e-9682-a30d245ed7fe/mzi.ndplymif.jpg/1200x1200bb.jpg" + }, + "41": { + "artist": "Rey Ruiz", + "title": "Ay Mujer", + "year": "2000-01-01", + "genre": [ "Música tropical" ], + "duration": 220, + "filename": "i.mmpYZvBtkvAK9k", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "41", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/58/15/0d/58150db1-0e74-dd19-f7eb-3f15e8a04b56/197187182459.jpg/1200x1200bb.jpg" + }, + "42": { + "artist": "Jennifer Lopez", + "title": "Let's Get Loud", + "year": "1999-06-01", + "genre": [ "Pop" ], + "duration": 239, + "filename": "i.eoD8NG8TWx1grW", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "42", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/c7/f4/6d/c7f46dbd-bc8d-7a7a-cf66-4b96dc59e105/888880316592.jpg/1200x1200bb.jpg" + }, + "43": { + "artist": "Riton & Nightcrawlers", + "title": "Friday (feat. Mufasa & Hypeman) [Dopamine Re-Edit]", + "year": "2021-01-15", + "genre": [ "Dance" ], + "duration": 169, + "filename": "i.eoDz5QWSWx1grW", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "43", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/f8/a5/5f/f8a55f83-f755-524c-aa9e-fd6a039e34e7/886448989318.jpg/1200x1200bb.jpg" + }, + "44": { + "artist": "a-ha", + "title": "Take On Me (2015 Remastered Version)", + "year": "1985-06-01", + "genre": [ "Pop" ], + "duration": 228, + "filename": "i.DVENx5mTzD5QMz", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "44", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/0b/5b/69/0b5b6991-cd46-7222-fca7-680b17318721/603497888191.jpg/1200x1200bb.jpg" + }, + "45": { + "artist": "ABBA", + "title": "Gimme! Gimme! Gimme! (A Man After Midnight)", + "year": "1979-04-23", + "genre": [ "Pop" ], + "duration": 290, + "filename": "i.DVEN9pGtzD5QMz", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "45", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/60/f8/a6/60f8a6bc-e875-238d-f2f8-f34a6034e6d2/14UMGIM07615.rgb.jpg/1200x1200bb.jpg" + }, + "46": { + "artist": "Black Eyed Peas", + "title": "I Gotta Feeling", + "year": "2009-01-01", + "genre": [ "Pop" ], + "duration": 289, + "filename": "i.b1Jvde0u09kp30", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "46", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/b1/d1/ae/b1d1ae62-12dd-eb84-3e46-643c444da662/09UMGIM13833.rgb.jpg/1200x1200bb.jpg" + }, + "47": { + "artist": "Robbie Williams", + "title": "Angels", + "year": "1997-12-01", + "genre": [ "Pop" ], + "duration": 265, + "filename": "i.GEG7XL1t2eOXN2", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "47", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/cf/86/e7/cf86e787-2177-6366-a5c3-2180c3031015/13ULAIM49472.rgb.jpg/1200x1200bb.jpg" + }, + "48": { + "artist": "Taio Cruz", + "title": "Hangover (feat. Flo Rida)", + "year": "2011-01-01", + "genre": [ "Pop" ], + "duration": 245, + "filename": "i.XMD6Rlxt9x1ea9", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "48", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/2e/fa/e2/2efae20b-7287-f437-f453-40ee0fd597f6/00602527869728.rgb.jpg/1200x1200bb.jpg" + }, + "49": { + "artist": "Eminem", + "title": "The Real Slim Shady", + "year": "2000-01-01", + "genre": [ "Hip-Hop/Rap" ], + "duration": 285, + "filename": "i.ldDOm09FR3XvxR", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "49", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/8a/a6/b5/8aa6b52a-d879-72c7-4289-85f8a9e5c535/06UMGIM17280.rgb.jpg/1200x1200bb.jpg" + }, + "50": { + "artist": "Icona Pop", + "title": "I Love It (feat. Charli XCX)", + "year": "2012-05-09", + "genre": [ "Pop" ], + "duration": 156, + "filename": "i.ldDOmElUR3XvxR", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "50", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music4/v4/cb/77/44/cb7744e2-5afe-3984-dbe6-bbbc2065cfd3/075678683800.jpg/1200x1200bb.jpg" + }, + "51": { + "artist": "Village People", + "title": "YMCA", + "year": "1978-01-01", + "genre": [ "Pop" ], + "duration": 287, + "filename": "i.GEGNom2H2eOXN2", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "51", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/92/cf/51/92cf5148-2b66-504a-8f6f-4b24e45c5195/mzi.hpkpognq.jpg/1200x1200bb.jpg" + }, + "52": { + "artist": "Rednex", + "title": "Cotton Eye Joe", + "year": "1994-01-01", + "genre": [ "Pop" ], + "duration": 194, + "filename": "i.mmpeN8JFkvAK9k", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "52", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/98/b2/f0/98b2f0fa-2964-3e8a-ffc2-bddff8fa8a42/38518.jpg/1200x1200bb.jpg" + }, + "53": { + "artist": "Sinéad O'Connor", + "title": "Nothing Compares 2 U (Edit)", + "year": "1990-03-12", + "genre": [ "Pop" ], + "duration": 307, + "filename": "i.mmpYZXEukvAK9k", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "53", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/a9/1e/a9/a91ea9bf-d6f3-8f96-3b95-f2bebf7c15c8/14ULAIM03937.rgb.jpg/1200x1200bb.jpg" + }, + "54": { + "artist": "Udo Lindenberg & Apache 207", + "title": "Komet", + "year": "2023-01-19", + "genre": [ "Pop" ], + "duration": 167, + "filename": "i.GEG7XxkF2eOXN2", + "coverArtOrigin": "api", + "hasCoverArt": true, + "queuePos": "54", + "origin": "apple-music", + "coverArtURL": "https://is1-ssl.mzstatic.com/image/thumb/Music123/v4/50/49/17/50491796-e488-a0ae-03ff-cab5afb4aef1/5054197494963.jpg/1200x1200bb.jpg" + } +} \ No newline at end of file diff --git a/frontend/src/app.js b/frontend/src/app.js index 42bd14e..74ce66e 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -11,6 +11,7 @@ const axios = require( 'axios' ); const ip = require( 'ip' ); const jwt = require( 'jsonwebtoken' ); const shell = require( 'electron' ).shell; +const beautify = require( 'json-beautify' ); app.use( bodyParser.urlencoded( { extended: false } ) ); @@ -232,6 +233,26 @@ app.get( '/indexDirs', ( req, res ) => { } } ); +app.get( '/loadPlaylist', ( req, res ) => { + res.send( JSON.parse( fs.readFileSync( dialog.showOpenDialogSync( { properties: [ 'openFile' ], title: 'Open file with playlist' } )[ 0 ] ) ) ); +} ); + +app.post( '/savePlaylist', ( req, res ) => { + fs.writeFileSync( dialog.showSaveDialogSync( { + properties: [ 'createDirectory' ], + title: 'Save the playlist as a json file', + filters: [ + { + extensions: [ 'json' ], + name: 'JSON files', + } + ], + defaultPath: 'songs.json' + } ), beautify( req.body, null, 2, 50 ) ); + console.log( req.body ); + res.send( 'ok' ); +} ); + app.get( '/getSongCover', ( req, res ) => { if ( req.query.filename ) { if ( indexer.getImages( req.query.filename ) ) { diff --git a/frontend/src/client/appleMusic/index.html b/frontend/src/client/appleMusic/index.html index 27f371c..f8afceb 100644 --- a/frontend/src/client/appleMusic/index.html +++ b/frontend/src/client/appleMusic/index.html @@ -26,6 +26,7 @@

Your playlists

+
autorenew

Loading playlists...

@@ -53,6 +54,7 @@ repeat_one_on repeat_on upload + ios_share
info
diff --git a/frontend/src/client/appleMusic/index.js b/frontend/src/client/appleMusic/index.js index b226424..4de6302 100644 --- a/frontend/src/client/appleMusic/index.js +++ b/frontend/src/client/appleMusic/index.js @@ -25,6 +25,11 @@ const app = Vue.createApp( { additionalSongInfo: {}, hasFinishedInit: false, + // For use with playlists that are partially from apple music and + // local drive + isUsingCustomPlaylist: false, + rawLoadedPlaylistData: {}, + // slider offset: 0, isDragging: false, @@ -74,6 +79,9 @@ const app = Vue.createApp( { // Assemble this.playingSong // TODO: Also add additional items to queue if there are new // items that weren't previously shown (limitation of MusicKitJS). + // TODO: Load from disk and stop MusicKit playback if next item in queue is + // to be loaded from disk + // TODO: Consideration: array with offsets to check if songs is correct if ( e.item ) { this.playingSong = this.songQueue[ this.musicKit.nowPlayingItemIndex ]; let url = e.item.attributes.artwork.url; @@ -167,7 +175,8 @@ const app = Vue.createApp( { } } } - this.playingSong = this.songQueue[ this.musicKit.nowPlayingItemIndex ]; + // TODO: update all those items to use custom queue manager for queue pos + this.playingSong = this.songQueue[ this.queuePos ]; this.sendUpdate( 'songQueue' ); this.sendUpdate( 'playingSong' ); } @@ -267,6 +276,7 @@ const app = Vue.createApp( { 'coverArtOrigin': 'api', 'hasCoverArt': true, 'queuePos': item, + 'origin': 'apple-music', } let url = songQueue[ item ].attributes.artwork.url; url = url.replace( '{w}', songQueue[ item ].attributes.artwork.width ); @@ -401,13 +411,17 @@ const app = Vue.createApp( { this.repeatMode = 'off'; } }, - play( song ) { - let foundSong = 0; - for ( let s in this.songQueue ) { - if ( this.songQueue[ s ] === song ) { - foundSong = s; + play( song, specificID ) { + let foundSong = specificID ?? 0; + if ( !specificID ) { + for ( let s in this.songQueue ) { + if ( this.songQueue[ s ] === song ) { + foundSong = s; + } } } + + // TODO: Update as well this.musicKit.changeToMediaItem( this.musicKit.queue.items[ foundSong ] ).then( () => { this.sendUpdate( 'queuePos' ); this.pos = 0; @@ -418,6 +432,107 @@ const app = Vue.createApp( { }, toggleShowMode() { this.isShowingRemainingTime = !this.isShowingRemainingTime; + }, + exportCurrentPlaylist() { + let fetchOptions = { + method: 'post', + body: JSON.stringify( this.songQueue ), + headers: { + 'Content-Type': 'application/json', + 'charset': 'utf-8' + }, + }; + fetch( '/savePlaylist', fetchOptions ).then( res => { + if ( res.status === 200 ) { + console.log( 'saved' ); + } + } ); + }, + selectPlaylistFromDisk() { + this.isPreparingToPlay = true; + let playlistSongs = []; + fetch( '/loadPlaylist' ).then( res => { + res.json().then( data => { + this.rawLoadedPlaylistData = data; + for ( let song in data ) { + if ( data[ song ].origin === 'apple-music' ) { + playlistSongs.push( data[ song ].filename ); + } + } + this.musicKit.setQueue( { songs: playlistSongs } ).then( () => { + this.isUsingCustomPlaylist = true; + try { + this.loadCustomPlaylist(); + this.hasSelectedPlaylist = true; + this.isPreparingToPlay = false; + } catch( err ) { + this.hasSelectedPlaylist = false; + console.error( err ); + alert( 'We were unable to play. Please ensure that DRM (yeah sorry it is Apple Music, we cannot do anything about that) is enabled and working' ); + } + } ).catch( err => { + console.error( 'ERROR whilst settings Queue', err ); + } ); + } ); + } ); + }, + loadCustomPlaylist() { + const songQueue = this.musicKit.queue.items; + let offset = 0; + ( async() => { + for ( let item in this.rawLoadedPlaylistData ) { + if ( this.rawLoadedPlaylistData[ item ].origin === 'apple-music' ) { + this.songQueue[ item ] = { + 'artist': songQueue[ item - offset ].attributes.artistName, + 'title': songQueue[ item - offset ].attributes.name, + 'year': songQueue[ item - offset ].attributes.releaseDate, + 'genre': songQueue[ item - offset ].attributes.genreNames, + 'duration': Math.round( songQueue[ item - offset ].attributes.durationInMillis / 1000 ), + 'filename': songQueue[ item - offset ].id, + 'coverArtOrigin': 'api', + 'hasCoverArt': true, + 'queuePos': item, + 'origin': 'apple-music', + } + let url = songQueue[ item - offset ].attributes.artwork.url; + url = url.replace( '{w}', songQueue[ item - offset ].attributes.artwork.width ); + url = url.replace( '{h}', songQueue[ item - offset ].attributes.artwork.height ); + this.songQueue[ item ][ 'coverArtURL' ] = url; + } else { + offset += 1; + const queryParameters = { + term: ( this.rawLoadedPlaylistData[ item ].artist ?? '' ) + ' ' + ( this.rawLoadedPlaylistData[ item ].title ?? '' ), + types: [ 'songs' ], + }; + // TODO: Make sure that playback duration is correct (get from backend with analysis?) + // TODO: Make storefront adjustable + const result = await this.musicKit.api.music( '/v1/catalog/ch/search', queryParameters ); + if ( result.data ) { + if ( result.data.results.songs ) { + const dat = result.data.results.songs.data[ 0 ] + this.songQueue[ item ] = { + 'artist': dat.attributes.artistName, + 'title': dat.attributes.name, + 'year': dat.attributes.releaseDate, + 'genre': dat.attributes.genreNames, + 'duration': Math.round( dat.attributes.durationInMillis / 1000 ), + 'filename': this.rawLoadedPlaylistData[ item ].filename, + 'coverArtOrigin': 'api', + 'hasCoverArt': true, + 'queuePos': item, + 'origin': 'apple-music', + } + let url = dat.attributes.artwork.url; + url = url.replace( '{w}', dat.attributes.artwork.width ); + url = url.replace( '{h}', dat.attributes.artwork.height ); + this.songQueue[ item ][ 'coverArtURL' ] = url; + } + } + } + this.handleAdditionalData(); + this.sendUpdate( 'songQueue' ); + } + } )(); } }, watch: {