Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filips testbranch #445

Open
wants to merge 97 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
6da7d00
Added title
eniteCZ Oct 18, 2022
6a0f27f
RR8 commit
eniteCZ Nov 11, 2022
7740fc7
Merge pull request #1 from MingC98/FilipsTestbranch
eniteCZ Nov 14, 2022
e94256e
Added API controller to script
eniteCZ Nov 22, 2022
e39c04b
Finished preliminary API controler
eniteCZ Nov 22, 2022
62fe04e
testing api code
eniteCZ Nov 22, 2022
969cef0
removed test because testing on own repo
eniteCZ Nov 22, 2022
44b0034
Moved away from object oriented way of coding to simpler stuff
eniteCZ Nov 22, 2022
5ff7cdd
removed await in func calls
eniteCZ Nov 22, 2022
e1267cb
Trying init async function
eniteCZ Nov 22, 2022
c742ce1
bugfix GenreId
eniteCZ Nov 22, 2022
c141c7e
bugfix
eniteCZ Nov 22, 2022
70c200f
Did some dev on the side but now the API call is fixed
eniteCZ Nov 22, 2022
9eb07d3
Added Icon
eniteCZ Nov 22, 2022
61a28a6
Merge pull request #2 from MingC98/FilipsTestbranch
MingC98 Nov 22, 2022
d33c0cb
Added injectHTML
MingC98 Nov 22, 2022
93d5596
Put in the html
MingC98 Nov 22, 2022
dc15ba4
Update script.js
MingC98 Nov 22, 2022
ba42017
fixed minor issue
MingC98 Nov 22, 2022
b404d8e
naming fixed
eniteCZ Nov 22, 2022
1ca0c4c
Merge pull request #3 from MingC98/MingTestbranch
eniteCZ Nov 22, 2022
0d7eb74
Moved index to root
eniteCZ Nov 22, 2022
51efb69
Merge branch 'main' of https://github.com/MingC98/Group102-01-Final-P…
eniteCZ Nov 22, 2022
a8e0877
Merge pull request #4 from MingC98/FilipsTestbranch
eniteCZ Nov 22, 2022
9e1249a
Update index.html
MingC98 Nov 30, 2022
3dd5f71
Started work on getting a large set of songs
eniteCZ Nov 30, 2022
130ef66
Idea is to have 100 genres
eniteCZ Nov 30, 2022
ebae3d9
removed issue with missing await in getGenres
eniteCZ Nov 30, 2022
fb689b9
Working on populating a list of playlists from different genres
eniteCZ Nov 30, 2022
deb5bd0
Added handling of playlists that could not be reached
eniteCZ Nov 30, 2022
852355b
polished handling of unanswered get reqs for getPlaylists
eniteCZ Nov 30, 2022
f635907
further work on getting a lot of songs
eniteCZ Nov 30, 2022
2046674
Functions not in sync
eniteCZ Dec 1, 2022
e22099a
polished response check
eniteCZ Dec 1, 2022
99bf397
Made the script create a list of links
eniteCZ Dec 1, 2022
aba8d1a
Merge pull request #5 from MingC98/FilipsTestbranch
eniteCZ Dec 1, 2022
845d2a9
Removed loading icon for now, start adding CSS
MingC98 Dec 1, 2022
9311b28
Added randomisation and selection of 10 songs only
eniteCZ Dec 1, 2022
7cfa9bd
Created some space in between elements
MingC98 Dec 1, 2022
4f2538c
Let the result box disapper until the result comes in
MingC98 Dec 1, 2022
39602fe
Fixed miner issue by putting display into the submit function
MingC98 Dec 1, 2022
759a252
Added a link to spotify, added some style
MingC98 Dec 1, 2022
9860161
Style changes
eniteCZ Dec 1, 2022
a72f995
Added an introduction page
MingC98 Dec 2, 2022
1a016fa
Merge branch 'main' of https://github.com/MingC98/Group102-01-Final-P…
MingC98 Dec 2, 2022
3f63402
Merge pull request #6 from MingC98/MingTestbranch
MingC98 Dec 2, 2022
8ccf0ae
moved files
MingC98 Dec 2, 2022
69c6619
Merge pull request #7 from MingC98/MingTestbranch
MingC98 Dec 2, 2022
e9eefb5
Added the link between two pages
MingC98 Dec 2, 2022
dafea77
Merge pull request #8 from MingC98/MingTestbranch
MingC98 Dec 2, 2022
1b78c74
Further polishing of the randomization
eniteCZ Dec 2, 2022
aceaf84
Merge branch 'main' into FilipsTestbranch
eniteCZ Dec 2, 2022
a04f5fc
Merge pull request #9 from MingC98/FilipsTestbranch
eniteCZ Dec 2, 2022
9fb70f9
Added new visualisation: Album image galery
eniteCZ Dec 2, 2022
1634614
Put the generated contents into a dedicated wrapper
eniteCZ Dec 2, 2022
13f1d0d
Played with the spacing
eniteCZ Dec 2, 2022
5f06740
Put the h2 to the center and spaced out the albums
eniteCZ Dec 2, 2022
909af34
Merge pull request #10 from MingC98/FilipsTestbranch
eniteCZ Dec 2, 2022
b1634f5
For partner's visualisation the songs include length
eniteCZ Dec 5, 2022
f1531af
bugfix
eniteCZ Dec 5, 2022
46be2b5
Added length param to songs
eniteCZ Dec 5, 2022
698bb8d
Created genre selection option
eniteCZ Dec 6, 2022
c0e6d2f
Page reacts to genre selection change
eniteCZ Dec 6, 2022
8f63c7c
Modified the song selection generation
eniteCZ Dec 6, 2022
0f6e404
Fixed genres appearing in Swedish
eniteCZ Dec 7, 2022
07104f0
Merge pull request #12 from MingC98/FilipsTestbranch
eniteCZ Dec 7, 2022
2e90a9a
fixed issue with failure to pick 10 random songs
eniteCZ Dec 7, 2022
4b0adcb
Merge pull request #13 from MingC98/FilipsTestbranch
eniteCZ Dec 7, 2022
ddcdd9a
Put in the chart and able to take input
MingC98 Dec 7, 2022
442a8f0
Fix the mistake, committed to main
MingC98 Dec 7, 2022
28d223b
Change the branch
MingC98 Dec 7, 2022
9a76f2b
Added the length array
MingC98 Dec 7, 2022
60b0fbb
Try to fix the chart input
MingC98 Dec 7, 2022
3250446
Change branch
MingC98 Dec 7, 2022
079eb0a
The chart worked, but still can not get the object property correctly
MingC98 Dec 7, 2022
ca72e66
hide chart box
MingC98 Dec 7, 2022
f0d4abb
Fixed the size of the chart container
MingC98 Dec 7, 2022
c51d05a
Changed size of the chat container to 150%
MingC98 Dec 7, 2022
d491bf0
fixed format, chart able to refresh
MingC98 Dec 8, 2022
2b7e6ba
Fixed error on the object property
MingC98 Dec 8, 2022
aaec046
Merge branch 'main' into MingTestbranch
eniteCZ Dec 8, 2022
f800c1f
Merge pull request #14 from MingC98/MingTestbranch
eniteCZ Dec 8, 2022
66ae146
Bugfix
eniteCZ Dec 8, 2022
513edc9
Merge pull request #15 from MingC98/FilipsTestbranch
eniteCZ Dec 8, 2022
3ad3c9d
Update script.js
MingC98 Dec 8, 2022
57a002f
Updated the Read Me
eniteCZ Dec 8, 2022
fd7b0af
Added a filter chart button to the chart
MingC98 Dec 11, 2022
0b75e57
Got the filter work, find no issue
MingC98 Dec 11, 2022
3af3cc0
Merge branch 'main' of https://github.com/MingC98/Group102-01-Final-P…
MingC98 Dec 11, 2022
95677c3
Fixed merging error
MingC98 Dec 11, 2022
78f7de9
Merge pull request #16 from MingC98/MingTestbranch
MingC98 Dec 11, 2022
83d97af
Change the filter to 200000ms
MingC98 Dec 11, 2022
f4adf99
Merge pull request #17 from MingC98/MingTestbranch
MingC98 Dec 11, 2022
5c03730
Added the user manual
MingC98 Dec 11, 2022
0a6b619
Merge pull request #18 from MingC98/MingTestbranch
MingC98 Dec 11, 2022
bbf71c9
Added an internal image and got ridof redundant server related things
eniteCZ Dec 11, 2022
a46ce7a
Stylistic changes
eniteCZ Dec 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
# This is your readme
You are required to fill it in with documentation similar to that found in the Sequelize example for the course as part of your final project.
# Music: New Horizons
This is an INST377 final project website by Filip Radmanovic and Minghan Cai. Please visit our webpage at:

