diff --git a/js/app.js b/js/app.js
deleted file mode 100644
index 8b93a3b..0000000
--- a/js/app.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-============================================
-Constants
-@example: https://github.com/S3ak/fed-javascript1-api-calls/blob/main/examples/games.html#L66
-============================================
-*/
-
-// TODO: Get DOM elements from the DOM
-
-/*
-============================================
-DOM manipulation
-@example: https://github.com/S3ak/fed-javascript1-api-calls/blob/main/examples/games.html#L89
-============================================
-*/
-
-// TODO: Fetch and Render the list to the DOM
-
-// TODO: Create event listeners for the filters and the search
-
-/**
- * TODO: Create an event listener to sort the list.
- * @example https://github.com/S3ak/fed-javascript1-api-calls/blob/main/examples/search-form.html#L91
- */
-
-/*
-============================================
-Data fectching
-@example: https://github.com/S3ak/fed-javascript1-api-calls/blob/main/examples/games.html#L104
-============================================
-*/
-
-// TODO: Fetch an array of objects from the API
-
-/*
-============================================
-Helper functions
-https://github.com/S3ak/fed-javascript1-api-calls/blob/main/examples/games.html#L154
-============================================
-*/
-
-/**
- * TODO: Create a function to filter the list of item.
- * @example https://github.com/S3ak/fed-javascript1-api-calls/blob/main/examples/search-form.html#L135
- * @param {item} item The object with properties from the fetched JSON data.
- * @param {searchTerm} searchTerm The string used to check if the object title contains it.
- */
-
-/**
- * TODO: Create a function to create a DOM element.
- * @example https://github.com/S3ak/fed-javascript1-api-calls/blob/main/src/js/detail.js#L36
- * @param {item} item The object with properties from the fetched JSON data.
- */
diff --git a/js/callback.js b/js/callback.js
new file mode 100644
index 0000000..a86c11d
--- /dev/null
+++ b/js/callback.js
@@ -0,0 +1,10 @@
+import { manageUserSessssion } from "./session.js";
+
+/*
+============================================
+Callback page specfic code
+============================================
+*/
+
+manageUserSessssion();
+window.location.replace("/index.html");
diff --git a/js/constants.js b/js/constants.js
new file mode 100644
index 0000000..26312b1
--- /dev/null
+++ b/js/constants.js
@@ -0,0 +1,128 @@
+export const GENRES = [
+ "acoustic",
+ "afrobeat",
+ "alt-rock",
+ "alternative",
+ "ambient",
+ "anime",
+ "black-metal",
+ "bluegrass",
+ "blues",
+ "bossanova",
+ "brazil",
+ "breakbeat",
+ "british",
+ "cantopop",
+ "chicago-house",
+ "children",
+ "chill",
+ "classical",
+ "club",
+ "comedy",
+ "country",
+ "dance",
+ "dancehall",
+ "death-metal",
+ "deep-house",
+ "detroit-techno",
+ "disco",
+ "disney",
+ "drum-and-bass",
+ "dub",
+ "dubstep",
+ "edm",
+ "electro",
+ "electronic",
+ "emo",
+ "folk",
+ "forro",
+ "french",
+ "funk",
+ "garage",
+ "german",
+ "gospel",
+ "goth",
+ "grindcore",
+ "groove",
+ "grunge",
+ "guitar",
+ "happy",
+ "hard-rock",
+ "hardcore",
+ "hardstyle",
+ "heavy-metal",
+ "hip-hop",
+ "holidays",
+ "honky-tonk",
+ "house",
+ "idm",
+ "indian",
+ "indie",
+ "indie-pop",
+ "industrial",
+ "iranian",
+ "j-dance",
+ "j-idol",
+ "j-pop",
+ "j-rock",
+ "jazz",
+ "k-pop",
+ "kids",
+ "latin",
+ "latino",
+ "malay",
+ "mandopop",
+ "metal",
+ "metal-misc",
+ "metalcore",
+ "minimal-techno",
+ "movies",
+ "mpb",
+ "new-age",
+ "new-release",
+ "opera",
+ "pagode",
+ "party",
+ "philippines-opm",
+ "piano",
+ "pop",
+ "pop-film",
+ "post-dubstep",
+ "power-pop",
+ "progressive-house",
+ "psych-rock",
+ "punk",
+ "punk-rock",
+ "r-n-b",
+ "rainy-day",
+ "reggae",
+ "reggaeton",
+ "road-trip",
+ "rock",
+ "rock-n-roll",
+ "rockabilly",
+ "romance",
+ "sad",
+ "salsa",
+ "samba",
+ "sertanejo",
+ "show-tunes",
+ "singer-songwriter",
+ "ska",
+ "sleep",
+ "songwriter",
+ "soul",
+ "soundtracks",
+ "spanish",
+ "study",
+ "summer",
+ "swedish",
+ "synth-pop",
+ "tango",
+ "techno",
+ "trance",
+ "trip-hop",
+ "turkish",
+ "work-out",
+ "world-music",
+];
diff --git a/js/helpers.js b/js/helpers.js
new file mode 100644
index 0000000..73acc66
--- /dev/null
+++ b/js/helpers.js
@@ -0,0 +1,31 @@
+/*
+============================================
+Helper functions
+https://github.com/S3ak/fed-javascript1-api-calls/blob/main/examples/games.html#L154
+============================================
+*/
+
+// TODO: Create a function that renders the playlists
+export function renderPlaylist({ title = "No title" }) {
+ return `
+
+
${title}
+
+ `;
+}
+
+export function hideProtectedContent(isLoggedIn) {
+ const protectedContent = document.querySelectorAll("[data-is-protected]");
+
+ if (isLoggedIn) {
+ protectedContent.forEach((content) => {
+ content.classList.remove("is-hidden");
+ });
+
+ return;
+ }
+
+ protectedContent.forEach((content) => {
+ content.classList.add("is-hidden");
+ });
+}
diff --git a/js/index.js b/js/index.js
new file mode 100644
index 0000000..33389a0
--- /dev/null
+++ b/js/index.js
@@ -0,0 +1,27 @@
+import { renderPlaylist } from "./helpers.js";
+
+import s from "../main.js";
+
+const playlistContainerEl = document.querySelector("#js-playlist-list");
+
+document.querySelector("#js-seach-form").addEventListener("submit", (event) => {
+ event.preventDefault();
+
+ const genre = event.target.querySelector("#genre").value;
+ s.searchPlaylists(genre)
+ .then((data) => {
+ const playlists = data.playlists.items;
+ console.log(playlists);
+
+ playlistContainerEl.innerHTML = "";
+
+ playlists.forEach((playlist) => {
+ playlistContainerEl.innerHTML += renderPlaylist({
+ title: playlist.name,
+ });
+ });
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+});
diff --git a/js/login.js b/js/login.js
new file mode 100644
index 0000000..80886f6
--- /dev/null
+++ b/js/login.js
@@ -0,0 +1,11 @@
+import { loginSpotifyUser } from "./session.js";
+
+/*
+============================================
+Login page specfic code
+============================================
+*/
+
+const loginBtnEl = document.querySelector("#js-login-btn");
+
+loginBtnEl.addEventListener("click", loginSpotifyUser);
diff --git a/js/randomize.js b/js/randomize.js
index 627b600..3bb5308 100644
--- a/js/randomize.js
+++ b/js/randomize.js
@@ -1,40 +1,96 @@
-import Spotify from "spotify-web-api-js";
-// import Spotify from "../node_modules/spotify-web-api-js/src/typings/spotify-web-api";
+import s from "../main.js";
+
+import { GENRES } from "./constants.js";
const generateBtn = document.querySelector("#js-gnrt-btn");
const resultHolder = document.querySelector("#js-res-holder");
-const yearInput = document.querySelector("#js-yr-input");
-console.log(resultHolder);
+// const resultHolder2 = document.querySelector("#js-res-holder-2");
+// const songPreview = document.querySelector("#js-iframe");
+const countryInp = document.querySelector("#js-country-input");
+const yearCalInput = document.querySelector("#js-yr-cal-input");
+const genreInput = document.querySelector("#js-genre-input");
+const genresList = document.querySelector("#js-genres-list");
+// const srchTypeInp = document.querySelector("#js-search-type-input");
+
+let selectedYear = "1950";
+let selectedGenre = "jazz";
+// let market = "NO";
+let srchQ = `year:${selectedYear} genre:${selectedGenre}`;
+// let srchQ = `isrc:${market} year:${selectedYear} genre:${selectedGenre}`;
+
+genresList.innerHTML = GENRES.map(
+ (genre) => `
`
+);
-generateBtn.addEventListener("click", () => {
- randomizer(yearInput.value);
+yearCalInput.addEventListener("change", (event) => {
+ selectedYear = event.target.value.substring(0, 4);
+ srchQ = `year:${selectedYear} genre:${selectedGenre}`;
});
-const accessToken = localStorage.getItem("access_token");
-console.log(accessToken);
+genreInput.addEventListener("change", (event) => {
+ selectedGenre = event.target.value;
+ srchQ = `isrc:JP year:${selectedYear} genre:${selectedGenre}`;
+});
-const dataBase = new Spotify();
-console.log(dataBase);
-// const accessToken = new URLSearchParams(
-// window.location.hash.replace("#", "")
-// ).get("access_token");
+// countryInp.addEventListener("change", (event) => {
+// market = event.target.value;
+// srchQ = `isrc:${market} year:${selectedYear} genre:${selectedGenre}`;
+// });
-// First get a list of songs from the country (Norway).
-// From the list pick a random song and get the id
-// get the song URI using the Id https://jmperezperez.com/spotify-web-api-js/#src-spotify-web-api.js-constr.prototype.gettrack
+generateBtn.addEventListener("click", getSong);
+
+const resultLmt = 50;
+// const searchType = ["track"];
+const optns = {
+ limit: resultLmt,
+ market: countryInp.value,
+ safeSearch: true,
+};
+
+function getSong() {
+ const randNum = Math.floor(Math.random() * (resultLmt - 1));
+
+ s.searchTracks(srchQ, optns).then((data) => {
+ console.log(data);
-function randomizer(yrInput = 0) {
- // randNum>> a random number between 0 and 19. replace 19 with response limit
- resultHolder.innerHTML = "";
- const randNum = Math.floor(Math.random() * 20);
- console.log(randNum);
- // Problem: the URI is unique for each song, so rand number wont work here.
- // we need to first get a catalog back and then use the rand number. but how?
- // dataBase.getCategories().then((tracks) => {
- // console.log(tracks);
+ if (data.tracks.items.length === 0) {
+ resultHolder.innerHTML = `
+
There were no ${selectedGenre} in ${selectedYear}'s
+
Please select another genre or year
+ `;
+ return;
+ }
+
+ const item = data.tracks.items[randNum];
+ const song = item.preview_url;
+ console.log(song);
+
+ console.log(item.album.images[0].url);
+
+ resultHolder.innerHTML = `
+
+
+
${item.name} - ${item.artists[0].name}
+
ID: ${randNum}
+
Open on Spotify
+ `;
+ });
+
+ // s.search(srchQ, searchType, optns).then((data) => {
+ // console.log(data);
+ // const item = data.tracks.items[randNum];
+
+ // resultHolder2.innerHTML = `
+ //
${item.name} - ${item.artists[0].name}
+ //
ID: ${randNum}
+ //
Open on Spotify
+ // `;
// });
- resultHolder.innerHTML = `
-
rand.nr: ${randNum}. Year input: ${yrInput}
- `;
- console.log(resultHolder);
}
+
+// First get a list of songs from the country (Norway).
+// From the list pick a random song and get the id
+// get the song URI using the Id https://jmperezperez.com/spotify-web-api-js/#src-spotify-web-api.js-constr.prototype.gettrack
+// https://api.spotify.com/v1/search?q=year:YEAR&type=track&limit=50&offset=OFFSET
diff --git a/js/session.js b/js/session.js
new file mode 100644
index 0000000..3848ff0
--- /dev/null
+++ b/js/session.js
@@ -0,0 +1,60 @@
+import { hideProtectedContent } from "./helpers.js";
+
+const ACCESS_TOKEN_KEY = "access_token";
+
+export const getAccessToken = () => {
+ let token = null;
+
+ const cachedAccessToken = localStorage.getItem(ACCESS_TOKEN_KEY);
+
+ const currentSessionToken = new URLSearchParams(
+ window.location.hash.replace("#", "")
+ ).get(ACCESS_TOKEN_KEY);
+
+ if (cachedAccessToken) {
+ token = cachedAccessToken;
+ }
+
+ if (currentSessionToken) {
+ localStorage.setItem(ACCESS_TOKEN_KEY, currentSessionToken);
+ window.location.hash = "";
+ token = currentSessionToken;
+ }
+
+ return token;
+};
+
+export const checkIfUserIsLoggedIn = () => !!getAccessToken();
+
+export const manageUserSessssion = () => {
+ const userIsLoggedIn = checkIfUserIsLoggedIn();
+
+ hideProtectedContent(userIsLoggedIn);
+
+ if (!userIsLoggedIn) {
+ window.location.href = "/login.html";
+ }
+};
+
+export async function loginSpotifyUser() {
+ // NOTE: We need to request authorization from the user to access their data.
+ const authUrl = new URL("https://accounts.spotify.com/authorize");
+
+ authUrl.searchParams.set("response_type", "token");
+ authUrl.searchParams.set("client_id", import.meta.env.VITE_CLIENT_ID);
+ authUrl.searchParams.set("redirect_uri", import.meta.env.VITE_CALLBACK_URL);
+ authUrl.searchParams.set("scope", "user-read-private user-read-email");
+ // REMOVE THIS IN PRODUCTION
+ authUrl.searchParams.set("show_dialog", "true");
+
+ try {
+ window.location.replace(authUrl);
+ } catch (error) {
+ console.log(error);
+ }
+}
+
+export function logOut() {
+ localStorage.removeItem(ACCESS_TOKEN_KEY);
+ window.location.replace("/login.html");
+}
diff --git a/login.html b/login.html
new file mode 100644
index 0000000..41bd549
--- /dev/null
+++ b/login.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
Bragi Mix | Login
+
+
+
+
+
+
+
+
+ Login into your Spotify
+
+
+
+
+
+
+
diff --git a/main.js b/main.js
index 70fc0ee..ebd54c3 100644
--- a/main.js
+++ b/main.js
@@ -1,95 +1,34 @@
import Spotify from "spotify-web-api-js";
-const playlistContainerEl = document.querySelector("#js-playlist-list");
-const loginContainerEl = document.querySelector("#js-login-holder");
-const randNavContainerEl = document.querySelector("#js-rand-nav-holder");
+import {
+ getAccessToken,
+ loginSpotifyUser,
+ logOut,
+ manageUserSessssion,
+} from "./js/session.js";
-// NOTE: We use this lib to create a Spotify instance.
+const loginBtnEl = document.querySelector("#js-login-btn");
+const logOutBtnEl = document.querySelector("#js-logout-btn");
+
+// NOTE: We use this lib to create a Spotify instance. It makes it easier to work with the Spotify API.
const s = new Spotify();
+manageUserSessssion();
+
// NOTE: We get the access token for the client from the callback URI issued when user logs into spotify.
-let cachedAccessToken = localStorage.getItem("access_token");
-const accessToken =
- cachedAccessToken ??
- new URLSearchParams(window.location.hash.replace("#", "")).get(
- "access_token"
- );
+// @alias accessToken
+const isLoggedIn = getAccessToken();
-if (accessToken) {
- cachedAccessToken = localStorage.setItem("access_token", accessToken);
+if (isLoggedIn) {
+ s.setAccessToken(isLoggedIn);
+ loginBtnEl.classList.add("is-hidden");
- s.setAccessToken(accessToken);
- loginContainerEl.classList.add("is-hidden");
- randNavContainerEl.innerHTML = `
-
randomizer
-
playlists
-
- `;
+ logOutBtnEl.addEventListener("click", logOut);
} else {
- loginContainerEl.classList.remove("is-hidden");
-}
-
-const randBtn = document.querySelector("#js-rand-btn");
-console.log(randBtn);
-
-// randBtn.addEventListener("click", () => {
-// randomizer();
-// });
-
-// TODO: Add event listener to login button only if user is not logged in
-document.querySelector("#js-login-btn").addEventListener("click", () => {
- // ???calling a function with a arg that is never used. func does not take an arg???
- loginSpotifyUser(s.setAccessToken);
-});
-
-document.querySelector("#js-seach-form").addEventListener("submit", (event) => {
- event.preventDefault();
+ loginBtnEl.classList.remove("is-hidden");
- const genre = event.target.querySelector("#genre").value;
- // s.searchPlaylists("NO", "market")
- s.searchPlaylists(genre)
- .then((data) => {
- const playlists = data.playlists.items;
- console.log(playlists);
- // console.log(data);
-
- playlistContainerEl.innerHTML = "";
-
- playlists.forEach((playlist) => {
- playlistContainerEl.innerHTML += renderPlaylist({
- title: playlist.name,
- });
- });
- })
- .catch((error) => {
- console.log(error);
- });
-});
-
-async function loginSpotifyUser() {
- // NOTE: We need to request authorization from the user to access their data.
- const authUrl = new URL("https://accounts.spotify.com/authorize");
-
- authUrl.searchParams.set("response_type", "token");
- authUrl.searchParams.set("client_id", import.meta.env.VITE_CLIENT_ID);
- authUrl.searchParams.set("redirect_uri", import.meta.env.VITE_CALLBACK_URL);
- authUrl.searchParams.set("scope", "user-read-private user-read-email");
- // REMOVE THIS IN PRODUCTION
- authUrl.searchParams.set("show_dialog", "true");
-
- try {
- window.location.replace(authUrl);
- } catch (error) {
- console.log(error);
- }
+ loginBtnEl.addEventListener("click", loginSpotifyUser);
}
-// TODO: Create a function that renders the playlists
-function renderPlaylist({ title = "No title" }) {
- return `
-
-
${title}
-
- `;
-}
+export default s;
diff --git a/randomizer.html b/randomizer.html
new file mode 100644
index 0000000..fb7be57
--- /dev/null
+++ b/randomizer.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
Bragi Mix | Randomizer
+
+
+
+
+
+
+
+
+
+