From 69a558b686a71020f4d48559e81b37f03fa45627 Mon Sep 17 00:00:00 2001 From: LeadFreeCandy Date: Fri, 16 Feb 2024 16:19:56 -0500 Subject: [PATCH 01/40] Add build script --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++ spotify_app/build.sh | 37 +++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100755 spotify_app/build.sh diff --git a/README.md b/README.md index c612b05..3758aea 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,58 @@ # SpotifyPlus Spotify with a better interface and a better algorithm + +To create a README that explains how to build the code using the build script located in the `/extension` folder of your repository, follow this template. This guide assumes the users have basic knowledge of using terminal or command prompt, have cloned the repository, and have basic setup requirements met, such as having Git and possibly Node.js (depending on your project's requirements). + +--- + +# Building SpotifyPlus Extension + +Welcome to the SpotifyPlus extension! This guide will walk you through the steps to build and deploy the SpotifyPlus extension from the cloned repository to your local Spotify application. + +## Prerequisites + +Before you begin, ensure you have the following prerequisites installed and set up: + +- **Git**: To clone the repository. +- **Spicetify**: Ensure Spicetify is installed and configured on your system. Spicetify is a tool to customize Spotify. +- **Windows Subsystem for Linux (WSL)** (for Windows users): Ensure WSL is installed and set up if you're on Windows, you cannot use powershell to run this script. + +## Clone the Repository + +If you haven't already cloned the repository, run the following command in your terminal or command prompt: + +```bash +git clone [https://github.com/LeadFreeCandy/SpotifyPlus] +``` + +## Navigate to the Extension Directory + +Change your current directory to the `/extension` folder within the cloned repository: + +```bash +cd SpotifyPlus/extension +``` + +## Running the Build Script + +To execute the build script, use the following command: + +```bash +./build.sh +``` + +### For macOS Users + +The script will automatically detect your operating system. If you're on macOS, it will copy the necessary files to `~/.config/spicetify/CustomApps/SpotifyPlus` and apply the Spicetify changes. + +### For Windows Users with WSL + +If you're using Windows Subsystem for Linux (WSL), the script will place the necessary files in your Windows `%appdata%\spicetify\CustomApps\SpotifyPlus` directory and then apply the Spicetify changes. + +## Troubleshooting + +If you encounter any errors during the build process: + +- Ensure you have all the prerequisites installed. +- Verify that Spicetify is correctly set up and that you have permissions to modify its directories. +- Check the script's error messages for hints on what went wrong and adjust your environment accordingly. diff --git a/spotify_app/build.sh b/spotify_app/build.sh new file mode 100755 index 0000000..eab407b --- /dev/null +++ b/spotify_app/build.sh @@ -0,0 +1,37 @@ +copy_and_apply() { + mkdir -p "$1" 2>/dev/null + if ! cp manifest.json index.js "$1"; then + echo "Error copying files. Ensure manifest.json and index.js exist in the current directory." + exit 1 + fi + + if ! spicetify config custom_apps SpotifyPlus; then + echo "Failed to configure spicetify for SpotifyPlus. Ensure spicetify is correctly installed." + exit 1 + fi + + if ! spicetify apply; then + echo "Failed to apply spicetify changes. Check your spicetify installation and configuration." + exit 1 + fi +} + +# Detect OS and set target path +if [ "$(uname)" = "Darwin" ]; then + # macOS + TARGET_DIR="$HOME/.config/spicetify/CustomApps/SpotifyPlus" + copy_and_apply "$TARGET_DIR" +elif [ "$(expr substr $(uname -s) 1 5)" = "Linux" ]; then + # Assuming WSL is being used on Windows + if [ -n "$WSL_DISTRO_NAME" ]; then + # Convert Windows %appdata% path to WSL path + TARGET_DIR="$(wslpath "$(wslvar APPDATA)")/spicetify/CustomApps/SpotifyPlus" + copy_and_apply "$TARGET_DIR" + else + echo "This script is intended to be run on macOS or within WSL for Windows." + exit 1 + fi +else + echo "Unsupported operating system. This script is intended for macOS or WSL on Windows." + exit 1 +fi From 50629b803efbcde4fa9eb7784c3895e597eea5b9 Mon Sep 17 00:00:00 2001 From: LeadFreeCandy Date: Fri, 16 Feb 2024 16:22:12 -0500 Subject: [PATCH 02/40] Add broken app --- spotify_app/index.js | 54 +++++++++++++++++++++++++++++++++++++++ spotify_app/manifest.json | 6 +++++ 2 files changed, 60 insertions(+) create mode 100644 spotify_app/index.js create mode 100644 spotify_app/manifest.json diff --git a/spotify_app/index.js b/spotify_app/index.js new file mode 100644 index 0000000..8b304da --- /dev/null +++ b/spotify_app/index.js @@ -0,0 +1,54 @@ +// Grab any variables you need +const react = Spicetify.React; +const reactDOM = Spicetify.ReactDOM; +const { + URI, + React: { useState, useEffect, useCallback }, + Platform: { History }, +} = Spicetify; + +// The main custom app render function. The component returned is what is rendered in Spotify. +function render() { + return react.createElement(Grid, { title: "My Custom App" }); +} + +// Our main component +class Grid extends react.Component { + constructor(props) { + super(props); + Object.assign(this, props); + this.state = { + foo: "bar", + data: "etc" + }; + } + + render() { + return react.createElement("section", { + className: "contentSpacing", + }, + react.createElement("div", { + className: "marketplace-header", + }, react.createElement("h1", null, this.props.title), + ), + ), react.createElement("div", { + id: "marketplace-grid", + className: "main-gridContainer-gridContainer", + "data-tab": CONFIG.activeTab, + style: { + "--minimumColumnWidth": "180px", + }, + }, [...cardList]), + react.createElement("footer", { + style: { + margin: "auto", + textAlign: "center", + }, + }, !this.state.endOfList && (this.state.rest ? react.createElement(LoadMoreIcon, { onClick: this.loadMore.bind(this) }) : react.createElement(LoadingIcon)), + ), react.createElement(TopBarContent, { + switchCallback: this.switchTo.bind(this), + links: CONFIG.tabs, + activeLink: CONFIG.activeTab, + })); + } +} diff --git a/spotify_app/manifest.json b/spotify_app/manifest.json new file mode 100644 index 0000000..d939da2 --- /dev/null +++ b/spotify_app/manifest.json @@ -0,0 +1,6 @@ +{ + "name": "My Custom App", + "icon": "", + "active-icon": "", + "subfiles": ["src/app.js"] +} From 847d0ce3f2ac2612ac027551773c8d22d0cd98fe Mon Sep 17 00:00:00 2001 From: LeadFreeCandy Date: Fri, 23 Feb 2024 16:50:14 -0500 Subject: [PATCH 03/40] Make app blank working page --- spotify_app/index.js | 47 +------------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 8b304da..09e1027 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -1,54 +1,9 @@ // Grab any variables you need const react = Spicetify.React; const reactDOM = Spicetify.ReactDOM; -const { - URI, - React: { useState, useEffect, useCallback }, - Platform: { History }, -} = Spicetify; // The main custom app render function. The component returned is what is rendered in Spotify. function render() { - return react.createElement(Grid, { title: "My Custom App" }); + return react.createElement("div", { title: "My Custom App" }); } -// Our main component -class Grid extends react.Component { - constructor(props) { - super(props); - Object.assign(this, props); - this.state = { - foo: "bar", - data: "etc" - }; - } - - render() { - return react.createElement("section", { - className: "contentSpacing", - }, - react.createElement("div", { - className: "marketplace-header", - }, react.createElement("h1", null, this.props.title), - ), - ), react.createElement("div", { - id: "marketplace-grid", - className: "main-gridContainer-gridContainer", - "data-tab": CONFIG.activeTab, - style: { - "--minimumColumnWidth": "180px", - }, - }, [...cardList]), - react.createElement("footer", { - style: { - margin: "auto", - textAlign: "center", - }, - }, !this.state.endOfList && (this.state.rest ? react.createElement(LoadMoreIcon, { onClick: this.loadMore.bind(this) }) : react.createElement(LoadingIcon)), - ), react.createElement(TopBarContent, { - switchCallback: this.switchTo.bind(this), - links: CONFIG.tabs, - activeLink: CONFIG.activeTab, - })); - } -} From 03d6fae87e4d6b59879e50fed8190630f0a714b1 Mon Sep 17 00:00:00 2001 From: LeadFreeCandy Date: Fri, 23 Feb 2024 16:50:34 -0500 Subject: [PATCH 04/40] Add vector logo to manifest --- spotify_app/manifest.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spotify_app/manifest.json b/spotify_app/manifest.json index d939da2..57022f4 100644 --- a/spotify_app/manifest.json +++ b/spotify_app/manifest.json @@ -1,6 +1,7 @@ { "name": "My Custom App", - "icon": "", - "active-icon": "", + "icon": "", + + "active-icon": "", "subfiles": ["src/app.js"] } From 7859c5c8cb328d9abc6e7411314ef4493bd75cdd Mon Sep 17 00:00:00 2001 From: LeadFreeCandy Date: Fri, 23 Feb 2024 16:55:24 -0500 Subject: [PATCH 05/40] Add untested windows build file --- spotify_app/build.bat | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 spotify_app/build.bat diff --git a/spotify_app/build.bat b/spotify_app/build.bat new file mode 100644 index 0000000..2c4623d --- /dev/null +++ b/spotify_app/build.bat @@ -0,0 +1,45 @@ +@echo off +SetLocal EnableDelayedExpansion + +:: Function equivalent in batch for copy_and_apply +:copy_and_apply +mkdir "%~1" 2>nul +copy manifest.json "%~1" >nul +if errorlevel 1 ( + echo Error copying files. Ensure manifest.json and index.js exist in the current directory. + exit /b 1 +) +copy index.js "%~1" >nul +if errorlevel 1 ( + echo Error copying files. Ensure manifest.json and index.js exist in the current directory. + exit /b 1 +) + +:: Attempt to configure spicetify for SpotifyPlus +spicetify config custom_apps SpotifyPlus +if errorlevel 1 ( + echo Failed to configure spicetify for SpotifyPlus. Ensure spicetify is correctly installed. + exit /b 1 +) + +:: Apply spicetify changes +spicetify apply +if errorlevel 1 ( + echo Failed to apply spicetify changes. Check your spicetify installation and configuration. + exit /b 1 +) + +goto :eof + +:: Detect OS and set target path +for /f "tokens=2 delims==" %%i in ('wmic os get caption /value') do set OS=%%i + +if "%OS%" == "Microsoft Windows 10 Pro" ( + :: Assuming this is for demonstration; adjust as necessary for your Windows version + :: Convert %appdata% to a direct path usage in PowerShell/Command Prompt + set TARGET_DIR=%appdata%\spicetify\CustomApps\SpotifyPlus + call :copy_and_apply "%TARGET_DIR%" +) else ( + echo Unsupported operating system. This script is intended for Windows with PowerShell. + exit /b 1 +) From 269b44ac4fa001213aea9afc61c57cefbeeed323 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Fri, 1 Mar 2024 16:18:16 -0500 Subject: [PATCH 06/40] Working index.js An index.js update that produces headers and subheaders on the spicetify wrapper of spotify, in the SpotifyPlus app. Right now it is only for testing purposes, But baseline code has been written for future changes. --- spotify_app/index.js | 76 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 09e1027..4ba5c9c 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -1,9 +1,83 @@ // Grab any variables you need const react = Spicetify.React; const reactDOM = Spicetify.ReactDOM; +const { + URI, + React: { useState, useEffect, useCallback }, + Platform: { History }, +} = Spicetify; +const CONFIG = { + activeTab: "Tinder", + tabs: ["Tinder", "Other"] +}; + +// Load More Icon component +const LoadMoreIcon = (props) => { + return react.createElement("button", { onClick: props.onClick }, "Load More"); +}; + +// Loading Icon component +const LoadingIcon = () => { + return react.createElement("div", null, "Loading..."); +}; + +// Top Bar Content component +const TopBarContent = (props) => { + return react.createElement("div", null, + props.links.map((link) => + react.createElement("a", { + key: link, + className: link === props.activeLink ? 'active' : '' + }, link) + ) + ); +}; + + +const cardList = ["Tinder1", "Other1", "Spot+"]; // The main custom app render function. The component returned is what is rendered in Spotify. function render() { - return react.createElement("div", { title: "My Custom App" }); + return react.createElement(Grid, { title: "SpotifyPlus" }); } +// Our main component +class Grid extends react.Component { + constructor(props) { + super(props); + Object.assign(this, props); + this.state = { + foo: "bar", + data: "etc" + }; + } + + render() { + return react.createElement("section", { + className: "contentSpacing", + }, + react.createElement("div", { + className: "marketplace-header", + }, react.createElement("h1", null, this.props.title), + ), + react.createElement("div", { + id: "marketplace-grid", + className: "main-gridContainer-gridContainer", + "data-tab": CONFIG.activeTab, + style: { + "--minimumColumnWidth": "180px", + }, + }, [...cardList]), + react.createElement("footer", { + style: { + margin: "auto", + textAlign: "center", + }, + }, !this.state.endOfList && (this.state.rest ? react.createElement(LoadMoreIcon, { onClick: this.loadMore.bind(this) }) : react.createElement(LoadingIcon)), + ), react.createElement(TopBarContent, { + links: CONFIG.tabs, + activeLink: CONFIG.activeTab, + }) + ); + } +} From 67fd81ec7ba4dc9d73e79ac2b19a3829b6ea737f Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:28:04 -0400 Subject: [PATCH 07/40] Update manifest.json Updated the name and icon so that it lights up when the user hovers over the icon in the UI. --- spotify_app/manifest.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spotify_app/manifest.json b/spotify_app/manifest.json index 57022f4..5a6ced6 100644 --- a/spotify_app/manifest.json +++ b/spotify_app/manifest.json @@ -1,7 +1,7 @@ { - "name": "My Custom App", - "icon": "", - - "active-icon": "", - "subfiles": ["src/app.js"] + "name": "SpotifyPlus", + "icon": "", + "active-icon": "", + "subfiles": ["src/app.js"], + "subfiles_extension": [] } From d15e88a9455ab601b736f35affb1192b80903bdc Mon Sep 17 00:00:00 2001 From: Augula33 Date: Tue, 12 Mar 2024 17:05:26 -0400 Subject: [PATCH 08/40] Updated the name and fixed the icon line so that the icon in the UI lights up properly when users hover over it --- spotify_app/manifest.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spotify_app/manifest.json b/spotify_app/manifest.json index 57022f4..29204c7 100644 --- a/spotify_app/manifest.json +++ b/spotify_app/manifest.json @@ -1,7 +1,7 @@ { - "name": "My Custom App", - "icon": "", - - "active-icon": "", - "subfiles": ["src/app.js"] -} + "name": "SpotifyPlus", + "icon": "", + "active-icon": "", + "subfiles": [], + "subfiles_extension": [] +} \ No newline at end of file From 7f9f0827ca8ffb1ef00c9623e9ad2f5ca7ad5ea7 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Tue, 12 Mar 2024 20:09:33 -0400 Subject: [PATCH 09/40] Update to SpotifyPlus spicetify app This commit continues to make progress on the spicetify app, starting the implementation of like, dislike, and skip buttons. It also added items for future implementation, like the beginning of a local storage for recent songs. --- spotify_app/index.js | 134 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 113 insertions(+), 21 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 4ba5c9c..5565c91 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -8,39 +8,85 @@ const { } = Spicetify; const CONFIG = { - activeTab: "Tinder", - tabs: ["Tinder", "Other"] -}; - -// Load More Icon component -const LoadMoreIcon = (props) => { - return react.createElement("button", { onClick: props.onClick }, "Load More"); -}; - -// Loading Icon component -const LoadingIcon = () => { - return react.createElement("div", null, "Loading..."); + activeTab: "Main", + tabs: ["Main","Recent Songs"] }; // Top Bar Content component const TopBarContent = (props) => { - return react.createElement("div", null, + return react.createElement("div", { + style: { + display: "flex", + paddingTop: "15px", + justifyContent: "flex-start", // Align tabs to the left + gap: "100px", // Adjust the spacing between tabs + } + }, props.links.map((link) => - react.createElement("a", { + react.createElement("div", { key: link, - className: link === props.activeLink ? 'active' : '' - }, link) + style: { + position: "relative", + } + }, + react.createElement("a", { + className: link === props.activeLink ? 'active' : '', + style: { + padding: "10px 20px", // Adjust the padding of the tabs + borderRadius: "20px", // Add border radius to create rounded edges + border: "1px solid white", // Add border with white color + color: "white", // Set text color + textDecoration: "none", // Remove underline + } + }, link), + ) ) ); }; +/* +const fetchTrack = async (uri) => { + const res = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/tracks/${uri.split(':')[2]}`); + return res.name; +}; +*/ +function clearsong() { + return Spicetify.Platform.LocalStorageAPI.clearItem(this.songname) + .then(() => true) // Resolves to true if the item is successfully cleared + .catch(() => false); // Resolves to false if there's an error while clearing the item +} +/*used like this: +clearsong() + .then(success => { + if (success) { + console.log("Item successfully cleared."); + } else { + console.error("Failed to clear item."); + } + }); +*/ +function handleLike(){ + //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: true, skipped: false, song: this.song}); + + return "Liked Song"; +} +function handleDislike(){ + //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: false, skipped: false,song: this.song }); + + + return "Disliked Song"; +} +function handleSkip(){ + //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: false, skipped: false, song: this.song }); -const cardList = ["Tinder1", "Other1", "Spot+"]; + return "Skip Song"; +} // The main custom app render function. The component returned is what is rendered in Spotify. function render() { return react.createElement(Grid, { title: "SpotifyPlus" }); } + // Our main component class Grid extends react.Component { constructor(props) { @@ -65,16 +111,62 @@ class Grid extends react.Component { className: "main-gridContainer-gridContainer", "data-tab": CONFIG.activeTab, style: { - "--minimumColumnWidth": "180px", + display: "flex", + justifyContent: "space-between", // This will evenly distribute the items + flexWrap: "wrap", // Allow items to wrap to the next line if needed }, - }, [...cardList]), + }), react.createElement("footer", { style: { margin: "auto", + bottom: 0, + left: 0, + position: "fixed", textAlign: "center", + width: "100%", // Ensure the footer spans the full width + paddingTop: "20px", // Add padding at the top for spacing + paddingBottom: "40px" + }, + }, + react.createElement("div", { + style: { + display: "flex", + justifyContent: "space-around", // This will evenly distribute the buttons + + }, }, - }, !this.state.endOfList && (this.state.rest ? react.createElement(LoadMoreIcon, { onClick: this.loadMore.bind(this) }) : react.createElement(LoadingIcon)), - ), react.createElement(TopBarContent, { + react.createElement("button", { + //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters + onClick: handleDislike, + style: { + backgroundColor: "red", // Change the background color of the button + color: "white", // Change the text color of the button + border: "none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius: "5px", // Add border radius + } + }, "Dislike"), + react.createElement("button", { + onClick: handleSkip, + style: { + backgroundColor: "blue", // Change the background color of the button + color: "white", // Change the text color of the button + border: "none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius: "5px", // Add border radius + } + }, "Skip"), + react.createElement("button", { + onClick: handleLike, + style: { + backgroundColor: "green", // Change the background color of the button + color: "white", // Change the text color of the button + border: "none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius: "5px", // Add border radius + } + }, "Like"),)), + react.createElement(TopBarContent, { links: CONFIG.tabs, activeLink: CONFIG.activeTab, }) From 3adcea1d28ad87e296ce1f329359d18f6f9401d1 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:14:58 -0400 Subject: [PATCH 10/40] Index.js new button Added a new button into Index.js and added a few new functions to index for future functionality. created a baseline for future communication with LLM and Spotify Local Storage. --- spotify_app/index.js | 101 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 5565c91..c22c7fa 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -11,6 +11,16 @@ const CONFIG = { activeTab: "Main", tabs: ["Main","Recent Songs"] }; +//should be used in the retrieve function +function ifItemIsTrack(uri) { + let uriObj = Spicetify.URI.fromString(uri[0]); + switch (uriObj.type) { + case Type.TRACK: + return true; + } + return false; +} + // Top Bar Content component const TopBarContent = (props) => { @@ -44,13 +54,45 @@ const TopBarContent = (props) => { ); }; +async function retrieve(playlistId) { + try { + // Get the playlist using Spicetify wrapper + const playlist = await Spicetify.Playlist.get(playlistId); + + // Extract songs from the playlist + const songs = playlist.data.items.map(item => ({ + name: item.track.name, + artist: item.track.artists.map(artist => artist.name).join(', '), // Concatenate artist names if there are multiple + duration: item.track.duration_ms, // You can extract other song details as needed + })); + + // Sort songs in ascending order by name + songs.sort((a, b) => a.name.localeCompare(b.name)); + + // Return the sorted songs + return songs; + } catch (error) { + console.error("Error retrieving songs:", error); + return []; // Return an empty array if there's an error + } +} + +async function retrievenext(){ + return trackUri; +} +async function send(){ + /* + Uncreated function to send information of the song and information on wether it was liked/disliked/skipped. + */ + return true; +} /* const fetchTrack = async (uri) => { const res = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/tracks/${uri.split(':')[2]}`); return res.name; }; */ -function clearsong() { +async function clearsong() { return Spicetify.Platform.LocalStorageAPI.clearItem(this.songname) .then(() => true) // Resolves to true if the item is successfully cleared .catch(() => false); // Resolves to false if there's an error while clearing the item @@ -65,11 +107,39 @@ clearsong() } }); */ -function handleLike(){ - //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: true, skipped: false, song: this.song}); - return "Liked Song"; +async function nextsong(uri){ + await Spicetify.addToQueue([{ uri: uri }]); +} + +// Example usage: +const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; +// +async function handleLike() { + try { + // Assuming send() is an asynchronous function + await send(); + } catch (error) { + console.error("Error sending like to LLM:", error); + } + + let uri; + try { + // Assuming retrievenext() is an asynchronous function + uri = await retrievenext(); + } catch (error) { + console.error("Error retrieving next song from LLM:", error); + } + + try { + // Assuming nextsong(uri) is an asynchronous function + await nextsong(uri); + } catch (error) { + console.error("Error playing next song:", error); + } + } + function handleDislike(){ //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: false, skipped: false,song: this.song }); @@ -81,12 +151,16 @@ function handleSkip(){ return "Skip Song"; } +function handlePlaySong(){ + return +} // The main custom app render function. The component returned is what is rendered in Spotify. function render() { return react.createElement(Grid, { title: "SpotifyPlus" }); } + // Our main component class Grid extends react.Component { constructor(props) { @@ -128,6 +202,25 @@ class Grid extends react.Component { paddingBottom: "40px" }, }, + react.createElement("div", { + style: { + display: "flex", + justifyContent: "space-around", // This will evenly distribute the buttons + + }, + }, + react.createElement("button", { + onClick: handlePlaySong, + style: { + backgroundColor: "orange", // Change the background color of the button + color: "white", // Change the text color of the button + border: "none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius: "5px", // Add border radius + marginBottom: "30px" // Add margin to separate from the buttons below + } + }, "Play Song"), + ), react.createElement("div", { style: { display: "flex", From 4075b469f03a7c942502cdc123dfed2a14f2c62c Mon Sep 17 00:00:00 2001 From: Augula33 Date: Fri, 15 Mar 2024 17:32:27 -0400 Subject: [PATCH 11/40] Added tinder logo cuz dalle sucks and cant make a good logo --- .vscode/launch.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5c7247b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file From 92c6ea82e88d6b9d49e64e4b040ac4ddb326b0ba Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Fri, 22 Mar 2024 17:24:52 -0400 Subject: [PATCH 12/40] Playing songs Added functionality to play songs when button is clicked, and began adding functionality for playlists. --- spotify_app/index.js | 61 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index c22c7fa..3881a32 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -21,7 +21,6 @@ function ifItemIsTrack(uri) { return false; } - // Top Bar Content component const TopBarContent = (props) => { return react.createElement("div", { @@ -54,6 +53,9 @@ const TopBarContent = (props) => { ); }; +//Get playlist ID by copying link to playlist, for example +//https://open.spotify.com/playlist/37i9dQZF1DWXRqgorJj26U?si=9f6A6U2jTk-njyZJ64rk3g ID would be 37i9dQZF1DWXRqgorJj26U +const playlistId = "2it9p5n9Eit7iGVy1djNP0"; async function retrieve(playlistId) { try { // Get the playlist using Spicetify wrapper @@ -109,7 +111,8 @@ clearsong() */ async function nextsong(uri){ - await Spicetify.addToQueue([{ uri: uri }]); + Spicetify.Player.playUri(uri); + } // Example usage: @@ -118,7 +121,7 @@ const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; async function handleLike() { try { // Assuming send() is an asynchronous function - await send(); + await send("liked"); } catch (error) { console.error("Error sending like to LLM:", error); } @@ -140,18 +143,56 @@ async function handleLike() { } -function handleDislike(){ - //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: false, skipped: false,song: this.song }); +async function handleDislike() { + try { + // Assuming send() is an asynchronous function + await send("disliked"); + } catch (error) { + console.error("Error sending like to LLM:", error); + } + + let uri; + try { + // Assuming retrievenext() is an asynchronous function + uri = await retrievenext(); + } catch (error) { + console.error("Error retrieving next song from LLM:", error); + } + + try { + // Assuming nextsong(uri) is an asynchronous function + await nextsong(uri); + } catch (error) { + console.error("Error playing next song:", error); + } - - return "Disliked Song"; } -function handleSkip(){ - //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: false, skipped: false, song: this.song }); +async function handleSkip() { + try { + // Assuming send() is an asynchronous function + await send("skipped"); + } catch (error) { + console.error("Error sending like to LLM:", error); + } + + let uri; + try { + // Assuming retrievenext() is an asynchronous function + uri = await retrievenext(); + } catch (error) { + console.error("Error retrieving next song from LLM:", error); + } + + try { + // Assuming nextsong(uri) is an asynchronous function + await nextsong(uri); + } catch (error) { + console.error("Error playing next song:", error); + } - return "Skip Song"; } function handlePlaySong(){ + nextsong(trackUri); return } // The main custom app render function. The component returned is what is rendered in Spotify. From 9e528d992f3fd837def97d49d9b0cca0119f6cc6 Mon Sep 17 00:00:00 2001 From: Augula33 Date: Tue, 26 Mar 2024 19:31:01 -0400 Subject: [PATCH 13/40] Added temporary song list as place holder for the retrieve uri function. Allows skip button to work --- spotify_app/index.js | 170 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 158 insertions(+), 12 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 5565c91..73931d1 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -1,4 +1,5 @@ // Grab any variables you need + const react = Spicetify.React; const reactDOM = Spicetify.ReactDOM; const { @@ -11,6 +12,15 @@ const CONFIG = { activeTab: "Main", tabs: ["Main","Recent Songs"] }; +//should be used in the retrieve function +function ifItemIsTrack(uri) { + let uriObj = Spicetify.URI.fromString(uri[0]); + switch (uriObj.type) { + case Type.TRACK: + return true; + } + return false; +} // Top Bar Content component const TopBarContent = (props) => { @@ -44,13 +54,59 @@ const TopBarContent = (props) => { ); }; +//Get playlist ID by copying link to playlist, for example +//https://open.spotify.com/playlist/37i9dQZF1DWXRqgorJj26U?si=9f6A6U2jTk-njyZJ64rk3g ID would be 37i9dQZF1DWXRqgorJj26U +const playlistId = "2it9p5n9Eit7iGVy1djNP0"; +async function retrieve(playlistId) { + try { + // Get the playlist using Spicetify wrapper + const playlist = await Spicetify.Playlist.get(playlistId); + + // Extract songs from the playlist + const songs = playlist.data.items.map(item => ({ + name: item.track.name, + artist: item.track.artists.map(artist => artist.name).join(', '), // Concatenate artist names if there are multiple + duration: item.track.duration_ms, // You can extract other song details as needed + })); + + // Sort songs in ascending order by name + songs.sort((a, b) => a.name.localeCompare(b.name)); + + // Return the sorted songs + return songs; + } catch (error) { + console.error("Error retrieving songs:", error); + return []; // Return an empty array if there's an error + } +} + + + +async function retrievenext() { + const popSongs = [ + 'spotify:track:3GCL1PydwsLodcpv0Ll1ch', + 'spotify:track:1p80LdxRV74UKvL8gnD7ky', + 'spotify:track:273dCMFseLcVsoSWx59IoE', + ]; + const randomIndex = Math.floor(Math.random() * popSongs.length); + return popSongs[randomIndex]; + }; + + + +async function send(){ + /* + Uncreated function to send information of the song and information on wether it was liked/disliked/skipped. + */ + return true; +} /* const fetchTrack = async (uri) => { const res = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/tracks/${uri.split(':')[2]}`); return res.name; }; */ -function clearsong() { +async function clearsong() { return Spicetify.Platform.LocalStorageAPI.clearItem(this.songname) .then(() => true) // Resolves to true if the item is successfully cleared .catch(() => false); // Resolves to false if there's an error while clearing the item @@ -65,21 +121,91 @@ clearsong() } }); */ -function handleLike(){ - //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: true, skipped: false, song: this.song}); - return "Liked Song"; +async function nextsong(uri){ + Spicetify.Player.playUri(uri); + +} + +// Example usage: +const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; +// +async function handleLike() { + try { + // Assuming send() is an asynchronous function + await send("liked"); + } catch (error) { + console.error("Error sending like to LLM:", error); + } + + let uri; + try { + // Assuming retrievenext() is an asynchronous function + uri = await retrievenext(); + } catch (error) { + console.error("Error retrieving next song from LLM:", error); + } + + try { + // Assuming nextsong(uri) is an asynchronous function + await nextsong(uri); + } catch (error) { + console.error("Error playing next song:", error); + } + } -function handleDislike(){ - //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: false, skipped: false,song: this.song }); - - return "Disliked Song"; +async function handleDislike() { + try { + // Assuming send() is an asynchronous function + await send("disliked"); + } catch (error) { + console.error("Error sending like to LLM:", error); + } + + let uri; + try { + // Assuming retrievenext() is an asynchronous function + uri = await retrievenext(); + } catch (error) { + console.error("Error retrieving next song from LLM:", error); + } + + try { + // Assuming nextsong(uri) is an asynchronous function + await nextsong(uri); + } catch (error) { + console.error("Error playing next song:", error); + } + } -function handleSkip(){ - //Spicetify.Platform.LocalStorageAPI.setItem(this.songname, { liked: false, skipped: false, song: this.song }); +async function handleSkip() { + try { + // Assuming send() is an asynchronous function + await send("skipped"); + } catch (error) { + console.error("Error sending like to LLM:", error); + } - return "Skip Song"; + let uri; + try { + // Assuming retrievenext() is an asynchronous function + uri = await retrievenext(); + } catch (error) { + console.error("Error retrieving next song from LLM:", error); + } + + try { + // Assuming nextsong(uri) is an asynchronous function + await nextsong(uri); + } catch (error) { + console.error("Error playing next song:", error); + } + +} +function handlePlaySong(){ + nextsong(trackUri); + return } // The main custom app render function. The component returned is what is rendered in Spotify. function render() { @@ -87,6 +213,7 @@ function render() { } + // Our main component class Grid extends react.Component { constructor(props) { @@ -128,6 +255,25 @@ class Grid extends react.Component { paddingBottom: "40px" }, }, + react.createElement("div", { + style: { + display: "flex", + justifyContent: "space-around", // This will evenly distribute the buttons + + }, + }, + react.createElement("button", { + onClick: handlePlaySong, + style: { + backgroundColor: "orange", // Change the background color of the button + color: "white", // Change the text color of the button + border: "none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius: "5px", // Add border radius + marginBottom: "30px" // Add margin to separate from the buttons below + } + }, "Play Song"), + ), react.createElement("div", { style: { display: "flex", @@ -172,4 +318,4 @@ class Grid extends react.Component { }) ); } -} +} \ No newline at end of file From 07c5bb9902ad762bfab2ca6ae8a8158ff1750022 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:05:10 -0400 Subject: [PATCH 14/40] Cleanup/Removal cleaned up functions and removed unnecessary functions/parts of functions that aren't used anymore. --- spotify_app/index.js | 102 ++----------------------------------------- 1 file changed, 4 insertions(+), 98 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index a134424..cb8eb98 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -12,15 +12,6 @@ const CONFIG = { activeTab: "Main", tabs: ["Main","Recent Songs"] }; -//should be used in the retrieve function -function ifItemIsTrack(uri) { - let uriObj = Spicetify.URI.fromString(uri[0]); - switch (uriObj.type) { - case Type.TRACK: - return true; - } - return false; -} // Top Bar Content component const TopBarContent = (props) => { @@ -54,31 +45,6 @@ const TopBarContent = (props) => { ); }; -//Get playlist ID by copying link to playlist, for example -//https://open.spotify.com/playlist/37i9dQZF1DWXRqgorJj26U?si=9f6A6U2jTk-njyZJ64rk3g ID would be 37i9dQZF1DWXRqgorJj26U -const playlistId = "2it9p5n9Eit7iGVy1djNP0"; -async function retrieve(playlistId) { - try { - // Get the playlist using Spicetify wrapper - const playlist = await Spicetify.Playlist.get(playlistId); - - // Extract songs from the playlist - const songs = playlist.data.items.map(item => ({ - name: item.track.name, - artist: item.track.artists.map(artist => artist.name).join(', '), // Concatenate artist names if there are multiple - duration: item.track.duration_ms, // You can extract other song details as needed - })); - - // Sort songs in ascending order by name - songs.sort((a, b) => a.name.localeCompare(b.name)); - - // Return the sorted songs - return songs; - } catch (error) { - console.error("Error retrieving songs:", error); - return []; // Return an empty array if there's an error - } -} async function retrievenext() { const popSongs = [ @@ -98,11 +64,6 @@ async function send(){ return true; } /* -const fetchTrack = async (uri) => { - const res = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/tracks/${uri.split(':')[2]}`); - return res.name; -}; -*/ async function clearsong() { return Spicetify.Platform.LocalStorageAPI.clearItem(this.songname) .then(() => true) // Resolves to true if the item is successfully cleared @@ -121,7 +82,6 @@ clearsong() async function nextsong(uri){ Spicetify.Player.playUri(uri); - } // Example usage: @@ -135,21 +95,6 @@ async function handleLike() { console.error("Error sending like to LLM:", error); } - let uri; - try { - // Assuming retrievenext() is an asynchronous function - uri = await retrievenext(); - } catch (error) { - console.error("Error retrieving next song from LLM:", error); - } - - try { - // Assuming nextsong(uri) is an asynchronous function - await nextsong(uri); - } catch (error) { - console.error("Error playing next song:", error); - } - } async function handleDislike() { @@ -160,23 +105,8 @@ async function handleDislike() { console.error("Error sending like to LLM:", error); } - let uri; - try { - // Assuming retrievenext() is an asynchronous function - uri = await retrievenext(); - } catch (error) { - console.error("Error retrieving next song from LLM:", error); - } - - try { - // Assuming nextsong(uri) is an asynchronous function - await nextsong(uri); - } catch (error) { - console.error("Error playing next song:", error); - } - } -async function handleSkip() { +async function handlePlayNext() { try { // Assuming send() is an asynchronous function await send("skipped"); @@ -198,11 +128,6 @@ async function handleSkip() { } catch (error) { console.error("Error playing next song:", error); } - -} -function handlePlaySong(){ - nextsong(trackUri); - return } // The main custom app render function. The component returned is what is rendered in Spotify. function render() { @@ -252,25 +177,6 @@ class Grid extends react.Component { paddingBottom: "40px" }, }, - react.createElement("div", { - style: { - display: "flex", - justifyContent: "space-around", // This will evenly distribute the buttons - - }, - }, - react.createElement("button", { - onClick: handlePlaySong, - style: { - backgroundColor: "orange", // Change the background color of the button - color: "white", // Change the text color of the button - border: "none", // Remove the border - padding: "10px 20px", // Add padding - borderRadius: "5px", // Add border radius - marginBottom: "30px" // Add margin to separate from the buttons below - } - }, "Play Song"), - ), react.createElement("div", { style: { display: "flex", @@ -290,7 +196,7 @@ class Grid extends react.Component { } }, "Dislike"), react.createElement("button", { - onClick: handleSkip, + onClick: handlePlayNext, style: { backgroundColor: "blue", // Change the background color of the button color: "white", // Change the text color of the button @@ -298,7 +204,7 @@ class Grid extends react.Component { padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } - }, "Skip"), + }, "Play Next"), react.createElement("button", { onClick: handleLike, style: { @@ -315,4 +221,4 @@ class Grid extends react.Component { }) ); } -} \ No newline at end of file +} From a18d3ea120deda354983e082bcea0427a7ed0074 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Fri, 29 Mar 2024 20:21:54 -0400 Subject: [PATCH 15/40] Add songs to playlist when user clicks the like button. Added funtionality to the like button which creates a playlist and adds songs to said playlist as the user likes different songs. Currently the user can add a song mutiple times which needs to be changed in the future. --- spotify_app/index.js | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/spotify_app/index.js b/spotify_app/index.js index cb8eb98..ee55f5f 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -3,6 +3,7 @@ const react = Spicetify.React; const reactDOM = Spicetify.ReactDOM; const { + CosmosAsync, URI, React: { useState, useEffect, useCallback }, Platform: { History }, @@ -46,6 +47,7 @@ const TopBarContent = (props) => { }; + async function retrievenext() { const popSongs = [ 'spotify:track:3GCL1PydwsLodcpv0Ll1ch', @@ -56,6 +58,29 @@ async function retrievenext() { return popSongs[randomIndex]; }; +const currenturi = []; +let playlistinfo = ''; +let playlistCreated = false; + +async function createPlaylist(){ + const user = await CosmosAsync.get('https://api.spotify.com/v1/me'); + playlistinfo = CosmosAsync.post('https://api.spotify.com/v1/users/' + user.id + '/playlists', { + name: 'SpotifyPlus Playlist' + }); + return playlistinfo; +} + + + +async function addtoplaylist(playlistinfo) { + const playlisturi = playlistinfo.uri.split(":")[2] + CosmosAsync.post('https://api.spotify.com/v1/playlists/' + playlisturi + '/tracks', { + uris: currenturi + }); + //createPlaylist(); + return true; +} + async function send(){ /* @@ -87,6 +112,7 @@ async function nextsong(uri){ // Example usage: const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; // +let tempplaylist = ''; async function handleLike() { try { // Assuming send() is an asynchronous function @@ -94,6 +120,23 @@ async function handleLike() { } catch (error) { console.error("Error sending like to LLM:", error); } + if (!playlistCreated){ + try { + playlistCreated = true + tempplaylist = await createPlaylist(); + await addtoplaylist(tempplaylist); + } catch (error) { + console.error("Error creating playlist:", error); + } + } + else { + try { + await addtoplaylist(tempplaylist); + } catch (error) { + console.error("Error adding song to playlist:", error); + } + } + } @@ -118,6 +161,8 @@ async function handlePlayNext() { try { // Assuming retrievenext() is an asynchronous function uri = await retrievenext(); + currenturi.length = 0; + currenturi.push(uri); } catch (error) { console.error("Error retrieving next song from LLM:", error); } From 2e9deb4b9941e26d8e2fd1edba5376f14c577f57 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:38:47 -0400 Subject: [PATCH 16/40] Not yet working Storage Partially implemented storage. --- spotify_app/index.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index ee55f5f..dfc63ee 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -8,6 +8,7 @@ const { React: { useState, useEffect, useCallback }, Platform: { History }, } = Spicetify; +//const [mysongs, setMysongs] = useState([]); const CONFIG = { activeTab: "Main", @@ -82,11 +83,13 @@ async function addtoplaylist(playlistinfo) { } -async function send(){ +async function send(liked, uri){ + return true; /* - Uncreated function to send information of the song and information on wether it was liked/disliked/skipped. + const songs = Spicetify.Platform.LocalStorageAPI.getItem(liked); + setMysongs([...songs, newSong]); // Use spread operator to create a new array with the added song + Spicetify.Platform.LocalStorageAPI.setItem(liked,songs); */ - return true; } /* async function clearsong() { @@ -124,14 +127,11 @@ async function handleLike() { try { playlistCreated = true tempplaylist = await createPlaylist(); - await addtoplaylist(tempplaylist); } catch (error) { console.error("Error creating playlist:", error); } - } - else { - try { - await addtoplaylist(tempplaylist); + try { + await addtoplaylist(tempplaylist); } catch (error) { console.error("Error adding song to playlist:", error); } @@ -150,12 +150,6 @@ async function handleDislike() { } async function handlePlayNext() { - try { - // Assuming send() is an asynchronous function - await send("skipped"); - } catch (error) { - console.error("Error sending like to LLM:", error); - } let uri; try { @@ -213,8 +207,9 @@ class Grid extends react.Component { react.createElement("footer", { style: { margin: "auto", - bottom: 0, - left: 0, + bottom: 70, + left: 150, + right:200, position: "fixed", textAlign: "center", width: "100%", // Ensure the footer spans the full width @@ -222,7 +217,7 @@ class Grid extends react.Component { paddingBottom: "40px" }, }, - react.createElement("div", { + react.createElement("div", { style: { display: "flex", justifyContent: "space-around", // This will evenly distribute the buttons @@ -249,7 +244,7 @@ class Grid extends react.Component { padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } - }, "Play Next"), + }, "Next Song"), react.createElement("button", { onClick: handleLike, style: { From b74b84b15fad8602f4764a464cb506a38a734058 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:54:03 -0400 Subject: [PATCH 17/40] Update index.js Created a create playlist button, changed like button to add liked songs to an internal list which create playlist makes a playlist off of. --- spotify_app/index.js | 78 ++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index dfc63ee..e329bd2 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -8,7 +8,6 @@ const { React: { useState, useEffect, useCallback }, Platform: { History }, } = Spicetify; -//const [mysongs, setMysongs] = useState([]); const CONFIG = { activeTab: "Main", @@ -76,12 +75,17 @@ async function createPlaylist(){ async function addtoplaylist(playlistinfo) { const playlisturi = playlistinfo.uri.split(":")[2] CosmosAsync.post('https://api.spotify.com/v1/playlists/' + playlisturi + '/tracks', { - uris: currenturi + uris: likedlist }); //createPlaylist(); return true; } +const likedlist = []; +async function addSongToLiked(song){ + likedlist.push(song); +} + async function send(liked, uri){ return true; @@ -116,6 +120,7 @@ async function nextsong(uri){ const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; // let tempplaylist = ''; +let uri = ''; async function handleLike() { try { // Assuming send() is an asynchronous function @@ -123,18 +128,10 @@ async function handleLike() { } catch (error) { console.error("Error sending like to LLM:", error); } - if (!playlistCreated){ - try { - playlistCreated = true - tempplaylist = await createPlaylist(); - } catch (error) { - console.error("Error creating playlist:", error); - } - try { - await addtoplaylist(tempplaylist); + try{ + addSongToLiked(uri); } catch (error) { - console.error("Error adding song to playlist:", error); - } + console.error("Error adding song to liked songs:", error); } @@ -150,8 +147,13 @@ async function handleDislike() { } async function handlePlayNext() { + try { + // Assuming send() is an asynchronous function + await send("skipped"); + } catch (error) { + console.error("Error sending like to LLM:", error); + } - let uri; try { // Assuming retrievenext() is an asynchronous function uri = await retrievenext(); @@ -168,6 +170,31 @@ async function handlePlayNext() { console.error("Error playing next song:", error); } } +async function handleCreatePlaylist() { + try { + // Assuming send() is an asynchronous function + await send("playlist created"); + } catch (error) { + console.error("Error sending playlist state to LLM:", error); + } + + if (!playlistCreated){ + try { + playlistCreated = true + tempplaylist = await createPlaylist(); + await addtoplaylist(tempplaylist); + } catch (error) { + console.error("Error creating playlist:", error); + } + } + else { + try { + await addtoplaylist(tempplaylist); + } catch (error) { + console.error("Error adding song to playlist:", error); + } + } +} // The main custom app render function. The component returned is what is rendered in Spotify. function render() { return react.createElement(Grid, { title: "SpotifyPlus" }); @@ -203,13 +230,24 @@ class Grid extends react.Component { justifyContent: "space-between", // This will evenly distribute the items flexWrap: "wrap", // Allow items to wrap to the next line if needed }, - }), + }, + react.createElement("button", { + //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters + onClick: handleCreatePlaylist, + style: { + backgroundColor: "purple", // Change the background color of the button + color: "white", // Change the text color of the button + border: "none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius: "5px", // Add border radius + } + }, "Create Playlist"), + ), react.createElement("footer", { style: { margin: "auto", - bottom: 70, - left: 150, - right:200, + bottom: 0, + left: 0, position: "fixed", textAlign: "center", width: "100%", // Ensure the footer spans the full width @@ -217,7 +255,7 @@ class Grid extends react.Component { paddingBottom: "40px" }, }, - react.createElement("div", { + react.createElement("div", { style: { display: "flex", justifyContent: "space-around", // This will evenly distribute the buttons @@ -244,7 +282,7 @@ class Grid extends react.Component { padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } - }, "Next Song"), + }, "Play Next"), react.createElement("button", { onClick: handleLike, style: { From e8badff9a14956ee39e9234bdefe82fe601d1374 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:05:01 -0400 Subject: [PATCH 18/40] Button placement Small fix to edit button placement. --- spotify_app/index.js | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index e329bd2..8c870f4 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -199,10 +199,6 @@ async function handleCreatePlaylist() { function render() { return react.createElement(Grid, { title: "SpotifyPlus" }); } - - - -// Our main component class Grid extends react.Component { constructor(props) { super(props); @@ -230,24 +226,13 @@ class Grid extends react.Component { justifyContent: "space-between", // This will evenly distribute the items flexWrap: "wrap", // Allow items to wrap to the next line if needed }, - }, - react.createElement("button", { - //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters - onClick: handleCreatePlaylist, - style: { - backgroundColor: "purple", // Change the background color of the button - color: "white", // Change the text color of the button - border: "none", // Remove the border - padding: "10px 20px", // Add padding - borderRadius: "5px", // Add border radius - } - }, "Create Playlist"), - ), + }), react.createElement("footer", { style: { margin: "auto", - bottom: 0, - left: 0, + bottom: 70, + left: 150, + right:200, position: "fixed", textAlign: "center", width: "100%", // Ensure the footer spans the full width @@ -255,7 +240,7 @@ class Grid extends react.Component { paddingBottom: "40px" }, }, - react.createElement("div", { + react.createElement("div", { style: { display: "flex", justifyContent: "space-around", // This will evenly distribute the buttons @@ -282,7 +267,7 @@ class Grid extends react.Component { padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } - }, "Play Next"), + }, "Next Song"), react.createElement("button", { onClick: handleLike, style: { From 9cc5921ed9dd1e6724cb314c60605ffd1ff880e9 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:22:49 -0400 Subject: [PATCH 19/40] Users can no longer add duplicate songs, fixed button placement for new button. --- spotify_app/index.js | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 8c870f4..b728d44 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -83,7 +83,10 @@ async function addtoplaylist(playlistinfo) { const likedlist = []; async function addSongToLiked(song){ - likedlist.push(song); + if(!likedlist.includes(song)){ + likedlist.push(song); + } + } @@ -199,6 +202,10 @@ async function handleCreatePlaylist() { function render() { return react.createElement(Grid, { title: "SpotifyPlus" }); } + + + +// Our main component class Grid extends react.Component { constructor(props) { super(props); @@ -226,21 +233,24 @@ class Grid extends react.Component { justifyContent: "space-between", // This will evenly distribute the items flexWrap: "wrap", // Allow items to wrap to the next line if needed }, - }), + }, + + ), react.createElement("footer", { style: { margin: "auto", - bottom: 70, - left: 150, + bottom: 0, + left: 420, right:200, position: "fixed", textAlign: "center", - width: "100%", // Ensure the footer spans the full width + width: "80%", // Ensure the footer spans the full width paddingTop: "20px", // Add padding at the top for spacing - paddingBottom: "40px" + paddingBottom: "150px" + }, }, - react.createElement("div", { + react.createElement("div", { style: { display: "flex", justifyContent: "space-around", // This will evenly distribute the buttons @@ -267,7 +277,7 @@ class Grid extends react.Component { padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } - }, "Next Song"), + }, "Play Next"), react.createElement("button", { onClick: handleLike, style: { @@ -277,7 +287,21 @@ class Grid extends react.Component { padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } - }, "Like"),)), + }, "Like"), + react.createElement("button", { + //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters + onClick: handleCreatePlaylist, + style: { + backgroundColor: "purple", // Change the background color of the button + color: "white", // Change the text color of the button + border: "none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius: "5px", // Add border radius + } + }, "Create Playlist"), + + + )), react.createElement(TopBarContent, { links: CONFIG.tabs, activeLink: CONFIG.activeTab, From ef0bdd5bc5ef852f0a8088a6564352e5c7bd77ed Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:23:42 -0400 Subject: [PATCH 20/40] Storage update to index 1/2 working storage update to Spicetify app. Can save information to the local storage and retrieve it, but have not implemented method to save the correct information. --- spotify_app/index.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index b728d44..92706ab 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -91,12 +91,27 @@ async function addSongToLiked(song){ async function send(liked, uri){ - return true; - /* - const songs = Spicetify.Platform.LocalStorageAPI.getItem(liked); - setMysongs([...songs, newSong]); // Use spread operator to create a new array with the added song - Spicetify.Platform.LocalStorageAPI.setItem(liked,songs); - */ + try { + // Retrieve the value from local storage + let songs = Spicetify.Platform.LocalStorageAPI.getItem(liked); + + // Check if the retrieved value is null or undefined + if (songs !== null && songs !== undefined) { + songs += uri; // Example of concatenating a string + // The key exists in local storage + console.log("The 'liked' key exists in local storage."); + } else { + songs = uri; // Example of concatenating a string + // The key exists in local storage but its value is null or undefined + console.log("The 'liked' key exists in local storage but its value is null or undefined."); + } + } catch (error) { + // Handle the error if the key is not found in local storage + console.error("Error:", error); + console.log("The 'liked' key is not found in local storage."); + } + // Add something to the string + Spicetify.Platform.LocalStorageAPI.setItem(liked, songs); } /* async function clearsong() { @@ -125,6 +140,8 @@ const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; let tempplaylist = ''; let uri = ''; async function handleLike() { + + try { // Assuming send() is an asynchronous function await send("liked"); From 1ac1a61d382998ff0046bcdbabde60e2cf0fb8f4 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Fri, 12 Apr 2024 17:23:27 -0400 Subject: [PATCH 21/40] Added function to display album cover. Buggy --- spotify_app/index.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spotify_app/index.js b/spotify_app/index.js index 92706ab..d3d9bab 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -47,6 +47,12 @@ const TopBarContent = (props) => { }; +let albumurl = ''; + +async function setAlbumUrl(id){ + let trackdata = CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); + albumurl = trackdata.images[0].url; +} async function retrievenext() { const popSongs = [ @@ -55,6 +61,7 @@ async function retrievenext() { 'spotify:track:273dCMFseLcVsoSWx59IoE', ]; const randomIndex = Math.floor(Math.random() * popSongs.length); + setAlbumUrl(popSongs[randomIndex].split(":")[2]); return popSongs[randomIndex]; }; @@ -90,6 +97,8 @@ async function addSongToLiked(song){ } + + async function send(liked, uri){ try { // Retrieve the value from local storage @@ -251,6 +260,14 @@ class Grid extends react.Component { flexWrap: "wrap", // Allow items to wrap to the next line if needed }, }, + react.createElement("img", { + src: albumurl, + alt: "Album cover could not be displayed", + style: { + maxWidth: "100%", // Ensure the image fits within the container + maxHeight: "100%", + } + }), ), react.createElement("footer", { From 7aa7cc85a4ba006ccfce98fd6a3363beffd2a9a8 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Fri, 12 Apr 2024 19:59:28 -0400 Subject: [PATCH 22/40] Working Storage Working storage created using Spotify Local Storage API. calls to storage include getItem(), setItem(), and clearItem(). Send function has been created and stores items in a method. So when calling getItem() will return an array of strings, with every string being a URI. --- spotify_app/index.js | 76 ++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 41 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index d3d9bab..e43c295 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -47,12 +47,6 @@ const TopBarContent = (props) => { }; -let albumurl = ''; - -async function setAlbumUrl(id){ - let trackdata = CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); - albumurl = trackdata.images[0].url; -} async function retrievenext() { const popSongs = [ @@ -61,7 +55,6 @@ async function retrievenext() { 'spotify:track:273dCMFseLcVsoSWx59IoE', ]; const randomIndex = Math.floor(Math.random() * popSongs.length); - setAlbumUrl(popSongs[randomIndex].split(":")[2]); return popSongs[randomIndex]; }; @@ -97,31 +90,34 @@ async function addSongToLiked(song){ } - - -async function send(liked, uri){ +function send(liked, auri) { try { + console.log("Retrieving items from local storage:", Spicetify.Platform.LocalStorageAPI.items); + // Retrieve the value from local storage let songs = Spicetify.Platform.LocalStorageAPI.getItem(liked); - - // Check if the retrieved value is null or undefined - if (songs !== null && songs !== undefined) { - songs += uri; // Example of concatenating a string - // The key exists in local storage - console.log("The 'liked' key exists in local storage."); + + // Check if songs is undefined or not an array + if (songs === undefined || !Array.isArray(songs)) { + songs = [auri]; } else { - songs = uri; // Example of concatenating a string - // The key exists in local storage but its value is null or undefined - console.log("The 'liked' key exists in local storage but its value is null or undefined."); + if (!songs.includes(auri)){ + songs.push(auri); + } } + + // Store the updated value in local storage + Spicetify.Platform.LocalStorageAPI.setItem(liked, songs); } catch (error) { - // Handle the error if the key is not found in local storage + // Handle the error if any console.error("Error:", error); - console.log("The 'liked' key is not found in local storage."); + console.log("Failed to update local storage for 'liked' key."); } - // Add something to the string - Spicetify.Platform.LocalStorageAPI.setItem(liked, songs); -} +} + + + + /* async function clearsong() { return Spicetify.Platform.LocalStorageAPI.clearItem(this.songname) @@ -139,6 +135,12 @@ clearsong() }); */ +let albumurl = ''; + +async function setAlbumUrl(id){ + let trackdata = CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); + albumurl = trackdata.images[0].url; +} async function nextsong(uri){ Spicetify.Player.playUri(uri); } @@ -153,7 +155,7 @@ async function handleLike() { try { // Assuming send() is an asynchronous function - await send("liked"); + await send("liked",uri); } catch (error) { console.error("Error sending like to LLM:", error); } @@ -169,20 +171,13 @@ async function handleLike() { async function handleDislike() { try { // Assuming send() is an asynchronous function - await send("disliked"); + await send("disliked",uri); } catch (error) { console.error("Error sending like to LLM:", error); } } async function handlePlayNext() { - try { - // Assuming send() is an asynchronous function - await send("skipped"); - } catch (error) { - console.error("Error sending like to LLM:", error); - } - try { // Assuming retrievenext() is an asynchronous function uri = await retrievenext(); @@ -261,14 +256,13 @@ class Grid extends react.Component { }, }, react.createElement("img", { - src: albumurl, - alt: "Album cover could not be displayed", - style: { - maxWidth: "100%", // Ensure the image fits within the container - maxHeight: "100%", - } - }), - + src: albumurl, + alt: "Album cover could not be displayed", + style: { + maxWidth: "100%", // Ensure the image fits within the container + maxHeight: "100%", + } + }), ), react.createElement("footer", { style: { From 0c888ed3e596e410b9794467bf494a95bddd000e Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:29:37 -0400 Subject: [PATCH 23/40] Issue fixed, Deleted Recent Tab Since the beginning of the project, we had to create a minimum of two tabs in the Top Bar for it to function properly, but the second tab was simply irrelevant to the project, and was unused. Therefore, I changed the tabs in topBarContent and removed the map created of the links, changing the
creation as well. This fixed the problem. --- spotify_app/index.js | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index e43c295..fceb225 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -24,24 +24,22 @@ const TopBarContent = (props) => { gap: "100px", // Adjust the spacing between tabs } }, - props.links.map((link) => - react.createElement("div", { - key: link, + react.createElement("div", { + key: "Main", + style: { + position: "relative", + } + }, + react.createElement("a", { + className: 'active', style: { - position: "relative", + padding: "10px 20px", // Adjust the padding of the tabs + borderRadius: "20px", // Add border radius to create rounded edges + border: "1px solid white", // Add border with white color + color: "white", // Set text color + textDecoration: "none", // Remove underline } - }, - react.createElement("a", { - className: link === props.activeLink ? 'active' : '', - style: { - padding: "10px 20px", // Adjust the padding of the tabs - borderRadius: "20px", // Add border radius to create rounded edges - border: "1px solid white", // Add border with white color - color: "white", // Set text color - textDecoration: "none", // Remove underline - } - }, link), - ) + }, "Main"), ) ); }; @@ -142,6 +140,7 @@ async function setAlbumUrl(id){ albumurl = trackdata.images[0].url; } async function nextsong(uri){ + Spicetify.Player.playUri(uri); } @@ -331,7 +330,6 @@ class Grid extends react.Component { )), react.createElement(TopBarContent, { - links: CONFIG.tabs, activeLink: CONFIG.activeTab, }) ); From 5755171177def410f232c200a6a1b68c727733be Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Mon, 15 Apr 2024 18:39:34 -0400 Subject: [PATCH 24/40] fixed spacing issues and added Image Fixed spacing issues that were created based on newest spotify update, changing the formatting and pixel offset of the footer element. I also created an image that sits in the center of the page, adding an interesting touch. Eventually, I will implement the image changing with album change. --- spotify_app/index.js | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index fceb225..a2ce78e 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -236,6 +236,7 @@ class Grid extends react.Component { }; } + render() { return react.createElement("section", { className: "contentSpacing", @@ -245,35 +246,32 @@ class Grid extends react.Component { }, react.createElement("h1", null, this.props.title), ), react.createElement("div", { - id: "marketplace-grid", - className: "main-gridContainer-gridContainer", - "data-tab": CONFIG.activeTab, style: { display: "flex", - justifyContent: "space-between", // This will evenly distribute the items - flexWrap: "wrap", // Allow items to wrap to the next line if needed - }, + justifyContent: "center", + alignItems: "center", + transform: "scale(2) translateY(20%)", // Scale the image to make it 4 times bigger + transformOrigin: "center top", // Set the transform origin to the center top + } }, react.createElement("img", { - src: albumurl, + src: "https://upload.wikimedia.org/wikipedia/en/thumb/7/70/Graduation_%28album%29.jpg/220px-Graduation_%28album%29.jpg", alt: "Album cover could not be displayed", style: { - maxWidth: "100%", // Ensure the image fits within the container + maxWidth: "100%", maxHeight: "100%", } - }), - ), + })), + react.createElement("footer", { style: { margin: "auto", - bottom: 0, - left: 420, - right:200, position: "fixed", textAlign: "center", + bottom: 120, width: "80%", // Ensure the footer spans the full width paddingTop: "20px", // Add padding at the top for spacing - paddingBottom: "150px" + paddingBottom: "20px" }, }, @@ -329,9 +327,6 @@ class Grid extends react.Component { )), - react.createElement(TopBarContent, { - activeLink: CONFIG.activeTab, - }) ); } } From 087a21990578743db3f68051014d5b33f3218fe2 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:26:16 -0400 Subject: [PATCH 25/40] Almost working image generation Image generation almost completed, just need to adjust HandleImageGen to be in scope. --- spotify_app/index.js | 50 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index a2ce78e..39f266d 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -133,11 +133,18 @@ clearsong() }); */ -let albumurl = ''; - -async function setAlbumUrl(id){ - let trackdata = CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); - albumurl = trackdata.images[0].url; +async function setAlbumUrl(uri){ + let id = uri.split(':')[2]; // Extract the ID from the URI + try { + const response = await CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); + const data = await response; // Assuming response.json() returns a promise + // Access the data fetched from the Spotify API here + const albumurl = data.album.images[0].url; + return albumurl; + } catch (error) { + // Handle any errors that occurred during the request + console.error('Img retrieval Error:', error); + } } async function nextsong(uri){ @@ -179,18 +186,17 @@ async function handleDislike() { async function handlePlayNext() { try { // Assuming retrievenext() is an asynchronous function - uri = await retrievenext(); + const uri = await retrievenext(); currenturi.length = 0; currenturi.push(uri); - } catch (error) { - console.error("Error retrieving next song from LLM:", error); - } - try { - // Assuming nextsong(uri) is an asynchronous function - await nextsong(uri); + // Call setAlbumUrl to get the album URL asynchronously + const albumurl = await setAlbumUrl(uri); + + // Call handleChangeImage with the obtained album URL + handleChangeImage(albumurl); } catch (error) { - console.error("Error playing next song:", error); + console.error("Error handling next song:", error); } } async function handleCreatePlaylist() { @@ -220,7 +226,7 @@ async function handleCreatePlaylist() { } // The main custom app render function. The component returned is what is rendered in Spotify. function render() { - return react.createElement(Grid, { title: "SpotifyPlus" }); + return react.createElement(Grid, { title: "SpotifyPlus", image: "" }); } @@ -235,7 +241,13 @@ class Grid extends react.Component { data: "etc" }; } - + handleChangeImage = (url) => { + // Change the image URL to trigger a re-render + this.setState({ + image: url + }); + }; + render() { return react.createElement("section", { @@ -255,11 +267,11 @@ class Grid extends react.Component { } }, react.createElement("img", { - src: "https://upload.wikimedia.org/wikipedia/en/thumb/7/70/Graduation_%28album%29.jpg/220px-Graduation_%28album%29.jpg", + src: this.props.image, alt: "Album cover could not be displayed", style: { - maxWidth: "100%", - maxHeight: "100%", + maxWidth: 315, + maxHeight: 220, } })), @@ -304,7 +316,7 @@ class Grid extends react.Component { } }, "Play Next"), react.createElement("button", { - onClick: handleLike, + onClick: handlePlayNext, style: { backgroundColor: "green", // Change the background color of the button color: "white", // Change the text color of the button From 395fc58a4575816253b989194fdad76085a021fa Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:17:57 -0400 Subject: [PATCH 26/40] Fully working Image Generation Working image generation that generates the album logo of the currently playing song and presents it in the middle of the page. --- spotify_app/index.js | 48 ++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 39f266d..83f3213 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -157,8 +157,6 @@ const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; let tempplaylist = ''; let uri = ''; async function handleLike() { - - try { // Assuming send() is an asynchronous function await send("liked",uri); @@ -183,22 +181,7 @@ async function handleDislike() { } } -async function handlePlayNext() { - try { - // Assuming retrievenext() is an asynchronous function - const uri = await retrievenext(); - currenturi.length = 0; - currenturi.push(uri); - - // Call setAlbumUrl to get the album URL asynchronously - const albumurl = await setAlbumUrl(uri); - // Call handleChangeImage with the obtained album URL - handleChangeImage(albumurl); - } catch (error) { - console.error("Error handling next song:", error); - } -} async function handleCreatePlaylist() { try { // Assuming send() is an asynchronous function @@ -226,7 +209,7 @@ async function handleCreatePlaylist() { } // The main custom app render function. The component returned is what is rendered in Spotify. function render() { - return react.createElement(Grid, { title: "SpotifyPlus", image: "" }); + return react.createElement(Grid, { title: "SpotifyPlus" }); } @@ -238,16 +221,24 @@ class Grid extends react.Component { Object.assign(this, props); this.state = { foo: "bar", - data: "etc" + data: "etc", }; } - handleChangeImage = (url) => { - // Change the image URL to trigger a re-render - this.setState({ - image: url - }); - }; + handlePlayNext = async () => { + try { + // Assuming retrievenext() is an asynchronous function + const uri = await retrievenext(); + currenturi.length = 0; + currenturi.push(uri); + await nextsong(uri); + const imageUrl = await setAlbumUrl(uri); + this.setState({ image: imageUrl }); // Update the image state + + } catch (error) { + console.error("Error handling next song:", error); + } + } render() { return react.createElement("section", { @@ -267,8 +258,7 @@ class Grid extends react.Component { } }, react.createElement("img", { - src: this.props.image, - alt: "Album cover could not be displayed", + src: this.state.image, style: { maxWidth: 315, maxHeight: 220, @@ -306,7 +296,7 @@ class Grid extends react.Component { } }, "Dislike"), react.createElement("button", { - onClick: handlePlayNext, + onClick: this.handlePlayNext, style: { backgroundColor: "blue", // Change the background color of the button color: "white", // Change the text color of the button @@ -316,7 +306,7 @@ class Grid extends react.Component { } }, "Play Next"), react.createElement("button", { - onClick: handlePlayNext, + onClick: handleLike, style: { backgroundColor: "green", // Change the background color of the button color: "white", // Change the text color of the button From 5e082222aeb12a3051b5697de8861c0bb51f755a Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:33:48 -0400 Subject: [PATCH 27/40] Created function to find song uri from the song title and artist name --- spotify_app/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 83f3213..77d70bf 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -44,7 +44,12 @@ const TopBarContent = (props) => { ); }; +async function getUriFromSongAndArtist(song, artist){ + let trackinfo = await CosmosAsync.get('https://api.spotify.com/v1/search?q=' + artist + '%25' + song + '&type=track'); + let newuri = trackinfo.tracks.items[0].uri; + return newuri; +} async function retrievenext() { const popSongs = [ @@ -228,7 +233,11 @@ class Grid extends react.Component { handlePlayNext = async () => { try { // Assuming retrievenext() is an asynchronous function - const uri = await retrievenext(); + //const uri = await retrievenext(); + + //testing geturifromsongandartistfunction + const uri = await getUriFromSongAndArtist("Space+Cadet", "Gunna"); + currenturi.length = 0; currenturi.push(uri); await nextsong(uri); From e371347f5e73eb5e81f92180ced96ae16281fec1 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Tue, 23 Apr 2024 03:25:23 -0400 Subject: [PATCH 28/40] Updated functionality to better interact with users, onclick settings Updated functionality, editing button functions to allow for users to know when an Item is selected and clicked. --- spotify_app/index.js | 73 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 77d70bf..e82dd38 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -227,6 +227,16 @@ class Grid extends react.Component { this.state = { foo: "bar", data: "etc", + h1: false, + h2: false, + h3: false, + h4: false, + c1: false, + c2: false, + c3: false, + c4: false, + + }; } @@ -250,6 +260,8 @@ class Grid extends react.Component { } render() { + const {h1,h2,h3,h4,c1,c2,c3,c4 } = this.state; + return react.createElement("section", { className: "contentSpacing", }, @@ -274,6 +286,7 @@ class Grid extends react.Component { } })), + react.createElement("footer", { style: { margin: "auto", @@ -295,44 +308,76 @@ class Grid extends react.Component { }, react.createElement("button", { //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters - onClick: handleDislike, + onClick: () => { + handleDislike(); + this.setState({ c1: true }); + setTimeout(() => { + this.setState({ c1: false }); + }, 125); + }, + onMouseOver: () => this.setState({h1: true}), + onMouseOut: () => this.setState({h1: false}), style: { - backgroundColor: "red", // Change the background color of the button + backgroundColor: this.state.h1 ? "darkred" : "red", // Change the background color of the button color: "white", // Change the text color of the button - border: "none", // Remove the border + border: this.state.c1 ? "1px solid white":"none", // Remove the border padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } }, "Dislike"), react.createElement("button", { - onClick: this.handlePlayNext, + onClick: () => { + this.handlePlayNext(); + this.setState({ c2: true }); + setTimeout(() => { + this.setState({ c2: false }); + }, 125); + }, + onMouseOver: () => this.setState({h2: true}), + onMouseOut: () => this.setState({h2: false}), style: { - backgroundColor: "blue", // Change the background color of the button + backgroundColor: this.state.h2 ? "darkblue": "blue", // Change the background color of the button color: "white", // Change the text color of the button - border: "none", // Remove the border + border: this.state.c2 ? "1px solid white":"none", // Remove the border padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius } }, "Play Next"), react.createElement("button", { - onClick: handleLike, + onClick: () => { + handleLike(); + this.setState({ c3: true }); + setTimeout(() => { + this.setState({ c3: false }); + }, 125); + }, + onMouseOver: () => this.setState({h3: true}), + onMouseOut: () => this.setState({h3: false}), style: { - backgroundColor: "green", // Change the background color of the button + backgroundColor: this.state.h3 ? "darkgreen" : "green", // Change the background color of the button color: "white", // Change the text color of the button - border: "none", // Remove the border + border: this.state.c3 ? "1px solid white":"none", // Remove the border padding: "10px 20px", // Add padding - borderRadius: "5px", // Add border radius + borderRadius:"5px", // Add border radius } }, "Like"), react.createElement("button", { //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters - onClick: handleCreatePlaylist, + onClick: () => { + handleCreatePlaylist(); + this.setState({ c4: true }); + setTimeout(() => { + this.setState({ c4: false }); + }, 125); + }, + onMouseOver: () => this.setState({h4: true}), + onMouseOut: () => this.setState({h4: false}), style: { - backgroundColor: "purple", // Change the background color of the button + backgroundColor: this.state.h4 ? "purple": "#8a2be2", color: "white", // Change the text color of the button - border: "none", // Remove the border + border: this.state.c4 ? "1px solid white":"none", // Remove the border padding: "10px 20px", // Add padding - borderRadius: "5px", // Add border radius + borderRadius:"5px", // Add border radius } }, "Create Playlist"), From df2d40f1626be76bf25ce218a7c1daade0eb84f9 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Tue, 23 Apr 2024 03:57:36 -0400 Subject: [PATCH 29/40] added keyboard shortcuts Added keyboard shortcuts for liking, disliking, playing next, and creating a playlist CTRL+ALT+l = like CTRL+ALT+d = dislike CTRL+ALT+n = play next CTRL+ALT+p = create playlist --- spotify_app/index.js | 96 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index e82dd38..fb525c8 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -240,6 +240,57 @@ class Grid extends react.Component { }; } + componentDidMount() { + this.addKeyboardShortcutListener(); + } + + componentWillUnmount() { + this.removeKeyboardShortcutListener(); + } + + handleKeyDown = (event) => { + // Check if CTRL, ALT, and L are pressed + if (event.ctrlKey && event.altKey && event.key === 'p') { + // Find the button element by ID or other means + const button = document.getElementById('playlist'); + // If the button is found, trigger its click event + if (button) { + button.click(); + } + } + else if (event.ctrlKey && event.altKey && event.key === 'l') { + // Find the button element by ID or other means + const button = document.getElementById('like'); + // If the button is found, trigger its click event + if (button) { + button.click(); + } + } + else if (event.ctrlKey && event.altKey && event.key === 'd') { + // Find the button element by ID or other means + const button = document.getElementById('dislike'); + // If the button is found, trigger its click event + if (button) { + button.click(); + } + } + else if (event.ctrlKey && event.altKey && event.key === 'n') { + // Find the button element by ID or other means + const button = document.getElementById('play-next'); + // If the button is found, trigger its click event + if (button) { + button.click(); + } + } + }; + + addKeyboardShortcutListener() { + document.addEventListener('keydown', this.handleKeyDown); + } + + removeKeyboardShortcutListener() { + document.removeEventListener('keydown', this.handleKeyDown); + } handlePlayNext = async () => { try { // Assuming retrievenext() is an asynchronous function @@ -258,6 +309,7 @@ class Grid extends react.Component { console.error("Error handling next song:", error); } } + render() { const {h1,h2,h3,h4,c1,c2,c3,c4 } = this.state; @@ -268,6 +320,26 @@ class Grid extends react.Component { react.createElement("div", { className: "marketplace-header", }, react.createElement("h1", null, this.props.title), + react.createElement("button", { + //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters + onClick: () => { + handleCreatePlaylist(); + this.setState({ c4: true }); + setTimeout(() => { + this.setState({ c4: false }); + }, 125); + }, + onMouseOver: () => this.setState({h4: true}), + onMouseOut: () => this.setState({h4: false}), + id: "playlist", + style: { + backgroundColor: this.state.h4 ? "purple": "#8a2be2", + color: "white", // Change the text color of the button + border: this.state.c4 ? "1px solid white":"none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius:"5px", // Add border radius + } + }, "Create Playlist"), ), react.createElement("div", { style: { @@ -307,7 +379,6 @@ class Grid extends react.Component { }, }, react.createElement("button", { - //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters onClick: () => { handleDislike(); this.setState({ c1: true }); @@ -317,6 +388,7 @@ class Grid extends react.Component { }, onMouseOver: () => this.setState({h1: true}), onMouseOut: () => this.setState({h1: false}), + id: "dislike", style: { backgroundColor: this.state.h1 ? "darkred" : "red", // Change the background color of the button color: "white", // Change the text color of the button @@ -335,6 +407,7 @@ class Grid extends react.Component { }, onMouseOver: () => this.setState({h2: true}), onMouseOut: () => this.setState({h2: false}), + id: "play-next", style: { backgroundColor: this.state.h2 ? "darkblue": "blue", // Change the background color of the button color: "white", // Change the text color of the button @@ -353,6 +426,8 @@ class Grid extends react.Component { }, onMouseOver: () => this.setState({h3: true}), onMouseOut: () => this.setState({h3: false}), + id: "like", + style: { backgroundColor: this.state.h3 ? "darkgreen" : "green", // Change the background color of the button color: "white", // Change the text color of the button @@ -361,25 +436,6 @@ class Grid extends react.Component { borderRadius:"5px", // Add border radius } }, "Like"), - react.createElement("button", { - //onClick: () => handleDislike(param1, param2), // Call handleDislike with parameters - onClick: () => { - handleCreatePlaylist(); - this.setState({ c4: true }); - setTimeout(() => { - this.setState({ c4: false }); - }, 125); - }, - onMouseOver: () => this.setState({h4: true}), - onMouseOut: () => this.setState({h4: false}), - style: { - backgroundColor: this.state.h4 ? "purple": "#8a2be2", - color: "white", // Change the text color of the button - border: this.state.c4 ? "1px solid white":"none", // Remove the border - padding: "10px 20px", // Add padding - borderRadius:"5px", // Add border radius - } - }, "Create Playlist"), )), From 67bf0c7a8ec9165206d4db61073ca2b7a7601557 Mon Sep 17 00:00:00 2001 From: Katijino <143554078+Katijino@users.noreply.github.com> Date: Tue, 23 Apr 2024 05:13:31 -0400 Subject: [PATCH 30/40] added song title above image Added the song title above the image, making it look more "clean" --- spotify_app/index.js | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index fb525c8..a617916 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -235,6 +235,8 @@ class Grid extends react.Component { c2: false, c3: false, c4: false, + songName: "", + Artist: "" }; @@ -303,7 +305,14 @@ class Grid extends react.Component { currenturi.push(uri); await nextsong(uri); const imageUrl = await setAlbumUrl(uri); - this.setState({ image: imageUrl }); // Update the image state + let id = uri.split(':')[2]; // Extract the ID from the URI + const response = await CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); + const data = await response; // Assuming response.json() returns a promise + const s = data.name; + const a = data.artists[0].name; + // Access the data fetched from the Spotify API here + this.setState({ image: imageUrl, songName: s,Artist: a}); // Update the image state + } catch (error) { console.error("Error handling next song:", error); @@ -312,7 +321,7 @@ class Grid extends react.Component { render() { - const {h1,h2,h3,h4,c1,c2,c3,c4 } = this.state; + const {h1,h2,h3,h4,c1,c2,c3,c4,songName,Artist } = this.state; return react.createElement("section", { className: "contentSpacing", @@ -343,13 +352,28 @@ class Grid extends react.Component { ), react.createElement("div", { style: { + flexDirection: "column", + textAlign: "center", display: "flex", justifyContent: "center", alignItems: "center", - transform: "scale(2) translateY(20%)", // Scale the image to make it 4 times bigger + transform: "scale(2)", // Scale the image to make it 4 times bigger transformOrigin: "center top", // Set the transform origin to the center top } }, + react.createElement("div",{ + style: { + margin: "8px" + } + }, + react.createElement("div",{ + style:{ + color: "white", + fontFamily: "Montserrat", + fontWeight: "bold", // Add fontWeight property + + } + },this.state.songName)), react.createElement("img", { src: this.state.image, style: { @@ -357,8 +381,6 @@ class Grid extends react.Component { maxHeight: 220, } })), - - react.createElement("footer", { style: { margin: "auto", From 967cf69a558438044775d99c06705483510671b3 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:35:41 -0400 Subject: [PATCH 31/40] Music genre dropdown menu to send to llm Does not work as intended yet. --- spotify_app/index.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index a617916..ab3ec4e 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -236,7 +236,8 @@ class Grid extends react.Component { c3: false, c4: false, songName: "", - Artist: "" + Artist: "", + selectedGenre: "" }; @@ -249,6 +250,10 @@ class Grid extends react.Component { componentWillUnmount() { this.removeKeyboardShortcutListener(); } + + handleGenreChange = (event) => { + this.setState({ selectedGenre: event.target.value }); + } handleKeyDown = (event) => { // Check if CTRL, ALT, and L are pressed @@ -361,6 +366,23 @@ class Grid extends react.Component { transformOrigin: "center top", // Set the transform origin to the center top } }, + + //genre selection for llm, work in progress + react.createElement("label", { htmlFor: "genreDropdown" }, "Select Genre: "), + react.createElement("select", { + id: "genreDropdown", + value: selectedGenre, + onChange: this.handleGenreChange, + style: { + marginLeft: "10px" + } + }, + react.createElement("option", { value: "" }, "Select Genre"), + react.createElement("option", { value: "Pop" }, "Pop"), + react.createElement("option", { value: "Rock" }, "Rock"), + react.createElement("option", { value: "Hip Hop" }, "Hip Hop"), + react.createElement("option", { value: "Electronic" }, "Electronic") + ) react.createElement("div",{ style: { margin: "8px" From 1c4b4beb74e77abce5a284fb236d52f1a37fad4a Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:52:46 -0400 Subject: [PATCH 32/40] Modified retrieve next to work with getUriFromSongAndArtist so that it can easily integrate llm in the future. Fixed playlist button as well --- spotify_app/index.js | 47 ++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index ab3ec4e..eaf42bb 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -53,12 +53,17 @@ async function getUriFromSongAndArtist(song, artist){ async function retrievenext() { const popSongs = [ - 'spotify:track:3GCL1PydwsLodcpv0Ll1ch', - 'spotify:track:1p80LdxRV74UKvL8gnD7ky', - 'spotify:track:273dCMFseLcVsoSWx59IoE', + 'Blank+Space', + 'You+Belong+With+Me', + 'Bad+Blood', + ]; + const popArtists = [ + 'Taylor+Swift', + 'Taylor+Swift', + 'Taylor+Swift', ]; const randomIndex = Math.floor(Math.random() * popSongs.length); - return popSongs[randomIndex]; + return getUriFromSongAndArtist(popSongs[randomIndex], popArtists[randomIndex]); }; const currenturi = []; @@ -301,10 +306,10 @@ class Grid extends react.Component { handlePlayNext = async () => { try { // Assuming retrievenext() is an asynchronous function - //const uri = await retrievenext(); + uri = await retrievenext(); //testing geturifromsongandartistfunction - const uri = await getUriFromSongAndArtist("Space+Cadet", "Gunna"); + //const uri = await getUriFromSongAndArtist("Space+Cadet", "Gunna"); currenturi.length = 0; currenturi.push(uri); @@ -368,21 +373,21 @@ class Grid extends react.Component { }, //genre selection for llm, work in progress - react.createElement("label", { htmlFor: "genreDropdown" }, "Select Genre: "), - react.createElement("select", { - id: "genreDropdown", - value: selectedGenre, - onChange: this.handleGenreChange, - style: { - marginLeft: "10px" - } - }, - react.createElement("option", { value: "" }, "Select Genre"), - react.createElement("option", { value: "Pop" }, "Pop"), - react.createElement("option", { value: "Rock" }, "Rock"), - react.createElement("option", { value: "Hip Hop" }, "Hip Hop"), - react.createElement("option", { value: "Electronic" }, "Electronic") - ) + // react.createElement("label", { htmlFor: "genreDropdown" }, "Select Genre: "), + // react.createElement("select", { + // id: "genreDropdown", + // value: selectedGenre, + // onChange: this.handleGenreChange, + // style: { + // marginLeft: "10px" + // } + // }, + // react.createElement("option", { value: "" }, "Select Genre"), + // react.createElement("option", { value: "Pop" }, "Pop"), + // react.createElement("option", { value: "Rock" }, "Rock"), + // react.createElement("option", { value: "Hip Hop" }, "Hip Hop"), + // react.createElement("option", { value: "Electronic" }, "Electronic") + // ) react.createElement("div",{ style: { margin: "8px" From 54abca65419f38250dc043a3251a9f96dcdec31f Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:16:52 -0400 Subject: [PATCH 33/40] Added heart and X images to be used as like and dislike buttons --- spotify_app/index.js | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index eaf42bb..e891144 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -407,7 +407,46 @@ class Grid extends react.Component { maxWidth: 315, maxHeight: 220, } - })), + }) + ), + react.createElement("div", { + style: { + flexDirection: "row", + display: "flex", + justifyContent: "flex-start", + alignItems: "left", + transform: "scale(1)", // Scale the image to make it 4 times bigger + transformOrigin: "center top", // Set the transform origin to the center top + } + }, + + react.createElement("img", { + src: "https://cdn.pixabay.com/photo/2020/09/30/07/48/heart-5614865_1280.png", //this.state.image, + style: { + maxWidth: 315, + maxHeight: 220, + } + }) + ), + react.createElement("div", { + style: { + flexDirection: "row", + display: "flex", + justifyContent: "flex-start", + alignItems: "right", + transform: "scale(1)", // Scale the image to make it 4 times bigger + transformOrigin: "center top", // Set the transform origin to the center top + } + }, + + react.createElement("img", { + src: "https://www.freeiconspng.com/thumbs/close-button-png/black-circle-close-button-png-5.png", //this.state.image, + style: { + maxWidth: 315, + maxHeight: 220, + } + }) + ), react.createElement("footer", { style: { margin: "auto", From 9b10ba37b2721bc3548a3f915d730f9ba5042655 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:03:20 -0400 Subject: [PATCH 34/40] Fixed song title display font --- spotify_app/index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index e891144..7b25ef5 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -363,6 +363,7 @@ class Grid extends react.Component { react.createElement("div", { style: { flexDirection: "column", + //flexDirection: "row", textAlign: "center", display: "flex", justifyContent: "center", @@ -396,8 +397,6 @@ class Grid extends react.Component { react.createElement("div",{ style:{ color: "white", - fontFamily: "Montserrat", - fontWeight: "bold", // Add fontWeight property } },this.state.songName)), @@ -447,12 +446,14 @@ class Grid extends react.Component { } }) ), + react.createElement("footer", { style: { margin: "auto", position: "fixed", textAlign: "center", bottom: 120, + left: 310, width: "80%", // Ensure the footer spans the full width paddingTop: "20px", // Add padding at the top for spacing paddingBottom: "20px" @@ -483,8 +484,14 @@ class Grid extends react.Component { border: this.state.c1 ? "1px solid white":"none", // Remove the border padding: "10px 20px", // Add padding borderRadius: "5px", // Add border radius + // background-image: url('https://www.freeiconspng.com/thumbs/close-button-png/black-circle-close-button-png-5.png'); + // width: 315px; + // height: 220px; + // border: none; + // cursor: pointer; } }, "Dislike"), + react.createElement("button", { onClick: () => { this.handlePlayNext(); From 6bb1db78b39709b83283a596c26f9a125df830ed Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:19:38 -0400 Subject: [PATCH 35/40] Made it so that createplaylist() makes a new playlist every time it's clicked. Also resets liked song list --- spotify_app/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 7b25ef5..7952ec6 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -202,9 +202,11 @@ async function handleCreatePlaylist() { if (!playlistCreated){ try { - playlistCreated = true + //playlistCreated = true tempplaylist = await createPlaylist(); await addtoplaylist(tempplaylist); + likedlist.length = 0; + tempplaylist = null; } catch (error) { console.error("Error creating playlist:", error); } From 5246341426ceb10f0b50f27148ea3a4d44f3e7da Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:40:05 -0400 Subject: [PATCH 36/40] Added artist name to display, doesnt work with multiple artists (only does first listed) --- spotify_app/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 7952ec6..3c8a2f6 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -321,7 +321,7 @@ class Grid extends react.Component { const response = await CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); const data = await response; // Assuming response.json() returns a promise const s = data.name; - const a = data.artists[0].name; + const a = " by: " + data.artists[0].name; // Access the data fetched from the Spotify API here this.setState({ image: imageUrl, songName: s,Artist: a}); // Update the image state @@ -401,7 +401,7 @@ class Grid extends react.Component { color: "white", } - },this.state.songName)), + },this.state.songName + this.state.Artist)), react.createElement("img", { src: this.state.image, style: { From 440cf125cd65197f12964bd2d1c4255126f4e643 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 20:47:38 -0400 Subject: [PATCH 37/40] Added new function for getting song uri from the name. Added display for songs that have been liked --- spotify_app/index.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/spotify_app/index.js b/spotify_app/index.js index 3c8a2f6..90e7faa 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -51,6 +51,13 @@ async function getUriFromSongAndArtist(song, artist){ } +async function getSongFromUri(uri){ + let id = uri.split(":")[2] + let temp = await CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); + let tempname = temp.name; + return tempname; +} + async function retrievenext() { const popSongs = [ 'Blank+Space', @@ -90,9 +97,14 @@ async function addtoplaylist(playlistinfo) { } const likedlist = []; +let likedSongs = []; async function addSongToLiked(song){ + let temp = getSongFromUri(song); if(!likedlist.includes(song)){ likedlist.push(song); + likedSongs.push(temp); + //likedSongs.push(", \n"); + } } @@ -166,6 +178,7 @@ const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"; // let tempplaylist = ''; let uri = ''; + async function handleLike() { try { // Assuming send() is an asynchronous function @@ -175,6 +188,9 @@ async function handleLike() { } try{ addSongToLiked(uri); + + //likedSongs.push(getSongFromUri(uri)); + //likedSongs.push("\n"); } catch (error) { console.error("Error adding song to liked songs:", error); } @@ -206,6 +222,7 @@ async function handleCreatePlaylist() { tempplaylist = await createPlaylist(); await addtoplaylist(tempplaylist); likedlist.length = 0; + likedSongs.length = 0; tempplaylist = null; } catch (error) { console.error("Error creating playlist:", error); @@ -245,6 +262,7 @@ class Grid extends react.Component { songName: "", Artist: "", selectedGenre: "" + //LikedSongs: []; }; @@ -449,6 +467,19 @@ class Grid extends react.Component { }) ), + react.createElement("div",{ + style: { + margin: "8px" + } + }, + react.createElement("div",{ + style:{ + color: "white", + + } + }, likedSongs)), + + react.createElement("footer", { style: { margin: "auto", From 7646b0e8676a141692c1c8c72cdf3a0482b1ec8e Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:07:04 -0400 Subject: [PATCH 38/40] Added button for toggling explicit songs. Made it so that playlists cannot be created if no songs have been liked. --- spotify_app/index.js | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 90e7faa..cb06f9f 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -58,6 +58,9 @@ async function getSongFromUri(uri){ return tempname; } +let x = 1000; +let randomIndex = 1000; + async function retrievenext() { const popSongs = [ 'Blank+Space', @@ -69,7 +72,10 @@ async function retrievenext() { 'Taylor+Swift', 'Taylor+Swift', ]; - const randomIndex = Math.floor(Math.random() * popSongs.length); + while (x == randomIndex){ + randomIndex = Math.floor(Math.random() * popSongs.length); + } + x = randomIndex; return getUriFromSongAndArtist(popSongs[randomIndex], popArtists[randomIndex]); }; @@ -79,9 +85,11 @@ let playlistCreated = false; async function createPlaylist(){ const user = await CosmosAsync.get('https://api.spotify.com/v1/me'); + if (likedlist.length != 0){ playlistinfo = CosmosAsync.post('https://api.spotify.com/v1/users/' + user.id + '/playlists', { name: 'SpotifyPlus Playlist' }); + } return playlistinfo; } @@ -102,7 +110,7 @@ async function addSongToLiked(song){ let temp = getSongFromUri(song); if(!likedlist.includes(song)){ likedlist.push(song); - likedSongs.push(temp); + //likedSongs.push(temp); //likedSongs.push(", \n"); } @@ -255,10 +263,12 @@ class Grid extends react.Component { h2: false, h3: false, h4: false, + h5: false, c1: false, c2: false, c3: false, c4: false, + c5: false, songName: "", Artist: "", selectedGenre: "" @@ -351,7 +361,7 @@ class Grid extends react.Component { render() { - const {h1,h2,h3,h4,c1,c2,c3,c4,songName,Artist } = this.state; + const {h1,h2,h3,h4,h5,c1,c2,c3,c4,songName,Artist } = this.state; return react.createElement("section", { className: "contentSpacing", @@ -379,6 +389,25 @@ class Grid extends react.Component { borderRadius:"5px", // Add border radius } }, "Create Playlist"), + react.createElement("button", { + onClick: () => { + //handleToggleExplicit(); + this.setState({ c5: true }); + setTimeout(() => { + this.setState({ c5: false }); + }, 125); + }, + onMouseOver: () => this.setState({h5: true}), + onMouseOut: () => this.setState({h5: false}), + id: "playlist", + style: { + backgroundColor: this.state.h5 ? "Dark Grey": "Black", + color: "white", // Change the text color of the button + border: this.state.c5 ? "1px solid white":"none", // Remove the border + padding: "10px 20px", // Add padding + borderRadius:"5px", // Add border radius + } + }, "Toggle Explicit"), ), react.createElement("div", { style: { From 52b3eaae78be1d2d3eb580b19525964d1003ed03 Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:53:01 -0400 Subject: [PATCH 39/40] Added functionality to toggle explicit function. If an explicit song is play it automatically gets skipped while the explicit toggle is set to not allowed. --- spotify_app/index.js | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index cb06f9f..780cc06 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -58,19 +58,32 @@ async function getSongFromUri(uri){ return tempname; } -let x = 1000; -let randomIndex = 1000; +async function checkIfExplicit(uri){ + let id = uri.split(":")[2] + let temp = await CosmosAsync.get('https://api.spotify.com/v1/tracks/' + id); + let isExplcit = temp.explicit; + return isExplcit; +} + +let x = -1; +let randomIndex = -1; async function retrievenext() { const popSongs = [ 'Blank+Space', 'You+Belong+With+Me', 'Bad+Blood', + 'Space+Cadet', + '心いう名の不可解', + '踊' ]; const popArtists = [ 'Taylor+Swift', 'Taylor+Swift', 'Taylor+Swift', + 'Gunna', + 'Ado', + 'Ado' ]; while (x == randomIndex){ randomIndex = Math.floor(Math.random() * popSongs.length); @@ -110,8 +123,8 @@ async function addSongToLiked(song){ let temp = getSongFromUri(song); if(!likedlist.includes(song)){ likedlist.push(song); - //likedSongs.push(temp); - //likedSongs.push(", \n"); + likedSongs.push(temp.toString()); + likedSongs.push(", \n"); } @@ -244,6 +257,26 @@ async function handleCreatePlaylist() { } } } + +let explicitAllowed = true; +async function handleToggleExplicit() { + try { + // Assuming send() is an asynchronous function + await send("explicit toggled",uri); + + } catch (error) { + console.error("Error sending explicit to LLM:", error); + } + + + if (explicitAllowed){ explicitAllowed = false;} + else {explicitAllowed = true;} + +} + + + + // The main custom app render function. The component returned is what is rendered in Spotify. function render() { return react.createElement(Grid, { title: "SpotifyPlus" }); @@ -338,6 +371,10 @@ class Grid extends react.Component { // Assuming retrievenext() is an asynchronous function uri = await retrievenext(); + while (!explicitAllowed && checkIfExplicit(uri)){ + uri = await retrievenext(); + } + //testing geturifromsongandartistfunction //const uri = await getUriFromSongAndArtist("Space+Cadet", "Gunna"); @@ -391,7 +428,7 @@ class Grid extends react.Component { }, "Create Playlist"), react.createElement("button", { onClick: () => { - //handleToggleExplicit(); + handleToggleExplicit(); this.setState({ c5: true }); setTimeout(() => { this.setState({ c5: false }); From a7c5efa241474df43d516cc89e5f70b654b0391f Mon Sep 17 00:00:00 2001 From: Ansh Revankar <157625261+Augula33@users.noreply.github.com> Date: Wed, 24 Apr 2024 22:11:50 -0400 Subject: [PATCH 40/40] Display whether explicit filter is toggled or not --- spotify_app/index.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/spotify_app/index.js b/spotify_app/index.js index 780cc06..4efbf65 100644 --- a/spotify_app/index.js +++ b/spotify_app/index.js @@ -269,7 +269,7 @@ async function handleToggleExplicit() { } - if (explicitAllowed){ explicitAllowed = false;} + if (explicitAllowed){explicitAllowed = false;} else {explicitAllowed = true;} } @@ -369,11 +369,16 @@ class Grid extends react.Component { handlePlayNext = async () => { try { // Assuming retrievenext() is an asynchronous function - uri = await retrievenext(); + // uri = await retrievenext(); - while (!explicitAllowed && checkIfExplicit(uri)){ + // while (!explicitAllowed && checkIfExplicit(uri)){ + // uri = await retrievenext(); + // } + + do{ uri = await retrievenext(); - } + let temp = checkIfExplicit(uri); + } while (!explicitAllowed && temp); //testing geturifromsongandartistfunction //const uri = await getUriFromSongAndArtist("Space+Cadet", "Gunna"); @@ -445,6 +450,17 @@ class Grid extends react.Component { borderRadius:"5px", // Add border radius } }, "Toggle Explicit"), + react.createElement("div",{ + style: { + margin: "8px" + } + }, + react.createElement("div",{ + style:{ + color: "white", + + } + }, explicitAllowed.toString())), ), react.createElement("div", { style: {