https://mingc98.github.io/Group102-01-Final-Project-Music-NewHorizon/index.html

## Broad description
While using spotify most of us search for a song we know and listen to and then either choose a playlist with what is already know or we let the algorithm take the reigns and play songs for us based on our known preferences.

The intent of the project is to provide the user with song suggestions for a particular genre that have not been generated based on their preferences, thus broadening their musical horizon. When a user selects a genre and presses the button, we show a list of 9 randomly selected songs along with the links to them on Spotify, a galery of their album covers and a chart of their length. Once a user has picked a song they can click on the link which will tak them to spotify web page where they can listen to it.



## Usage manual
This page should work on all mainstram browsers on mobile and fixed divices.

* First when you open the page, it will load a selection of genres to the dropdown menu prompting you to select a genre
* Once you have selected a genre give the page a second to retrieve a list of songs
* Then press the "Broaden my horizon" button
* You can look at the names of the songs and select whichever you like best, you will be redirected to spotify where you can listen to it.
* If you want to know more about us, please visit the "About us" link at the bottom of the page.


## API
We are using the Spotify API. For details please refer to the official documentation:

https://developer.spotify.com/documentation/web-api/

## Visualizations
We use 2 visualizations in this project:
* An image galery of album covers handled internaly by our code.
* A chart of song lengths using the chart.js library


