From 2274662117cb11095e71871fdfcf4ffb32f75944 Mon Sep 17 00:00:00 2001 From: Benoit Pimpaud Date: Sun, 24 Sep 2023 12:00:07 +0200 Subject: [PATCH 1/3] [feature] add artist metadata --- src/CustomNode.tsx | 2 +- src/SearchList.tsx | 9 ++++++--- src/nodes.tsx | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/CustomNode.tsx b/src/CustomNode.tsx index dfdab71..682746b 100644 --- a/src/CustomNode.tsx +++ b/src/CustomNode.tsx @@ -11,7 +11,7 @@ function CustomNode({ data, isConnectable }) {
- +
Key: {data.key} BPM: {data.bpm} diff --git a/src/SearchList.tsx b/src/SearchList.tsx index 24a6591..68c90c6 100644 --- a/src/SearchList.tsx +++ b/src/SearchList.tsx @@ -16,7 +16,7 @@ function SearchList({ nodes, setNodes }: Props) { nodes.concat({ id: node.id, type: "customNode", - data: { label: node.data.label, bpm: node.data.bpm, key: node.data.key, style: node.data.style }, + data: { title: node.data.title, artist: node.data.artist, bpm: node.data.bpm, key: node.data.key, style: node.data.style}, position: { x: 500, y: 25 }, }), ) @@ -28,8 +28,11 @@ function SearchList({ nodes, setNodes }: Props) {
onSubmit(node, e)} key={node.id}>
-

- {node.data.label} +

+ {node.data.title} +

+

+ {node.data.artist}

diff --git a/src/nodes.tsx b/src/nodes.tsx index 981d7a3..9694c61 100644 --- a/src/nodes.tsx +++ b/src/nodes.tsx @@ -7,7 +7,7 @@ function create_library(nb_title: number){ id: `${i}`, sourcePosition: 'right', targetPosition: 'left', - data: { label: `Title ${i}`, bpm: '110', key: 'Eb', style:'Disco' }, + data: { title: `Title ${i}`, artist: `Artist ${i*2}`, bpm: '110', key: 'Eb', style:'Disco' }, position: { x: 500, y: 100 }, }; tmp.push(node); From 9263ffa0c5a7cfbab362257916765e942be229f9 Mon Sep 17 00:00:00 2001 From: Benoit Pimpaud Date: Sun, 24 Sep 2023 21:54:32 +0200 Subject: [PATCH 2/3] [feature] add connection to Spotify --- package-lock.json | 91 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/Header.tsx | 3 ++ src/Search.tsx | 63 ++++++++++++++++++++++++++++++-- src/SearchList.tsx | 23 ++++++------ 5 files changed, 167 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 071f5f4..471b12f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "track-lineage", "version": "0.0.0", "dependencies": { + "axios": "^1.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "reactflow": "^11.8.3" @@ -1620,6 +1621,11 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/autoprefixer": { "version": "10.4.15", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz", @@ -1657,6 +1663,16 @@ "postcss": "^8.1.0" } }, + "node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1837,6 +1853,17 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -2009,6 +2036,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2480,6 +2515,38 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz", @@ -2903,6 +2970,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3371,6 +3457,11 @@ } } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", diff --git a/package.json b/package.json index eb5d4f6..11423b4 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "prettier:write": "prettier --check --write './**/*'" }, "dependencies": { + "axios": "^1.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "reactflow": "^11.8.3" diff --git a/src/Header.tsx b/src/Header.tsx index 2d5ab02..bdd23e7 100644 --- a/src/Header.tsx +++ b/src/Header.tsx @@ -1,4 +1,6 @@ + function Header() { + return (

Track Lineage

@@ -7,3 +9,4 @@ function Header() { } export default Header + diff --git a/src/Search.tsx b/src/Search.tsx index 8255027..b5f537b 100644 --- a/src/Search.tsx +++ b/src/Search.tsx @@ -1,10 +1,67 @@ -import SearchList from './SearchList.tsx' +import SearchList from './SearchList.tsx'; +import {useEffect, useState} from 'react'; +import axios from 'axios'; + + +const CLIENT_ID = "0350c90137454dc5a748549664e5ba75" +const REDIRECT_URI = "http://localhost:5173" +const AUTH_ENDPOINT = "https://accounts.spotify.com/authorize" +const RESPONSE_TYPE = "token" function Search({ nodes, setNodes }: Props) { + + const [token, setToken] = useState("") + + useEffect(() => { + const hash = window.location.hash + let token = window.localStorage.getItem("token") + + if (!token && hash) { + token = hash.substring(1).split("&").find(elem => elem.startsWith("access_token")).split("=")[1] + + window.location.hash = "" + window.localStorage.setItem("token", token) + } + + setToken(token) + + }, []) + + const logout = () => { + setToken("") + window.localStorage.removeItem("token") + } + + const [searchKey, setSearchKey] = useState("") + const [tracks, setTracks] = useState([]) + + const searchTracks = async (e) => { + e.preventDefault() + const {data} = await axios.get("https://api.spotify.com/v1/search", { + headers: { + Authorization: `Bearer ${token}` + }, + params: { + q: searchKey, + type: "track" + } + }) + console.log(data) + setTracks(data.tracks.items) + + } + return (
- Search - + {!token ? + Login + to Spotify + : } + + setSearchKey(e.target.value)}/> + + +
) } diff --git a/src/SearchList.tsx b/src/SearchList.tsx index 68c90c6..2f30e33 100644 --- a/src/SearchList.tsx +++ b/src/SearchList.tsx @@ -7,16 +7,16 @@ type Props = { nodes: Node[] setNodes: React.Dispatch> } -function SearchList({ nodes, setNodes }: Props) { +function SearchList({ nodes, setNodes, tracks}: Props) { - function onSubmit(node, event: FormEvent) { + function onSubmit(track, event: FormEvent) { event.preventDefault() - console.log(node) + console.log(track) setNodes( nodes.concat({ - id: node.id, + id: track.id, type: "customNode", - data: { title: node.data.title, artist: node.data.artist, bpm: node.data.bpm, key: node.data.key, style: node.data.style}, + data: { title: track.name, artist: track.artists[0].name, bpm: "110", key: "Eb", style: "Disco", image: track.album.images[0].url }, position: { x: 500, y: 25 }, }), ) @@ -24,15 +24,16 @@ function SearchList({ nodes, setNodes }: Props) { return (
- {node_library.map(node => ( + {tracks.map(track => (
-
onSubmit(node, e)} key={node.id}> + onSubmit(track, e)} key={track.id}>
-

- {node.data.title} +

+ + {track.name}

-

- {node.data.artist} +

+ {track.artists[0].name}

From 7a5cf8720dc6bfaadaaa54c738caccac87f85504 Mon Sep 17 00:00:00 2001 From: Benoit Pimpaud Date: Sun, 24 Sep 2023 22:24:52 +0200 Subject: [PATCH 3/3] [style] update colors/style --- src/CustomNode.tsx | 4 ++-- src/Search.tsx | 60 +++++++++++++++++++++++----------------------- src/SearchList.tsx | 2 +- tailwind.config.js | 1 + 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/CustomNode.tsx b/src/CustomNode.tsx index 682746b..1bd4e12 100644 --- a/src/CustomNode.tsx +++ b/src/CustomNode.tsx @@ -11,8 +11,8 @@ function CustomNode({ data, isConnectable }) {
- -
+ {data.title} - {data.artist} +
Key: {data.key} BPM: {data.bpm} Style: {data.style} diff --git a/src/Search.tsx b/src/Search.tsx index b5f537b..a1892e2 100644 --- a/src/Search.tsx +++ b/src/Search.tsx @@ -1,5 +1,5 @@ import SearchList from './SearchList.tsx'; -import {useEffect, useState} from 'react'; +import { useEffect, useState } from 'react'; import axios from 'axios'; @@ -17,10 +17,10 @@ function Search({ nodes, setNodes }: Props) { let token = window.localStorage.getItem("token") if (!token && hash) { - token = hash.substring(1).split("&").find(elem => elem.startsWith("access_token")).split("=")[1] + token = hash.substring(1).split("&").find(elem => elem.startsWith("access_token")).split("=")[1] - window.location.hash = "" - window.localStorage.setItem("token", token) + window.location.hash = "" + window.localStorage.setItem("token", token) } setToken(token) @@ -37,34 +37,34 @@ function Search({ nodes, setNodes }: Props) { const searchTracks = async (e) => { e.preventDefault() - const {data} = await axios.get("https://api.spotify.com/v1/search", { - headers: { - Authorization: `Bearer ${token}` - }, - params: { - q: searchKey, - type: "track" - } + const { data } = await axios.get("https://api.spotify.com/v1/search", { + headers: { + Authorization: `Bearer ${token}` + }, + params: { + q: searchKey, + type: "track" + } }) console.log(data) setTracks(data.tracks.items) - - } - return ( -
- {!token ? - Login - to Spotify - : } - - setSearchKey(e.target.value)}/> - - - -
- ) } - - export default Search - \ No newline at end of file + + return ( +
+ {!token ? + Login + to Spotify + : } +
+ setSearchKey(e.target.value)} class="col-span-4 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" /> + +
+
+ +
+ ) +} + +export default Search diff --git a/src/SearchList.tsx b/src/SearchList.tsx index 2f30e33..1427c83 100644 --- a/src/SearchList.tsx +++ b/src/SearchList.tsx @@ -23,7 +23,7 @@ function SearchList({ nodes, setNodes, tracks}: Props) { } return ( -
+
{tracks.map(track => (
onSubmit(track, e)} key={track.id}> diff --git a/tailwind.config.js b/tailwind.config.js index 59a0365..086818b 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -8,6 +8,7 @@ export default { extend: { colors: { 'purple': '#8926D7', + 'light-purple': 'rgba(137, 38, 215, 0.2)', }, }, },