Skip to content

Commit

Permalink
Merge pull request #27 from stephaniejnc/finalBranch
Browse files Browse the repository at this point in the history
Implementing confirm playlist array on confirm() button and server
  • Loading branch information
stephaniejnc authored Sep 9, 2020
2 parents e443562 + 39dedbf commit 1fa8339
Show file tree
Hide file tree
Showing 13 changed files with 462 additions and 263 deletions.
47 changes: 42 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,45 @@
# Spotify recommender
# Spotify recommender + insights

### Google SPS Taiwan Team 6

#### Run locally
- Navigate to working directory
- In terminal, run 'node server.js'
- Application should be running on local host port 8888
Used Javascript, Node.js/Express.js, Python, and Google Datastore to create a Spotify playlist recommender + insights web application :)

Music taste is unique to everyone and is hard to describe in words - with this app, you can compare your music preferences with friends and enjoy some new tracks!

![Spotify App Flow](demo/spotify_app_flow.png)

### Video demos
**Click on the images below** to watch the Youtube demos!

#### Desktop view
[![Watch the desktop demo](demo/desktop_preview.png)](https://youtu.be/qDLzCbezRU8)

#### Tablet view
[![Watch the tablet demo](demo/tablet_preview.png)](https://youtu.be/0BhAvgtzgTw)

#### Mobile view
[![Watch the mobile demo](demo/mobile_preview.png)](https://youtu.be/YwTwcW77QB0)
[![Watch the mobile demo](demo/mobile_preview2.png)](https://youtu.be/YwTwcW77QB0)

### Contributors
- Phoebe (UI)
- UI beginning stages: colour palette, basic design; more responsive data population by Stephanie
- Assisted looking into machine learning models in beginning stages
- Stephanie (Spotify API, frontend + backend)
- Spotify API calls: login authorization flow, access tokens, get user, user playlists, playlist and track objects, personalized user insights, search Spotify user
- Frontend: communicate with server using Javascript fetching, ie. send selected user playlists, populate DOM with playlists and data after calling API, responsive navigation + grid layout to display playlists, cookies, user login status, lots of rendering!
- Backend: Node.js server, handles user authorization, page rendering, GET/POST requests, and Spotify API calls
- Client-server communication: Javascript fetch, GET, POST, JSON formatting/parsing
- Jessica C (Datastore)
- Created Datastore entities for tracks (name, artists, audio_featrures, track_id, playlist_id)
- Implemented functions for inserting/retrieving to/from Datastore, ie. addTracks(), getTrackByPlaylist(), getTrackById()
- Jessica F (Recommender)
- Modified Spotify's recommendation function to fit our app purpose and functionality, ex. getTracks(), getTracksByPlaylistId(), getRecommendations()
- Ran tracks from Datastore playlists through recommendation function to output a final playlist of recommended songs starting from 'most recommended'

### To run locally
- Git clone the repository
- You might have to delete the `node_modules` folder and run `npm install`
- Navigate to working directory/repository
- In Terminal/Powershell, run `node server.js` or `npm run devStart` (nodemon)
- Application should be running on local host port 8888!
Binary file added demo/desktop_preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/mobile_preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/mobile_preview2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/spotify_app_flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/tablet_preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
299 changes: 164 additions & 135 deletions public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,29 @@
--spotify-green: #1ed760;
}

button {
background-color: white;
}

#searchButton {
font-family: 'Montserrat', sans-serif;
background-color: #1ed760;
width: 10%;
border-radius: 10px;
padding: 0.35em 1.2em;
margin: 0 0.3em 0.3em 0;
box-sizing: border-box;
text-decoration: none;
color: white;
}

.content {
font-family: 'Montserrat', sans-serif;
margin: 50px;
color: white;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}

.center-text {
Expand Down Expand Up @@ -305,6 +324,141 @@ body {
padding-left: 20px;
}

:root {
--spotify-green: #1ed760;
}

#tracks {
background-color: black;
display: grid;
grid-template-rows: 1fr;
grid-template-columns: 1fr 2fr;

margin-top: 50px;
}

#recs {
background-color: black;
display: grid;
grid-template-rows: 1fr;
grid-template-columns: 1fr;

margin-top: 5%;
margin-left: 10%;
margin-bottom: 5%;
margin-right: 10%;
}

#playlist-info {
grid-row: 1 / span 1;
grid-column: 1 / span 1;

/* display: grid;
grid-template-rows: 3fr 1fr 1fr; */
margin: 0px auto;
}

#playlist-cover {
grid-row: 1 / span 1;
padding: 30px 10px;
max-width: 300px;
max-height: 300px;
}