### How to use Markdown
Markdown is a text notation system used in Discord, Whatsapp and similar to structure pages without writing HTML at all. You'll be using it for your documentation.
* [Markdown guide](https://www.markdownguide.org/cheat-sheet/)
57 changes: 57 additions & 0 deletions about_us.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Music: Broad Horizons</title>
<link rel="stylesheet" href="./client/styles.css">
</head>
<body>
<div class="Wrapper">
<div class='header'>
<h2> INST377 group 102-01 </h2>
</div>

<div class="paragraph">
<p>
This is Minghan Cai and Filip Radmanovic's final project for INST377. Please visit our Webpage at:
</p>
<p><a href='https://mingc98.github.io/Group102-01-Final-Project-Music-NewHorizon/index.html'>'https://mingc98.github.io/Group102-01-Final-Project-Music-NewHorizon/index.html'</a></p>

<p1>
Broad description
</p1>
<p>
While using spotify most of us search for a song we know and listen to and then either choose a playlist with what is already know or we let the algorithm take the reigns and play songs for us based on our known preferences.
The intent of the project is to provide the user with song suggestions for a particular genre that have not been generated based on their preferences, thus broadening their musical horizon. When a user selects a genre and presses the button, we show a list of 9 randomly selected songs along with the links to them on Spotify, a galery of their album covers and a chart of their length. Once a user has picked a song they can click on the link which will tak them to spotify web page where they can listen to it.
</p>

<p1>
Usage manual
</p1>
<p>First when you open the page, it will load a selection of genres to the dropdown menu prompting you to select a genre</p>
<p>Once you have selected a genre give the page a second to retrieve a list of songs</p>
<p>Then press the "Broaden my horizon" button</p>
<p>You can look at the names of the songs and select whichever you like best, you will be redirected to spotify where you can listen to it.</p>
<p>If you want to know more about us, please visit the "About us" link at the bottom of the page.</p>

<p1>API</p1>
<p>We are using the Spotify API. For details please refer to the official documentation:</p>
<p><a href='https://developer.spotify.com/documentation/web-api/'>'https://developer.spotify.com/documentation/web-api/'</a></p>

<p1>Visualizations</p1>
<p>We use 2 visualizations in this project:</p>
<p>An image galery of album covers handled internaly by our code.</p>
<p>A chart of song lengths using the chart.js library</p>
</div>


<div class='footer'>
<p>Go to <a href='index.html'>Our project's main page</a></p>
<p>MingC98 <a href='https://github.com/MingC98/INST377-Lab-Work'>My Github account</a></p>
<p>eniteCZ <a href='https://github.com/eniteCZ/INST377-Lab-Work'>My Github account</a></p>
</div>
</div>
<script src="./script.js"></script>
</body>
</html>
Binary file added client/favicon.ico
Binary file not shown.
12 changes: 0 additions & 12 deletions client/index.html

This file was deleted.

268 changes: 268 additions & 0 deletions client/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
/* eslint-disable no-trailing-spaces */
/* eslint-disable max-len */
/* eslint-disable linebreak-style */
// const e = require("express");

const clientId = 'd9827efb2c79463b92becb457a635a04';
const clientSecret = '6f2f0a36046f4f21980873a48c7bdab0';
// --------------------- API dialogue functions ---------------------

function getRandomIntInclusive(min, max) {
const newMin = Math.ceil(min);
const newMax = Math.floor(max);
return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); // The maximum is inclusive and the minimum is inclusive
}

