Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:Ben8t/track-lineage into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben8t committed Sep 29, 2023
2 parents 25a02d9 + 88cfe98 commit 4be1c80
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 236 deletions.
7 changes: 4 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import 'reactflow/dist/style.css'
import './custom_node.css'
import Header from './Header.tsx'
import Flow from './Flow.tsx'
import Search from './Search.tsx'
import Header from './Header'
import Flow from './Flow'
import Search from './Search'
import React from 'react'

const App = () => {
return (
Expand Down
1 change: 1 addition & 0 deletions src/CustomNode.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react'
import { Handle, Position } from 'reactflow'

type NodeData = {
Expand Down
1 change: 1 addition & 0 deletions src/Flow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'reactflow/dist/style.css'
import './custom_node.css'
import CustomNode from './CustomNode'
import { FlowContext } from './context/FlowContext'
import React from 'react'

const Flow = () => {
const { nodes, setNodes, edges, setEdges } = useContext(FlowContext)
Expand Down
2 changes: 2 additions & 0 deletions src/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import React from "react"

function Header() {
return (
<div className="header mb-5">
Expand Down
275 changes: 132 additions & 143 deletions src/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,158 +1,147 @@
import React from 'react';
import SearchList from './SearchList.tsx'
import { useContext, useState } from 'react'
import SearchList from './SearchList'
import {useContext, useState} from 'react'
import axios from 'axios'
import { SpotifyContext } from './context/SpotifyContext.tsx'
import { FlowContext } from './context/FlowContext.tsx'
import { saveAs } from 'file-saver';
import {SpotifyContext} from './context/SpotifyContext'
import {FlowContext} from './context/FlowContext'
import {saveAs} from 'file-saver';

const CLIENT_ID = '0350c90137454dc5a748549664e5ba75'
const REDIRECT_URI = window.location.href
console.log(REDIRECT_URI);
const AUTH_ENDPOINT = 'https://accounts.spotify.com/authorize'
const RESPONSE_TYPE = 'token'

function Search() {
const { token, logout } = useContext(SpotifyContext)
const { nodes, setNodes, edges, setEdges } = useContext(FlowContext)

const [searchKey, setSearchKey] = useState('')
const [tracks, setTracks] = useState([])

const getTrackFeatures = async (token, trackId) => {
const response = await axios.get(`https://api.spotify.com/v1/audio-features/${trackId}`, {
headers: {
Authorization: `Bearer ${token}`,
}
});

return response.data;
};

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 trackItems = data.tracks.items;

const trackFeaturesPromises = trackItems.map(async (item) => {
const features = await getTrackFeatures(token, item.id);
return {
track: item,
features: features
};
});

const trackFeatures = await Promise.all(trackFeaturesPromises);

setTracks(trackFeatures)
}

const handleExport = (e) => {
const data = {
nodes: nodes,
edges: edges
const {token, logout} = useContext(SpotifyContext)
const {nodes, setNodes, edges, setEdges} = useContext(FlowContext)

const [searchKey, setSearchKey] = useState('')
const [tracks, setTracks] = useState([])

async function getTrackFeatures(token, track_id) {
const response = await axios.get(`https://api.spotify.com/v1/audio-features/${track_id}`, {
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data;
};

const json = JSON.stringify(data);
const blob = new Blob([json], { type: 'application/json' });

saveAs(blob, 'track_lineage_export.json');
}

const fileInputRef = React.createRef();

const handleImportButtonClick = () => {
fileInputRef.current.click();
};

const handleImport = (event) => {
const file = event.target.files[0];
const reader = new FileReader();

reader.onload = (e) => {
try {
const data = JSON.parse(e.target.result);

if (data.nodes && data.edges) {
setNodes(data.nodes);
setEdges(data.edges);
alert('Import successful!');
} else {
alert('Invalid file format. Please select a valid JSON file.');
async function searchTracks(e) {
e.preventDefault()
const {data} = await axios.get('https://api.spotify.com/v1/search', {
headers: {
Authorization: `Bearer ${token}`
},
params: {
q: searchKey,
type: 'track'
}
})

const trackItems = data.tracks.items;

const trackFeaturesPromises = trackItems.map(async (item) => {
const features = await getTrackFeatures(token, item.id);
return {track: item, features: features};
});
const trackFeatures = await Promise.all(trackFeaturesPromises);

setTracks(trackFeatures)
}

function handleExport(e) {
const data = {
nodes: nodes,
edges: edges
};
const json = JSON.stringify(data);
const blob = new Blob([json], {type: 'application/json'});
saveAs(blob, 'track_lineage_export.json');
}

const fileInputRef = React.createRef();

function handleImportButtonClick() {
fileInputRef.current.click();
}


function handleImport(event) {
const file = event.target.files[0];
const reader = new FileReader();

reader.onload = (e) => {
try {
const data = JSON.parse(e.target.result);

if (data.nodes && data.edges) {
setNodes(data.nodes);
setEdges(data.edges);
alert('Import successful!');
} else {
alert('Invalid file format. Please select a valid JSON file.');
}
} catch (error) {
alert('Error parsing JSON. Please check the file format.');
}
};

reader.readAsText(file);
}

return (
<div className="search rounded-lg bg-gray-100 gap-2">
{
!token ? (
<a className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
href={
`${AUTH_ENDPOINT}?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=${RESPONSE_TYPE}`
}>
Login to Spotify
</a>
) : (
<button className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
onClick={logout}>
Logout
</button>
)
}
} catch (error) {
alert('Error parsing JSON. Please check the file format.');
}
};

reader.readAsText(file);
};

return (
<div className="search rounded-lg bg-gray-100 gap-2">
{!token ? (
<a
className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
href={`${AUTH_ENDPOINT}?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=${RESPONSE_TYPE}`}
>
Login to Spotify
</a>
) : (
<button
className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
onClick={logout}
>
Logout
</button>
)}
<div>
<button
className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
onClick={handleImportButtonClick}
>
Import
</button>
<input
type="file"
accept=".json"
ref={fileInputRef}
style={{ display: 'none' }}
onChange={handleImport}
/>
</div>

<button
className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
onClick={handleExport}
>
Export
</button>
<form onSubmit={searchTracks} className="form grid grid-cols-6 gap-2">
<input
type="text"
onChange={(e) => setSearchKey(e.target.value)}
className="col-span-4 block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-blue-500 dark:focus:ring-blue-500"
/>
<button
className="hover:bg-purple-700 col-span-1 col-span-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
type={'submit'}
>
Search
</button>
</form>
<hr className="my-2 h-px border-0 bg-light-purple" />
<SearchList nodes={nodes} setNodes={setNodes} tracks={tracks} />
</div>
)
<div>
<button className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
onClick={handleImportButtonClick}>
Import
</button>
<input type="file" accept=".json"
ref={fileInputRef}
style={
{display: 'none'}
}
onChange={handleImport}/>
</div>

<button className="hover:bg-purple-700 col-span-1 mb-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
onClick={handleExport}>
Export
</button>
<form onSubmit={searchTracks}
className="form grid grid-cols-6 gap-2">
<input type="text"
onChange={
(e) => setSearchKey(e.target.value)
}
className="col-span-4 block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-blue-500 dark:focus:ring-blue-500"/>
<button className="hover:bg-purple-700 col-span-1 col-span-2 rounded bg-purple px-4 py-2 font-mono font-bold text-white"
type={'submit'}>
Search
</button>
</form>
<hr className="my-2 h-px border-0 bg-light-purple"/>
<SearchList nodes={nodes}
setNodes={setNodes}
tracks={tracks}/>
</div>
)
}

export default Search
Loading

0 comments on commit 4be1c80

Please sign in to comment.