From 60f068226f2d906d59ceba0368d592a6b4659398 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Thu, 30 Jul 2020 11:21:25 -0400 Subject: [PATCH 01/11] likedMusicHistory initialize --- .../main/java/com/google/musicanalysis/site/YoutubeGenres.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java index 76374236..0e3abcfb 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java @@ -22,6 +22,7 @@ public class YoutubeGenres { public HashMap genreData = new HashMap(); public int totalMusic = 0; public int maxGenreCount = 0; + public int[] likedMusicHistory; public YoutubeGenres() { From cc80ea332b94adaa5f8407fbbca8a5dc6332bde0 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Thu, 30 Jul 2020 11:46:51 -0400 Subject: [PATCH 02/11] implemented likedMusicHistory --- .../google/musicanalysis/site/YoutubeGenres.java | 16 +++++++++++----- .../musicanalysis/site/YoutubeServlet.java | 4 +++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java index 0e3abcfb..8fe7dee4 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonArray; import com.google.gson.Gson; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.lang.Math; @@ -22,7 +23,7 @@ public class YoutubeGenres { public HashMap genreData = new HashMap(); public int totalMusic = 0; public int maxGenreCount = 0; - public int[] likedMusicHistory; + public ArrayList likedMusicHistory = new ArrayList(); public YoutubeGenres() { @@ -33,7 +34,7 @@ public YoutubeGenres() { * updates hash map to contain frequency count of each music genre * @param videos json array of youtube liked videos */ - protected void calculateMusicCount(JsonArray videos) { + protected int calculateMusicCount(int firstVideoCount, JsonArray videos) { for (int i = 0; i < videos.size(); i++) { JsonObject video = videos.get(i).getAsJsonObject(); JsonObject topicDetails = video.getAsJsonObject("topicDetails"); @@ -68,13 +69,18 @@ protected void calculateMusicCount(JsonArray videos) { continue; } } + if (isMusic) { + // likedMusicHistory records what video is music + likedMusicHistory.add(firstVideoCount + i); - if (isMusic && totalSubgenres == 0) { + if (totalSubgenres == 0) { // video only classified as Music so we update as "Other music" - this.updateGenre("Other music"); + this.updateGenre("Other music"); + } } + } - return; + return firstVideoCount + videos.size(); } /** diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java index cc7b3fc8..e8886376 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java @@ -96,6 +96,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) JsonObject likedVideoRes; JsonArray videos; YoutubeGenres genreAnalysis = new YoutubeGenres(); + int videosRetrieved = 0; // next Page Token must be an empty string for first http call String nextPageToken = ""; @@ -111,7 +112,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) } videos = likedVideoRes.getAsJsonArray("items"); - genreAnalysis.calculateMusicCount(videos); + videosRetrieved = + genreAnalysis.calculateMusicCount(videosRetrieved, videos); nextPageToken = getNextPageToken(likedVideoRes); } From d3dfb851c34292cad1181b5aa4d916058f334e70 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Thu, 30 Jul 2020 11:57:27 -0400 Subject: [PATCH 03/11] added comments --- client/js/genre.js | 1 + .../java/com/google/musicanalysis/site/YoutubeGenres.java | 8 ++++++-- .../com/google/musicanalysis/site/YoutubeServlet.java | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/client/js/genre.js b/client/js/genre.js index f9dffd51..360249ee 100644 --- a/client/js/genre.js +++ b/client/js/genre.js @@ -20,5 +20,6 @@ async function displayMusicGenre() { const genreCount = await response.text(); genreBlock.innerHTML = genreCount; + console.log(JSON.parse(genreCount)); } diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java index 8fe7dee4..e9a6c62f 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java @@ -23,6 +23,8 @@ public class YoutubeGenres { public HashMap genreData = new HashMap(); public int totalMusic = 0; public int maxGenreCount = 0; + // element of value x means xth latest video is music + // needed for heat map public ArrayList likedMusicHistory = new ArrayList(); public YoutubeGenres() { @@ -32,7 +34,9 @@ public YoutubeGenres() { /** * parses through youtube liked videos json array, * updates hash map to contain frequency count of each music genre + * @param firstVideoCount the number of videos retrieved before this http call * @param videos json array of youtube liked videos + * @return number of videos retrieved so far */ protected int calculateMusicCount(int firstVideoCount, JsonArray videos) { for (int i = 0; i < videos.size(); i++) { @@ -69,8 +73,9 @@ protected int calculateMusicCount(int firstVideoCount, JsonArray videos) { continue; } } + if (isMusic) { - // likedMusicHistory records what video is music + // likedMusicHistory records video numbers that are music likedMusicHistory.add(firstVideoCount + i); if (totalSubgenres == 0) { @@ -78,7 +83,6 @@ protected int calculateMusicCount(int firstVideoCount, JsonArray videos) { this.updateGenre("Other music"); } } - } return firstVideoCount + videos.size(); } diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java index e8886376..1bafd6f3 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java @@ -96,6 +96,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) JsonObject likedVideoRes; JsonArray videos; YoutubeGenres genreAnalysis = new YoutubeGenres(); + // needed to keep track of likedMusicHistory for heat map int videosRetrieved = 0; // next Page Token must be an empty string for first http call @@ -112,8 +113,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) } videos = likedVideoRes.getAsJsonArray("items"); - videosRetrieved = - genreAnalysis.calculateMusicCount(videosRetrieved, videos); + videosRetrieved = genreAnalysis + .calculateMusicCount(videosRetrieved, videos); nextPageToken = getNextPageToken(likedVideoRes); } From 9c7c25a514c17b7ae3f75a52b9cb447ec852f8bb Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Thu, 30 Jul 2020 13:01:23 -0400 Subject: [PATCH 04/11] got rid of console.log --- client/js/genre.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/js/genre.js b/client/js/genre.js index 360249ee..f9dffd51 100644 --- a/client/js/genre.js +++ b/client/js/genre.js @@ -20,6 +20,5 @@ async function displayMusicGenre() { const genreCount = await response.text(); genreBlock.innerHTML = genreCount; - console.log(JSON.parse(genreCount)); } From c9f12b4b250200378f16cf801bb6e6ffac2185c9 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Thu, 30 Jul 2020 13:32:48 -0400 Subject: [PATCH 05/11] deleted console.log --- client/js/genre.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/js/genre.js b/client/js/genre.js index f9dffd51..44426f89 100644 --- a/client/js/genre.js +++ b/client/js/genre.js @@ -21,4 +21,3 @@ async function displayMusicGenre() { const genreCount = await response.text(); genreBlock.innerHTML = genreCount; } - From b1f603e90202615da8a83b3e153d099a9aae5e05 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Thu, 30 Jul 2020 21:06:29 -0400 Subject: [PATCH 06/11] merge with master --- client/css/bar.css | 60 ++++++++++++++++++++++++++++++++++++++++++++ client/js/bar.js | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 client/css/bar.css create mode 100644 client/js/bar.js diff --git a/client/css/bar.css b/client/css/bar.css new file mode 100644 index 00000000..484961f3 --- /dev/null +++ b/client/css/bar.css @@ -0,0 +1,60 @@ +.hero { + display: grid; + align-content: center; + justify-items: center; + width: 100%; /* don't use 100vw, that will cause horizontal scrollbar */ + height: 100vh; +} + +.svg { + width: 100%; + height: 100%; +} + +#vis { + display: flex; + align-items: stretch; + width: 50vh; + + height: 60vh; + margin-left: 0; + + background-color: #222425; +} + +#graph { + display: inline-block; + width: 70%; +} + +.bar { + cursor: pointer; + + transition: fill .3s ease; + + fill: var(--color-accent-primary-2); +} + +.bar:hover, .bar:focus { + fill: var(--color-accent-special); +} + +#bar-text { + display: flex; + flex-flow: column nowrap; + width: 25%; + height: 100%; + + text-align: right; + vertical-align: top; +} + +.category { + display: flex; + flex-basis: 0; + flex-direction: column; + flex-grow: 1; + justify-content: center; + + text-align: right; +} diff --git a/client/js/bar.js b/client/js/bar.js new file mode 100644 index 00000000..9b6f2f2b --- /dev/null +++ b/client/js/bar.js @@ -0,0 +1,62 @@ +/** + * @file constructs bar graph from scratch + */ + +// hard coded data for bar chart for now +const CHART_VALUES = [1, 3, 1, 2]; +const CHART_CATEGORIES = [ + 'Pop Music', + 'Other Music', + 'Electronic Music', + 'Music of Latin America', +]; + +const GRAPH_HEIGHT = 100; +// each bar container is composed of bar padding and fill +const BAR_PERCENT_FILL = 0.7; +const BAR_PERCENT_PADDING = 1 - BAR_PERCENT_FILL; + +const GRAPH_LEFT_PADDING = 2.5; + +/** + * creates SVG bar chart given chart values and categories + * @param {number[]} chartValues array of bar values/lengths + * @param {string[]} chartCategories array of bar categories/labels + */ +function createBarChart(chartValues, chartCategories) { + const maxChartValues = Math.max(...chartValues); + const barContainerHeight = GRAPH_HEIGHT / chartValues.length; + + const barThickness = BAR_PERCENT_FILL * barContainerHeight; + const barUnitLength = 100 / maxChartValues; + + // top graph padding depends on bar padding + const graphTopPadding = (BAR_PERCENT_PADDING / 2) * barContainerHeight; + + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svg.setAttribute('viewBox', '0 0 100 100'); + svg.setAttribute('preserveAspectRatio', 'none'); + svg.setAttribute('class', 'svg'); + document.getElementById('graph').appendChild(svg); + + for (let i = 0; i < chartValues.length; i++) { + const g = document.createElementNS('http://www.w3.org/2000/svg', 'g'); + svg.appendChild(g); + g.setAttribute('class', 'bar'); + + const bar = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); + g.appendChild(bar); + bar.setAttribute('width', barUnitLength * chartValues[i]); + bar.setAttribute('height', barThickness); + bar.setAttribute('x', GRAPH_LEFT_PADDING); + bar.setAttribute('y', graphTopPadding + barContainerHeight * i); + + const barTextContainer = document.getElementById('bar-text'); + const category = document.createElement('div'); + barTextContainer.appendChild(category); + category.setAttribute('class', 'category'); + category.textContent = chartCategories[i]; + } +} + +createBarChart(CHART_VALUES, CHART_CATEGORIES); From 4734a3e437b26ced7b0121d0af1617f9d452fe72 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Mon, 3 Aug 2020 15:52:58 -0400 Subject: [PATCH 07/11] changes to js/html to retrieve json --- client/js/genre.js | 3 ++- client/youtube-genre.html | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client/js/genre.js b/client/js/genre.js index 44426f89..f9c790cd 100644 --- a/client/js/genre.js +++ b/client/js/genre.js @@ -3,12 +3,13 @@ * and displays on youtube-genre.html */ -const genreBlock = document.getElementById('genres'); /** * fetches genre count hashmap from /api/youtube and updates html */ async function displayMusicGenre() { + const genreBlock = document.getElementById('genres'); + // keep track of num_videos in URL w/o reload history.pushState('', '', `youtube-genre.html`); diff --git a/client/youtube-genre.html b/client/youtube-genre.html index c7d4cb87..2efa59b4 100644 --- a/client/youtube-genre.html +++ b/client/youtube-genre.html @@ -15,6 +15,7 @@

What music do you listen to on youtube?

+
From 2ea7481d657d6171324984eff8ea4879ebff24e9 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Mon, 3 Aug 2020 16:21:52 -0400 Subject: [PATCH 08/11] added comments --- .../com/google/musicanalysis/site/YoutubeGenres.java | 11 ++++++----- .../com/google/musicanalysis/site/YoutubeServlet.java | 6 ++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java index e9a6c62f..bc0a632a 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeGenres.java @@ -34,12 +34,13 @@ public YoutubeGenres() { /** * parses through youtube liked videos json array, * updates hash map to contain frequency count of each music genre - * @param firstVideoCount the number of videos retrieved before this http call * @param videos json array of youtube liked videos - * @return number of videos retrieved so far + * @param firstVideoCount the number of videos retrieved before this http call + * @return number of videos retrieved in this call */ - protected int calculateMusicCount(int firstVideoCount, JsonArray videos) { - for (int i = 0; i < videos.size(); i++) { + protected int calculateMusicCount(JsonArray videos, int firstVideoCount) { + int videosSize = videos.size(); + for (int i = 0; i < videosSize; i++) { JsonObject video = videos.get(i).getAsJsonObject(); JsonObject topicDetails = video.getAsJsonObject("topicDetails"); @@ -84,7 +85,7 @@ protected int calculateMusicCount(int firstVideoCount, JsonArray videos) { } } } - return firstVideoCount + videos.size(); + return videosSize; } /** diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java index 1bafd6f3..d1a5f541 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java @@ -101,6 +101,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) // next Page Token must be an empty string for first http call String nextPageToken = ""; + // make multiple calls to youtube API. A page token determines each call while (nextPageToken != null) { youtubeResBody = getYoutubeRes(API_KEY, accessToken.toString(), @@ -113,8 +114,9 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) } videos = likedVideoRes.getAsJsonArray("items"); - videosRetrieved = genreAnalysis - .calculateMusicCount(videosRetrieved, videos); + // videosRetrieved keeps track of music video order in calculateMusicCount + videosRetrieved += genreAnalysis + .calculateMusicCount(videos, videosRetrieved); nextPageToken = getNextPageToken(likedVideoRes); } From 44c8c52226e2cfa85a8bf1778910b52ed362b657 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Mon, 3 Aug 2020 16:24:27 -0400 Subject: [PATCH 09/11] added comments --- .../java/com/google/musicanalysis/site/YoutubeServlet.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java index d1a5f541..37ecbcfd 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java @@ -101,7 +101,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) // next Page Token must be an empty string for first http call String nextPageToken = ""; - // make multiple calls to youtube API. A page token determines each call + // Make multiple paginated calls to youtube API. + // Each call has a new page token while (nextPageToken != null) { youtubeResBody = getYoutubeRes(API_KEY, accessToken.toString(), From 41b45e0165391e1931bf4dee30fb2782bdb4d185 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Mon, 3 Aug 2020 16:28:28 -0400 Subject: [PATCH 10/11] modified videosRetrieved comment for clarity --- .../main/java/com/google/musicanalysis/site/YoutubeServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java index 37ecbcfd..b61536b4 100644 --- a/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java +++ b/server/src/main/java/com/google/musicanalysis/site/YoutubeServlet.java @@ -115,7 +115,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) } videos = likedVideoRes.getAsJsonArray("items"); - // videosRetrieved keeps track of music video order in calculateMusicCount + // videosRetrieved keeps track of music video order in genreAnalysis videosRetrieved += genreAnalysis .calculateMusicCount(videos, videosRetrieved); From f024c16659b4190ca71ff49228b3489ebfb2df39 Mon Sep 17 00:00:00 2001 From: Grace Tian Date: Thu, 6 Aug 2020 15:21:12 -0400 Subject: [PATCH 11/11] delete num videos comment --- client/js/genre.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/js/genre.js b/client/js/genre.js index f9c790cd..37c53a87 100644 --- a/client/js/genre.js +++ b/client/js/genre.js @@ -10,9 +10,6 @@ async function displayMusicGenre() { const genreBlock = document.getElementById('genres'); - // keep track of num_videos in URL w/o reload - history.pushState('', '', `youtube-genre.html`); - const response = await fetch(`/api/youtube`); if (response.status == 401) { // no oauth login so redirect to new page