async function getToken() {
// Gets authorisation token
const result = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}`
},
body: 'grant_type=client_credentials'
});

const data = await result.json();
return data.access_token;
}

async function getGenres(token) {
// Gets a list of genres
const result = await fetch(
'https://api.spotify.com/v1/browse/categories?locale=US&limit=45',
{
method: 'GET',
headers: { Authorization: `Bearer ${token}` }
}
);

const data = await result.json();
return data.categories.items;
}

async function getPlaylistsByGenre(token, genreId, limit) {
// Based on genre ID gets a list of playlists of that genre
const result = await fetch(
`https://api.spotify.com/v1/browse/categories/${genreId}/playlists?limit=${limit}`,
{
method: 'GET',
headers: { Authorization: `Bearer ${token}` }
}
);

const data = await result.json();
if (typeof data.playlists !== 'undefined') {
return data.playlists.items;
}
}

async function getTracks(token, tracksEndPoint, limit) {
// Based on a playlist gets a list of songs from that playlist
const result = await fetch(`${tracksEndPoint}?limit=${limit}`, {
method: 'GET',
headers: { Authorization: `Bearer ${token}` }
});

const data = result.json();
return data;
}

// --------------------- Data handling functions ---------------------

async function initSongs(plalylistSg, genre, token) {
// A function that gets us a the songs from a playlist

const tracks = await getTracks(token, plalylistSg, 60);
console.log(tracks.items);
return tracks.items.map((obj) => ({ ...obj, gen: genre }));
}

function songsToArray(songs) {
console.log(songs);
const array = [];
songs.forEach((element) => {
array.push({
name: element.track.name,
link: element.track.external_urls.spotify,
image_url: element.track.album.images[0].url,
genre: element.gen,
length: element.track.duration_ms
});
});
return array;
}

function songLenArray(list) {
const array = [];
list.forEach((element) => {
array.push(element.length);
});
return array;
}

function songNameArray(list) {
const array = [];
list.forEach((element) => {
array.push(element.name);
});
return array;
}
// -------------------UI Handling-------------------

// Inject genres into the dropdown menu
function insertGenres(text, value, element) {
const html = `<option value="${value}">${text}</option>`;
element.insertAdjacentHTML('beforeend', html);
}