#playlist-name {
grid-row: 2 / span 1;
margin: 0px auto;
font-size: 24px;
font-family: 'Montserrat', 'Noto Sans TC', sans-serif;
font-weight: bold;
color: white;
}

#track-info {
display: flex;
flex-direction: column;
color: white;
margin: 0px 300px 0px 10px;
}

#rec-track-info {
display: flex;
flex-direction: column;
color: white;
margin: 0px 50px 0px 50px;
}

.track {
width: 100%;
margin: 15px 10px;
}

.track-name {
color: white;
text-decoration: none;
font-size: 20px;
font-family: 'Montserrat', 'Noto Sans TC', sans-serif;
font-weight: bold;
}

.track-name:hover {
background: linear-gradient(180deg,rgba(255,255,255,0) 70%, #5C5C5C 70%);
}

.duration {
color: #C2C2C2;
padding: 0px 20px;
}

#buttons {
grid-row: 3 / span 1;
grid-column: 1 / span 1;
}

.button {
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
border-radius: 24px;
opacity: 0.9;
transition: 0.3s;
font-family: inherit;
}

.button:hover {
opacity: 1.0;
}

#confirm {
background-color: var(--spotify-green);
}

#back {
background-color: #5C5C5C;
}

.icon {
grid-row: 1 / span 2;
grid-column: 1 / span 1;
max-width: 10px;
max-height: 10px;
margin-right: 10px;

cursor: pointer;
}

.artist {
margin: 10px 0px;
padding-left: 20px;
color: white;
}

@media(max-width: 1333px) {
.grid-item {
flex-basis: 33.33%;
Expand Down Expand Up @@ -508,141 +662,6 @@ body {
background-color: #1ed760;
}

:root {
--spotify-green: #1ed760;
}

#tracks {
background-color: black;
display: grid;
grid-template-rows: 1fr;
grid-template-columns: 1fr 2fr;

margin-top: 50px;
}

#recs {
background-color: black;
display: grid;
grid-template-rows: 1fr;
grid-template-columns: 1fr;

margin-top: 5%;
margin-left: 10%;
margin-bottom: 5%;
margin-right: 10%;
}

#playlist-info {
grid-row: 1 / span 1;
grid-column: 1 / span 1;

display: grid;
grid-template-rows: 3fr 1fr 1fr;
margin: 0px auto;
}

#playlist-cover {
grid-row: 1 / span 1;
padding: 30px 0px;
max-width: 300px;
max-height: 300px;
}

#playlist-name {
grid-row: 2 / span 1;
margin: 0px auto;
font-size: 24px;
font-family: 'Montserrat', 'Noto Sans TC', sans-serif;
font-weight: bold;
color: white;
}

#track-info {
display: flex;
flex-direction: column;
color: white;
margin: 0px 300px 0px 10px;
}

#rec-track-info {
display: flex;
flex-direction: column;
color: white;
margin: 0px 50px 0px 50px;
}

.track {
width: 100%;
margin: 15px 10px;
}

.track-name {
color: white;
text-decoration: none;
font-size: 20px;
font-family: 'Montserrat', 'Noto Sans TC', sans-serif;
font-weight: bold;
}

.track-name:hover {
background: linear-gradient(180deg,rgba(255,255,255,0) 70%, #5C5C5C 70%);
}

.duration {
color: #C2C2C2;
padding: 0px 20px;
}

#buttons {
grid-row: 3 / span 1;
grid-column: 1 / span 1;
}

.button {
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
border-radius: 24px;
opacity: 0.9;
transition: 0.3s;
font-family: inherit;
}

.button:hover {
opacity: 1.0;
}

#confirm {
background-color: var(--spotify-green);
}

#back {
background-color: #5C5C5C;
}

.icon {
grid-row: 1 / span 2;
grid-column: 1 / span 1;
max-width: 10px;
max-height: 10px;
margin-right: 10px;

cursor: pointer;
}

.artist {
margin: 10px 0px;
padding-left: 20px;
color: white;
}

input[type=text] {
font-family: 'Montserrat', sans-serif;
width: 80%;
Expand All @@ -667,3 +686,13 @@ input[type=submit] {
text-align: center;
transition: all 0.2s;
}

@media(max-width: 815px) {
#searchButton {
width: auto;
}

input[type=text] {
width: 75%;
}
}
2 changes: 1 addition & 1 deletion public/scripts/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ async function loadPlaylists() {
// create span and set text to playlist title
const title = document.createElement('span');
title.setAttribute('class', 'item-title');
title.textContent = playlist.name;
title.textContent = playlist.name.substring(0,12);

// create span and set text to playlist title
const tracks = document.createElement('span');
Expand Down
Loading

0 comments on commit 1fa8339

Please sign in to comment.