// Get random 9 items from an aray (to be replacedby betterselection item)
function getRandomTen(list) {
console.log('fired get 9 songs');
const range = [...Array(9).keys()];
const newArray = range.map(() => {
const index = getRandomIntInclusive(0, list.length - 1);
const picked = list[index];
return picked;
});
return newArray;
}

// Inject a song to the page
function injectHTML(list) {
console.log('fired injectHTML');
const target = document.querySelector('#music_list');
target.innerHTML = '';

const listEl = document.createElement('ol');
target.appendChild(listEl);
list.forEach((item) => {
const el = document.createElement('li');
el.innerHTML = `<a href=${item.link}>${item.name}</a>`;
listEl.appendChild(el);
});
}

// Inject images
function injectImages(list) {
console.log('fired injectImages');
const target = document.querySelector('#Imagebox');
target.innerHTML = '<h2>Songs are from these albums</h2><br>';

list.forEach((item) => {
const el = `<img src="${item.image_url}"></img>`;
target.innerHTML += el;
});
}

function initChart(songs, songlength) {
const ctx = document.getElementById('myChart');

// eslint-disable-next-line no-new
const m_chart = new Chart(ctx, {
type: 'bar',
// eslint-disable-next-line linebreak-style
data: {
labels: songs,
datasets: [
{
label: 'Length of the song(ms)',
data: songlength,
borderWidth: 4
}
]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
return m_chart;
}

// ---------------------------Page Initialisation-------------------------------------------

// Turn the site script on
async function init() {
// Step 1: Get token, initialise variables
const token = await getToken();

let myChart = new Chart();

document.getElementById('GeneratedContents').style.display = 'none';
document.getElementById('Chartbox').style.display = 'none';
const selectGenre = document.querySelector('#select_genre');
const submit = document.querySelector('#submit');
let playlistEndpoint = '';
let songArray = [];
const chartTarget = document.querySelector('#myChart');

// Step 2: Get genre selection and insert the options into HTML
const genres = await getGenres(token);
console.log(genres);
genres.map((genre) => {
insertGenres(genre.name, genre.id, selectGenre);
});

// Step 3: When user selects a genre get a playlist for it.
selectGenre.addEventListener('change', async () => {
// get the genre id and name associated with the selected genre
const genreId = selectGenre.options[selectGenre.selectedIndex].value;
const genreName = selectGenre.options[selectGenre.selectedIndex].innerHTML;

// get the playlist based on a genre
console.log(
`Getting tracks from genre: ${genreName} which has the id: ${genreId}`
);
const playlist = await getPlaylistsByGenre(token, genreId, 1);

// store the track endpoint of the playlist
playlistEndpoint = `${playlist[0].href}/tracks`;
console.log(playlistEndpoint);

// Finally get the tracks and turn them into an array
const tracks = await initSongs(playlistEndpoint, genreName, token);
songArray = songsToArray(tracks);
document.getElementById('GeneratedContents').style.display = 'none';
});

// Step 4: When user presses the submit button (broaden my horizons) we display 9 random songs out of those retrived.
// If the user keeps pressing submit he should get new songs from the same genre.
// If user changes genre the generate content will be hidden until he presses the button again
submit.addEventListener('click', (e) => {
e.preventDefault();
const sample = getRandomTen(songArray);
const sample_name = songNameArray(sample);
const sample_len = songLenArray(sample);
injectHTML(sample);
injectImages(sample);
document.getElementById('GeneratedContents').style.display = 'flex';

document.getElementById('Chartbox').style.display = 'block';

myChart.destroy();
myChart = initChart(sample_name, sample_len);

filter.addEventListener('click', (z) => {
z.preventDefault();
const filterData = myChart.data.datasets[0].data.filter((value) => value > 200000);

const filterLabels = [];
let i = 0;
for (i; i < filterData.length; i += 1) {
const result = myChart.data.datasets[0].data.indexOf(filterData[i]);
const label = myChart.data.labels[result];
filterLabels.push(label);
}
myChart.data.datasets[0].data = filterData;
myChart.data.labels = filterLabels;
myChart.update();
});
});
}

document.addEventListener('DOMContentLoaded', async () => init());
Loading