diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml index c7ecf9f2..c3868c4f 100644 --- a/.idea/dataSources.local.xml +++ b/.idea/dataSources.local.xml @@ -1,6 +1,6 @@ - + #@ diff --git a/MovieVerse-Frontend/js/favorites.js b/MovieVerse-Frontend/js/favorites.js index 44af428a..d3841f0a 100644 --- a/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Frontend/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); diff --git a/MovieVerse-Frontend/js/movie-timeline.js b/MovieVerse-Frontend/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Frontend/js/movie-timeline.js +++ b/MovieVerse-Frontend/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Frontend/js/search.js b/MovieVerse-Frontend/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Frontend/js/search.js +++ b/MovieVerse-Frontend/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/.idea/caches/deviceStreaming.xml b/MovieVerse-Mobile/.idea/caches/deviceStreaming.xml index af74dbfd..5a2f8669 100644 --- a/MovieVerse-Mobile/.idea/caches/deviceStreaming.xml +++ b/MovieVerse-Mobile/.idea/caches/deviceStreaming.xml @@ -25,6 +25,17 @@ diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js index 44af428a..d3841f0a 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-timeline.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-timeline.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/search.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/search.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/about.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/about.js new file mode 100644 index 00000000..916bbac0 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/about.js @@ -0,0 +1,336 @@ +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/actor-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/actor-details.js new file mode 100644 index 00000000..b3d7fe24 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/actor-details.js @@ -0,0 +1,824 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +let initialMainContent = ''; + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + currentIndex = 0; + + const actorId = localStorage.getItem('selectedActorId'); + if (actorId) { + fetchActorDetails(actorId); + } else { + fetchActorDetails(2037); + } +}); + +async function fetchActorDetails(actorId) { + showSpinner(); + const actorUrl = `https://${getMovieVerseData()}/3/person/${actorId}?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/${actorId}/movie_credits?${generateMovieNames()}${getMovieCode()}`; + + try { + const [actorResponse, creditsResponse] = await Promise.all([fetch(actorUrl), fetch(creditsUrl)]); + + const actor = await actorResponse.json(); + const credits = await creditsResponse.json(); + if (actor.success === false) { + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details currently unavailable - please try again

+
`; + } else { + updateBrowserURL(actor.name); + populateActorDetails(actor, credits); + } + hideSpinner(); + } catch (error) { + console.log('Error fetching actor details:', error); + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details currently unavailable - please try again

+
`; + hideSpinner(); + } +} + +async function populateActorDetails(actor, credits) { + const actorImage = document.getElementById('actor-image'); + const actorName = document.getElementById('actor-name'); + const actorDescription = document.getElementById('actor-description'); + + if (actor.profile_path) { + actorImage.src = `https://image.tmdb.org/t/p/w1280${actor.profile_path}`; + actorName.textContent = actor.name; + document.title = `${actor.name} - Actor's Details`; + } else { + actorImage.style.display = 'none'; + actorName.textContent = actor.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.actor-left').appendChild(noImageText); + } + + let ageOrStatus; + if (actor.birthday) { + if (actor.deathday) { + ageOrStatus = calculateAge(actor.birthday, actor.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(actor.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + actorDescription.innerHTML = ` +

Biography: ${actor.biography || 'Information Unavailable'}

+

Also Known As: ${actor.also_known_as.join(', ') || 'Information Unavailable'}

+

Date of Birth: ${actor.birthday || 'Information Unavailable'}

+

Date of Death: ${actor.deathday || 'Information Unavailable'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${actor.place_of_birth || 'Information Unavailable'}

+

Known For: ${actor.known_for_department || 'Information Unavailable'}

+

Height: ${actor.height || 'Information Unavailable'}

+ `; + + const gender = document.createElement('div'); + gender.innerHTML = `

Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'Information Unavailable'}

`; + actorDescription.appendChild(gender); + + const popularity = document.createElement('div'); + popularity.innerHTML = `

Popularity Score: ${actor.popularity.toFixed(2)}

`; + actorDescription.appendChild(popularity); + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + actorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + movieList.style.display = 'flex'; + movieList.style.flexWrap = 'wrap'; + movieList.style.justifyContent = 'center'; + movieList.style.gap = '5px'; + + let filmsToDisplay = credits.cast; + filmsToDisplay = filmsToDisplay.sort((a, b) => b.popularity - a.popularity); + + filmsToDisplay.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + movieList.appendChild(movieLink); + + if (index < credits.cast.length - 1) { + movieList.appendChild(document.createTextNode('')); + } + }); + + filmographyHeading.appendChild(movieList); + + const mediaUrl = `https://${getMovieVerseData()}/3/person/${actor.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + const detailsContainer = document.getElementById('actor-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + const imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + applySettings(); +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +function calculateAge(birthday, deathday = null) { + const birthDate = new Date(birthday); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const diff = referenceDate - birthDate.getTime(); + const ageDate = new Date(diff); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + applySettings(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/add-to-favorites.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/add-to-favorites.js new file mode 100644 index 00000000..eae22b78 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/add-to-favorites.js @@ -0,0 +1,252 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + query, + where, + getDocs, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function checkAndUpdateFavoriteButton() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const movieId = localStorage.getItem('selectedMovieId'); + + if (!movieId) { + console.log('Movie ID is missing'); + return; + } + + try { + if (!userEmail) { + console.log('User is not signed in. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + if (querySnapshot.empty) { + console.log('No user found with that email'); + return; + } + + const userData = querySnapshot.docs[0].data(); + const favorites = userData.favoritesMovies || []; + + updateFavoriteButton(movieId, favorites); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + } else { + console.error('An error occurred:', error); + } + } +} + +function updateFavoriteButton(movieId, favorites) { + const favoriteButton = document.getElementById('favorite-btn'); + + if (favorites.includes(movieId)) { + favoriteButton.classList.add('favorited'); + favoriteButton.style.backgroundColor = 'grey'; + favoriteButton.title = 'Remove from favorites'; + } else { + favoriteButton.classList.remove('favorited'); + favoriteButton.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + favoriteButton.title = 'Add to favorites'; + } +} + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +async function getMovieGenre(movieId) { + const tmdbUrl = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(tmdbUrl); + const movieData = await response.json(); + return movieData.genres.length > 0 ? movieData.genres[0].name : 'Unknown'; +} + +export async function toggleFavorite() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const movieId = localStorage.getItem('selectedMovieId'); + + if (!movieId) { + console.log('Movie ID is missing'); + return; + } + + const movieGenre = await getMovieGenre(movieId); + + try { + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + let userDocRef; + + if (querySnapshot.empty && userEmail === '') { + const newUserRef = doc(collection(db, 'MovieVerseUsers')); + userDocRef = newUserRef; + await setDoc(newUserRef, { + email: userEmail, + favoritesMovies: [movieId], + }); + console.log('New user created with favorite movie.'); + } else if (!querySnapshot.empty) { + userDocRef = doc(db, 'MovieVerseUsers', querySnapshot.docs[0].id); + } else { + console.log('No user found with that email and user is supposed to be signed in.'); + return; + } + + if (userDocRef) { + const userData = querySnapshot.empty ? { favoritesMovies: [] } : querySnapshot.docs[0].data(); + let favoritesMovies = userData.favoritesMovies || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + await updateDoc(userDocRef, { favoritesMovies }); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in Firestore'); + } + + updateMoviesFavorited(movieId); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; + } else { + console.error('An error occurred:', error); + } + + updateMoviesFavorited(movieId); + } + window.location.reload(); +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js new file mode 100644 index 00000000..704efa91 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js @@ -0,0 +1,169 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + query, + where, + getDocs, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function toggleFavoriteTVSeries() { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } + + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + await checkAndUpdateFavoriteButtonTVSeries(); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + let userDocRef; + if (querySnapshot.empty) { + console.log('Signed-in user does not have a Firestore document.'); + return; + } else { + userDocRef = doc(db, 'MovieVerseUsers', querySnapshot.docs[0].id); + } + + const userData = querySnapshot.docs[0].data(); + let favoritesTVSeries = userData.favoritesTVSeries || []; + + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + + await updateDoc(userDocRef, { favoritesTVSeries }); + console.log('Favorites TV Series updated successfully in Firestore'); + await checkAndUpdateFavoriteButtonTVSeries(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + } else { + console.error('An error occurred:', error); + } + window.location.reload(); + } +} + +export async function checkAndUpdateFavoriteButtonTVSeries() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } + + let favoritesTVSeries = []; + + if (userEmail) { + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + if (!querySnapshot.empty) { + const userData = querySnapshot.docs[0].data(); + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); + } else { + console.error('An error occurred:', error); + } + } +} + +function updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries) { + const favoriteBtn = document.getElementById('favorite-btn'); + + if (favoritesTVSeries.includes(tvSeriesId)) { + favoriteBtn.classList.add('favorited'); + favoriteBtn.title = 'Remove from Favorites'; + favoriteBtn.style.backgroundColor = 'grey'; + } else { + favoriteBtn.classList.remove('favorited'); + favoriteBtn.title = 'Add to Favorites'; + favoriteBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + } +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/analytics.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/analytics.js new file mode 100644 index 00000000..f8e4b2dd --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/analytics.js @@ -0,0 +1,867 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const string = `${getMovieCode()}`; + +async function fetchData(url) { + try { + const response = await fetch(url); + return await response.json(); + } catch (error) { + console.log('Error fetching data:', error); + return null; + } +} + +function createChart(canvasId, chartType, data, options = {}) { + const ctx = document.getElementById(canvasId).getContext('2d'); + new Chart(ctx, { + type: chartType, + data: data, + options: options, + }); +} + +async function loadMoviesByYearChart() { + showSpinner(); + const years = []; + const movieCounts = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + movieCounts.push(response.total_results); + } + + createChart('chart1', 'line', { + labels: years, + datasets: [ + { + label: 'Number of Movies Released', + data: movieCounts, + backgroundColor: 'rgba(0,148,255,1)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadGenrePopularityChart() { + showSpinner(); + const genresResponse = await fetchData(`${BASE_URL}/genre/movie/list?${generateMovieNames()}=${string}`); + const genres = genresResponse.genres; + + const genreNames = []; + const genrePopularity = []; + + for (const genre of genres) { + genreNames.push(genre.name); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_genres=${genre.id}`); + genrePopularity.push(response.results.reduce((acc, movie) => acc + movie.popularity, 0) / response.results.length); + } + + createChart('chart2', 'bar', { + labels: genreNames, + datasets: [ + { + label: 'Average Popularity', + data: genrePopularity, + backgroundColor: 'rgba(255, 99, 132, 1)', + borderColor: 'rgba(255, 99, 132, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMoviesByCertificationChart() { + showSpinner(); + const certifications = ['G', 'PG', 'PG-13', 'R']; + const movieCounts = []; + + for (const certification of certifications) { + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&certification_country=US&certification=${certification}` + ); + movieCounts.push(response.total_results); + } + + createChart('chart3', 'bar', { + labels: certifications, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(75, 192, 192, 1)', + borderColor: 'rgba(75, 192, 192, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadAveragePopularityChart() { + showSpinner(); + const years = []; + const averagePopularity = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 4; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + const totalPopularity = response.results.reduce((sum, movie) => sum + movie.popularity, 0); + averagePopularity.push(totalPopularity / response.results.length); + } + + createChart('chart4', 'line', { + labels: years, + datasets: [ + { + label: 'Average Popularity', + data: averagePopularity, + backgroundColor: 'rgba(255, 159, 64, 1)', + borderColor: 'rgba(255, 159, 64, 1)', + borderWidth: 1, + }, + ], + }); + showSpinner(); +} + +Chart.defaults.color = 'black'; +Chart.defaults.scale.grid.borderColor = 'black'; + +async function loadMoviesByLanguageChart() { + showSpinner(); + const languages = ['en', 'es', 'fr', 'de', 'it']; + const movieCounts = []; + + for (const language of languages) { + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_original_language=${language}`); + movieCounts.push(response.total_results); + } + + createChart('chart5', 'bar', { + labels: languages.map(lang => lang.toUpperCase()), + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(153, 102, 255, 1)', + borderColor: 'rgba(153, 102, 255, 1)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + }, + }); + + hideSpinner(); +} + +async function loadVoteCountByGenreChart() { + showSpinner(); + const genreResponse = await fetchData(`${BASE_URL}/genre/movie/list?${generateMovieNames()}=${string}`); + const genres = genreResponse.genres.slice(0, 5); + const genreNames = []; + const averageVoteCounts = []; + + for (const genre of genres) { + genreNames.push(genre.name); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_genres=${genre.id}`); + const totalVotes = response.results.reduce((sum, movie) => sum + movie.vote_count, 0); + averageVoteCounts.push(totalVotes / response.results.length); + } + + createChart('chart6', 'bar', { + labels: genreNames, + datasets: [ + { + label: 'Average Vote Count', + data: averageVoteCounts, + backgroundColor: 'rgba(255, 206, 86, 1)', + borderColor: 'rgba(255, 206, 86, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMovieReleaseDatesByMonthChart() { + showSpinner(); + const months = Array.from({ length: 12 }, (_, i) => new Date(0, i).toLocaleString('en', { month: 'long' })); + const movieCounts = Array(12).fill(0); + const currentYear = new Date().getFullYear(); + + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${currentYear}`); + response.results.forEach(movie => { + const releaseDate = new Date(movie.release_date); + movieCounts[releaseDate.getMonth()]++; + }); + + createChart('chart7', 'bar', { + labels: months, + datasets: [ + { + label: 'Movies Released', + data: movieCounts, + backgroundColor: 'rgba(123, 239, 178, 1)', + borderColor: 'rgba(123, 239, 178, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMoviesByDecadeChart() { + showSpinner(); + const decades = ['1980s', '1990s', '2000s', '2010s', '2020s']; + const decadeStartYears = [1980, 1990, 2000, 2010, 2020]; + const movieCounts = []; + + for (const startYear of decadeStartYears) { + const endYear = startYear + 9; + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31` + ); + movieCounts.push(response.total_results); + } + + createChart('chart8', 'bar', { + labels: decades, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgb(255,0,0)', + borderColor: 'rgb(255,0,0)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + ticks: { + color: 'black', + }, + }, + y: { + ticks: { + color: 'black', + }, + }, + }, + plugins: { + legend: { + position: 'right', + labels: { + color: 'black', + }, + }, + }, + }, + }); + + hideSpinner(); +} + +async function loadMoviesByProductionCountriesChart() { + showSpinner(); + const countries = ['US', 'GB', 'CA', 'FR', 'DE']; + const countryNames = ['USA', 'UK', 'Canada', 'France', 'Germany']; + const movieCounts = []; + + for (const country of countries) { + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_original_language=en®ion=${country}`); + movieCounts.push(response.total_results); + } + + createChart('chart9', 'bar', { + labels: countryNames, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(0,32,255,0.75)', + borderColor: 'rgb(0,21,255)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + ticks: { + color: 'black', + }, + }, + y: { + ticks: { + color: 'black', + }, + }, + }, + plugins: { + legend: { + position: 'right', + labels: { + color: 'black', + }, + }, + }, + }, + }); + + hideSpinner(); +} + +async function loadTopRatedMoviesPerYearChart() { + const years = []; + const topMovies = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&sort_by=vote_average.desc&vote_count.gte=100` + ); + if (response.results.length > 0) { + topMovies.push(response.results[0].vote_average); + } else { + topMovies.push(0); + } + } + + createChart('chart11', 'bar', { + labels: years, + datasets: [ + { + label: 'Top Rated Movie Score', + data: topMovies, + backgroundColor: 'rgba(255, 159, 64, 1)', + borderColor: 'rgba(255, 159, 64, 1)', + borderWidth: 1, + }, + ], + }); +} + +async function loadTotalMovieVotesOverYearsChart() { + const years = []; + const totalVoteCounts = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + const yearlyTotalVotes = response.results.reduce((sum, movie) => sum + movie.vote_count, 0); + totalVoteCounts.push(yearlyTotalVotes); + } + + createChart('chartVotesOverYears', 'line', { + labels: years, + datasets: [ + { + label: 'Total Movie Votes', + data: totalVoteCounts, + backgroundColor: 'rgba(255, 193, 7, 1)', + borderColor: 'rgba(255, 193, 7, 1)', + borderWidth: 1, + }, + ], + }); +} + +async function loadHighlyRatedMoviesOverYearsChart() { + const years = []; + const highRatedMovieCounts = []; + const currentYear = new Date().getFullYear(); + const startYear = currentYear - 10; + + for (let year = startYear; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&vote_average.gte=8`); + highRatedMovieCounts.push(response.total_results); + } + + createChart('chartHighlyRatedMovies', 'line', { + labels: years, + datasets: [ + { + label: 'Highly Rated Movies (Rating >= 8)', + data: highRatedMovieCounts, + backgroundColor: 'rgba(0, 206, 209, 1)', + borderColor: 'rgba(0, 206, 209, 1)', + borderWidth: 1, + }, + ], + }); +} + +function loadAllCharts() { + showSpinner(); + loadMoviesByYearChart(); + loadGenrePopularityChart(); + loadMoviesByCertificationChart(); + loadAveragePopularityChart(); + loadMoviesByLanguageChart(); + loadVoteCountByGenreChart(); + loadMovieReleaseDatesByMonthChart(); + loadMoviesByDecadeChart(); + loadMoviesByProductionCountriesChart(); + loadTopRatedMoviesPerYearChart(); + loadTotalMovieVotesOverYearsChart(); + loadHighlyRatedMoviesOverYearsChart(); + hideSpinner(); +} + +document.addEventListener('DOMContentLoaded', loadAllCharts); + +const BASE_URL = `https://${getMovieVerseData()}/3`; + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}=${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.png'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +document.getElementById('chart-title1').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title1').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title2').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title3').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title4').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title4').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title5').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title5').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title6').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title6').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title7').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title7').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title8').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title8').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title9').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title9').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title11').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title11').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title10').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title10').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title12').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title12').scrollIntoView({ behavior: 'smooth' }); +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chat-auxiliary.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chat-auxiliary.js new file mode 100644 index 00000000..165d6e5b --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chat-auxiliary.js @@ -0,0 +1,268 @@ +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chat.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chat.js new file mode 100644 index 00000000..b3a0da63 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chat.js @@ -0,0 +1,496 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + collection, + addDoc, + doc, + startAfter, + getDocs, + query, + where, + orderBy, + onSnapshot, + documentId, + serverTimestamp, + limit, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +document.addEventListener('DOMContentLoaded', () => { + const mainElement = document.getElementById('main'); + const isLoggedIn = localStorage.getItem('isSignedIn'); + + if (!isLoggedIn || isLoggedIn !== 'true') { + mainElement.style.display = 'none'; + + const signInMessage = document.createElement('div'); + signInMessage.innerHTML = '

You must be signed in to access MovieVerse chat services.

'; + signInMessage.style.display = 'flex'; + signInMessage.style.justifyContent = 'center'; + signInMessage.style.alignItems = 'center'; + signInMessage.style.height = '100vh'; + signInMessage.style.borderRadius = '12px'; + signInMessage.style.margin = '10px auto'; + signInMessage.style.marginRight = '20px'; + signInMessage.style.marginLeft = '20px'; + signInMessage.style.marginBottom = '20px'; + signInMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'; + document.getElementById('footer').style.display = 'none'; + + const adContainer2 = document.getElementById('ad-container2'); + if (adContainer2) { + document.body.insertBefore(signInMessage, adContainer2); + } else { + document.body.appendChild(signInMessage); + } + } else { + mainElement.style.display = ''; + loadUserList(); + setupSearchListeners(); + } +}); + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +initializeApp(firebaseConfig); +const db = getFirestore(); + +const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); +let selectedUserEmail = null; + +const messagesDiv = document.getElementById('messages'); +const userListDiv = document.getElementById('userList'); +const messageInput = document.getElementById('messageInput'); +const sendButton = document.getElementById('sendButton'); + +sendButton.addEventListener('click', async () => { + const text = messageInput.value.trim(); + if (text && selectedUserEmail) { + try { + await addDoc(collection(db, 'messages'), { + sender: currentUserEmail, + recipient: selectedUserEmail, + message: text, + timestamp: serverTimestamp(), + readBy: [currentUserEmail], + }); + messageInput.value = ''; + + const userElement = document.querySelector(`.user[data-email="${selectedUserEmail}"]`); + + if (!userElement) { + const newUserElement = await createUserElement(selectedUserEmail); + userListDiv.prepend(newUserElement); + selectUser(newUserElement); + } else { + userListDiv.prepend(userElement); + selectUser(userElement); + } + } catch (error) { + console.error('Error adding message: ', error); + } + } +}); + +async function createUserElement(email) { + const userElement = document.createElement('div'); + userElement.classList.add('user'); + userElement.setAttribute('data-email', email); + userElement.addEventListener('click', () => loadMessages(email)); + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '50px'; + img.style.borderRadius = '25px'; + img.style.marginRight = '10px'; + userElement.appendChild(img); + + const emailDiv = document.createElement('div'); + emailDiv.textContent = email; + userElement.appendChild(emailDiv); + + return userElement; +} + +function selectUser(userElement) { + if (previouslySelectedUserElement) { + previouslySelectedUserElement.classList.remove('selected'); + previouslySelectedUserElement.style.backgroundColor = ''; + } + userElement.classList.add('selected'); + userElement.style.backgroundColor = '#ff8623'; + previouslySelectedUserElement = userElement; +} + +document.getElementById('messageInput').addEventListener('keydown', function (event) { + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault(); + sendButton.click(); + } +}); + +function formatMessage(message, isCurrentUser, timestamp) { + const messageElement = document.createElement('div'); + messageElement.classList.add('message'); + messageElement.textContent = isCurrentUser ? `You: ${message}` : `${selectedUserEmail}: ${message}`; + + if (timestamp && timestamp.toDate) { + messageElement.dataset.timestamp = timestamp.toDate().toISOString(); + } else { + console.log('Timestamp is not in the expected format:', timestamp); + messageElement.dataset.timestamp = 'Unknown time'; + } + + messageElement.classList.add(isCurrentUser ? 'my-message' : 'other-message'); + messageElement.addEventListener('mouseover', showTooltip); + messageElement.addEventListener('click', showTooltip); + + return messageElement; +} + +function showTooltip(event) { + const messageElement = event.target.closest('.message'); + const timestampString = messageElement.dataset.timestamp; + + const date = new Date(timestampString); + const tooltipText = isNaN(date.getTime()) + ? 'Unknown time' + : date.toLocaleString('default', { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + }); + + const tooltip = document.createElement('div'); + tooltip.className = 'tooltip'; + tooltip.textContent = tooltipText; + document.body.appendChild(tooltip); + + const rect = messageElement.getBoundingClientRect(); + const tooltipRect = tooltip.getBoundingClientRect(); + + const leftPosition = rect.left + rect.width / 2 - tooltipRect.width / 2; + tooltip.style.position = 'fixed'; + tooltip.style.top = `${rect.top - tooltipRect.height - 5}px`; + tooltip.style.left = `${Math.max(leftPosition, 0) - 12}px`; + + function removeTooltip() { + tooltip.remove(); + } + messageElement.addEventListener('mouseout', removeTooltip); + setTimeout(removeTooltip, 5000); +} + +const chatSection = document.getElementById('chatSection'); +const noUserSelected = document.getElementById('noUserSelected'); + +chatSection.style.display = 'none'; +noUserSelected.style.display = 'flex'; + +async function loadMessages(userEmail) { + selectedUserEmail = userEmail; + messagesDiv.innerHTML = ''; + + chatSection.style.display = 'flex'; + noUserSelected.style.display = 'none'; + + const userEmailDisplay = document.getElementById('userEmailDisplay'); + if (userEmailDisplay) { + userEmailDisplay.textContent = `Chatting with: ${selectedUserEmail}`; + } + + document.querySelectorAll('.user').forEach(user => user.classList.remove('selected')); + const selectedUser = document.querySelector(`.user[data-email="${selectedUserEmail}"]`); + if (selectedUser) { + selectedUser.classList.add('selected'); + } + + const messagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp'), + where('sender', 'in', [currentUserEmail, selectedUserEmail]), + where('recipient', 'in', [currentUserEmail, selectedUserEmail]) + ); + + onSnapshot(messagesQuery, snapshot => { + messagesDiv.innerHTML = ''; + snapshot.docs.forEach(doc => { + const messageData = doc.data(); + const isCurrentUser = messageData.sender === currentUserEmail; + const timestamp = messageData.timestamp; + const messageElement = formatMessage(messageData.message, isCurrentUser, timestamp); + messagesDiv.appendChild(messageElement); + + if (!isCurrentUser && (!messageData.readBy || !messageData.readBy.includes(currentUserEmail))) { + updateReadStatus(doc.id); + } + }); + + messagesDiv.scrollTop = messagesDiv.scrollHeight; + }); +} + +async function updateReadStatus(messageId) { + const messageRef = doc(db, 'messages', messageId); + await updateDoc(messageRef, { + readBy: arrayUnion(currentUserEmail), + }); +} + +let searchDebounceTimeout; +let lastVisible = null; +const initialFetchLimit = 5; +const maxTotalFetch = 20; + +function setupSearchListeners() { + const searchUserInput = document.getElementById('searchUserInput'); + const searchUserResults = document.getElementById('searchUserResults'); + + searchUserInput.addEventListener('input', () => { + clearTimeout(searchDebounceTimeout); + const searchText = searchUserInput.value.trim(); + + if (searchText) { + searchDebounceTimeout = setTimeout(() => { + lastVisible = null; + performSearch(searchText, true); + }, 300); + } else { + searchUserResults.innerHTML = ''; + searchUserResults.style.display = 'none'; + } + }); +} + +async function performSearch(searchText, isNewSearch = false) { + const searchUserResults = document.getElementById('searchUserResults'); + + try { + showSpinner(); + animateLoadingDots(); + + let userQuery = query( + collection(db, 'MovieVerseUsers'), + where('email', '>=', searchText), + where('email', '<=', searchText + '\uf8ff'), + orderBy('email'), + limit(initialFetchLimit) + ); + + if (!isNewSearch && lastVisible) { + userQuery = query(userQuery, startAfter(lastVisible)); + } + + const querySnapshot = await getDocs(userQuery); + + if (isNewSearch) { + searchUserResults.innerHTML = ''; + } + + if (!querySnapshot.empty) { + lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; + } + + for (const doc of querySnapshot.docs) { + const user = doc.data(); + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadMessages(user.email)); + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.email}

${user.bio || ''}

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + } + + searchUserResults.style.display = 'block'; + hideSpinner(); + + if (isNewSearch || (!querySnapshot.empty && querySnapshot.size === initialFetchLimit)) { + const loadMoreButton = document.createElement('button'); + loadMoreButton.textContent = 'Load More'; + loadMoreButton.id = 'loadMoreButton'; + loadMoreButton.style.marginBottom = '20px'; + loadMoreButton.addEventListener('click', () => performSearch(searchText)); + searchUserResults.appendChild(loadMoreButton); + + if (searchUserResults.children.length >= maxTotalFetch) { + loadMoreButton.style.display = 'none'; + } + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.margin = '25px auto'; + } + hideSpinner(); + } + } +} + +let previouslySelectedUserElement = null; + +async function loadUserList() { + try { + showSpinner(); + animateLoadingDots(); + + const userLimit = 5; + const messageLimit = 30; + + const sentMessagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp', 'desc'), + where('sender', '==', currentUserEmail), + limit(messageLimit) + ); + const receivedMessagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp', 'desc'), + where('recipient', '==', currentUserEmail), + limit(messageLimit) + ); + + const [sentMessagesSnapshot, receivedMessagesSnapshot] = await Promise.all([getDocs(sentMessagesQuery), getDocs(receivedMessagesQuery)]); + + let userEmails = new Set(); + sentMessagesSnapshot.forEach(doc => userEmails.add(doc.data().recipient)); + receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); + + let users = []; + for (let email of userEmails) { + if (email) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + let userData = doc.data(); + if (userData.email) { + users.push(userData); + } + }); + } + } + + users.sort((a, b) => { + const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( + doc => doc.data().sender === a.email || doc.data().recipient === a.email + ); + const bLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( + doc => doc.data().sender === b.email || doc.data().recipient === b.email + ); + return (bLastMessage?.data().timestamp.toDate() || 0) - (aLastMessage?.data().timestamp.toDate() || 0); + }); + + users = users.slice(0, userLimit); + + userListDiv.innerHTML = ''; + for (const user of users) { + const userElement = document.createElement('div'); + userElement.classList.add('user'); + userElement.setAttribute('data-email', user.email); + userElement.onclick = () => { + if (previouslySelectedUserElement) { + previouslySelectedUserElement.classList.remove('selected'); + previouslySelectedUserElement.style.backgroundColor = ''; + } + selectedUserEmail = user.email; + loadMessages(user.email); + document.querySelectorAll('.user').forEach(u => u.classList.remove('selected')); + userElement.classList.add('selected'); + userElement.style.backgroundColor = '#ff8623'; + previouslySelectedUserElement = userElement; + }; + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '50px'; + img.style.borderRadius = '25px'; + img.style.marginRight = '10px'; + userElement.appendChild(img); + + const emailDiv = document.createElement('div'); + emailDiv.textContent = user.email; + userElement.appendChild(emailDiv); + + userListDiv.appendChild(userElement); + } + + hideSpinner(); + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + } + hideSpinner(); + } + } +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chatbot.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chatbot.js new file mode 100644 index 00000000..db8687e8 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/chatbot.js @@ -0,0 +1,501 @@ +import { GoogleGenerativeAI, HarmBlockThreshold, HarmCategory } from '@google/generative-ai'; + +const chatbotBody = document.getElementById('chatbotBody'); +const movieee = `https://${getMovieVerseData()}/3`; + +let initialMainContent; +let conversationHistory = []; + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +document.addEventListener('DOMContentLoaded', function () { + initialMainContent = document.getElementById('main').innerHTML; + initializeChatbot(); + document.getElementById('clear-search-btn').style.display = 'none'; +}); + +const searchTitle = document.getElementById('search-title'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function initializeChatbot() { + const chatbotInput = document.getElementById('chatbotInput'); + sendInitialInstructions(); + chatbotInput.addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + sendMessage(chatbotInput.value); + chatbotInput.value = ''; + } + }); + + const sendButton = document.getElementById('sendButton'); + sendButton.addEventListener('click', function () { + sendMessage(chatbotInput.value); + chatbotInput.value = ''; + }); +} + +async function sendMessage(message) { + chatbotBody.innerHTML += `
You: ${message}
`; + const botReply = await movieVerseResponse(message); + setTimeout(() => { + chatbotBody.innerHTML += `
MovieVerse Assistant: ${botReply}
`; + scrollToBottom(); + }, 1000); + scrollToBottom(); +} + +function sendInitialInstructions() { + const initialMessage = ` +
+ MovieVerse Assistant: + + Welcome to MovieVerse Assistant 🍿! Here's how to get started: + +
+
    +
  • To quickly find the trailer of a movie, type "Show trailer for [movie name]".
  • +
  • You can also ask about genres, top-rated movies, latest movies, get a recommended movie, and any general questions!
  • +
  • 💡Tip: To get the best results, try to avoid phrasing requests like "Show trailer for ...", as they might trigger specific functions instead of a broader search.
  • +
+
How may I assist you today? 🎬🍿
+ `; + chatbotBody.innerHTML += `
${initialMessage}
`; + scrollToBottom(); +} + +function scrollToBottom() { + chatbotBody.scrollTop = chatbotBody.scrollHeight; +} + +document.getElementById('clear-search-btn').addEventListener('click', function () { + document.getElementById('main').innerHTML = initialMainContent; + initializeChatbot(); + searchTitle.innerHTML = ''; + this.style.display = 'none'; +}); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +async function fetchMovieTrailer(movieName) { + const searchUrl = SEARCHPATH + encodeURIComponent(movieName); + try { + const response = await fetch(searchUrl); + const data = await response.json(); + const movie = data.results[0]; + if (movie) { + const trailerUrl = await getTrailerUrl(movie.id); + if (trailerUrl) { + createTrailerButton(trailerUrl, movie.title); + } else { + chatbotBody.innerHTML += '
No trailer available for this movie.
'; + } + } else { + chatbotBody.innerHTML += '
Movie not found. Please try another search.
'; + } + } catch (error) { + console.log('Error fetching movie trailer:', error); + } +} + +async function getTrailerUrl(movieId) { + const trailerApiUrl = `https://${getMovieVerseData()}/3/movie/${movieId}/videos?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(trailerApiUrl); + const data = await response.json(); + const trailer = data.results.find(video => video.type === 'Trailer' && video.site === 'YouTube'); + return trailer ? `https://www.youtube.com/watch?v=${trailer.key}` : null; + } catch (error) { + console.log('Error fetching trailer:', error); + return null; + } +} + +function createTrailerButton(trailerUrl, movieTitle) { + const buttonId = 'trailerButton'; + chatbotBody.innerHTML += ` + + `; + chatbotBody.addEventListener('click', function (event) { + if (event.target && event.target.id === buttonId) { + window.open(trailerUrl, '_blank'); + } + }); +} + +async function movieVerseResponse(message) { + const lowerMessage = message.toLowerCase(); + + if (lowerMessage.startsWith('show trailer for ')) { + const movieName = lowerMessage.replace('show trailer for ', ''); + fetchMovieTrailer(movieName); + return `Searching for the trailer of "${movieName}". Please wait...`; + } + + if (lowerMessage.startsWith('hello') || lowerMessage.startsWith('hi') || lowerMessage.startsWith('hey')) { + return 'Hello! How can I assist you with MovieVerse today?'; + } else if (lowerMessage.startsWith('bye') || lowerMessage.startsWith('goodbye')) { + return 'Goodbye! Thank you for using MovieVerse Assistant and have a nice day!'; + } else { + showSpinner(); + animateLoadingDots(); + + let fullResponse = ''; + try { + const genAI = new GoogleGenerativeAI(getAIResponse()); + const model = genAI.getGenerativeModel({ + model: 'gemini-1.5-flash', + systemInstruction: + 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + }); + + conversationHistory.push({ role: 'user', parts: [{ text: message }] }); + + const chatSession = model.startChat({ + generationConfig: { + temperature: 1, + topP: 0.95, + topK: 64, + maxOutputTokens: 8192, + responseMimeType: 'text/plain', + }, + safetySettings: [ + { + category: HarmCategory.HARM_CATEGORY_HARASSMENT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + ], + history: conversationHistory, + }); + + const result = await chatSession.sendMessage(message); + fullResponse = result.response.text(); + conversationHistory.push({ + role: 'model', + parts: [{ text: fullResponse }], + }); + } catch (error) { + console.error('Error fetching response:', error.message); + fullResponse = + 'An error occurred while generating the response, possibly due to high traffic or safety concerns. Please understand that I am trained by MovieVerse to provide safe and helpful responses within my limitations. I apologize for any inconvenience caused. Please try again with a different query or contact MovieVerse support for further assistance.'; + } + + hideSpinner(); + return removeMarkdown(fullResponse); + } +} + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading response${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + +function removeMarkdown(text) { + const converter = new showdown.Converter(); + const html = converter.makeHtml(text); + + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = html; + return tempDiv.textContent || tempDiv.innerText || ''; +} + +function getAIResponse() { + const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + return atob(response); +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/christopher-nolan.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/christopher-nolan.js new file mode 100644 index 00000000..ddddd17a --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/christopher-nolan.js @@ -0,0 +1,488 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const searchTitle = document.getElementById('search-title'); + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function showMovies(movies) { + main.innerHTML = ''; + movies.forEach(movie => { + const { id, poster_path, title, vote_average, overview } = movie; + const movieE1 = document.createElement('div'); + const voteAverage = vote_average.toFixed(1); + movieE1.classList.add('movie'); + const movieImage = poster_path + ? `${title}` + : `
Image Not Available
`; + movieE1.innerHTML = ` + ${movieImage} +
+

${title}

+ ${voteAverage} +
+
+

Movie Overview:

+ ${overview} +
`; + movieE1.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); + window.location.href = 'movie-details.html'; + updateMovieVisitCount(id, title); + }); + main.appendChild(movieE1); + }); + applySettings(); +} + +function clearMovieDetails() { + const movieDetailsContainer = document.getElementById('director-details-container'); + if (movieDetailsContainer) { + movieDetailsContainer.innerHTML = ''; + } +} + +document.addEventListener('DOMContentLoaded', () => { + const directorId = '525'; + if (directorId) { + fetchDirectorDetails(directorId); + } else { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details not found.

+
`; + } +}); + +async function fetchDirectorDetails(directorId) { + const directorUrl = `https://${getMovieVerseData()}/3/person/525?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/525/movie_credits?${generateMovieNames()}${getMovieCode()}`; + try { + const [directorResponse, creditsResponse] = await Promise.all([fetch(directorUrl), fetch(creditsUrl)]); + + const director = await directorResponse.json(); + const credits = await creditsResponse.json(); + + if (director.success === false) { + document.getElementById('director-details-container').innerHTML = '

No Information is Available for this Director

'; + } else { + updateBrowserURL(director.name); + populateDirectorDetails(director, credits); + } + } catch (error) { + console.log('Error fetching director details:', error); + document.getElementById('director-details-container').innerHTML = '

Error fetching director details

'; + } +} + +function populateDirectorDetails(director, credits) { + const directorImage = document.getElementById('director-image'); + const directorName = document.getElementById('director-name'); + const directorDescription = document.getElementById('director-description'); + + if (director.profile_path) { + directorImage.src = `https://image.tmdb.org/t/p/w1280${director.profile_path}`; + directorName.textContent = director.name; + document.title = `${director.name} - Director's Details`; + } else { + directorImage.style.display = 'none'; + directorName.textContent = director.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.director-left').appendChild(noImageText); + } + + let ageOrStatus; + if (director.birthday) { + if (director.deathday) { + ageOrStatus = calculateAge(director.birthday, director.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(director.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + directorDescription.innerHTML = ` +

Biography: ${director.biography || 'N/A'}

+

Date of Birth: ${director.birthday || 'N/A'}

+

Date of Death: ${director.deathday || 'N/A'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${director.place_of_birth || 'N/A'}

+

Known For: Directing

+ `; + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + directorDescription.appendChild(filmographyHeading); + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + credits.crew.forEach(movie => { + if (movie.job === 'Director') { + const movieLink = document.createElement('span'); + movieLink.textContent = movie.title; + movieLink.classList.add('movie-link'); + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + window.location.href = 'movie-details.html'; + }); + movieList.appendChild(movieLink); + movieList.appendChild(document.createTextNode(', ')); + } + }); + filmographyHeading.appendChild(movieList); + + applySettings(); +} + +function calculateAge(dob, deathday = null) { + const birthDate = new Date(dob); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const ageDifMs = referenceDate - birthDate.getTime(); + const ageDate = new Date(ageDifMs); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + applyTextColor(savedTextColor); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/comments-tv.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/comments-tv.js new file mode 100644 index 00000000..9217424f --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/comments-tv.js @@ -0,0 +1,156 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, addDoc, getDocs, query, orderBy, where } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { app, db } from './firebase.js'; + +const commentForm = document.getElementById('comment-form'); +commentForm.addEventListener('submit', async e => { + e.preventDefault(); + const userName = document.getElementById('user-name').value; + const userComment = document.getElementById('user-comment').value; + const commentDate = new Date(); + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + await addDoc(collection(db, 'comments'), { + userName, + userComment, + commentDate, + tvSeriesId, + }); + commentForm.reset(); + fetchComments(); + } catch (error) { + console.log('Error adding comment: ', error); + } +}); + +let modal = document.getElementById('comment-modal'); +let btn = document.getElementById('toggle-comment-modal'); +let span = document.getElementsByClassName('close')[0]; + +btn.onclick = function () { + modal.style.display = 'block'; +}; + +span.onclick = function () { + modal.style.display = 'none'; +}; + +document.getElementById('post-comment-btn').onclick = function () { + modal.style.display = 'none'; +}; + +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } +}; + +let currentPage = 1; +const commentsPerPage = 3; +let totalComments = 0; +let totalPages = 1; + +async function fetchComments() { + try { + const commentsContainer = document.getElementById('comments-container'); + commentsContainer.innerHTML = ''; + commentsContainer.style.maxWidth = '100%'; + const movieId = localStorage.getItem('selectedTvSeriesId'); + + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', movieId), orderBy('commentDate', 'desc')); + const querySnapshot = await getDocs(q); + + totalComments = querySnapshot.size; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let index = 0; + let displayedComments = 0; + + if (querySnapshot.empty) { + const noCommentsMsg = document.createElement('p'); + noCommentsMsg.textContent = 'No comments for this TV series yet.'; + commentsContainer.appendChild(noCommentsMsg); + } else { + querySnapshot.forEach(doc => { + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { + const comment = doc.data(); + const commentDate = comment.commentDate.toDate(); + + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; + } + hideSpinner(); + } + } +} + +function formatCommentDate(commentDate) { + const formattedDate = commentDate.toLocaleString('default', { month: 'short' }) + ' ' + commentDate.getDate() + 'th, ' + commentDate.getFullYear(); + return formattedDate; +} + +function formatAMPM(date) { + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours || 12; + minutes = minutes < 10 ? '0' + minutes : minutes; + const strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +document.getElementById('prev-page').addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + fetchComments(); + } +}); + +document.getElementById('next-page').addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage++; + fetchComments(); + } +}); + +fetchComments(); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/comments.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/comments.js new file mode 100644 index 00000000..1d2e97a9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/comments.js @@ -0,0 +1,156 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, addDoc, getDocs, query, orderBy, where } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { app, db } from './firebase.js'; + +const commentForm = document.getElementById('comment-form'); +commentForm.addEventListener('submit', async e => { + e.preventDefault(); + const userName = document.getElementById('user-name').value; + const userComment = document.getElementById('user-comment').value; + const commentDate = new Date(); + const movieId = localStorage.getItem('selectedMovieId'); + + try { + await addDoc(collection(db, 'comments'), { + userName, + userComment, + commentDate, + movieId, + }); + commentForm.reset(); + fetchComments(); + } catch (error) { + console.log('Error adding comment: ', error); + } +}); + +let modal = document.getElementById('comment-modal'); +let btn = document.getElementById('toggle-comment-modal'); +let span = document.getElementsByClassName('close')[0]; + +btn.onclick = function () { + modal.style.display = 'block'; +}; + +span.onclick = function () { + modal.style.display = 'none'; +}; + +document.getElementById('post-comment-btn').onclick = function () { + modal.style.display = 'none'; +}; + +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } +}; + +let currentPage = 1; +const commentsPerPage = 3; +let totalComments = 0; +let totalPages = 1; + +async function fetchComments() { + try { + const commentsContainer = document.getElementById('comments-container'); + commentsContainer.innerHTML = ''; + commentsContainer.style.maxWidth = '100%'; + const movieId = localStorage.getItem('selectedMovieId'); + + const q = query(collection(db, 'comments'), where('movieId', '==', movieId), orderBy('commentDate', 'desc')); + const querySnapshot = await getDocs(q); + + totalComments = querySnapshot.size; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let index = 0; + let displayedComments = 0; + + if (querySnapshot.empty) { + const noCommentsMsg = document.createElement('p'); + noCommentsMsg.textContent = 'No comments for this movie yet.'; + commentsContainer.appendChild(noCommentsMsg); + } else { + querySnapshot.forEach(doc => { + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { + const comment = doc.data(); + const commentDate = comment.commentDate.toDate(); + + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; + } + hideSpinner(); + } + } +} + +function formatCommentDate(commentDate) { + const formattedDate = commentDate.toLocaleString('default', { month: 'short' }) + ' ' + commentDate.getDate() + 'th, ' + commentDate.getFullYear(); + return formattedDate; +} + +function formatAMPM(date) { + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours || 12; + minutes = minutes < 10 ? '0' + minutes : minutes; + const strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +document.getElementById('prev-page').addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + fetchComments(); + } +}); + +document.getElementById('next-page').addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage++; + fetchComments(); + } +}); + +fetchComments(); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/company-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/company-details.js new file mode 100644 index 00000000..b87c3bcf --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/company-details.js @@ -0,0 +1,742 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +document.addEventListener('DOMContentLoaded', () => { + const companyId = localStorage.getItem('selectedCompanyId'); + if (companyId) { + fetchCompanyDetails(companyId); + fetchCompanyMovies(companyId); + } else { + fetchCompanyDetails(521); + fetchCompanyMovies(521); + } +}); + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function fetchCompanyDetails(companyId) { + showSpinner(); + const url = `https://${getMovieVerseData()}/3/company/${companyId}?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const company = await response.json(); + const logoImg = document.getElementById('company-logo'); + + if (company.logo_path) { + logoImg.src = `https://image.tmdb.org/t/p/w500${company.logo_path}`; + } else { + logoImg.style.display = 'none'; + const logoFallbackText = document.createElement('p'); + logoFallbackText.textContent = 'Logo Not Available'; + logoImg.parentNode.insertBefore(logoFallbackText, logoImg); + } + + const fullCountryName = twoLetterCountryCodes.find(country => country.code === company.origin_country)?.name; + + document.getElementById('company-name').textContent = company.name || 'Information Unavailable'; + document.getElementById('company-headquarters').textContent = company.headquarters || 'Information Unavailable'; + document.getElementById('company-country').textContent = fullCountryName || 'Information Unavailable'; + document.title = `${company.name} - Company Details`; + + const homepage = company.homepage || '#'; + const companyWebsite = document.getElementById('company-website'); + + if (homepage !== '#') { + companyWebsite.href = homepage; + companyWebsite.textContent = homepage; + } else { + companyWebsite.textContent = 'Information Unavailable'; + } + + updateBrowserURL(company.name); + hideSpinner(); + } catch (error) { + console.log('Error fetching company details:', error); + const companyDetailsContainer = document.getElementById('company-details-container'); + companyDetailsContainer.innerHTML = ` +
+

Company details currently unavailable - please try again

+
`; + hideSpinner(); + } +} + +async function fetchCompanyMovies(companyId) { + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_companies=${companyId}`; + try { + const response = await fetch(url); + const data = await response.json(); + + if (data.results.length === 0) { + const companyMoviesContainer = document.getElementById('company-movies-container'); + companyMoviesContainer.innerHTML = `

No movies found for this company.

`; + return; + } + displayCompanyMovies(data.results); + } catch (error) { + console.log('Error fetching movies:', error); + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +const twoLetterCountryCodes = [ + { name: 'Afghanistan', code: 'AF' }, + { name: 'Albania', code: 'AL' }, + { name: 'Algeria', code: 'DZ' }, + { name: 'American Samoa', code: 'AS' }, + { name: 'Andorra', code: 'AD' }, + { name: 'Angola', code: 'AO' }, + { name: 'Anguilla', code: 'AI' }, + { name: 'Antarctica', code: 'AQ' }, + { name: 'Antigua and Barbuda', code: 'AG' }, + { name: 'Argentina', code: 'AR' }, + { name: 'Armenia', code: 'AM' }, + { name: 'Aruba', code: 'AW' }, + { name: 'Australia', code: 'AU' }, + { name: 'Austria', code: 'AT' }, + { name: 'Azerbaijan', code: 'AZ' }, + { name: 'Bahamas', code: 'BS' }, + { name: 'Bahrain', code: 'BH' }, + { name: 'Bangladesh', code: 'BD' }, + { name: 'Barbados', code: 'BB' }, + { name: 'Belarus', code: 'BY' }, + { name: 'Belgium', code: 'BE' }, + { name: 'Belize', code: 'BZ' }, + { name: 'Benin', code: 'BJ' }, + { name: 'Bermuda', code: 'BM' }, + { name: 'Bhutan', code: 'BT' }, + { name: 'Bolivia', code: 'BO' }, + { name: 'Bonaire', code: 'BQ' }, + { name: 'Bosnia and Herzegovina', code: 'BA' }, + { name: 'Botswana', code: 'BW' }, + { name: 'Bouvet Island', code: 'BV' }, + { name: 'Brazil', code: 'BR' }, + { name: 'British Indian Ocean Territory', code: 'IO' }, + { name: 'Brunei Darussalam', code: 'BN' }, + { name: 'Bulgaria', code: 'BG' }, + { name: 'Burkina Faso', code: 'BF' }, + { name: 'Burundi', code: 'BI' }, + { name: 'Cambodia', code: 'KH' }, + { name: 'Cameroon', code: 'CM' }, + { name: 'Canada', code: 'CA' }, + { name: 'Cape Verde', code: 'CV' }, + { name: 'Cayman Islands', code: 'KY' }, + { name: 'Central African Republic', code: 'CF' }, + { name: 'Chad', code: 'TD' }, + { name: 'Chile', code: 'CL' }, + { name: 'China', code: 'CN' }, + { name: 'Christmas Island', code: 'CX' }, + { name: 'Cocos (Keeling) Islands', code: 'CC' }, + { name: 'Colombia', code: 'CO' }, + { name: 'Comoros', code: 'KM' }, + { name: 'Congo', code: 'CG' }, + { name: 'Congo, The Democratic Republic of the', code: 'CD' }, + { name: 'Cook Islands', code: 'CK' }, + { name: 'Costa Rica', code: 'CR' }, + { name: 'Cote D Ivoire', code: 'CI' }, + { name: 'Croatia', code: 'HR' }, + { name: 'Cuba', code: 'CU' }, + { name: 'Curacao', code: 'CW' }, + { name: 'Cyprus', code: 'CY' }, + { name: 'Czech Republic', code: 'CZ' }, + { name: 'Denmark', code: 'DK' }, + { name: 'Djibouti', code: 'DJ' }, + { name: 'Dominica', code: 'DM' }, + { name: 'Dominican Republic', code: 'DO' }, + { name: 'Ecuador', code: 'EC' }, + { name: 'Egypt', code: 'EG' }, + { name: 'El Salvador', code: 'SV' }, + { name: 'Equatorial Guinea', code: 'GQ' }, + { name: 'Eritrea', code: 'ER' }, + { name: 'Estonia', code: 'EE' }, + { name: 'Eswatini', code: 'SZ' }, + { name: 'Ethiopia', code: 'ET' }, + { name: 'Falkland Islands (Malvinas)', code: 'FK' }, + { name: 'Faroe Islands', code: 'FO' }, + { name: 'Fiji', code: 'FJ' }, + { name: 'Finland', code: 'FI' }, + { name: 'France', code: 'FR' }, + { name: 'French Guiana', code: 'GF' }, + { name: 'French Polynesia', code: 'PF' }, + { name: 'French Southern Territories', code: 'TF' }, + { name: 'Gabon', code: 'GA' }, + { name: 'Gambia', code: 'GM' }, + { name: 'Georgia', code: 'GE' }, + { name: 'Germany', code: 'DE' }, + { name: 'Ghana', code: 'GH' }, + { name: 'Gibraltar', code: 'GI' }, + { name: 'Greece', code: 'GR' }, + { name: 'Greenland', code: 'GL' }, + { name: 'Grenada', code: 'GD' }, + { name: 'Guadeloupe', code: 'GP' }, + { name: 'Guam', code: 'GU' }, + { name: 'Guatemala', code: 'GT' }, + { name: 'Guernsey', code: 'GG' }, + { name: 'Guinea', code: 'GN' }, + { name: 'Guinea-Bissau', code: 'GW' }, + { name: 'Guyana', code: 'GY' }, + { name: 'Haiti', code: 'HT' }, + { name: 'Heard Island and Mcdonald Islands', code: 'HM' }, + { name: 'Holy See (Vatican City State)', code: 'VA' }, + { name: 'Honduras', code: 'HN' }, + { name: 'Hong Kong', code: 'HK' }, + { name: 'Hungary', code: 'HU' }, + { name: 'Iceland', code: 'IS' }, + { name: 'India', code: 'IN' }, + { name: 'Indonesia', code: 'ID' }, + { name: 'Iran, Islamic Republic Of', code: 'IR' }, + { name: 'Iraq', code: 'IQ' }, + { name: 'Ireland', code: 'IE' }, + { name: 'Isle of Man', code: 'IM' }, + { name: 'Israel', code: 'IL' }, + { name: 'Italy', code: 'IT' }, + { name: 'Ivory Coast', code: 'CI' }, + { name: 'Jamaica', code: 'JM' }, + { name: 'Japan', code: 'JP' }, + { name: 'Jersey', code: 'JE' }, + { name: 'Jordan', code: 'JO' }, + { name: 'Kazakhstan', code: 'KZ' }, + { name: 'Kenya', code: 'KE' }, + { name: 'Kiribati', code: 'KI' }, + { name: 'DPR Korea', code: 'KP' }, + { name: 'South Korea', code: 'KR' }, + { name: 'Kuwait', code: 'KW' }, + { name: 'Kyrgyzstan', code: 'KG' }, + { name: 'Laos', code: 'LA' }, + { name: 'Latvia', code: 'LV' }, + { name: 'Lebanon', code: 'LB' }, + { name: 'Lesotho', code: 'LS' }, + { name: 'Liberia', code: 'LR' }, + { name: 'Libyan Arab Jamahiriya', code: 'LY' }, + { name: 'Liechtenstein', code: 'LI' }, + { name: 'Lithuania', code: 'LT' }, + { name: 'Luxembourg', code: 'LU' }, + { name: 'Macao', code: 'MO' }, + { name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK' }, + { name: 'Madagascar', code: 'MG' }, + { name: 'Malawi', code: 'MW' }, + { name: 'Malaysia', code: 'MY' }, + { name: 'Maldives', code: 'MV' }, + { name: 'Mali', code: 'ML' }, + { name: 'Malta', code: 'MT' }, + { name: 'Marshall Islands', code: 'MH' }, + { name: 'Martinique', code: 'MQ' }, + { name: 'Mauritania', code: 'MR' }, + { name: 'Mauritius', code: 'MU' }, + { name: 'Mayotte', code: 'YT' }, + { name: 'Mexico', code: 'MX' }, + { name: 'Micronesia, Federated States of', code: 'FM' }, + { name: 'Moldova, Republic of', code: 'MD' }, + { name: 'Monaco', code: 'MC' }, + { name: 'Mongolia', code: 'MN' }, + { name: 'Montenegro', code: 'ME' }, + { name: 'Montserrat', code: 'MS' }, + { name: 'Morocco', code: 'MA' }, + { name: 'Mozambique', code: 'MZ' }, + { name: 'Myanmar', code: 'MM' }, + { name: 'Namibia', code: 'NA' }, + { name: 'Nauru', code: 'NR' }, + { name: 'Nepal', code: 'NP' }, + { name: 'Netherlands', code: 'NL' }, + { name: 'Netherlands Antilles', code: 'AN' }, + { name: 'New Caledonia', code: 'NC' }, + { name: 'New Zealand', code: 'NZ' }, + { name: 'Nicaragua', code: 'NI' }, + { name: 'Niger', code: 'NE' }, + { name: 'Nigeria', code: 'NG' }, + { name: 'Niue', code: 'NU' }, + { name: 'Norfolk Island', code: 'NF' }, + { name: 'Northern Mariana Islands', code: 'MP' }, + { name: 'Norway', code: 'NO' }, + { name: 'Oman', code: 'OM' }, + { name: 'Pakistan', code: 'PK' }, + { name: 'Palau', code: 'PW' }, + { name: 'Palestinian Territory, Occupied', code: 'PS' }, + { name: 'Panama', code: 'PA' }, + { name: 'Papua New Guinea', code: 'PG' }, + { name: 'Paraguay', code: 'PY' }, + { name: 'Peru', code: 'PE' }, + { name: 'Philippines', code: 'PH' }, + { name: 'Pitcairn', code: 'PN' }, + { name: 'Poland', code: 'PL' }, + { name: 'Portugal', code: 'PT' }, + { name: 'Puerto Rico', code: 'PR' }, + { name: 'Qatar', code: 'QA' }, + { name: 'RWANDA', code: 'RW' }, + { name: 'Reunion', code: 'RE' }, + { name: 'Romania', code: 'RO' }, + { name: 'Russian Federation', code: 'RU' }, + { name: 'Saint Barthelemy', code: 'BL' }, + { name: 'Saint Helena', code: 'SH' }, + { name: 'Saint Kitts and Nevis', code: 'KN' }, + { name: 'Saint Lucia', code: 'LC' }, + { name: 'Saint Martin', code: 'MF' }, + { name: 'Saint Pierre and Miquelon', code: 'PM' }, + { name: 'Saint Vincent and the Grenadines', code: 'VC' }, + { name: 'Samoa', code: 'WS' }, + { name: 'San Marino', code: 'SM' }, + { name: 'Sao Tome and Principe', code: 'ST' }, + { name: 'Saudi Arabia', code: 'SA' }, + { name: 'Senegal', code: 'SN' }, + { name: 'Serbia', code: 'RS' }, + { name: 'Seychelles', code: 'SC' }, + { name: 'Sierra Leone', code: 'SL' }, + { name: 'Singapore', code: 'SG' }, + { name: 'Sint Maarten', code: 'SX' }, + { name: 'Slovakia', code: 'SK' }, + { name: 'Slovenia', code: 'SI' }, + { name: 'Solomon Islands', code: 'SB' }, + { name: 'Somalia', code: 'SO' }, + { name: 'South Africa', code: 'ZA' }, + { name: 'South Georgia and the South Sandwich Islands', code: 'GS' }, + { name: 'South Sudan', code: 'SS' }, + { name: 'Spain', code: 'ES' }, + { name: 'Sri Lanka', code: 'LK' }, + { name: 'Sudan', code: 'SD' }, + { name: 'Suriname', code: 'SR' }, + { name: 'Svalbard and Jan Mayen', code: 'SJ' }, + { name: 'Swaziland', code: 'SZ' }, + { name: 'Sweden', code: 'SE' }, + { name: 'Switzerland', code: 'CH' }, + { name: 'Syrian Arab Republic', code: 'SY' }, + { name: 'Taiwan', code: 'TW' }, + { name: 'Tajikistan', code: 'TJ' }, + { name: 'Tanzania, United Republic of', code: 'TZ' }, + { name: 'Thailand', code: 'TH' }, + { name: 'Timor-Leste', code: 'TL' }, + { name: 'Togo', code: 'TG' }, + { name: 'Tokelau', code: 'TK' }, + { name: 'Tonga', code: 'TO' }, + { name: 'Trinidad and Tobago', code: 'TT' }, + { name: 'Tunisia', code: 'TN' }, + { name: 'Turkey', code: 'TR' }, + { name: 'Turkmenistan', code: 'TM' }, + { name: 'Turks and Caicos Islands', code: 'TC' }, + { name: 'Tuvalu', code: 'TV' }, + { name: 'Uganda', code: 'UG' }, + { name: 'Ukraine', code: 'UA' }, + { name: 'United Arab Emirates', code: 'AE' }, + { name: 'United Kingdom', code: 'GB' }, + { name: 'United States', code: 'US' }, + { name: 'United States Minor Outlying Islands', code: 'UM' }, + { name: 'Uruguay', code: 'UY' }, + { name: 'Uzbekistan', code: 'UZ' }, + { name: 'Vanuatu', code: 'VU' }, + { name: 'Venezuela', code: 'VE' }, + { name: 'Viet Nam', code: 'VN' }, + { name: 'Vietnam', code: 'VN' }, + { name: 'Virgin Islands, British', code: 'VG' }, + { name: 'Virgin Islands, U.S.', code: 'VI' }, + { name: 'Wallis and Futuna', code: 'WF' }, + { name: 'Western Sahara', code: 'EH' }, + { name: 'Yemen', code: 'YE' }, + { name: 'Zambia', code: 'ZM' }, + { name: 'Zimbabwe', code: 'ZW' }, + { name: 'Åland Islands', code: 'AX' }, +]; + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function displayCompanyMovies(movies) { + const moviesList = document.getElementById('company-movies-list'); + moviesList.style.display = 'flex'; + moviesList.style.flexWrap = 'wrap'; + moviesList.style.justifyContent = 'center'; + moviesList.style.gap = '5px'; + + let moviesToDisplay = movies.sort((a, b) => b.popularity - a.popularity); + + moviesToDisplay.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + moviesList.appendChild(movieLink); + + if (index < movies.length - 1) { + const separator = document.createTextNode(' '); + moviesList.appendChild(separator); + } + }); +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/create-account.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/create-account.js new file mode 100644 index 00000000..33047f26 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/create-account.js @@ -0,0 +1,140 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + collection, + addDoc, + getDocs, + query, + where, + doc, + setDoc, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function isValidPassword(password) { + const minLength = 8; + const hasUppercase = /[A-Z]/.test(password); + const hasLowercase = /[a-z]/.test(password); + const hasNumbers = /\d/.test(password); + const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password); + + return password.length >= minLength && hasUppercase && hasLowercase && hasNumbers && hasSpecialChar; +} + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('createAccountForm').addEventListener('submit', async e => { + try { + e.preventDefault(); + const email = document.getElementById('newEmail').value; + const password = document.getElementById('newPassword').value; + const confirmPassword = document.getElementById('confirmPassword').value; + + if (!isValidPassword(password)) { + alert( + 'Password does not meet the security requirements.\n\n' + + 'Your password must include:\n' + + '- At least 8 characters\n' + + '- At least one uppercase letter\n' + + '- At least one lowercase letter\n' + + '- At least one number\n' + + '- At least one special character (e.g., !@#$%^&*)' + ); + return; + } + + if (password !== confirmPassword) { + alert('Passwords do not match.'); + return; + } + + const exists = await accountExists(email); + if (exists) { + alert('An account with this email already exists.'); + return; + } + + try { + await addDoc(collection(db, 'MovieVerseUsers'), { + email: email, + password: password, + }); + + const profileRef = doc(db, 'profiles', email); // Using email as document ID for simplicity + await setDoc(profileRef, { + username: 'N/A', + dob: 'N/A', + bio: 'N/A', + favoriteGenres: ['N/A'], + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: ['N/A'], + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }); + + alert('Account created successfully! Now please sign in on the sign in page to proceed.'); + window.location.href = 'sign-in.html'; + } catch (error) { + console.log('Error creating account: ', error); + alert('Failed to create account. Please try again later.'); + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('account-creation-form-container'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +async function accountExists(email) { + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); + const querySnapshot = await getDocs(q); + return !querySnapshot.empty; +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/director-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/director-details.js new file mode 100644 index 00000000..4a0dfc46 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/director-details.js @@ -0,0 +1,781 @@ +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + currentIndex = 0; + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', () => { + const directorId = localStorage.getItem('selectedDirectorId'); + + if (directorId) { + fetchDirectorDetails(directorId); + } else { + fetchDirectorDetails(488); + } +}); + +async function fetchDirectorDetails(directorId) { + showSpinner(); + + const directorUrl = `https://${getMovieVerseData()}/3/person/${directorId}?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/${directorId}/movie_credits?${generateMovieNames()}${getMovieCode()}`; + + try { + const [directorResponse, creditsResponse] = await Promise.all([fetch(directorUrl), fetch(creditsUrl)]); + + const director = await directorResponse.json(); + const credits = await creditsResponse.json(); + + if (director.success === false) { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details currently unavailable - please try again

+
`; + } else { + updateBrowserURL(director.name); + populateDirectorDetails(director, credits); + } + hideSpinner(); + } catch (error) { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details currently unavailable - please try again

+
`; + console.log('Error fetching director details:', error); + hideSpinner(); + } +} + +async function populateDirectorDetails(director, credits) { + const directorImage = document.getElementById('director-image'); + const directorName = document.getElementById('director-name'); + const directorDescription = document.getElementById('director-description'); + + if (director.profile_path) { + directorImage.src = `https://image.tmdb.org/t/p/w1280${director.profile_path}`; + directorName.textContent = director.name; + document.title = `${director.name} - Director's Details`; + } else { + directorImage.style.display = 'none'; + directorName.textContent = director.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.director-left').appendChild(noImageText); + } + + let ageOrStatus; + if (director.birthday) { + if (director.deathday) { + ageOrStatus = calculateAge(director.birthday, director.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(director.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + directorDescription.innerHTML = ` +

Biography: ${director.biography || 'Information Unavailable'}

+

Also Known As: ${director.also_known_as.join(', ') || 'Information Unavailable'}

+

Date of Birth: ${director.birthday || 'Information Unavailable'}

+

Date of Death: ${director.deathday || 'Information Unavailable'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${director.place_of_birth || 'Information Unavailable'}

+

Known For: Directing

+ `; + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + directorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + movieList.style.display = 'flex'; + movieList.style.flexWrap = 'wrap'; + movieList.style.justifyContent = 'center'; + movieList.style.gap = '5px'; + + let directedMovies = credits.crew.filter(movie => movie.job === 'Director'); + directedMovies = directedMovies.sort((a, b) => b.popularity - a.popularity); + + directedMovies.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + movieList.appendChild(movieLink); + + if (index < directedMovies.length - 1) { + movieList.appendChild(document.createTextNode('')); + } + }); + + filmographyHeading.appendChild(movieList); + + const mediaUrl = `https://${getMovieVerseData()}/3/person/${director.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + + const detailsContainer = document.getElementById('director-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + let modalOpen = false; + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + imageElement.addEventListener('click', function () { + const imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 380); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + applySettings(); +} + +function calculateAge(dob, deathday = null) { + const birthDate = new Date(dob); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const ageDifMs = referenceDate - birthDate.getTime(); + const ageDate = new Date(ageDifMs); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + applyTextColor(savedTextColor); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/favorites.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/favorites.js new file mode 100644 index 00000000..fcb4771a --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/favorites.js @@ -0,0 +1,2062 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + getDocs, + getDoc, + query, + where, + orderBy, + writeBatch, + deleteDoc, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +let initialMoviesSelection = []; +let initialTVSeriesSelection = []; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.addEventListener('DOMContentLoaded', function () { + loadWatchLists(); +}); + +const tvCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(tvCode.part1) + atob(tvCode.part2) + atob(tvCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +document.addEventListener('DOMContentLoaded', function () { + adjustButtonMargin(); + document.getElementById('how-to-use-btn').addEventListener('click', function () { + let howToUseSection = document.getElementById('how-to-use-section'); + if (howToUseSection.style.display === 'none') { + howToUseSection.style.display = 'block'; + window.location.href = '#how-to-use-section'; + document.getElementById('how-to-use-btn').textContent = 'Hide Tutorial'; + document.getElementById('how-to-use-btn').style.marginBottom = '0'; + } else { + howToUseSection.style.display = 'none'; + document.getElementById('how-to-use-btn').textContent = 'How to Use'; + document.getElementById('how-to-use-btn').style.marginBottom = '180px'; + } + }); +}); + +function adjustButtonMargin() { + let howToUseSection = document.getElementById('how-to-use-section'); + if (howToUseSection.style.display === 'none' || !howToUseSection.style.display) { + document.getElementById('how-to-use-btn').style.marginBottom = '200px'; + } else { + document.getElementById('how-to-use-btn').style.marginBottom = '0'; + } +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function openModal(modalId) { + document.getElementById(modalId).style.display = 'block'; +} + +document.addEventListener('DOMContentLoaded', () => { + const closeButtons = document.querySelectorAll('.close-button'); + + closeButtons.forEach(button => { + button.addEventListener('click', function () { + const modalId = this.closest('.modal').id; + closeModal(modalId); + }); + }); +}); + +function closeModal(modalId) { + document.getElementById(modalId).style.display = 'none'; +} + +document.getElementById('delete-watchlist-btn').addEventListener('click', () => openModal('delete-watchlist-modal')); + +async function getMovieTitle(movieId) { + const apiKey = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${apiKey}`; + + try { + const response = await fetch(url); + const movie = await response.json(); + return movie.title; + } catch (error) { + return 'Unknown Movie'; + } +} + +async function populateCreateModalWithFavorites() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || ''; + + if (!currentUserEmail) { + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + + const createForm = document.getElementById('create-watchlist-form'); + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + createForm.insertBefore(container, createForm.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + const moviesFavorited = userData.favoritesMovies || []; + const favoritesTVSeries = userData.favoritesTVSeries || []; + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + } else { + container.innerHTML = '

No favorites found. Please add some favorites first.

'; + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('create-watchlist-modal'); + } + }); +} + +document.getElementById('create-watchlist-form').addEventListener('submit', async function (e) { + e.preventDefault(); + showSpinner(); + + const name = document.getElementById('new-watchlist-name').value.trim(); + const description = document.getElementById('new-watchlist-description').value; + const selectedMovies = Array.from(document.querySelectorAll('#movies-container input:checked')).map(checkbox => checkbox.value); + const selectedTVSeries = Array.from(document.querySelectorAll('#tvseries-container input:checked')).map(checkbox => checkbox.value); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let isDuplicate = false; + let maxOrder = 0; + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + try { + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + maxOrder = querySnapshot.docs.reduce((max, docSnapshot) => Math.max(max, docSnapshot.data().order || 0), 0); + isDuplicate = querySnapshot.docs.some(doc => doc.data().name.toLowerCase() === name.toLowerCase()); + } else { + isDuplicate = localWatchlists.some(watchlist => watchlist.name.toLowerCase() === name.toLowerCase()); + } + + if (isDuplicate) { + alert('A watchlist with this name already exists. Please choose a different name.'); + hideSpinner(); + return; + } + + if (currentUserEmail) { + const newWatchlistRef = doc(collection(db, 'watchlists')); + await setDoc(newWatchlistRef, { + userEmail: currentUserEmail, + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + order: maxOrder + 1, + }); + } else { + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: '', + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: '', + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } else { + console.error('An error occurred while creating a watchlist:', error); + alert('Failed to create the watchlist due to an error.'); + } + } + + closeModal('create-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); +}); + +async function getTVSeriesTitle(seriesId) { + const apiKey = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/tv/${seriesId}?${generateMovieNames()}${apiKey}`; + + try { + const response = await fetch(url); + const series = await response.json(); + return series.name; + } catch (error) { + return 'Unknown Series'; + } +} + +function appendCheckbox(container, id, title, name, isChecked = false) { + const item = document.createElement('div'); + item.classList.add('favorite-item'); + item.style.display = 'flex'; + item.style.alignItems = 'center'; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `${name}-${id}`; + checkbox.value = id; + checkbox.name = name; + checkbox.checked = isChecked; + + const label = document.createElement('label'); + label.htmlFor = `${name}-${id}`; + label.textContent = title; + label.style.marginTop = '12px'; + label.style.marginLeft = '10px'; + + item.appendChild(checkbox); + item.appendChild(label); + container.appendChild(item); +} + +document.getElementById('create-watchlist-btn').addEventListener('click', function () { + document.getElementById('create-watchlist-form').reset(); + populateCreateModalWithFavorites(); + openModal('create-watchlist-modal'); + updateWatchlistsCreated(); +}); + +function generateUniqueId() { + return Date.now().toString(36) + Math.random().toString(36).substr(2); +} + +document.getElementById('edit-watchlist-btn').addEventListener('click', async function () { + await populateEditModal(); + openModal('edit-watchlist-modal'); +}); + +async function populateEditModal() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let watchlists = []; + let moviesFavorited = []; + let favoritesTVSeries = []; + + if (currentUserEmail) { + const qWatchlists = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const qUsers = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + + const [watchlistsSnapshot, usersSnapshot] = await Promise.all([getDocs(qWatchlists), getDocs(qUsers)]); + + watchlists = watchlistsSnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + if (!usersSnapshot.empty) { + const userData = usersSnapshot.docs[0].data(); + moviesFavorited = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; + + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } + + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute('for', 'watchlist-select'); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach(watchlist => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); + + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; + + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); + + const updateForm = async watchlist => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; + + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } + } + + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; + + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); + + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } + + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; + + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } + + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute('for', 'watchlist-select'); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach(watchlist => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); + + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; + + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); + + const updateForm = async watchlist => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; + + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } + } + + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; + + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); + + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } + + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('edit-watchlist-modal'); + } + }); +} + +document.getElementById('edit-watchlist-form').addEventListener('submit', async function (e) { + try { + showSpinner(); + e.preventDefault(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; + + let selectedMovies; + let selectedTVSeries; + + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + + const moviesSelectionChanged = !( + initialMoviesSelection.length === currentMoviesSelection.length && initialMoviesSelection.every(value => currentMoviesSelection.includes(value)) + ); + const tvSeriesSelectionChanged = !( + initialTVSeriesSelection.length === currentTVSeriesSelection.length && + initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value)) + ); + + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } else { + selectedMovies = initialMoviesSelection; + } + + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } else { + selectedTVSeries = initialTVSeriesSelection; + } + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + + const watchlistRef = doc(db, 'watchlists', watchlistId); + await updateDoc(watchlistRef, { + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }); + } else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); + + e.preventDefault(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; + + let selectedMovies; + let selectedTVSeries; + + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + + const moviesSelectionChanged = !( + initialMoviesSelection.length === currentMoviesSelection.length && + initialMoviesSelection.every(value => currentMoviesSelection.includes(value)) + ); + const tvSeriesSelectionChanged = !( + initialTVSeriesSelection.length === currentTVSeriesSelection.length && + initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value)) + ); + + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } else { + selectedMovies = initialMoviesSelection; + } + + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } else { + selectedTVSeries = initialTVSeriesSelection; + } + + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } +}); + +async function populateDeleteModal() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; + + let watchlists = []; + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + } else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + } + + if (watchlists.length === 0) { + deleteForm.innerHTML = '

No Watchlists Available to Delete.

'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); + + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; + + if (watchlists.length === 0) { + deleteForm.innerHTML = '

No Watchlists Available to Delete.

'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); + + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('delete-watchlist-modal'); + } + }); +} + +async function deleteSelectedWatchlists() { + try { + showSpinner(); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + + for (const id of selectedIds) { + await deleteDoc(doc(db, 'watchlists', id)); + } + } else { + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + } + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); + + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } +} + +document.getElementById('delete-watchlist-btn').addEventListener('click', populateDeleteModal); + +async function fetchMovieDetails(movieId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + + try { + const response = await fetch(url); + const movie = await response.json(); + const movieCard = await createMovieCard(movie); + movieCard.setAttribute('data-movie-title', movie.title); + return movieCard; + } catch (error) { + const errorDiv = document.createElement('div'); + errorDiv.textContent = 'Error loading movie card. Please try refreshing the page.'; + return errorDiv; + } +} + +async function getAdditionalMovieImages(movieId) { + const response = await fetch(`https://api.themoviedb.org/3/movie/${movieId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +async function createMovieCard(movie) { + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = movie.title; + const words = movieTitle.split(' '); + if (words.length >= 9) { + words[8] = '...'; + movieTitle = words.slice(0, 9).join(' '); + } + + const ratingClass = movie.vote_count === 0 ? 'unrated' : getClassByRate(movie.vote_average); + const voteAvg = movie.vote_count === 0 ? 'Unrated' : movie.vote_average.toFixed(1); + + let overview = movie.overview; + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+ ${movie.title} +
+
+

${movieTitle}

+ ${voteAvg} +
+
+

Movie Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + updateUniqueMoviesViewed(movie.id); + updateFavoriteGenre(movie.genre_ids); + updateMovieVisitCount(movie.id, movie.title); + window.location.href = 'movie-details.html'; + }); + + const additionalImages = await getAdditionalMovieImages(movie.id); + let allImages = [movie.poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + + return movieEl; +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +const searchForm = document.getElementById('form'); + +searchForm.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function loadWatchLists() { + const displaySection = document.getElementById('watchlists-display-section'); + + try { + showSpinner(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + const watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + if (watchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Click on "Create Watch Lists" to start adding movies.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += + '

Your Watch Lists

'; + document.getElementById('watchlist-header').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); + }); + watchlists.sort((a, b) => a.order - b.order); + watchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of watchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + } else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + if (localWatchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += '

Your Watch Lists

'; + localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + } + + let favorites = []; + let favoritesTVSeries = []; + + if (currentUserEmail) { + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + if (favorites.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite Movies'; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite movies.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const movieId of favorites) { + const movieCard = await fetchMovieDetails(movieId); + moviesContainer.appendChild(movieCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + favoritesDiv.innerHTML = + '

Favorite Movies

No favorite movies added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + if (favoritesTVSeries.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite TV Series'; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite TV series.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const tvSeriesId of favoritesTVSeries) { + const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); + moviesContainer.appendChild(tvSeriesCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + favoritesDiv.innerHTML = + '

Favorite TV Series

No favorite TV series added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + hideSpinner(); + } catch (error) { + if (error.code === 'resource-exhausted') { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + if (localWatchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += '

Your Watch Lists

'; + localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + + let favorites = []; + let favoritesTVSeries = []; + + favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + if (favorites.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite Movies'; + title.className = 'watchlist-title'; + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite movies.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const movieId of favorites) { + const movieCard = await fetchMovieDetails(movieId); + moviesContainer.appendChild(movieCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + favoritesDiv.innerHTML = + '

Favorite Movies

No favorite movies added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + if (favoritesTVSeries.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite TV Series'; + title.className = 'watchlist-title'; + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite TV series.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const tvSeriesId of favoritesTVSeries) { + const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); + moviesContainer.appendChild(tvSeriesCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + hideSpinner(); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + favoritesDiv.innerHTML = + '

Favorite TV Series

No favorite TV series added yet.

'; + displaySection.appendChild(favoritesDiv); + hideSpinner(); + } + } else { + console.error('An error occurred:', error); + } + } +} + +async function fetchTVSeriesDetails(tvSeriesId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + + try { + const response = await fetch(url); + const series = await response.json(); + const seriesCard = await createTVSeriesCard(series); + seriesCard.setAttribute('data-series-title', series.name); + return seriesCard; + } catch (error) { + const errorDiv = document.createElement('div'); + errorDiv.textContent = 'Error loading series details. Please try refreshing the page.'; + return errorDiv; + } +} + +async function getAdditionalTVSeriesImages(tvSeriesId) { + const response = await fetch(`https://api.themoviedb.org/3/tv/${tvSeriesId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +async function createTVSeriesCard(tvSeries) { + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = tvSeries.name; + const words = movieTitle.split(' '); + if (words.length >= 9) { + words[8] = '...'; + movieTitle = words.slice(0, 9).join(' '); + } + + const ratingClass = tvSeries.vote_count === 0 ? 'unrated' : getClassByRate(tvSeries.vote_average); + const voteAvg = tvSeries.vote_count === 0 ? 'Unrated' : tvSeries.vote_average.toFixed(1); + + let overview = tvSeries.overview; + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+ ${tvSeries.name} +
+
+

${movieTitle}

+ ${voteAvg} +
+
+

TV Series Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedTvSeriesId', tvSeries.id); + updateMovieVisitCount(tvSeries.id, tvSeries.name); + updateUniqueMoviesViewed(tvSeries.id); + updateFavoriteGenre(tvSeries.genres_ids); + window.location.href = 'tv-details.html'; + }); + + const additionalImages = await getAdditionalTVSeriesImages(tvSeries.id); + let allImages = [tvSeries.poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + + return movieEl; +} + +function updateFavoriteGenre(genre_ids) { + if (genre_ids && genre_ids.length > 0) { + const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + favoriteGenres.push(genre_ids[0]); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + } +} + +function updateUniqueMoviesViewed(movieId) { + let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + if (!viewedMovies.includes(movieId)) { + viewedMovies.push(movieId); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); + } +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +async function isListPinned(watchlistId) { + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (currentUserEmail) { + try { + const watchlistRef = doc(db, 'watchlists', watchlistId); + const watchlistDoc = await getDoc(watchlistRef); + + if (watchlistDoc.exists()) { + const watchlistData = watchlistDoc.data(); + return watchlistData.pinned || false; + } else { + return false; + } + } catch (error) { + return false; + } + } else { + const watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + const watchlist = watchlists.find(watchlist => watchlist.id === watchlistId); + return watchlist ? watchlist.pinned : false; + } +} + +function addWatchListControls(watchlistDiv, watchlistId) { + if (!watchlistId) { + return; + } + + const controlContainer = document.createElement('div'); + controlContainer.className = 'watchlist-controls'; + + const pinBtn = document.createElement('button'); + pinBtn.innerHTML = ''; + pinBtn.classList.add('pin-btn'); + + isListPinned(watchlistId).then(isPinned => { + pinBtn.title = isPinned ? 'Unpin this watch list' : 'Pin this watch list'; + if (isPinned) { + pinBtn.classList.add('pinned'); + } else { + pinBtn.classList.remove('pinned'); + } + pinBtn.onclick = function () { + pinWatchList(watchlistDiv, watchlistId); + }; + }); + + const moveUpBtn = document.createElement('button'); + moveUpBtn.innerHTML = ''; + moveUpBtn.onclick = function () { + moveWatchList(watchlistDiv, true); + }; + moveUpBtn.title = 'Move this watch list up'; + + const moveDownBtn = document.createElement('button'); + moveDownBtn.innerHTML = ''; + moveDownBtn.onclick = function () { + moveWatchList(watchlistDiv, false); + }; + moveDownBtn.title = 'Move this watch list down'; + + const shareBtn = document.createElement('button'); + shareBtn.innerHTML = ''; + shareBtn.title = 'Share this watch list'; + shareBtn.onclick = function () { + shareWatchList(watchlistDiv); + }; + + controlContainer.appendChild(pinBtn); + controlContainer.appendChild(moveUpBtn); + controlContainer.appendChild(moveDownBtn); + controlContainer.appendChild(shareBtn); + watchlistDiv.appendChild(controlContainer); +} + +function shareWatchList(watchlistDiv) { + const watchlistTitle = watchlistDiv.querySelector('.watchlist-title').textContent; + let itemsToShare = `Explore my curated watchlist, "${watchlistTitle}", which contains:\n`; + let finalLine = 'Happy Watching! 🍿🎬🎥\n\n'; + const movieCards = watchlistDiv.querySelectorAll('[data-movie-title]'); + const tvSeriesCards = watchlistDiv.querySelectorAll('[data-series-title]'); + + movieCards.forEach(movieCard => { + itemsToShare += `- ${movieCard.getAttribute('data-movie-title')}\n`; + }); + + tvSeriesCards.forEach(seriesCard => { + itemsToShare += `- ${seriesCard.getAttribute('data-series-title')}\n`; + }); + + itemsToShare += finalLine; + + if (navigator.share) { + navigator + .share({ + title: `Share Watchlist: ${watchlistTitle}`, + text: itemsToShare, + }) + .catch(err => { + console.error('Error sharing the watchlist:', err); + }); + } else { + downloadWatchlist(watchlistTitle, itemsToShare); + } +} + +function downloadWatchlist(title, content) { + const encodedContent = encodeURIComponent(content); + const dataUri = `data:text/plain;charset=utf-8,${encodedContent}`; + + const element = document.createElement('a'); + element.setAttribute('href', dataUri); + element.setAttribute('download', `${title.replace(/[\s]+/g, '_')}.txt`); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + document.body.removeChild(element); +} + +function createWatchListDiv(watchlist) { + const watchlistDiv = document.createElement('div'); + watchlistDiv.className = 'watchlist'; + watchlistDiv.setAttribute('data-watchlist-id', watchlist.id); + + const title = document.createElement('h3'); + title.textContent = watchlist.name; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + watchlistDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = watchlist.description; + description.className = 'watchlist-description'; + + watchlistDiv.appendChild(title); + watchlistDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + moviesContainer.style.flexWrap = 'wrap'; + + if (watchlist.movies === undefined) { + moviesContainer.innerHTML = ''; + } else { + watchlist.movies.forEach(movieId => { + fetchMovieDetails(movieId).then(movieCard => moviesContainer.appendChild(movieCard)); + }); + } + + if (watchlist.tvSeries === undefined) { + moviesContainer.innerHTML = ''; + } else { + watchlist.tvSeries.forEach(tvSeriesId => { + fetchTVSeriesDetails(tvSeriesId).then(tvSeriesCard => moviesContainer.appendChild(tvSeriesCard)); + }); + } + + watchlistDiv.appendChild(moviesContainer); + addWatchListControls(watchlistDiv, watchlist.id); + return watchlistDiv; +} + +function updateWatchlistsOrderInLS() { + const watchlistsDivs = document.querySelectorAll('#watchlists-display-section > .watchlist'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + const newOrder = Array.from(watchlistsDivs).map(div => div.getAttribute('data-watchlist-id')); + + watchlists.sort((a, b) => newOrder.indexOf(a.id) - newOrder.indexOf(b.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); +} + +async function moveWatchList(watchlistDiv, moveUp) { + showSpinner(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const watchlistId = watchlistDiv.getAttribute('data-watchlist-id'); + + if (currentUserEmail) { + try { + const watchlistsQuery = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail), orderBy('order', 'asc')); + const snapshot = await getDocs(watchlistsQuery); + let watchlists = snapshot.docs.map(doc => { + return { docId: doc.id, ...doc.data() }; + }); + + const index = watchlists.findIndex(watchlist => watchlist.docId === watchlistId); + if (index === -1 || watchlists.length < 2) { + hideSpinner(); + return; + } + + const swapIndex = moveUp ? index - 1 : index + 1; + if (swapIndex < 0 || swapIndex >= watchlists.length) { + hideSpinner(); + return; + } + + let currentOrder = watchlists[index].order; + let swapOrder = watchlists[swapIndex].order; + + const batch = writeBatch(db); + batch.update(doc(db, 'watchlists', watchlists[index].docId), { + order: swapOrder, + }); + batch.update(doc(db, 'watchlists', watchlists[swapIndex].docId), { + order: currentOrder, + }); + + await batch.commit(); + } catch (error) { + hideSpinner(); + } + hideSpinner(); + } else { + const sibling = moveUp ? watchlistDiv.previousElementSibling : watchlistDiv.nextElementSibling; + if (sibling) { + const parent = watchlistDiv.parentNode; + if (moveUp) { + parent.insertBefore(watchlistDiv, sibling); + } else { + parent.insertBefore(sibling, watchlistDiv); + } + updateWatchlistsOrderInLS(); + } + hideSpinner(); + } + + loadWatchLists(); + window.location.reload(); +} + +async function pinWatchList(watchlistDiv, watchlistId) { + showSpinner(); + + const isPinned = watchlistDiv.classList.contains('pinned'); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (currentUserEmail) { + const watchlistRef = doc(db, 'watchlists', watchlistId); + await updateDoc(watchlistRef, { + pinned: !isPinned, + }); + hideSpinner(); + } else { + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists.forEach(watchlist => { + if (watchlist.id === watchlistId) { + watchlist.pinned = !isPinned; + } + }); + + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + hideSpinner(); + } + + loadWatchLists(); + window.location.reload(); +} + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +function updateWatchlistsCreated() { + let watchlistsCount = parseInt(localStorage.getItem('watchlistsCreated')) || 0; + watchlistsCount++; + localStorage.setItem('watchlistsCreated', watchlistsCount.toString()); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/firebase.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/firebase.js new file mode 100644 index 00000000..bddd3301 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/firebase.js @@ -0,0 +1,43 @@ +import { initializeApp, getApps, getApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +export const app = !getApps().length ? initializeApp(firebaseConfig) : getApp(); +export const db = getFirestore(app); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/inception.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/inception.js new file mode 100644 index 00000000..cf9779e6 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/inception.js @@ -0,0 +1,1265 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const favoriteButton = document.getElementById('favorite-btn'); +const searchTitle = document.getElementById('search-title'); + +let trailerUrlGlobal; +let initialMainContent; +let trailerButton; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function setStarRating(rating) { + const stars = document.querySelectorAll('.rating .star'); + stars.forEach(star => { + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; + }); + + document.getElementById('rating-value').textContent = `${rating}.0/5.0`; +} + +document.querySelectorAll('.rating .star').forEach(star => { + star.addEventListener('mouseover', e => { + setStarRating(e.target.dataset.value); + }); + + star.addEventListener('mouseout', () => { + const movieId = localStorage.getItem('selectedMovieId'); + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); + }); + + star.addEventListener('click', e => { + const movieId = localStorage.getItem('selectedMovieId'); + const rating = e.target.dataset.value; + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + savedRatings[movieId] = rating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + setStarRating(rating); + updateAverageMovieRating(movieId, rating); + window.location.reload(); + }); +}); + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + + const movieId = localStorage.getItem('selectedMovieId'); + if (movieId) { + fetchMovieDetails(movieId); + } else { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details not found.

+
`; + } + + document.getElementById('clear-search-btn').style.display = 'none'; + + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButton(); + initClient(); + applySettings(); +}); + +async function fetchMovieDetails(movieId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + const url2 = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=videos`; + const imdbUrl = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=external_ids`; + + try { + const response = await fetch(url); + const movie = await response.json(); + const imdbId = movie.imdb_id; + + fetchMovieRatings(imdbId, movie); + + const response2 = await fetch(url2); + const movie2 = await response2.json(); + const trailers = movie2.videos.results.filter(video => video.type === 'Trailer'); + + if (trailers.length > 0) { + const trailerUrl = `https://www.youtube.com/watch?v=${trailers[0].key}`; + trailerButton = createTrailerButton(trailerUrl); + positionTrailerButton(); + } + updateBrowserURL(movie.title); + } catch (error) { + console.log('Error fetching movie details:', error); + } +} + +function getRatingDetails(rating) { + let details = { color: 'black', text: rating, description: '' }; + + switch (rating) { + case 'R': + details = { + color: 'red', + text: 'R (Restricted)', + description: ' - No one 17 and under admitted', + }; + break; + case 'PG-13': + details = { + color: 'yellow', + text: 'PG-13 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 13', + }; + break; + case 'PG': + details = { + color: 'orange', + text: 'PG (Parental Guidance Suggested)', + description: ' - May not be suitable for children', + }; + break; + case 'G': + details = { + color: 'green', + text: 'G (General Audiences)', + description: ' - All ages admitted', + }; + break; + case 'NC-17': + details = { + color: 'darkred', + text: 'NC-17 (Adults Only)', + description: ' - No one 17 and under admitted', + }; + break; + case 'TV-Y': + details = { + color: 'lightgreen', + text: 'TV-Y (All Children)', + description: ' - Appropriate for all children', + }; + break; + case 'TV-Y7': + details = { + color: 'lightblue', + text: 'TV-Y7 (Directed to Older Children)', + description: ' - Suitable for children ages 7 and up', + }; + break; + case 'TV-G': + details = { + color: 'green', + text: 'TV-G (General Audience)', + description: ' - Suitable for all ages', + }; + break; + case 'TV-PG': + details = { + color: 'orange', + text: 'TV-PG (Parental Guidance Suggested)', + description: ' - May not be suitable for younger children', + }; + break; + case 'TV-14': + details = { + color: 'yellow', + text: 'TV-14 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 14', + }; + break; + case 'TV-MA': + details = { + color: 'red', + text: 'TV-MA (Mature Audience Only)', + description: ' - Specifically designed to be viewed by adults', + }; + break; + case 'NR': + details = { + color: 'grey', + text: 'NR (Not Rated)', + description: ' - Movie has not been officially rated', + }; + break; + case 'UR': + case 'Unrated': + details = { + color: 'grey', + text: 'UR (Unrated)', + description: ' - Contains content not used in the rated version', + }; + break; + default: + details = { + color: 'white', + text: rating, + description: ' - Rating information not available', + }; + break; + } + + return details; +} + +async function fetchMovieRatings(imdbId, tmdbMovieData) { + const omdbApiKey = '2ba8e536'; + const omdbUrl = `https://www.omdbapi.com/?i=${imdbId}&apikey=${omdbApiKey}`; + + try { + const response = await fetch(omdbUrl); + const data = await response.json(); + + let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + + if (imdbRating === 'N/A' && tmdbMovieData.vote_average) { + imdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; + } + + const rtRatingObj = data.Ratings.find(rating => rating.Source === 'Rotten Tomatoes'); + let rtRating = rtRatingObj ? rtRatingObj.Value : 'N/A'; + + let metascore = data.Metascore ? `${data.Metascore}/100` : 'N/A'; + let awards = data.Awards; + let rated = data.Rated ? data.Rated : 'Rating information unavailable'; + + if (awards === 'N/A') { + awards = 'No awards information available'; + } + + if (metascore === 'N/A/100') { + const metacriticsRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + metascore = calculateFallbackMetacriticsRating(metacriticsRatingValue, tmdbMovieData.vote_average) + '/100'; + } + + if (rtRating === 'N/A') { + const imdbRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + rtRating = calculateFallbackRTRating(imdbRatingValue, tmdbMovieData.vote_average); + } + populateMovieDetails(tmdbMovieData, imdbRating, rtRating, metascore, awards, rated); + } catch (error) { + console.log('Error fetching movie ratings:', error); + const fallbackImdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; + populateMovieDetails(tmdbMovieData, fallbackImdbRating, 'N/A', 'No metascore information available', 'No awards information available'); + } +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +function calculateFallbackRTRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0) + '%'; // Calculate fallback RT rating out of 100% scale (in case data is not available from OMDB) +} + +function calculateFallbackMetacriticsRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0); // Calculate fallback Metacritics rating out of 100 scale (in case data is not available from OMDB) +} + +let trailerIframeDisplayed = false; + +function createTrailerButton(trailerUrl) { + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + + trailerButton.addEventListener('click', function () { + if (!trailerIframeDisplayed) { + showTrailerIframe(trailerUrl); + trailerButton.textContent = 'Close Trailer'; + trailerButton.title = 'Click to close the trailer'; + } else { + closeTrailerIframe(); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + } + }); + + trailerButton.classList.add('trailer-button'); + trailerButton.style.font = 'inherit'; + + return trailerButton; +} + +function closeTrailerIframe() { + const iframeContainer = document.querySelector('.trailer-button + div'); + + if (iframeContainer) { + iframeContainer.style.height = '0'; + setTimeout(() => iframeContainer.remove(), 500); + } + trailerIframeDisplayed = false; +} + +function getYouTubeVideoId(url) { + const urlObj = new URL(url); + return urlObj.searchParams.get('v'); +} + +function positionTrailerButton() { + if (!trailerButton) return; + + if (window.innerWidth <= 900) { + const movieDescription = document.getElementById('movie-description'); + movieDescription.parentNode.insertBefore(trailerButton, movieDescription); + } else { + const movieRating = document.getElementById('movie-rating'); + movieRating.parentNode.insertBefore(trailerButton, movieRating.nextSibling); + } +} + +document.addEventListener('DOMContentLoaded', positionTrailerButton); + +function showTrailerIframe(trailerUrl) { + trailerUrlGlobal = trailerUrl; + + const iframeContainer = document.createElement('div'); + iframeContainer.style.position = 'relative'; + iframeContainer.style.width = '400px'; + iframeContainer.style.margin = '0 auto'; + iframeContainer.style.overflow = 'hidden'; + iframeContainer.style.height = '0'; + iframeContainer.style.transition = 'height 0.5s ease-in-out'; + + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', `https://www.youtube.com/embed/${getYouTubeVideoId(trailerUrl)}?autoplay=1`); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('height', '315'); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'); + iframe.setAttribute('allowfullscreen', true); + + iframeContainer.appendChild(iframe); + + const trailerButton = document.querySelector('.trailer-button'); + trailerButton.parentNode.insertBefore(iframeContainer, trailerButton.nextSibling); + + setTimeout(() => (iframeContainer.style.height = '315px'), 50); + + trailerIframeDisplayed = true; +} + +function toggleFavorite(movie) { + let favorites = JSON.parse(localStorage.getItem('favorites')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || {}; + + if (favorites.includes(movie.id)) { + favorites = favorites.filter(favId => favId !== movie.id); + movie.genres.forEach(genre => { + favoriteGenres[genre.name] = favoriteGenres[genre.name] ? favoriteGenres[genre.name] - 1 : 0; + }); + } else { + favorites.push(movie.id); + movie.genres.forEach(genre => { + favoriteGenres[genre.name] = favoriteGenres[genre.name] ? favoriteGenres[genre.name] + 1 : 1; + }); + } + + localStorage.setItem('favorites', JSON.stringify(favorites)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + + updateFavoriteButton(movie.id); +} + +function updateFavoriteButton(movieId) { + const favorites = JSON.parse(localStorage.getItem('favorites')) || []; + const favoriteButton = document.getElementById('favorite-btn'); + + if (favorites.includes(movieId)) { + favoriteButton.classList.add('favorited'); + favoriteButton.style.backgroundColor = 'grey'; + favoriteButton.title = 'Remove from favorites'; + } else { + favoriteButton.classList.remove('favorited'); + favoriteButton.style.background = 'transparent'; + favoriteButton.title = 'Add to favorites'; + } +} + +function getRtSlug(title) { + return title + .toLowerCase() + .replace(/:/g, '') + .replace(/part one/g, 'part_1') + .replace(/-/g, '') + .replace(/&/g, 'and') + .replace(/ /g, '_') + .replace(/[^\w-]/g, ''); +} + +function createMetacriticSlug(title) { + return title + .toLowerCase() + .replace(/part\sone/g, 'part-1') + .replace(/:|_|-|\s/g, '-') + .replace(/&/g, 'and') + .replace(/--+/g, '-') + .replace(/[^\w-]/g, ''); +} + +function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, rated) { + document.getElementById('movie-image').src = `https://image.tmdb.org/t/p/w1280${movie.poster_path}`; + document.getElementById('movie-title').textContent = movie.title; + + const movieRating = movie.vote_average.toFixed(1); + const imdbLink = `https://www.imdb.com/title/${movie.imdb_id}`; + + const rtLink = rtRating !== 'N/A' ? `https://www.rottentomatoes.com/m/${getRtSlug(movie.title)}` : '#'; + const metaCriticsLink = metascore !== 'N/A' ? `https://www.metacritic.com/movie/${createMetacriticSlug(movie.title)}` : '#'; + + const ratingDetails = getRatingDetails(rated); + const ratedElement = rated + ? `

Rated: ${ratingDetails.text}${ratingDetails.description}

` + : ''; + + document.getElementById('movie-rating').innerHTML = ` + IMDB Rating: ${imdbRating} + `; + document.getElementById('movie-rating').style.marginTop = '120px'; + document.title = movie.title + ' - Movie Details'; + + const movieImage = document.getElementById('movie-image'); + const movieDescription = document.getElementById('movie-description'); + + const metascoreElement = metascore ? `

Metascore: ${metascore}

` : ''; + const awardsElement = awards ? `

Awards: ${awards}

` : ''; + + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + } else { + movieImage.style.display = 'none'; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.movie-left').appendChild(noImageText); + } + + const fullLanguage = twoLetterLangCodes.find(lang => lang.code === movie.original_language).name; + const overview = movie.overview; + const genres = movie.genres.map(genre => genre.name).join(', '); + const releaseDate = movie.release_date; + + const budget = movie.budget === 0 ? 'Information Not Available' : `$${movie.budget.toLocaleString()}`; + const revenue = movie.revenue <= 1000 ? 'Information Not Available' : `$${movie.revenue.toLocaleString()}`; + const tagline = movie.tagline ? movie.tagline : 'No tagline found'; + const languages = movie.spoken_languages.map(lang => lang.name).join(', '); + + const countries = movie.production_countries.map(country => country.name).join(', '); + const originalLanguage = fullLanguage; + const popularityScore = movie.popularity.toFixed(0); + const status = movie.status; + + const voteCount = movie.vote_count.toLocaleString(); + let keywords = movie.keywords ? movie.keywords.keywords.map(kw => kw.name).join(', ') : 'None Available'; + const similarTitles = movie.similar ? movie.similar.results.map(m => m.title).join(', ') : 'None Available'; + const scaledRating = (movie.vote_average / 2).toFixed(1); + + if (keywords.length === 0) { + keywords = 'None Available'; + } + + const popularityThreshold = 80; + const isPopular = movie.popularity >= popularityThreshold; + const popularityText = isPopular ? `${popularityScore} (This movie is popular)` : `${popularityScore} (This movie is unpopular)`; + + const adultContentIndicator = movie.adult + ? `Adult Content` + : `General Audience`; + + const movieStatus = `

Status: ${movie.status}

`; + + const runtime = movie.runtime > 0 ? movie.runtime + ' minutes' : 'Runtime Info Not Available'; + + document.getElementById('movie-description').innerHTML += ` +

Description: ${overview}

+

Genres: ${genres}

+ ${ratedElement} + ${movieStatus} +

Release Date: ${releaseDate}

+

Runtime: ${runtime}

+

Budget: ${budget}

+

Revenue: ${revenue}

+

Languages: ${languages}

+

Countries of Production: ${countries}

+

Original Language: ${originalLanguage}

+

Popularity Score: ${popularityText}

+

Averaged User Ratings: ${scaledRating}/5.0 (based on ${ + movie.vote_count + } votes)

+ ${awardsElement} + ${metascoreElement} +

Rotten Tomatoes: ${rtRating}

+

Tagline: ${tagline}

+ `; + + if (movie.credits && movie.credits.crew) { + const director = movie.credits.crew.find(member => member.job === 'Director'); + if (director) { + const directorAge = director.birthday ? calculateAge(director.birthday) : 'N/A'; + const directorElement = document.createElement('p'); + directorElement.innerHTML = `Director: ${director.name}`; + directorElement.querySelector('.director-link').addEventListener('click', e => { + e.preventDefault(); + localStorage.setItem('selectedDirectorId', director.id); + document.title = `${director.name} - Director's Details`; + window.location.href = 'director-details.html'; + updateUniqueDirectorsViewed(director.id); + updateDirectorVisitCount(director.id, director.name); + }); + document.getElementById('movie-description').appendChild(directorElement); + } + } + + const castHeading = document.createElement('p'); + castHeading.innerHTML = 'Cast: '; + document.getElementById('movie-description').appendChild(castHeading); + + if (movie.credits && movie.credits.cast.length > 0) { + const topTenCast = movie.credits.cast.slice(0, 10); + topTenCast.forEach((actor, index) => { + const actorLink = document.createElement('span'); + actorLink.textContent = actor.name; + actorLink.classList.add('actor-link'); + actorLink.addEventListener('click', () => { + localStorage.setItem('selectedActorId', actor.id); + window.location.href = 'actor-details.html'; + updateUniqueActorsViewed(actor.id); + updateActorVisitCount(actor.id, actor.name); + }); + + castHeading.appendChild(actorLink); + + if (index < topTenCast.length - 1) { + castHeading.appendChild(document.createTextNode(', ')); + } + }); + } else { + castHeading.appendChild(document.createTextNode('None available.')); + } + + const productionCompanies = movie.production_companies; + const productionCompaniesElement = document.createElement('p'); + productionCompaniesElement.innerHTML = 'Production Companies: '; + + if (productionCompanies.length === 0) { + productionCompaniesElement.innerHTML += 'None available.'; + } + productionCompanies.forEach((company, index) => { + const companyLink = document.createElement('a'); + companyLink.textContent = company.name; + companyLink.style.cursor = 'pointer'; + companyLink.style.textDecoration = 'underline'; + companyLink.href = '#'; + companyLink.classList.add('company-link'); + companyLink.addEventListener('click', e => { + e.preventDefault(); + localStorage.setItem('selectedCompanyId', company.id); + window.location.href = 'company-details.html'; + updateUniqueCompaniesViewed(company.id); + }); + + productionCompaniesElement.appendChild(companyLink); + + if (index < productionCompanies.length - 1) { + productionCompaniesElement.appendChild(document.createTextNode(', ')); + } + }); + + document.getElementById('movie-description').appendChild(productionCompaniesElement); + const similarMoviesHeading = document.createElement('p'); + + similarMoviesHeading.innerHTML = 'Similar Movies: '; + document.getElementById('movie-description').appendChild(similarMoviesHeading); + + if (movie.similar && movie.similar.results.length > 0) { + movie.similar.results.forEach((similarMovie, index) => { + const movieLink = document.createElement('span'); + movieLink.textContent = similarMovie.title; + movieLink.style.cursor = 'pointer'; + movieLink.style.textDecoration = 'underline'; + movieLink.addEventListener('mouseenter', () => { + movieLink.style.color = '#f509d9'; + }); + + movieLink.addEventListener('mouseleave', () => { + movieLink.style.color = getSavedTextColor(); + }); + + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', similarMovie.id); + window.location.href = 'movie-details.html'; + }); + + similarMoviesHeading.appendChild(movieLink); + + if (index < movie.similar.results.length - 1) { + similarMoviesHeading.appendChild(document.createTextNode(', ')); + } + }); + } else { + similarMoviesHeading.appendChild(document.createTextNode('None available.')); + } + + const keywordsElement = document.createElement('p'); + keywordsElement.innerHTML = `Keywords: ${keywords}`; + + movieDescription.appendChild(keywordsElement); + updateFavoriteButton(movie.id); + + favoriteButton.addEventListener('click', () => { + toggleFavorite(movie); + updateMoviesFavorited(movie.id); + window.location.reload(); + }); + + updateMoviesFavorited(movie.id); + applySettings(); +} + +function getSavedTextColor() { + return localStorage.getItem('textColor') || 'white'; +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} + +function updateAverageMovieRating(movieId, newRating) { + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + + let totalRating = 0; + let totalMoviesRated = 0; + + for (let id in savedRatings) { + totalRating += parseFloat(savedRatings[id]); + totalMoviesRated++; + } + let averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1).toString()); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function updateUniqueActorsViewed(actorId) { + let viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + if (!viewedActors.includes(actorId)) { + viewedActors.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(viewedActors)); + } +} + +function updateUniqueCompaniesViewed(companyId) { + let viewedCompanies = JSON.parse(localStorage.getItem('uniqueCompaniesViewed')) || []; + if (!viewedCompanies.includes(companyId)) { + viewedCompanies.push(companyId); + localStorage.setItem('uniqueCompaniesViewed', JSON.stringify(viewedCompanies)); + } +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js new file mode 100644 index 00000000..0628d210 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js @@ -0,0 +1,486 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const searchTitle = document.getElementById('search-title'); + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +let initialMainContent = ''; + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + + const actorId = 6193; + if (actorId) { + fetchActorDetails(actorId); + } else { + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details not found.

+
`; + } + + document.getElementById('clear-search-btn').style.display = 'none'; +}); + +async function fetchActorDetails(actorId) { + const actorUrl = `https://${getMovieVerseData()}/3/person/6193?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/6193/movie_credits?${generateMovieNames()}${getMovieCode()}`; + try { + const [actorResponse, creditsResponse] = await Promise.all([fetch(actorUrl), fetch(creditsUrl)]); + + const actor = await actorResponse.json(); + const credits = await creditsResponse.json(); + if (actor.success === false) { + document.getElementById('actor-details-container').innerHTML = '

No Information is Available for this Actor

'; + } else { + updateBrowserURL(actor.name); + populateActorDetails(actor, credits); + } + } catch (error) { + console.log('Error fetching actor details:', error); + document.getElementById('actor-details-container').innerHTML = '

Error fetching actor details

'; + } +} + +function populateActorDetails(actor, credits) { + const actorImage = document.getElementById('actor-image'); + const actorName = document.getElementById('actor-name'); + const actorDescription = document.getElementById('actor-description'); + + if (actor.profile_path) { + actorImage.src = `https://image.tmdb.org/t/p/w1280${actor.profile_path}`; + actorName.textContent = actor.name; + document.title = `${actor.name} - Actor's Details`; + } else { + actorImage.style.display = 'none'; + actorName.textContent = actor.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.actor-left').appendChild(noImageText); + } + + let ageOrStatus; + if (actor.birthday) { + if (actor.deathday) { + ageOrStatus = calculateAge(actor.birthday, actor.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(actor.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + actorDescription.innerHTML = ` +

Biography: ${actor.biography || 'N/A'}

+

Date of Birth: ${actor.birthday || 'N/A'}

+

Date of Death: ${actor.deathday || 'N/A'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${actor.place_of_birth || 'N/A'}

+

Known For: ${actor.known_for_department || 'N/A'}

+

Height: ${actor.height || 'N/A'}

+ `; + + const gender = document.createElement('div'); + gender.innerHTML = `

Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'N/A'}

`; + actorDescription.appendChild(gender); + + const popularity = document.createElement('div'); + popularity.innerHTML = `

Popularity Score: ${actor.popularity.toFixed(2)}

`; + actorDescription.appendChild(popularity); + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + actorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + credits.cast.forEach(movie => { + const movieLink = document.createElement('span'); + movieLink.textContent = movie.title; + movieLink.classList.add('movie-link'); + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + window.location.href = 'movie-details.html'; + }); + movieList.appendChild(movieLink); + movieList.appendChild(document.createTextNode(', ')); + }); + + filmographyHeading.appendChild(movieList); + applySettings(); +} + +function calculateAge(birthday, deathday = null) { + const birthDate = new Date(birthday); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const diff = referenceDate - birthDate.getTime(); + const ageDate = new Date(diff); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + applySettings(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-details.js new file mode 100644 index 00000000..dcaa4028 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-details.js @@ -0,0 +1,1902 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w780'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const favoriteButton = document.getElementById('favorite-btn'); +const searchTitle = document.getElementById('search-title'); + +let trailerUrlGlobal; +let initialMainContent; +let trailerButton; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + console.log(genreMap); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let uniqueMoviesViewed = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + + if (!uniqueMoviesViewed.includes(movieId)) { + uniqueMoviesViewed.push(movieId); + } + + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(uniqueMoviesViewed)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +document.addEventListener('DOMContentLoaded', () => { + showSpinner(); + initialMainContent = document.getElementById('main').innerHTML; + currentIndex = 0; + + const movieId = localStorage.getItem('selectedMovieId'); + if (movieId) { + fetchMovieDetails(movieId); + } else { + fetchMovieDetails(1011985); + } + + hideSpinner(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + showSpinner(); + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + hideSpinner(); +}); + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +document.addEventListener('DOMContentLoaded', function () { + applySettings(); +}); + +async function fetchMovieDetails(movieId) { + showSpinner(); + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + const url2 = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=videos`; + + try { + showSpinner(); + const response = await fetch(url); + const movie = await response.json(); + const imdbId = movie.imdb_id; + + fetchMovieRatings(imdbId, movie); + updateBrowserURL(movie.title); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details currently unavailable - please try again

+
`; + console.log('Error fetching movie details:', error); + } finally { + hideSpinner(); + } +} + +function getRatingDetails(rating) { + let details = { color: 'black', text: rating, description: '' }; + + switch (rating) { + case 'R': + details = { + color: 'red', + text: 'R (Restricted)', + description: ' - No one 17 and under admitted', + }; + break; + case 'PG-13': + details = { + color: 'yellow', + text: 'PG-13 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 13', + }; + break; + case 'PG': + details = { + color: 'orange', + text: 'PG (Parental Guidance Suggested)', + description: ' - May not be suitable for children', + }; + break; + case 'G': + details = { + color: 'green', + text: 'G (General Audiences)', + description: ' - All ages admitted', + }; + break; + case 'NC-17': + details = { + color: 'darkred', + text: 'NC-17 (Adults Only)', + description: ' - No one 17 and under admitted', + }; + break; + case 'TV-Y': + details = { + color: 'lightgreen', + text: 'TV-Y (All Children)', + description: ' - Appropriate for all children', + }; + break; + case 'TV-Y7': + details = { + color: 'lightblue', + text: 'TV-Y7 (Directed to Older Children)', + description: ' - Suitable for children ages 7 and up', + }; + break; + case 'TV-G': + details = { + color: 'green', + text: 'TV-G (General Audience)', + description: ' - Suitable for all ages', + }; + break; + case 'TV-PG': + details = { + color: 'orange', + text: 'TV-PG (Parental Guidance Suggested)', + description: ' - May not be suitable for younger children', + }; + break; + case 'TV-14': + details = { + color: 'yellow', + text: 'TV-14 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 14', + }; + break; + case 'TV-MA': + details = { + color: 'red', + text: 'TV-MA (Mature Audience Only)', + description: ' - Specifically designed to be viewed by adults', + }; + break; + case 'NR': + details = { + color: 'white', + text: 'NR (Not Rated)', + description: ' - Movie has not been officially rated', + }; + break; + case 'UR': + case 'Unrated': + details = { + color: 'white', + text: 'UR (Unrated)', + description: ' - Contains content not used in the rated version', + }; + break; + default: + details = { + color: 'white', + text: rating, + description: ' - Rating information not available', + }; + break; + } + + return details; +} + +async function fetchMovieRatings(imdbId, tmdbMovieData) { + showSpinner(); + document.body.offsetHeight; + + const req = [await getMovieCode2(), '58efe859', '60a09d79', '956e468a', 'bd55ada4', 'cbfc076', 'dc091ff2', '6e367eef', '2a2a3080', 'd20a931f']; + const baseURL = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}`; + + async function tryFetch(apiKey) { + const url = `${baseURL}${apiKey}`; + + try { + const response = await fetch(url); + if (!response.ok) throw new Error('API limit reached or other error'); + return await response.json(); + } catch (error) { + return null; + } + } + + async function fetchWithTimeout(apiKey, timeout = 5000) { + return new Promise(resolve => { + const timer = setTimeout(() => resolve(null), timeout); + tryFetch(apiKey) + .then(data => { + clearTimeout(timer); + resolve(data); + }) + .catch(() => { + clearTimeout(timer); + resolve(null); + }); + }); + } + + const requests = req.map(key => fetchWithTimeout(key)); + const responses = await Promise.all(requests); + const data = responses.find(response => response !== null); + + if (!data) { + populateMovieDetails(tmdbMovieData, tmdbMovieData.vote_average, 'N/A', 'View on Metacritics', 'Awards information unavailable'); + return; + } + + let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + if (imdbRating === 'N/A' || imdbRating === '0.0' || imdbRating === null) { + imdbRating = 'N/A'; + } + + let rtRating = 'N/A'; + let metascore = data.Metascore ? `${data.Metascore}/100` : 'N/A'; + let awards = data.Awards; + let rated = data.Rated ? data.Rated : 'Rating information unavailable'; + + if (awards === 'N/A') { + awards = 'Awards information unavailable'; + } + if (metascore === 'N/A/100') { + const metacriticsRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + metascore = calculateFallbackMetacriticsRating(metacriticsRatingValue, tmdbMovieData.vote_average) + '/100'; + } + if (rtRating === 'N/A') { + const imdbRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + rtRating = calculateFallbackRTRating(imdbRatingValue, tmdbMovieData.vote_average); + } + + populateMovieDetails(tmdbMovieData, imdbRating, rtRating, metascore, awards, rated); + hideSpinner(); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +function calculateFallbackRTRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0) + '%'; +} + +function calculateFallbackMetacriticsRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0); +} + +let trailerIframeDisplayed = false; + +function createTrailerButton(trailerUrl) { + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + trailerButton.id = 'trailerButton'; + + trailerButton.addEventListener('click', function () { + if (!trailerIframeDisplayed) { + showTrailerIframe(trailerUrl); + trailerButton.textContent = 'Close Trailer'; + trailerButton.title = 'Click to close the trailer'; + } else { + closeTrailerIframe(); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + } + }); + + trailerButton.classList.add('trailer-button'); + trailerButton.style.font = 'inherit'; + + return trailerButton; +} + +function closeTrailerIframe() { + const iframeContainer = document.querySelector('.trailer-button + div'); + + if (iframeContainer) { + iframeContainer.style.height = '0'; + setTimeout(() => iframeContainer.remove(), 500); + } + trailerIframeDisplayed = false; +} + +function getYouTubeVideoId(url) { + const urlObj = new URL(url); + return urlObj.searchParams.get('v'); +} + +function showTrailerIframe(trailerUrl) { + trailerUrlGlobal = trailerUrl; + + const iframeContainer = document.createElement('div'); + iframeContainer.style.position = 'relative'; + iframeContainer.style.width = '400px'; + iframeContainer.style.margin = '0 auto'; + iframeContainer.style.overflow = 'hidden'; + iframeContainer.style.height = '0'; + iframeContainer.style.transition = 'height 0.5s ease-in-out'; + iframeContainer.style.borderRadius = '8px'; + + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', `https://www.youtube.com/embed/${getYouTubeVideoId(trailerUrl)}?autoplay=1`); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('height', '315'); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'); + iframe.setAttribute('allowfullscreen', true); + + iframeContainer.appendChild(iframe); + + const trailerButton = document.querySelector('.trailer-button'); + trailerButton.parentNode.insertBefore(iframeContainer, trailerButton.nextSibling); + trailerButton.id = 'trailerButton'; + + setTimeout(() => (iframeContainer.style.height = '315px'), 50); + + trailerIframeDisplayed = true; +} + +function getRtSlug(title) { + return title + .toLowerCase() + .replace(/:/g, '') + .replace(/part one/g, 'part_1') + .replace(/-/g, '') + .replace(/&/g, 'and') + .replace(/ /g, '_') + .replace(/[^\w-]/g, ''); +} + +function createMetacriticSlug(title) { + return title + .toLowerCase() + .replace(/part\sone/g, 'part-1') + .replace(/:|_|-|\s/g, '-') + .replace(/&/g, 'and') + .replace(/--+/g, '-') + .replace(/[^\w-]/g, ''); +} + +async function fetchStreamingLinks(movieId) { + const url = `https://${getMovieVerseData()}/3/movie/${movieId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const results = data.results || {}; + let providersMap = {}; + + Object.values(results).forEach(region => { + if (region.flatrate) { + region.flatrate.forEach(provider => { + providersMap[provider.provider_id] = provider; + }); + } + }); + + return Object.values(providersMap).slice(0, 7); + } catch (error) { + console.error('Error fetching streaming links:', error); + } +} + +async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, rated) { + showSpinner(); + document.getElementById('movie-title').textContent = movie.title; + + const imdbLink = `https://www.imdb.com/title/${movie.imdb_id}`; + const streamingProviders = await fetchStreamingLinks(movie.id); + const movieTitleEncoded = encodeURIComponent(movie.title); + + const streamingHTML = + streamingProviders.length > 0 + ? streamingProviders + .map(provider => { + let providerLink; + switch (provider.provider_name.toLowerCase()) { + case 'netflix': + providerLink = `https://www.netflix.com/search?q=${movieTitleEncoded}`; + break; + case 'disney plus': + providerLink = `https://www.disneyplus.com/search?q=${movieTitleEncoded}`; + break; + case 'hbo max': + providerLink = `https://www.hbomax.com/search?q=${movieTitleEncoded}`; + break; + case 'hulu': + providerLink = `https://www.hulu.com/search?q=${movieTitleEncoded}`; + break; + case 'amazon prime video': + providerLink = `https://www.amazon.com/s?k=${movieTitleEncoded}`; + break; + case 'apple tv plus': + providerLink = `https://tv.apple.com/search?term=${movieTitleEncoded}`; + break; + case 'stan': + providerLink = `https://www.stan.com.au/search?q=${movieTitleEncoded}`; + break; + case 'player': + providerLink = `https://player.pl/szukaj?search=${movieTitleEncoded}`; + break; + default: + providerLink = `https://www.google.com/search?q=watch+${movieTitleEncoded}+on+${encodeURIComponent(provider.provider_name)}`; + break; + } + + return ``; + }) + .join('') + + `` + : 'No streaming options available.'; + + const metaCriticsLink = metascore !== 'N/A' ? `https://www.metacritic.com/search/${createMetacriticSlug(movie.title)}` : '#'; + const ratingDetails = getRatingDetails(rated); + const ratedElement = rated + ? `

Rated: ${ratingDetails.text}${ratingDetails.description}

` + : ''; + + document.getElementById('movie-rating').innerHTML = ``; + document.title = movie.title + ' - Movie Details'; + + const movieDescription = document.getElementById('movie-description'); + const metascoreElement = metascore + ? `

Metascore: ${metascore}

` + : ''; + const awardsElement = awards ? `

Awards: ${awards}

` : ''; + + const overview = movie.overview ? movie.overview : 'No overview available'; + const genres = movie.genres.map(genre => genre.name).join(', '); + + const releaseDate = movie.release_date || 'Release date not available'; + const releaseDateObj = new Date(releaseDate); + const currentDate = new Date(); + + let timeAgoString = ''; + if (releaseDateObj > currentDate) { + timeAgoString = '0 months'; + } else { + const timeDiff = currentDate - releaseDateObj; + let years = Math.floor(timeDiff / (1000 * 60 * 60 * 24 * 365.25)); + let remainingMonths = Math.round((timeDiff % (1000 * 60 * 60 * 24 * 365.25)) / (1000 * 60 * 60 * 24 * 30.44)); + + if (remainingMonths >= 12) { + years += 1; + remainingMonths -= 12; + } + if (years > 0) { + timeAgoString += `${years} year${years > 1 ? 's' : ''}`; + if (remainingMonths > 0) { + timeAgoString += ` and `; + } + } + if (remainingMonths > 0 || years === 0) { + timeAgoString += `${remainingMonths} month${remainingMonths > 1 ? 's' : ''}`; + } + } + + const releaseDateWithTimeAgo = `${releaseDate} (${timeAgoString} ago)`; + const budget = movie.budget === 0 ? 'Information Not Available' : `$${movie.budget.toLocaleString()}`; + const revenue = movie.revenue <= 1000 ? 'Information Not Available' : `$${movie.revenue.toLocaleString()}`; + const tagline = movie.tagline ? movie.tagline : 'No tagline found'; + const languages = movie.spoken_languages.map(lang => lang.name).join(', '); + + const countries = movie.production_countries.map(country => country.name).join(', '); + const popularityScore = movie.popularity.toFixed(0); + + let keywords = movie.keywords + ? movie.keywords.keywords + .map( + kw => `${kw.name}` + ) + .join(', ') + : 'None Available'; + + if (keywords.length === 0) { + keywords = 'No keywords have been added'; + } + + const scaledRating = (movie.vote_average / 2).toFixed(1); + const popularityThreshold = 80; + const isPopular = movie.popularity >= popularityThreshold; + const popularityText = isPopular + ? `${popularityScore} (This movie is popular)` + : `${popularityScore} (This movie is unpopular)`; + + const movieStatus = `

Status: ${movie.status}

`; + const runtime = movie.runtime > 0 ? movie.runtime + ' minutes' : 'Runtime Info Not Available'; + + const originalTitle = + movie.original_title !== movie.title + ? `

Original Title: ${movie.original_title}

` + : `

Original Title: ${movie.title}

`; + const tmdbRating = movie.vote_average.toFixed(1); + + document.getElementById('movie-description').innerHTML += ` +

Description: ${overview}

+ ${originalTitle} +

Tagline: ${tagline}

+

Genres: ${genres}

+ ${ratedElement} + ${movieStatus} +

Release Date: ${releaseDateWithTimeAgo}

+

Runtime: ${runtime}

+

Budget: ${budget}

+

Revenue: ${revenue}

+

Languages: ${languages}

+

Countries of Production: ${countries}

+

Popularity Score: ${popularityText}

+

MovieVerse User Rating: ${scaledRating}/5.0 (based on ${ + movie.vote_count + } votes)

+ ${awardsElement} +

TMDb Rating: ${tmdbRating}/10.0

+ ${metascoreElement} + `; + + if (movie.credits && movie.credits.crew) { + const directors = movie.credits.crew.filter(member => member.job === 'Director'); + + if (directors.length > 0) { + const directorSection = document.createElement('div'); + directorSection.classList.add('director-section'); + directorSection.style.textAlign = 'center'; + + const directorTitle = document.createElement('p'); + directorTitle.innerHTML = 'Director:'; + directorTitle.style.padding = '0'; + directorSection.appendChild(directorTitle); + + const directorList = document.createElement('div'); + directorList.classList.add('director-list'); + + directors.forEach(director => { + const directorLink = document.createElement('a'); + directorLink.classList.add('director-link'); + directorLink.href = 'javascript:void(0);'; + directorLink.style.textDecoration = 'none'; + directorLink.setAttribute('onclick', `handleDirectorClick(${director.id}, '${director.name.replace(/'/g, "\\'")}');`); + + const directorItem = document.createElement('div'); + directorItem.classList.add('cast-item'); + + const directorImage = document.createElement('img'); + directorImage.classList.add('cast-image'); + + if (director.profile_path) { + directorImage.src = IMGPATH2 + director.profile_path; + directorImage.alt = `${director.name} Profile Picture`; + } else { + directorImage.alt = 'Image Not Available'; + directorImage.src = 'https://movie-verse.com/images/user-default.png'; + directorImage.style.filter = 'grayscale(100%)'; + directorImage.style.objectFit = 'cover'; + } + + directorItem.appendChild(directorImage); + + const directorDetails = document.createElement('div'); + directorDetails.classList.add('cast-details'); + + const directorName = document.createElement('p'); + directorName.classList.add('actor-name'); + directorName.textContent = director.name; + directorDetails.appendChild(directorName); + + directorItem.appendChild(directorDetails); + directorLink.appendChild(directorItem); + directorList.appendChild(directorLink); + }); + + directorSection.appendChild(directorList); + document.getElementById('movie-description').appendChild(directorSection); + } else { + const noDirectorsElement = document.createElement('p'); + noDirectorsElement.innerHTML = `Director: Information not available`; + document.getElementById('movie-description').appendChild(noDirectorsElement); + } + } + + const castSection = document.createElement('div'); + castSection.classList.add('cast-section'); + + const castTitle = document.createElement('p'); + castTitle.innerHTML = 'Notable Cast:'; + castSection.appendChild(castTitle); + + if (movie.credits && movie.credits.cast.length > 0) { + const castList = document.createElement('div'); + castList.classList.add('cast-list'); + castList.style.display = 'flex'; + castList.style.flexWrap = 'wrap'; + castList.style.justifyContent = 'center'; + castList.style.gap = '3px'; + const topTwelveCast = movie.credits.cast.slice(0, 12); + + topTwelveCast.forEach(actor => { + const castItemLink = document.createElement('a'); + castItemLink.classList.add('actor-link'); + castItemLink.href = 'javascript:void(0);'; + castItemLink.setAttribute('onclick', `selectActorId(${actor.id}, '${actor.name.replace(/'/g, "\\'")}');`); + + const castItem = document.createElement('div'); + castItem.classList.add('cast-item'); + + const actorImage = document.createElement('img'); + actorImage.classList.add('cast-image'); + + if (actor.profile_path) { + actorImage.src = IMGPATH2 + actor.profile_path; + actorImage.alt = `${actor.name} Profile Picture`; + } else { + actorImage.alt = 'Image Not Available'; + actorImage.src = 'https://movie-verse.com/images/user-default.png'; + actorImage.style.filter = 'grayscale(100%)'; + actorImage.style.objectFit = 'cover'; + } + + castItem.appendChild(actorImage); + + const actorDetails = document.createElement('div'); + actorDetails.classList.add('cast-details'); + + const actorName = document.createElement('p'); + actorName.classList.add('actor-name'); + actorName.textContent = actor.name; + actorDetails.appendChild(actorName); + + const character = actor.character ? ` (as ${actor.character})` : ''; + const actorRole = document.createElement('p'); + actorRole.classList.add('actor-role'); + actorRole.textContent = character; + actorDetails.appendChild(actorRole); + + castItem.appendChild(actorDetails); + castItemLink.appendChild(castItem); + castList.appendChild(castItemLink); + }); + + castSection.appendChild(castList); + } else { + castSection.appendChild(document.createTextNode('None available.')); + } + + document.getElementById('movie-description').appendChild(castSection); + + if (movie.similar && movie.similar.results && movie.similar.results.length > 0) { + const similarMoviesSection = document.createElement('div'); + similarMoviesSection.classList.add('similar-movies-section'); + + const similarMoviesTitle = document.createElement('p'); + similarMoviesTitle.innerHTML = 'Similar Movies:'; + similarMoviesSection.appendChild(similarMoviesTitle); + + const similarMoviesList = document.createElement('div'); + similarMoviesList.classList.add('similar-movies-list'); + similarMoviesList.style.display = 'flex'; + similarMoviesList.style.flexWrap = 'wrap'; + similarMoviesList.style.justifyContent = 'center'; + similarMoviesList.style.gap = '3px'; + + let topTenSimilarMovies = movie.similar.results; + topTenSimilarMovies = topTenSimilarMovies.sort((a, b) => b.popularity - a.popularity); + topTenSimilarMovies = topTenSimilarMovies.slice(0, 18); + topTenSimilarMovies.forEach(similarMovie => { + const similarMovieLink = document.createElement('a'); + similarMovieLink.classList.add('similar-movie-link'); + similarMovieLink.href = 'javascript:void(0);'; + similarMovieLink.setAttribute('onclick', `handleSimilarMovieClick(${similarMovie.id}, '${similarMovie.title.replace(/'/g, "\\'")}');`); + + const similarMovieItem = document.createElement('div'); + similarMovieItem.classList.add('cast-item'); + + const similarMovieImage = document.createElement('img'); + similarMovieImage.classList.add('cast-image'); + + if (similarMovie.poster_path) { + similarMovieImage.src = IMGPATH2 + similarMovie.poster_path; + similarMovieImage.alt = `${similarMovie.title} Poster`; + similarMovieImage.style.objectFit = 'fill'; + } else { + similarMovieImage.alt = 'Image Not Available'; + similarMovieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + similarMovieImage.style.filter = 'grayscale(100%)'; + similarMovieImage.style.objectFit = 'cover'; + } + + similarMovieItem.appendChild(similarMovieImage); + + const similarMovieDetails = document.createElement('div'); + similarMovieDetails.classList.add('cast-details'); + + const similarMovieTitle = document.createElement('p'); + similarMovieTitle.classList.add('actor-name'); + similarMovieTitle.textContent = similarMovie.title; + similarMovieDetails.appendChild(similarMovieTitle); + + similarMovieItem.appendChild(similarMovieDetails); + similarMovieLink.appendChild(similarMovieItem); + similarMoviesList.appendChild(similarMovieLink); + }); + + similarMoviesSection.appendChild(similarMoviesList); + document.getElementById('movie-description').appendChild(similarMoviesSection); + } else { + const noSimilarMoviesElement = document.createElement('p'); + noSimilarMoviesElement.innerHTML = `Similar Movies: None available`; + document.getElementById('movie-description').appendChild(noSimilarMoviesElement); + } + + if (movie.production_companies && movie.production_companies.length > 0) { + const companiesSection = document.createElement('div'); + companiesSection.classList.add('companies-section'); + + const companiesTitle = document.createElement('p'); + companiesTitle.innerHTML = 'Production Companies:'; + companiesSection.appendChild(companiesTitle); + + const companiesList = document.createElement('div'); + companiesList.classList.add('companies-list'); + companiesList.style.display = 'flex'; + companiesList.style.flexWrap = 'wrap'; + companiesList.style.justifyContent = 'center'; + companiesList.style.gap = '5px'; + + let productionCompanies = movie.production_companies.slice(0, 6); + + productionCompanies.forEach(company => { + const companyLink = document.createElement('a'); + companyLink.classList.add('company-link'); + companyLink.href = 'javascript:void(0);'; + companyLink.setAttribute('onclick', `handleCompanyClick(${company.id}, '${company.name.replace(/'/g, "\\'")}');`); + + const companyItem = document.createElement('div'); + companyItem.classList.add('company-item'); + + const companyLogo = document.createElement('img'); + companyLogo.classList.add('company-logo'); + + const IMGPATH3 = 'https://image.tmdb.org/t/p/w300'; + + if (company.logo_path) { + companyLogo.src = IMGPATH3 + company.logo_path; + companyLogo.alt = `${company.name} Logo`; + companyLogo.style.backgroundColor = 'white'; + } else { + companyLogo.alt = 'Logo Not Available'; + companyLogo.src = 'https://movie-verse.com/images/company-default.png'; + companyLogo.style.filter = 'grayscale(100%)'; + companyLogo.style.objectFit = 'cover'; + } + + companyItem.appendChild(companyLogo); + + const companyDetails = document.createElement('div'); + companyDetails.classList.add('company-details'); + + const companyName = document.createElement('p'); + companyName.classList.add('company-name'); + companyName.textContent = company.name; + companyDetails.appendChild(companyName); + + companyItem.appendChild(companyDetails); + companyLink.appendChild(companyItem); + companiesList.appendChild(companyLink); + }); + + companiesSection.appendChild(companiesList); + document.getElementById('movie-description').appendChild(companiesSection); + } else { + const noCompaniesElement = document.createElement('p'); + noCompaniesElement.innerHTML = `Production Companies: Information not available`; + document.getElementById('movie-description').appendChild(noCompaniesElement); + } + + document.getElementById('movie-description').innerHTML += ` +

Streaming Options: ${streamingHTML}

`; + + const homepage = document.createElement('p'); + homepage.innerHTML = movie.homepage + ? `Homepage: Visit homepage` + : `Homepage: Information unavailable`; + movieDescription.appendChild(homepage); + + const keywordsElement = document.createElement('p'); + keywordsElement.innerHTML = `Keywords: ${keywords}`; + movieDescription.appendChild(keywordsElement); + + createImdbRatingCircle(imdbRating, imdbLink); + + const mediaUrl = `https://${getMovieVerseData()}/3/movie/${movie.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + const mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 90vw; + max-width: 450px; + margin: 20px auto; + overflow: hidden; + box-sizing: border-box; + border-radius: 16px; + `; + + const mediaTitle = document.createElement('p'); + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + const imageWrapper = document.createElement('div'); + imageWrapper.style = ` + width: 100%; + max-height: 210px; + border-radius: 16px; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + position: relative; + `; + + const imageElement = document.createElement('img'); + imageElement.style = ` + width: 100%; + height: auto; + transition: opacity 0.5s ease-in-out; + opacity: 1; + cursor: pointer; + object-fit: contain; + border-radius: 16px; + `; + + imageWrapper.appendChild(imageElement); + mediaContainer.appendChild(imageWrapper); + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Movie Image + + × +
+ `; + + document.body.insertAdjacentHTML('beforeend', modalHtml); + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const prevButton = document.createElement('button'); + prevButton.innerHTML = ''; + prevButton.style = ` + position: absolute; + left: 5px; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + z-index: 10; + `; + prevButton.onmouseover = () => (prevButton.style.backgroundColor = '#ff8623'); + prevButton.onmouseout = () => (prevButton.style.backgroundColor = '#7378c5'); + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + imageWrapper.appendChild(prevButton); + + const nextButton = document.createElement('button'); + nextButton.innerHTML = ''; + nextButton.style = ` + position: absolute; + right: 5px; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + z-index: 10; + `; + nextButton.onmouseover = () => (nextButton.style.backgroundColor = '#ff8623'); + nextButton.onmouseout = () => (nextButton.style.backgroundColor = '#7378c5'); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + imageWrapper.appendChild(nextButton); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + const movieImage = document.getElementById('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + movieImage.loading = 'lazy'; + } else { + const noImageContainer = document.createElement('div'); + noImageContainer.id = 'no-image-container'; + noImageContainer.style.textAlign = 'center'; + + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageContainer.appendChild(noImageText); + + if (movieImage.parentNode) { + movieImage.parentNode.replaceChild(noImageContainer, movieImage); + } else { + document.body.appendChild(noImageContainer); + } + } + + const movieId = movie.id; + const code = `${getMovieCode()}`; + const url2 = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=videos`; + + try { + const response2 = await fetch(url2); + const movie2 = await response2.json(); + const trailers = movie2.videos.results.filter(video => video.type === 'Trailer'); + + if (trailers.length > 0) { + const trailerUrl = `https://www.youtube.com/watch?v=${trailers[0].key}`; + trailerButton = createTrailerButton(trailerUrl); + detailsContainer.appendChild(trailerButton); + } + + updateBrowserURL(movie.title); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details not found - Try again with a different movie

+
`; + console.log('Error fetching movie details:', error); + } + + hideSpinner(); +} + +function createImdbRatingCircle(imdbRating, imdbId) { + if (imdbRating === 'N/A' || imdbRating === null || imdbRating === undefined) { + imdbRating = 'N/A'; + } else { + imdbRating = parseFloat(imdbRating); + if (!isNaN(imdbRating)) { + imdbRating = imdbRating.toFixed(1); + } else { + imdbRating = 'N/A'; + } + } + + let circleContainer = document.getElementById('imdbRatingCircleContainer'); + if (!circleContainer) { + circleContainer = document.createElement('div'); + circleContainer.id = 'imdbRatingCircleContainer'; + circleContainer.className = 'progress-container'; + const imdbLink = `${imdbId}`; + circleContainer.innerHTML = ` + +
IMDb Rating
+
+ + + + ${imdbRating} + + `; + + if (imdbRating === 'N/A') { + circleContainer.innerHTML += `

Rating information currently unavailable

`; + } + + document.getElementById('movie-description').appendChild(circleContainer); + } else { + const text = document.getElementById('imdbRatingText'); + text.textContent = `${imdbRating}`; + } + + const circle = circleContainer.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); +} + +function setProgress(circle, text, rating) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (rating / 10) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', rating <= 5 ? '#FF0000' : rating >= 7.5 ? '#4CAF50' : '#2196F3'); + text.textContent = `${rating}`; + }, 10); +} + +function retriggerAnimation(imdbRating) { + const circle = document.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); +} + +function getSavedTextColor() { + return localStorage.getItem('textColor') || 'white'; +} + +function handleKeywordClick(keyword) { + localStorage.setItem('searchQuery', keyword); + window.location.href = 'search.html'; +} + +function handleActorClick(actorId, actorName) { + selectActorId(actorId, actorName); +} + +function handleDirectorClick(directorId, directorName) { + localStorage.setItem('selectedDirectorId', directorId); + document.title = `${directorName} - Director's Details`; + updateUniqueDirectorsViewed(directorId); + updateDirectorVisitCount(directorId, directorName); + window.location.href = 'director-details.html'; +} + +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + localStorage.setItem('selectedActorId', actorId); + window.location.href = 'actor-details.html'; +} + +function handleCompanyClick(companyId, companyName) { + localStorage.setItem('selectedCompanyId', companyId); + document.title = `${companyName} - Company Details`; + window.location.href = 'company-details.html'; + updateUniqueCompaniesViewed(companyId); +} + +function handleSimilarMovieClick(movieId, movieTitle) { + localStorage.setItem('selectedMovieId', movieId); + document.title = `${movieTitle} - Movie Details`; + window.location.href = 'movie-details.html'; + updateMovieVisitCount(movieId, movieTitle); +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} + +function getMovieCode2() { + const codeOfMovie = 'MmJhOGU1MzY='; + return atob(codeOfMovie); +} + +function getMovieName() { + const moviename = 'YXBpa2V5PQ=='; + return atob(moviename); +} + +function getMovieActor() { + const actor = 'd3d3Lm9tZGJhcGkuY29t'; + return atob(actor); +} + +function updateAverageMovieRating(movieId, newRating) { + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + + let totalRating = 0; + let totalMoviesRated = 0; + + for (let id in savedRatings) { + totalRating += parseFloat(savedRatings[id]); + totalMoviesRated++; + } + let averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1).toString()); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + fallbackMovieSelection(); + } +} + +function updateUniqueActorsViewed(actorId) { + let viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + if (!viewedActors.includes(actorId)) { + viewedActors.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(viewedActors)); + } +} + +function updateUniqueCompaniesViewed(companyId) { + let viewedCompanies = JSON.parse(localStorage.getItem('uniqueCompaniesViewed')) || []; + if (!viewedCompanies.includes(companyId)) { + viewedCompanies.push(companyId); + localStorage.setItem('uniqueCompaniesViewed', JSON.stringify(viewedCompanies)); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-match.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-match.js new file mode 100644 index 00000000..069f5c82 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-match.js @@ -0,0 +1,1378 @@ +const main = document.getElementById('movie-match-form'); +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const searchTitle = document.getElementById('search-title'); +const otherTitle = document.getElementById('other1'); + +document.getElementById('movie-match-form').addEventListener('submit', function (event) { + event.preventDefault(); + const mood = document.getElementById('mood').value; + const genre = document.getElementById('genre').value; + const period = document.getElementById('period').value; + findMovieMatch(mood, genre, period); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://api.themoviedb.org/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function findMovieMatch(mood, genre, period) { + const movieDatabase = [ + // Movies starting with the mood "happy" + { + id: '432413', + title: 'The Avengers', + mood: 'happy', + genre: 'action', + period: '2010s', + }, + { + id: '299534', + title: 'Avengers: Endgame', + mood: 'happy', + genre: 'action', + period: '2020s', + }, + { + id: '1726', + title: 'Iron Man', + mood: 'happy', + genre: 'action', + period: '2000s', + }, + { + id: '562', + title: 'Die Hard', + mood: 'happy', + genre: 'action', + period: '90s', + }, + { + id: '89', + title: 'Indiana Jones and the Last Crusade', + mood: 'happy', + genre: 'action', + period: '80s', + }, + + { + id: '620', + title: 'Ghostbusters', + mood: 'happy', + genre: 'comedy', + period: '80s', + }, + { + id: '105', + title: 'Back to the Future', + mood: 'happy', + genre: 'comedy', + period: '90s', + }, + { + id: '18785', + title: 'The Hangover', + mood: 'happy', + genre: 'comedy', + period: '2000s', + }, + { + id: '284053', + title: 'Thor: Ragnarok', + mood: 'happy', + genre: 'comedy', + period: '2010s', + }, + { + id: '515001', + title: 'Jojo Rabbit', + mood: 'happy', + genre: 'comedy', + period: '2020s', + }, + + { + id: '773', + title: 'Little Miss Sunshine', + mood: 'happy', + genre: 'drama', + period: '2000s', + }, + { + id: '1402', + title: 'The Pursuit of Happyness', + mood: 'happy', + genre: 'drama', + period: '2010s', + }, + { + id: '508442', + title: 'Soul', + mood: 'happy', + genre: 'drama', + period: '2020s', + }, + { + id: '489', + title: 'Good Will Hunting', + mood: 'happy', + genre: 'drama', + period: '90s', + }, + { + id: '207', + title: 'Dead Poets Society', + mood: 'happy', + genre: 'drama', + period: '80s', + }, + + { + id: '118340', + title: 'Guardians of the Galaxy', + mood: 'happy', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '607', + title: 'Men in Black', + mood: 'happy', + genre: 'sci-fi', + period: '90s', + }, + { + id: '601', + title: 'E.T. the Extra-Terrestrial', + mood: 'happy', + genre: 'sci-fi', + period: '80s', + }, + { + id: '333339', + title: 'Ready Player One', + mood: 'happy', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '438631', + title: 'Dune', + mood: 'happy', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '50646', + title: 'Crazy Stupid Love', + mood: 'happy', + genre: 'romance', + period: '2010s', + }, + { + id: '1581', + title: 'The Holiday', + mood: 'happy', + genre: 'romance', + period: '2000s', + }, + { + id: '114', + title: 'Pretty Woman', + mood: 'happy', + genre: 'romance', + period: '90s', + }, + { + id: '2028', + title: 'Say Anything...', + mood: 'happy', + genre: 'romance', + period: '80s', + }, + { + id: '614409', + title: 'To All the Boys: Always and Forever', + mood: 'happy', + genre: 'romance', + period: '2020s', + }, + + // Movies starting with the mood "sad" + { + id: '424', + title: "Schindler's List", + mood: 'sad', + genre: 'drama', + period: '90s', + }, + { + id: '334541', + title: 'Manchester by the Sea', + mood: 'sad', + genre: 'drama', + period: '2010s', + }, + { + id: '4148', + title: 'Revolutionary Road', + mood: 'sad', + genre: 'drama', + period: '2000s', + }, + { + id: '16619', + title: 'Ordinary People', + mood: 'sad', + genre: 'drama', + period: '80s', + }, + { + id: '1135095', + title: 'Pieces of a Woman', + mood: 'sad', + genre: 'drama', + period: '2020s', + }, + + { + id: '38', + title: 'Eternal Sunshine of the Spotless Mind', + mood: 'sad', + genre: 'romance', + period: '2000s', + }, + { + id: '46705', + title: 'Blue Valentine', + mood: 'sad', + genre: 'romance', + period: '2010s', + }, + { + id: '222935', + title: 'The Fault in Our Stars', + mood: 'sad', + genre: 'romance', + period: '2010s', + }, + { + id: '142', + title: 'Brokeback Mountain', + mood: 'sad', + genre: 'romance', + period: '2000s', + }, + { + id: '589049', + title: 'The Photograph', + mood: 'sad', + genre: 'romance', + period: '2020s', + }, + + { + id: '335984', + title: 'Blade Runner 2049', + mood: 'sad', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '644', + title: 'A.I. Artificial Intelligence', + mood: 'sad', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '152601', + title: 'Her', + mood: 'sad', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '9426', + title: 'The Fly', + mood: 'sad', + genre: 'sci-fi', + period: '80s', + }, + { + id: '419704', + title: 'Ad Astra', + mood: 'sad', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '637', + title: 'Life Is Beautiful', + mood: 'sad', + genre: 'comedy', + period: '90s', + }, + { + id: '9428', + title: 'The Royal Tenenbaums', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '153', + title: 'Lost in Translation', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '9675', + title: 'Sideways', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '7326', + title: 'Juno', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + + { + id: '263115', + title: 'Logan', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '70', + title: 'Million Dollar Baby', + mood: 'sad', + genre: 'action', + period: '2000s', + }, + { + id: '49026', + title: 'The Dark Knight Rises', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '475557', + title: 'Joker', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '98', + title: 'Gladiator', + mood: 'sad', + genre: 'action', + period: '2000s', + }, + + // Movies starting with the mood "adventurous" + { + id: '85', + title: 'Indiana Jones and the Raiders of the Lost Ark', + mood: 'adventurous', + genre: 'action', + period: '80s', + }, + { + id: '76341', + title: 'Mad Max: Fury Road', + mood: 'adventurous', + genre: 'action', + period: '2010s', + }, + { + id: '98', + title: 'Gladiator', + mood: 'adventurous', + genre: 'action', + period: '2000s', + }, + { + id: '562', + title: 'Die Hard', + mood: 'adventurous', + genre: 'action', + period: '90s', + }, + { + id: '438631', + title: 'Dune', + mood: 'adventurous', + genre: 'action', + period: '2020s', + }, + + { + id: '620', + title: 'Ghostbusters', + mood: 'adventurous', + genre: 'comedy', + period: '80s', + }, + { + id: '353486', + title: 'Jumanji: Welcome to the Jungle', + mood: 'adventurous', + genre: 'comedy', + period: '2010s', + }, + { + id: '22', + title: 'Pirates of the Caribbean', + mood: 'adventurous', + genre: 'comedy', + period: '2000s', + }, + { + id: '607', + title: 'Men in Black', + mood: 'adventurous', + genre: 'comedy', + period: '90s', + }, + { + id: '550988', + title: 'Free Guy', + mood: 'adventurous', + genre: 'comedy', + period: '2020s', + }, + + { + id: '281957', + title: 'The Revenant', + mood: 'adventurous', + genre: 'drama', + period: '2010s', + }, + { + id: '8358', + title: 'Cast Away', + mood: 'adventurous', + genre: 'drama', + period: '2000s', + }, + { + id: '947', + title: 'Lawrence of Arabia', + mood: 'adventurous', + genre: 'drama', + period: '80s', + }, + { + id: '13', + title: 'Forrest Gump', + mood: 'adventurous', + genre: 'drama', + period: '90s', + }, + { + id: '581734', + title: 'Nomadland', + mood: 'adventurous', + genre: 'drama', + period: '2020s', + }, + + { + id: '11', + title: 'Star Wars', + mood: 'adventurous', + genre: 'sci-fi', + period: '80s', + }, + { + id: '19995', + title: 'Avatar', + mood: 'adventurous', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '27205', + title: 'Inception', + mood: 'adventurous', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '335984', + title: 'Blade Runner', + mood: 'adventurous', + genre: 'sci-fi', + period: '90s', + }, + { + id: '438631', + title: 'Dune', + mood: 'adventurous', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '2493', + title: 'The Princess Bride', + mood: 'adventurous', + genre: 'romance', + period: '80s', + }, + { + id: '313369', + title: 'La La Land', + mood: 'adventurous', + genre: 'romance', + period: '2010s', + }, + { + id: '24420', + title: "The Time Traveler's Wife", + mood: 'adventurous', + genre: 'romance', + period: '2000s', + }, + { + id: '597', + title: 'Titanic', + mood: 'adventurous', + genre: 'romance', + period: '90s', + }, + { + id: '672647', + title: 'The Map of Tiny Perfect Things', + mood: 'adventurous', + genre: 'romance', + period: '2020s', + }, + + // Movies starting with the mood "romantic" + { + id: '11036', + title: 'The Notebook', + mood: 'romantic', + genre: 'drama', + period: '2000s', + }, + { + id: '332562', + title: 'A Star is Born', + mood: 'romantic', + genre: 'drama', + period: '2010s', + }, + { + id: '4348', + title: 'Pride and Prejudice', + mood: 'romantic', + genre: 'drama', + period: '2000s', + }, + { + id: '289', + title: 'Casablanca', + mood: 'romantic', + genre: 'drama', + period: 'classic', + }, + { + id: '398818', + title: 'Call Me by Your Name', + mood: 'romantic', + genre: 'drama', + period: '2010s', + }, + + { + id: '194', + title: 'Amélie', + mood: 'romantic', + genre: 'romance', + period: '2000s', + }, + { + id: '313369', + title: 'La La Land', + mood: 'romantic', + genre: 'romance', + period: '2010s', + }, + { + id: '76', + title: 'Before Sunrise', + mood: 'romantic', + genre: 'romance', + period: '90s', + }, + { + id: '416477', + title: 'The Big Sick', + mood: 'romantic', + genre: 'romance', + period: '2010s', + }, + { + id: '531428', + title: 'Portrait of a Lady on Fire', + mood: 'romantic', + genre: 'romance', + period: '2020s', + }, + + { + id: '152601', + title: 'Her', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '38050', + title: 'The Adjustment Bureau', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '38', + title: 'Eternal Sunshine of the Spotless Mind', + mood: 'romantic', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '274870', + title: 'Passengers', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '122906', + title: 'About Time', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + + { + id: '639', + title: 'When Harry Met Sally', + mood: 'romantic', + genre: 'comedy', + period: '80s', + }, + { + id: '455207', + title: 'Crazy Rich Asians', + mood: 'romantic', + genre: 'comedy', + period: '2010s', + }, + { + id: '509', + title: 'Notting Hill', + mood: 'romantic', + genre: 'comedy', + period: '90s', + }, + { + id: '4951', + title: '10 Things I Hate About You', + mood: 'romantic', + genre: 'comedy', + period: '90s', + }, + { + id: '18240', + title: 'The Proposal', + mood: 'romantic', + genre: 'comedy', + period: '2000s', + }, + + { + id: '787', + title: 'Mr. & Mrs. Smith', + mood: 'romantic', + genre: 'action', + period: '2000s', + }, + { + id: '36955', + title: 'True Lies', + mood: 'romantic', + genre: 'action', + period: '90s', + }, + { + id: '10529', + title: 'Outlander', + mood: 'romantic', + genre: 'action', + period: '2000s', + }, + { + id: '2493', + title: 'The Princess Bride', + mood: 'romantic', + genre: 'action', + period: '80s', + }, + { + id: '547016', + title: 'The Old Guard', + mood: 'romantic', + genre: 'action', + period: '2020s', + }, + + // Movies starting with the mood "scary" + { + id: '493922', + title: 'Hereditary', + mood: 'scary', + genre: 'drama', + period: '2010s', + }, + { + id: '274', + title: 'The Silence of the Lambs', + mood: 'scary', + genre: 'drama', + period: '90s', + }, + { + id: '539', + title: 'Psycho', + mood: 'scary', + genre: 'drama', + period: 'classic', + }, + { + id: '44214', + title: 'Black Swan', + mood: 'scary', + genre: 'drama', + period: '2000s', + }, + { + id: '503919', + title: 'The Lighthouse', + mood: 'scary', + genre: 'drama', + period: '2020s', + }, + + { + id: '310131', + title: 'The Witch', + mood: 'scary', + genre: 'horror', + period: '2010s', + }, + { + id: '694', + title: 'The Shining', + mood: 'scary', + genre: 'horror', + period: '80s', + }, + { + id: '377', + title: 'A Nightmare on Elm Street', + mood: 'scary', + genre: 'horror', + period: '80s', + }, + { + id: '419430', + title: 'Get Out', + mood: 'scary', + genre: 'horror', + period: '2010s', + }, + { + id: '565', + title: 'The Ring', + mood: 'scary', + genre: 'horror', + period: '2000s', + }, + + { + id: '8413', + title: 'Event Horizon', + mood: 'scary', + genre: 'sci-fi', + period: '90s', + }, + { + id: '348', + title: 'Alien', + mood: 'scary', + genre: 'sci-fi', + period: '80s', + }, + { + id: '300668', + title: 'Annihilation', + mood: 'scary', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '447332', + title: 'A Quiet Place', + mood: 'scary', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '443791', + title: 'Underwater', + mood: 'scary', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '747', + title: 'Shaun of the Dead', + mood: 'scary', + genre: 'comedy', + period: '2000s', + }, + { + id: '19908', + title: 'Zombieland', + mood: 'scary', + genre: 'comedy', + period: '2000s', + }, + { + id: '4011', + title: 'Beetlejuice', + mood: 'scary', + genre: 'comedy', + period: '80s', + }, + { + id: '22970', + title: 'The Cabin in the Woods', + mood: 'scary', + genre: 'comedy', + period: '2010s', + }, + { + id: '425909', + title: 'Ghostbusters: Afterlife', + mood: 'scary', + genre: 'comedy', + period: '2020s', + }, + + { + id: '72190', + title: 'World War Z', + mood: 'scary', + genre: 'action', + period: '2010s', + }, + { + id: '6479', + title: 'I Am Legend', + mood: 'scary', + genre: 'action', + period: '2000s', + }, + { + id: '106', + title: 'Predator', + mood: 'scary', + genre: 'action', + period: '80s', + }, + { + id: '396535', + title: 'Train to Busan', + mood: 'scary', + genre: 'action', + period: '2010s', + }, + { + id: '503736', + title: 'Army of the Dead', + mood: 'scary', + genre: 'action', + period: '2020s', + }, + + // Movies starting with the mood "thoughtful" + { + id: '8967', + title: 'The Tree of Life', + mood: 'thoughtful', + genre: 'drama', + period: '2010s', + }, + { + id: '14', + title: 'American Beauty', + mood: 'thoughtful', + genre: 'drama', + period: '90s', + }, + { + id: '453', + title: 'A Beautiful Mind', + mood: 'thoughtful', + genre: 'drama', + period: '2000s', + }, + { + id: '595', + title: 'To Kill a Mockingbird', + mood: 'thoughtful', + genre: 'drama', + period: 'classic', + }, + { + id: '581734', + title: 'Nomadland', + mood: 'thoughtful', + genre: 'drama', + period: '2020s', + }, + + { + id: '419430', + title: 'Get Out', + mood: 'thoughtful', + genre: 'horror', + period: '2010s', + }, + { + id: '1933', + title: 'The Others', + mood: 'thoughtful', + genre: 'horror', + period: '2000s', + }, + { + id: '745', + title: 'The Sixth Sense', + mood: 'thoughtful', + genre: 'horror', + period: '90s', + }, + { + id: '805', + title: "Rosemary's Baby", + mood: 'thoughtful', + genre: 'horror', + period: 'classic', + }, + { + id: '530385', + title: 'Midsommar', + mood: 'thoughtful', + genre: 'horror', + period: '2020s', + }, + + { + id: '335984', + title: 'Blade Runner 2049', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '27205', + title: 'Inception', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '141', + title: 'Donnie Darko', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '62', + title: '2001: A Space Odyssey', + mood: 'thoughtful', + genre: 'sci-fi', + period: 'classic', + }, + { + id: '264660', + title: 'Ex Machina', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '120467', + title: 'The Grand Budapest Hotel', + mood: 'thoughtful', + genre: 'comedy', + period: '2010s', + }, + { + id: '153', + title: 'Lost in Translation', + mood: 'thoughtful', + genre: 'comedy', + period: '2000s', + }, + { + id: '137', + title: 'Groundhog Day', + mood: 'thoughtful', + genre: 'comedy', + period: '90s', + }, + { + id: '935', + title: 'Dr. Strangelove', + mood: 'thoughtful', + genre: 'comedy', + period: 'classic', + }, + { + id: '515001', + title: 'Jojo Rabbit', + mood: 'thoughtful', + genre: 'comedy', + period: '2020s', + }, + + { + id: '603', + title: 'The Matrix', + mood: 'thoughtful', + genre: 'action', + period: '90s', + }, + { + id: '76341', + title: 'Mad Max: Fury Road', + mood: 'thoughtful', + genre: 'action', + period: '2010s', + }, + { + id: '9693', + title: 'Children of Men', + mood: 'thoughtful', + genre: 'action', + period: '2000s', + }, + { + id: '577922', + title: 'Tenet', + mood: 'thoughtful', + genre: 'action', + period: '2020s', + }, + { + id: '335984', + title: 'Blade Runner', + mood: 'thoughtful', + genre: 'action', + period: '80s', + }, + ]; + + const filteredMovies = movieDatabase.filter(movie => movie.mood === mood && movie.genre === genre && movie.period === period); + + if (filteredMovies.length > 0) { + const randomIndex = Math.floor(Math.random() * filteredMovies.length); + const matchedMovie = filteredMovies[randomIndex]; + + localStorage.setItem('selectedMovieId', matchedMovie.id); + window.location.href = 'movie-details.html'; + } else { + alert('No match found. Try different criteria.'); + } +} + +const form = document.getElementById('form1'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-timeline.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-timeline.js new file mode 100644 index 00000000..5d947c26 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/movie-timeline.js @@ -0,0 +1,647 @@ +let alertShown = false; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.getElementById('start-year').addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + event.preventDefault(); + updateMovies(); + } +}); + +document.getElementById('end-year').addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + event.preventDefault(); + updateMovies(); + } +}); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const IMGPATH = 'https://image.tmdb.org/t/p/w500'; +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const searchTitle = document.getElementById('select-text'); +const searchButton = document.getElementById('button-search'); +const search = document.getElementById('search'); +const main = document.getElementById('results'); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +async function getMovies(url) { + clearMovieDetails(); + const numberOfMovies = calculateMoviesToDisplay(); + const pagesToFetch = numberOfMovies <= 20 ? 1 : 2; + let allMovies = []; + + for (let page = 1; page <= pagesToFetch; page++) { + const response = await fetch(`${url}&page=${page}`); + const data = await response.json(); + allMovies = allMovies.concat(data.results); + } + + const popularityThreshold = 0.5; + + allMovies.sort((a, b) => { + const popularityDifference = Math.abs(a.popularity - b.popularity); + if (popularityDifference < popularityThreshold) { + return b.vote_average - a.vote_average; + } + return b.popularity - a.popularity; + }); + + if (allMovies.length > 0) { + showMovies(allMovies.slice(0, numberOfMovies), main); + } else { + main.innerHTML = `

No movie with the specified search term found. Please try again.

`; + } +} + +function clearMovieDetails() { + const movieDetailsContainer = document.getElementById('movie-details-container'); + if (movieDetailsContainer) { + movieDetailsContainer.innerHTML = ''; + } +} + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function updateMovies() { + showSpinner(); + let startYear = document.getElementById('start-year').value; + let endYear = document.getElementById('end-year').value; + let currentYear = new Date().getFullYear(); + if (startYear && endYear && startYear <= endYear && endYear <= currentYear && startYear >= 1900 && startYear <= currentYear) { + fetchMoviesByTimePeriod(startYear, endYear); + hideSpinner(); + alertShown = false; + } else { + if (!alertShown) { + alert( + 'Please ensure the start year is before the end year, the start year is later than the year 1900, and both are not later than the current year.' + ); + alertShown = true; + } + hideSpinner(); + } +} + +async function getAdditionalPosters(movieId) { + const response = await fetch(`https://api.themoviedb.org/3/movie/${movieId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +function showMovies(movies, mainElement, startYear, endYear, append) { + showSpinner(); + + if (!append) { + mainElement.innerHTML = ''; + const header = document.createElement('h2'); + header.style.textAlign = 'center'; + header.style.marginTop = '20px'; + header.style.marginBottom = '20px'; + header.style.color = '#ff8623'; + header.style.fontSize = '23px'; + if (startYear === endYear) { + header.textContent = `Movies released in ${startYear}`; + } else { + header.textContent = `Movies released between ${startYear} and ${endYear}`; + } + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.innerHTML = ''; + centerContainer1.appendChild(header); + centerContainer1.appendChild(mainElement); + } + + const observer = new IntersectionObserver( + async (entries, observer) => { + for (const entry of entries) { + if (entry.isIntersecting) { + const movieEl = entry.target; + const movieId = movieEl.dataset.id; + + const additionalPosters = await getAdditionalPosters(movieId); + let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; + + const movieImageContainer = movieEl.querySelector('.movie-images'); + + allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imagePromises = allPosters.map((poster, index) => { + const img = new Image(); + img.src = `${IMGPATH + poster}`; + img.loading = index === 0 ? 'eager' : 'lazy'; + img.alt = `${movieEl.dataset.title} poster ${index + 1}`; + img.width = 300; + img.height = 435; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = '0'; + img.classList.add('poster-img'); + movieImageContainer.appendChild(img); + + return new Promise(resolve => { + img.onload = () => resolve(img); + }); + }); + + const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); + await Promise.race([Promise.all(imagePromises), maxWait]); + + movieImageContainer.querySelector('.poster-img').style.opacity = '1'; + + rotateImages(Array.from(movieImageContainer.children)); + observer.unobserve(movieEl); + } + } + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + movies.forEach(movie => { + let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; + + const movieEl = document.createElement('div'); + movieEl.style.zIndex = '1000'; + movieEl.classList.add('movie'); + movieEl.dataset.id = id; + movieEl.dataset.posterPath = poster_path; + movieEl.dataset.title = title; + + const words = title.split(' '); + if (words.length >= 8) { + words[7] = '...'; + title = words.slice(0, 8).join(' '); + } + + const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); + const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); + + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+
+ ${title} poster +
+
+
+

${title}

+ ${voteAvg} +
+
+

Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); + updateUniqueMoviesViewed(id); + updateFavoriteGenre(genre_ids); + updateMovieVisitCount(id, title); + window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + }); + + mainElement.appendChild(movieEl); + observer.observe(movieEl); + }); + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.appendChild(mainElement); + + createLoadMoreButton(startYear, endYear, mainElement); + hideSpinner(); +} + +function createLoadMoreButton(startYear, endYear, mainElement) { + const existingButtonDiv = mainElement.querySelector('.load-more-container'); + if (existingButtonDiv) { + mainElement.removeChild(existingButtonDiv); + } + + const buttonContainer = document.createElement('div'); + buttonContainer.className = 'load-more-container'; + buttonContainer.style.width = '100%'; + buttonContainer.style.textAlign = 'center'; + buttonContainer.style.marginTop = '20px'; + + const moreButton = document.createElement('button'); + moreButton.textContent = 'Get More Movies in this Period'; + moreButton.style.margin = '10px auto'; + + moreButton.addEventListener('click', function () { + currentPage++; + fetchMoviesByTimePeriod(startYear, endYear, true); + }); + + buttonContainer.appendChild(moreButton); + mainElement.appendChild(buttonContainer); +} + +let currentPage = 1; + +async function fetchMoviesByTimePeriod(startYear, endYear, append = false) { + showSpinner(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31&page=${currentPage}`; + const response = await fetch(url); + const data = await response.json(); + const moviesToShow = data.results; + + if (append) { + showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, true); + } else { + showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, false); + } + hideSpinner(); +} + +document.getElementById('load-movies').addEventListener('click', () => { + showSpinner(); + updateMovies(); + alertShown = false; + hideSpinner(); +}); + +function calculateMoviesToDisplay() { + const screenWidth = window.innerWidth; + if (screenWidth <= 689.9) return 10; // 1 movie per row + if (screenWidth <= 1021.24) return 20; // 2 movies per row + if (screenWidth <= 1353.74) return 21; // 3 movies per row + if (screenWidth <= 1684.9) return 20; // 4 movies per row + if (screenWidth <= 2017.49) return 20; // 5 movies per row + if (screenWidth <= 2349.99) return 18; // 6 movies per row + if (screenWidth <= 2681.99) return 21; // 7 movies per row + if (screenWidth <= 3014.49) return 24; // 8 movies per row + if (screenWidth <= 3345.99) return 27; // 9 movies per row + if (screenWidth <= 3677.99) return 20; // 10 movies per row + if (screenWidth <= 4009.99) return 22; // 11 movies per row + if (screenWidth <= 4340.99) return 24; // 12 movies per row + if (screenWidth <= 4673.49) return 26; // 13 movies per row + if (screenWidth <= 5005.99) return 28; // 14 movies per row + if (screenWidth <= 5337.99) return 30; // 15 movies per row + if (screenWidth <= 5669.99) return 32; // 16 movies per row + if (screenWidth <= 6001.99) return 34; // 17 movies per row + if (screenWidth <= 6333.99) return 36; // 18 movies per row + if (screenWidth <= 6665.99) return 38; // 19 movies per row + if (screenWidth <= 6997.99) return 40; // 20 movies per row + if (screenWidth <= 7329.99) return 42; // 21 movies per row + if (screenWidth <= 7661.99) return 44; // 22 movies per row + if (screenWidth <= 7993.99) return 46; // 23 movies per row + if (screenWidth <= 8325.99) return 48; // 24 movies per row + return 20; +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/notifications.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/notifications.js new file mode 100644 index 00000000..4ea7acef --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/notifications.js @@ -0,0 +1,176 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +document.addEventListener('DOMContentLoaded', () => { + const today = new Date(); + fetchReleasesByCategory('releasesSinceLastVisit', new Date(localStorage.getItem('lastVisit')), today, true); + fetchReleasesByCategory('releasesThisMonth', new Date(today.getFullYear(), today.getMonth(), 1), today, false); + fetchReleasesByCategory('releasesThisYear', new Date(today.getFullYear(), 0, 1), today, false); + fetchRecommendedReleases(); +}); + +async function fetchReleasesByCategory(elementId, startDate, endDate, isLastVisit) { + const list = document.getElementById(elementId); + list.innerHTML = ''; + + let movies = await fetchMovies(startDate, endDate); + + movies = movies.sort((a, b) => new Date(b.release_date) - new Date(a.release_date)); + + populateList(elementId, movies.slice(0, 5)); +} + +async function fetchMovies(startDate, endDate) { + const formattedStartDate = `${startDate.getFullYear()}-${(startDate.getMonth() + 1) + .toString() + .padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`; + const formattedEndDate = `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`; + + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&release_date.gte=${formattedStartDate}&release_date.lte=${formattedEndDate}`; + + try { + const response = await fetch(url); + const data = await response.json(); + return data.results; + } catch (error) { + console.log('Failed to fetch movies for', elementId + ':', error); + return []; + } +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +async function getMostVisitedMovieGenre() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedGenre = null; + let maxVisits = 0; + for (const movieId in movieVisits) { + const visits = movieVisits[movieId]; + if (visits.count > maxVisits) { + maxVisits = visits.count; + mostVisitedGenre = await fetchGenreForMovie(movieId); + } + } + return mostVisitedGenre; +} + +async function fetchGenreForMovie(movieId) { + const movieDetailsUrl = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(movieDetailsUrl); + const movieDetails = await response.json(); + return movieDetails.genres[0] ? movieDetails.genres[0].id : null; +} + +async function fetchRecommendedReleases() { + let url; + + const mostCommonGenre = getMostCommonGenre(); + const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); + + try { + const genreId = mostVisitedMovieGenre || mostCommonGenre; + if (!genreId) { + throw new Error('Genre ID is not valid.'); + } + url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${genreId}`; + } catch (error) { + console.log('Fetching recommended movies failed or data issues:', error); + url = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}&language=en-US&page=1`; + } + + try { + const response = await fetch(url); + const data = await response.json(); + populateList('recommendedReleases', data.results.slice(0, 5)); + } catch (error) { + console.log('Failed to fetch movies:', error); + } +} + +function populateList(elementId, movies) { + const list = document.getElementById(elementId); + list.innerHTML = ''; + movies.forEach(movie => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id.toString()); + window.location.href = 'movie-details.html'; + }); + + const title = document.createElement('span'); + title.textContent = movie.title; + title.style.color = 'black'; + li.appendChild(title); + list.appendChild(li); + }); +} + +document.addEventListener('DOMContentLoaded', () => { + populateActors(); + populateDirectors(); +}); + +function populateActors() { + const actors = [ + { name: 'Robert Downey Jr.', id: 3223 }, + { name: 'Scarlett Johansson', id: 1245 }, + { name: 'Denzel Washington', id: 5292 }, + { name: 'Meryl Streep', id: 5064 }, + { name: 'Leonardo DiCaprio', id: 6193 }, + { name: 'Sandra Bullock', id: 18277 }, + { name: 'Tom Hanks', id: 31 }, + ]; + + const list = document.getElementById('popularActors').querySelector('ul'); + actors.forEach(actor => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedActorId', actor.id.toString()); + window.location.href = 'actor-details.html'; + }); + + const name = document.createElement('span'); + name.textContent = actor.name; + li.appendChild(name); + list.appendChild(li); + }); +} + +function populateDirectors() { + const directors = [ + { name: 'Steven Spielberg', id: 488 }, + { name: 'Martin Scorsese', id: 1032 }, + { name: 'Christopher Nolan', id: 525 }, + { name: 'Quentin Tarantino', id: 138 }, + { name: 'Kathryn Bigelow', id: 14392 }, + { name: 'James Cameron', id: 2710 }, + { name: 'Sofia Coppola', id: 1776 }, + ]; + + const list = document.getElementById('popularDirectors').querySelector('ul'); + directors.forEach(director => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedDirectorId', director.id.toString()); + window.location.href = 'director-details.html'; + }); + + const name = document.createElement('span'); + name.textContent = director.name; + li.appendChild(name); + + list.appendChild(li); + }); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/privacy-policy.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/privacy-policy.js new file mode 100644 index 00000000..7f4afb2d --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/privacy-policy.js @@ -0,0 +1,789 @@ +function toggleNav() { + const sideNav = document.getElementById('side-nav'); + sideNav.classList.toggle('manual-toggle'); + adjustNavBar(); +} + +function removeNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + } + + adjustNavBar(); +} + +function adjustNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0px'; + } else { + sideNav.style.left = '-250px'; + } +} + +document.addEventListener('mousemove', function (event) { + const sideNav = document.getElementById('side-nav'); + if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0'; + } +}); + +document.getElementById('side-nav').addEventListener('mouseleave', function () { + const sideNav = document.getElementById('side-nav'); + if (!sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '-250px'; + } +}); + +document.addEventListener('click', function (event) { + const sideNav = document.getElementById('side-nav'); + const navToggle = document.getElementById('nav-toggle'); + if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + adjustNavBar(); + } +}); + +document.getElementById('introduction').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('introduction').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('consent').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('consent').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading2').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading3').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading4').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading4').scrollIntoView({ behavior: 'smooth' }); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.webp'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +window.addEventListener('load', function () { + adjustAnchorHeights(); +}); + +window.addEventListener('resize', adjustAnchorHeights); + +function adjustAnchorHeights() { + const bottomBarAnchors = document.querySelectorAll('.mobile-bottom-bar a'); + let maxHeight = 0; + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = 'auto'; + const anchorHeight = anchor.getBoundingClientRect().height; + maxHeight = Math.max(maxHeight, anchorHeight); + }); + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = `${maxHeight}px`; + }); +} + +let lastScrollY = window.scrollY; + +window.addEventListener('scroll', () => { + const currentScrollY = window.scrollY; + + if (currentScrollY > lastScrollY && currentScrollY > 0) { + document.querySelector('.mobile-bottom-bar').classList.add('hide-bar'); + } else { + document.querySelector('.mobile-bottom-bar').classList.remove('hide-bar'); + } + + lastScrollY = currentScrollY; +}); + +let isAnimating = false; + +document.getElementById('menu-btn').addEventListener('click', () => { + if (isAnimating) return; + + isAnimating = true; + + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach((id, index) => { + const button = document.getElementById(id); + if (button.style.display === 'none' || !button.style.display) { + button.style.display = 'block'; + setTimeout(() => { + button.style.opacity = '1'; + button.style.transform = 'translateY(0)'; + }, 50 * index); + } else { + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + } + + setTimeout( + () => { + button.style.display = button.style.opacity === '1' ? 'block' : 'none'; + if (index === buttonIds.length - 1) { + isAnimating = false; + } + }, + 500 + 50 * index + ); + }); +}); + +window.addEventListener('resize', () => { + if (window.innerWidth < 767) { + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach(id => { + const button = document.getElementById(id); + button.style.display = 'none'; + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + }); + } +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/quiz.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/quiz.js new file mode 100644 index 00000000..c5adcd57 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/quiz.js @@ -0,0 +1,859 @@ +import { updateTriviaStats } from './triviaModule.js'; + +const questionBank = [ + { + question: 'What movie won the Academy Award for Best Picture in 2020?', + options: ['Joker', '1917', 'Parasite'], + answer: 'Parasite', + }, + { + question: "Who directed the movie 'The Godfather'?", + options: ['Steven Spielberg', 'Francis Ford Coppola', 'Martin Scorsese'], + answer: 'Francis Ford Coppola', + }, + { + question: 'What was the first feature-length animated movie ever released?', + options: ['Snow White and the Seven Dwarfs', 'Bambi', 'Pinocchio'], + answer: 'Snow White and the Seven Dwarfs', + }, + { + question: "What was the highest-grossing movie of all time before the release of 'Avatar'?", + options: ['Titanic', 'Star Wars: The Force Awakens', 'Avengers: Endgame'], + answer: 'Titanic', + }, + { + question: "Who played the lead role in the movie 'Forrest Gump'?", + options: ['Tom Hanks', 'Brad Pitt', 'Leonardo DiCaprio'], + answer: 'Tom Hanks', + }, + { + question: 'What movie won the Academy Award for Best Picture in 2019?', + options: ['Bohemian Rhapsody', 'Green Book', 'Roma'], + answer: 'Green Book', + }, + { + question: 'Who played the character of John McClane in the Die Hard movie series?', + options: ['Arnold Schwarzenegger', 'Sylvester Stallone', 'Bruce Willis'], + answer: 'Bruce Willis', + }, + { + question: 'What movie is based on a novel by Stephen King and features a character named Jack Torrance?', + options: ['Carrie', 'The Shining', 'Misery'], + answer: 'The Shining', + }, + { + question: "Who directed the movie 'Forrest Gump'?", + options: ['Steven Spielberg', 'Robert Zemeckis', 'Martin Scorsese'], + answer: 'Robert Zemeckis', + }, + { + question: 'What is the highest-grossing movie of all time (as of 2021)?', + options: ['Avatar', 'Avengers: Endgame', 'Titanic'], + answer: 'Avatar', + }, + { + question: "What movie features the line 'You can't handle the truth!'?", + options: ['The Shawshank Redemption', 'A Few Good Men', 'Goodfellas'], + answer: 'A Few Good Men', + }, + { + question: 'Who played the character of Tony Stark/Iron Man in the Marvel Cinematic Universe?', + options: ['Chris Hemsworth', 'Mark Ruffalo', 'Robert Downey Jr.'], + answer: 'Robert Downey Jr.', + }, + { + question: "In which movie did Tom Hanks say, 'Houston, we have a problem'?", + options: ['Apollo 13', 'Cast Away', 'The Terminal'], + answer: 'Apollo 13', + }, + { + question: 'What is the name of the hobbit played by Elijah Wood in the Lord of the Rings movies?', + options: ['Frodo', 'Sam', 'Merry'], + answer: 'Frodo', + }, + { + question: "What is the name of the kingdom where the 2013 animated movie 'Frozen' is set?", + options: ['Arendelle', 'Genovia', 'DunBroch'], + answer: 'Arendelle', + }, + { + question: 'Which 1997 science fiction movie stars Will Smith and Tommy Lee Jones?', + options: ['Independence Day', 'Men in Black', 'Wild Wild West'], + answer: 'Men in Black', + }, + { + question: 'Which movie features Bruce Willis as a child psychologist?', + options: ['Die Hard', 'The Sixth Sense', 'Unbreakable'], + answer: 'The Sixth Sense', + }, + { + question: "In 'The Matrix', does Neo take the blue pill or the red pill?", + options: ['Blue', 'Red', 'Green'], + answer: 'Red', + }, + { + question: "Which actress played Katniss Everdeen in 'The Hunger Games' movies?", + options: ['Jennifer Lawrence', 'Emma Watson', 'Shailene Woodley'], + answer: 'Jennifer Lawrence', + }, + { + question: "Who directed 'Jurassic Park'?", + options: ['James Cameron', 'Steven Spielberg', 'George Lucas'], + answer: 'Steven Spielberg', + }, + { + question: 'What 1980s movie was the highest grossing film of the decade?', + options: ['E.T. the Extra-Terrestrial', 'Star Wars: Episode V', 'Back to the Future'], + answer: 'E.T. the Extra-Terrestrial', + }, + { + question: "Which movie features the song 'My Heart Will Go On'?", + options: ['The Bodyguard', 'Titanic', 'Romeo + Juliet'], + answer: 'Titanic', + }, + { + question: 'What was the first Pixar movie?', + options: ['Toy Story', "A Bug's Life", 'Monsters, Inc.'], + answer: 'Toy Story', + }, + { + question: 'Who played Wolverine in the X-Men movies?', + options: ['Hugh Jackman', 'Liam Hemsworth', 'Chris Evans'], + answer: 'Hugh Jackman', + }, + { + question: 'Which film did NOT win the Academy Award for Best Picture?', + options: ['The Shawshank Redemption', 'The Godfather', 'Forrest Gump'], + answer: 'The Shawshank Redemption', + }, + { + question: "What is Indiana Jones' real first name?", + options: ['Henry', 'John', 'Walter'], + answer: 'Henry', + }, + { + question: "In 'The Wizard of Oz', what did the Scarecrow want from the wizard?", + options: ['Heart', 'Brain', 'Courage'], + answer: 'Brain', + }, + { + question: 'Who is the only actor to receive an Oscar nomination for acting in a Lord of the Rings movie?', + options: ['Viggo Mortensen', 'Ian McKellen', 'Elijah Wood'], + answer: 'Ian McKellen', + }, + { + question: 'Which movie features an iconic dance scene between Uma Thurman and John Travolta?', + options: ['Pulp Fiction', 'Kill Bill', 'Saturday Night Fever'], + answer: 'Pulp Fiction', + }, + { + question: 'What is the highest-grossing R-rated movie of all time?', + options: ['Deadpool', 'Joker', 'The Matrix'], + answer: 'Joker', + }, + { + question: 'Which Alfred Hitchcock movie is notorious for its shower scene?', + options: ['Vertigo', 'Psycho', 'Rear Window'], + answer: 'Psycho', + }, + { + question: "What is Darth Vader's real name?", + options: ['Anakin Skywalker', 'Luke Skywalker', 'Obi-Wan Kenobi'], + answer: 'Anakin Skywalker', + }, + { + question: "Who directed 'Schindler's List'?", + options: ['Martin Scorsese', 'Steven Spielberg', 'Ridley Scott'], + answer: 'Steven Spielberg', + }, + { + question: 'In which movie does Tom Cruise perform his own stunts climbing the Burj Khalifa?', + options: ['Mission: Impossible - Rogue Nation', 'Mission: Impossible - Ghost Protocol', 'Edge of Tomorrow'], + answer: 'Mission: Impossible - Ghost Protocol', + }, + { + question: "What is the name of the fictional African country where 'Black Panther' is set?", + options: ['Wakanda', 'Genovia', 'Zamunda'], + answer: 'Wakanda', + }, + { + question: "Who directed 'Inception' and 'Interstellar'?", + options: ['Christopher Nolan', 'James Cameron', 'Steven Spielberg'], + answer: 'Christopher Nolan', + }, + { + question: "In 'The Hunger Games', what district do Katniss and Peeta represent?", + options: ['District 12', 'District 9', 'District 7'], + answer: 'District 12', + }, + { + question: 'Which movie features a character named Tyler Durden?', + options: ['Fight Club', 'Gone Girl', 'Seven'], + answer: 'Fight Club', + }, + { + question: "What is the name of the island in 'Jurassic Park'?", + options: ['Isla Nublar', 'Isla Sorna', 'Skull Island'], + answer: 'Isla Nublar', + }, + { + question: "Who played the Joker in 'The Dark Knight'?", + options: ['Heath Ledger', 'Joaquin Phoenix', 'Jared Leto'], + answer: 'Heath Ledger', + }, + { + question: 'In which movie is the fictional company Initech featured?', + options: ['Office Space', 'The Social Network', 'Wall Street'], + answer: 'Office Space', + }, + { + question: "What year was the first 'Harry Potter' movie released?", + options: ['2001', '2003', '1999'], + answer: '2001', + }, + { + question: "What fictional country is 'Wonder Woman' from?", + options: ['Themyscira', 'Asgard', 'Genovia'], + answer: 'Themyscira', + }, + { + question: "Which movie is known for the quote 'Here's looking at you, kid'?", + options: ['Casablanca', 'Gone with the Wind', 'The Maltese Falcon'], + answer: 'Casablanca', + }, + { + question: "In 'The Lion King', what is Simba's mother's name?", + options: ['Nala', 'Sarabi', 'Shenzi'], + answer: 'Sarabi', + }, + { + question: "Who directed 'Avengers: Endgame'?", + options: ['The Russo Brothers', 'Joss Whedon', 'Jon Favreau'], + answer: 'The Russo Brothers', + }, + { + question: "What is the name of the kingdom in 'Tangled'?", + options: ['Corona', 'Far Far Away', 'Arendelle'], + answer: 'Corona', + }, + { + question: 'Which film features a famous dance scene with Uma Thurman and John Travolta?', + options: ['Pulp Fiction', 'Saturday Night Fever', 'Kill Bill'], + answer: 'Pulp Fiction', + }, + { + question: "Who played Jack Dawson in 'Titanic'?", + options: ['Leonardo DiCaprio', 'Brad Pitt', 'Johnny Depp'], + answer: 'Leonardo DiCaprio', + }, + { + question: 'What is the highest-grossing film of all time?', + options: ['Avengers: Endgame', 'Avatar', 'Titanic'], + answer: 'Avatar', + }, + { + question: 'In which movie does the character Neo appear?', + options: ['The Matrix', 'John Wick', 'Speed'], + answer: 'The Matrix', + }, + { + question: 'What is the real name of the Black Panther in the Marvel Cinematic Universe?', + options: ["T'Challa", "M'Baku", "N'Jadaka"], + answer: "T'Challa", + }, + { + question: "Who directed 'Mad Max: Fury Road'?", + options: ['George Miller', 'Ridley Scott', 'Peter Jackson'], + answer: 'George Miller', + }, + { + question: "What animated film features a character named 'Hiccup'?", + options: ['Brave', 'How to Train Your Dragon', 'Shrek'], + answer: 'How to Train Your Dragon', + }, + { + question: "In which film is the fictional mineral 'Unobtainium' sought after?", + options: ['Avatar', 'The Core', 'Transformers'], + answer: 'Avatar', + }, + { + question: 'What is the name of the fictional city where the Batman movies take place?', + options: ['Gotham City', 'Metropolis', 'Star City'], + answer: 'Gotham City', + }, + { + question: "Who directed 'The Dark Knight'?", + options: ['Christopher Nolan', 'Martin Scorsese', 'Steven Spielberg'], + answer: 'Christopher Nolan', + }, + { + question: 'Who won the Best Actress award at the Oscars in 2021?', + options: ['Viola Davis', 'Frances McDormand', 'Carey Mulligan'], + answer: 'Frances McDormand', + }, + { + question: 'Which movie features a dystopian future divided into faction-based societies?', + options: ['The Hunger Games', 'Divergent', 'The Maze Runner'], + answer: 'Divergent', + }, + { + question: "What is the name of the spaceship in 'Alien' (1979)?", + options: ['Nostromo', 'Serenity', 'Millennium Falcon'], + answer: 'Nostromo', + }, + { + question: "Which director is known for the 'Dark Knight' trilogy?", + options: ['Christopher Nolan', 'Tim Burton', 'Joel Schumacher'], + answer: 'Christopher Nolan', + }, + { + question: "In 'The Terminator', what is the name of the company that created Skynet?", + options: ['Cyberdyne Systems', 'Wayland Industries', 'Oscorp'], + answer: 'Cyberdyne Systems', + }, + { + question: "What 1994 film revitalized John Travolta's career?", + options: ['Get Shorty', 'Pulp Fiction', 'Face/Off'], + answer: 'Pulp Fiction', + }, + { + question: 'Which movie was incorrectly announced as the Best Picture winner at the 2017 Academy Awards?', + options: ['La La Land', 'Moonlight', 'Manchester by the Sea'], + answer: 'La La Land', + }, + { + question: "What animated film was Disney's first ever full-length feature?", + options: ['Snow White and the Seven Dwarfs', 'Cinderella', 'The Little Mermaid'], + answer: 'Snow White and the Seven Dwarfs', + }, + { + question: "Who directed 'E.T. the Extra-Terrestrial'?", + options: ['Steven Spielberg', 'George Lucas', 'Ridley Scott'], + answer: 'Steven Spielberg', + }, + { + question: "Which film contains the quote, 'There's no place like home'?", + options: ['The Wizard of Oz', 'Gone with the Wind', 'Casablanca'], + answer: 'The Wizard of Oz', + }, + { + question: 'What is the highest grossing film of all time (not adjusted for inflation) as of 2023?', + options: ['Avengers: Endgame', 'Avatar', 'Titanic'], + answer: 'Avatar', + }, + { + question: "Who composed the score for 'The Lion King' (1994)?", + options: ['John Williams', 'Hans Zimmer', 'Alan Menken'], + answer: 'Hans Zimmer', + }, + { + question: 'Which movie did Leonardo DiCaprio win his first Oscar for Best Actor?', + options: ['The Revenant', 'The Wolf of Wall Street', 'Inception'], + answer: 'The Revenant', + }, + { + question: 'In which film does the character Maximus Decimus Meridius appear?', + options: ['300', 'Gladiator', 'Troy'], + answer: 'Gladiator', + }, + { + question: 'What is the name of the fictional British spy in the film series created by Ian Fleming?', + options: ['James Bond', 'Jason Bourne', 'Jack Ryan'], + answer: 'James Bond', + }, + { + question: 'Which movie won the Academy Award for Best Animated Feature in 2021?', + options: ['Onward', 'Soul', 'Wolfwalkers'], + answer: 'Soul', + }, + { + question: "Who played the role of Michael Corleone in 'The Godfather'?", + options: ['Al Pacino', 'Robert De Niro', 'Marlon Brando'], + answer: 'Al Pacino', + }, + { + question: 'What 2009 film is known for pioneering modern 3D cinema technology?', + options: ['Inception', 'Avatar', 'The Hurt Locker'], + answer: 'Avatar', + }, + { + question: 'Which 2012 film features a protagonist who survives a shipwreck with a tiger?', + options: ['Life of Pi', 'Cast Away', 'The Revenant'], + answer: 'Life of Pi', + }, + { + question: "What is the main theme of the movie 'Inception'?", + options: ['Time travel', 'Dream manipulation', 'Space exploration'], + answer: 'Dream manipulation', + }, + { + question: 'Which film features the character Sarah Connor, who is central to the plot?', + options: ['The Terminator', 'Aliens', 'Jurassic Park'], + answer: 'The Terminator', + }, + { + question: "What 1999 movie is famous for the quote, 'I see dead people'?", + options: ['The Sixth Sense', 'Ghost', 'The Others'], + answer: 'The Sixth Sense', + }, + { + question: "Who directed 'Titanic', which won the Academy Award for Best Picture in 1997?", + options: ['James Cameron', 'Steven Spielberg', 'Martin Scorsese'], + answer: 'James Cameron', + }, + { + question: 'Which film did NOT feature Leonardo DiCaprio?', + options: ['Titanic', 'The Great Gatsby', 'The Prestige'], + answer: 'The Prestige', + }, + { + question: "In which movie do characters compete in the 'Hunger Games'?", + options: ['Catching Fire', 'The Hunger Games', 'Battle Royale'], + answer: 'The Hunger Games', + }, + { + question: 'What film, released in 1982, features a character named E.T.?', + options: ['Star Wars', 'Close Encounters of the Third Kind', 'E.T. the Extra-Terrestrial'], + answer: 'E.T. the Extra-Terrestrial', + }, + { + question: "Who starred as the lead in the 2018 film 'Black Panther'?", + options: ['Chadwick Boseman', 'Michael B. Jordan', 'Denzel Washington'], + answer: 'Chadwick Boseman', + }, + { + question: "What iconic 1980s movie features the quote, 'Say hello to my little friend!'?", + options: ['Scarface', 'The Godfather', 'Goodfellas'], + answer: 'Scarface', + }, + { + question: 'Which film features a unique spinning top in its final scene?', + options: ['Inception', 'Minority Report', 'The Matrix'], + answer: 'Inception', + }, + { + question: 'What movie, featuring a journey to Mordor, won the Academy Award for Best Picture in 2003?', + options: [ + 'The Lord of the Rings: The Two Towers', + 'The Lord of the Rings: The Return of the King', + 'The Lord of the Rings: The Fellowship of the Ring', + ], + answer: 'The Lord of the Rings: The Return of the King', + }, + { + question: 'Which movie features a giant monster known as Godzilla?', + options: ['Pacific Rim', 'Godzilla', 'Cloverfield'], + answer: 'Godzilla', + }, + { + question: 'What classic film was remade in 2005 starring Naomi Watts and Jack Black?', + options: ['King Kong', 'Godzilla', 'Planet of the Apes'], + answer: 'King Kong', + }, + { + question: "Who directed the 1994 crime film 'Pulp Fiction'?", + options: ['Quentin Tarantino', 'Steven Spielberg', 'Martin Scorsese'], + answer: 'Quentin Tarantino', + }, + { + question: 'Which movie includes a character named Norman Bates?', + options: ['Psycho', 'Rebecca', 'The Birds'], + answer: 'Psycho', + }, + { + question: "What is the name of the fictional theme park in 'Jurassic Park'?", + options: ['Dinosaur Land', 'Jurassic World', 'Isla Nublar'], + answer: 'Isla Nublar', + }, + { + question: "Who played the role of Clarice Starling in the film 'The Silence of the Lambs'?", + options: ['Jodie Foster', 'Julianne Moore', 'Sigourney Weaver'], + answer: 'Jodie Foster', + }, + { + question: "Which film is famous for the line, 'May the Force be with you'?", + options: ['Star Trek', 'Star Wars', 'Guardians of the Galaxy'], + answer: 'Star Wars', + }, + { + question: 'What 1975 thriller is known for its menacing shark and famous soundtrack?', + options: ['Deep Blue Sea', 'Jaws', 'Sharknado'], + answer: 'Jaws', + }, + { + question: 'Which film did Tom Hanks win his first Academy Award for Best Actor?', + options: ['Big', 'Philadelphia', 'Forrest Gump'], + answer: 'Philadelphia', + }, + { + question: "What is the name of the ring in 'The Lord of the Rings'?", + options: ['The Ring of Power', 'The One Ring', 'The Master Ring'], + answer: 'The One Ring', + }, + { + question: "Who directed 'Avatar', the groundbreaking sci-fi movie released in 2009?", + options: ['James Cameron', 'George Lucas', 'Steven Spielberg'], + answer: 'James Cameron', + }, + { + question: 'Which 1988 animated film features a dystopian future and psychic powers?', + options: ['Ghost in the Shell', 'Akira', 'Blade Runner'], + answer: 'Akira', + }, + { + question: 'Who played the role of Hermione Granger in the Harry Potter films?', + options: ['Emma Watson', 'Emma Stone', 'Emily Blunt'], + answer: 'Emma Watson', + }, + { + question: "Which film features a group of friends who use a map to find a pirate's treasure?", + options: ['The Goonies', 'Treasure Island', 'Pirates of the Caribbean'], + answer: 'The Goonies', + }, + { + question: 'What was the first animated film to receive a Best Picture nomination at the Oscars?', + options: ['Beauty and the Beast', 'The Lion King', 'Up'], + answer: 'Beauty and the Beast', + }, + { + question: "What is the fictional sport played in the 'Harry Potter' series?", + options: ['Quidditch', 'Bludgers', 'Snitchball'], + answer: 'Quidditch', + }, + { + question: "Who composed the iconic score for 'Star Wars'?", + options: ['Hans Zimmer', 'John Williams', 'Danny Elfman'], + answer: 'John Williams', + }, + { + question: 'What 2000 film, directed by Ridley Scott, features a Roman general turned gladiator?', + options: ['Spartacus', 'Gladiator', 'Ben-Hur'], + answer: 'Gladiator', + }, + { + question: "Which movie's plot centers around a unique wooden board game?", + options: ['Clue', 'Jumanji', 'Zathura'], + answer: 'Jumanji', + }, + { + question: "Who directed the 1980 horror film 'The Shining'?", + options: ['Stanley Kubrick', 'Alfred Hitchcock', 'Stephen King'], + answer: 'Stanley Kubrick', + }, + { + question: 'What 1993 science fiction film directed by Steven Spielberg features dinosaurs brought back to life through cloning?', + options: ['Jurassic Park', 'The Lost World', 'Dinosaur'], + answer: 'Jurassic Park', + }, + { + question: "Who voiced the character of Woody in the 'Toy Story' movies?", + options: ['Tom Hanks', 'Tim Allen', 'Billy Crystal'], + answer: 'Tom Hanks', + }, + { + question: 'Which 2010 film directed by Christopher Nolan explores dream-sharing technology?', + options: ['Inception', 'Interstellar', 'Memento'], + answer: 'Inception', + }, + { + question: 'What film series features a secret British spy agency known as Kingsman?', + options: ['James Bond', 'Kingsman', 'Johnny English'], + answer: 'Kingsman', + }, + { + question: "Who played the role of Jack Sparrow in the 'Pirates of the Caribbean' film series?", + options: ['Johnny Depp', 'Orlando Bloom', 'Keira Knightley'], + answer: 'Johnny Depp', + }, + { + question: "Which 2001 film, based on a J.R.R. Tolkien novel, follows a hobbit's quest to destroy a powerful ring?", + options: ['The Hobbit', 'The Lord of the Rings: The Fellowship of the Ring', 'The Lord of the Rings: The Two Towers'], + answer: 'The Lord of the Rings: The Fellowship of the Ring', + }, + { + question: 'What 2003 animated film features a fish named Nemo?', + options: ['Shark Tale', 'Finding Nemo', 'The Little Mermaid'], + answer: 'Finding Nemo', + }, + { + question: 'Which 2017 film is based on a DC Comics character and set during World War I?', + options: ['Wonder Woman', 'Captain America: The First Avenger', 'Justice League'], + answer: 'Wonder Woman', + }, + { + question: "Who directed the 1994 film 'Pulp Fiction'?", + options: ['Quentin Tarantino', 'Martin Scorsese', 'Ridley Scott'], + answer: 'Quentin Tarantino', + }, + { + question: 'What movie introduced the character of Hannibal Lecter?', + options: ['Silence of the Lambs', 'Hannibal', 'Manhunter'], + answer: 'Manhunter', + }, + { + question: 'Which 2016 film tells the story of a group of rebels who plan to steal plans for the Death Star?', + options: ['Star Wars: The Force Awakens', 'Rogue One: A Star Wars Story', 'Star Wars: The Last Jedi'], + answer: 'Rogue One: A Star Wars Story', + }, + { + question: "What is the name of the fictional African kingdom in 'Coming to America'?", + options: ['Wakanda', 'Zamunda', 'Genovia'], + answer: 'Zamunda', + }, + { + question: "Who directed the 2017 movie 'Get Out'?", + options: ['Jordan Peele', 'Spike Lee', 'John Singleton'], + answer: 'Jordan Peele', + }, + { + question: 'Which movie features an AI character named HAL 9000?', + options: ['Blade Runner', 'Ex Machina', '2001: A Space Odyssey'], + answer: '2001: A Space Odyssey', + }, + { + question: "What 1980s movie is known for the quote 'Nobody puts Baby in a corner'?", + options: ['Dirty Dancing', 'Footloose', 'Flashdance'], + answer: 'Dirty Dancing', + }, + { + question: 'What 1995 film directed by Michael Mann stars Robert De Niro and Al Pacino?', + options: ['Heat', 'The Godfather', 'Scarface'], + answer: 'Heat', + }, + { + question: "Who starred as the titular character in the 2014 film 'Maleficent'?", + options: ['Angelina Jolie', 'Charlize Theron', 'Nicole Kidman'], + answer: 'Angelina Jolie', + }, + { + question: 'Which film is about a board game that becomes real for the players?', + options: ['Zathura', 'Jumanji', 'The Game'], + answer: 'Jumanji', + }, + { + question: 'In which movie does a group of archaeologists find a frozen prehistoric man?', + options: ['Encino Man', 'Ice Age', 'The Thing'], + answer: 'Encino Man', + }, + { + question: 'What movie features a theme park filled with cloned dinosaurs?', + options: ['Jurassic Park', 'Westworld', 'Prehistoric Park'], + answer: 'Jurassic Park', + }, +]; + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function generateRandomQuestions() { + const questionsToDisplay = 10; + const shuffledQuestions = questionBank.sort(() => 0.5 - Math.random()); + let selectedQuestions = shuffledQuestions.slice(0, questionsToDisplay); + + const quizContainer = document.getElementById('quiz-container'); + quizContainer.innerHTML = ''; + + selectedQuestions.forEach((question, index) => { + const questionElement = document.createElement('div'); + questionElement.innerHTML = ` +

Question ${index + 1}:

+

${question.question}

+ ${question.options.map((option, i) => `
`).join('')} +
`; + quizContainer.appendChild(questionElement); + + const headerElement = questionElement.querySelector(`h2`); + + headerElement.addEventListener('click', function (e) { + e.preventDefault(); + + headerElement.scrollIntoView({ behavior: 'smooth' }); + }); + + headerElement.addEventListener('mouseover', function () { + headerElement.style.color = 'orange'; + }); + + headerElement.addEventListener('mouseout', function () { + headerElement.style.color = '#ff8623'; + }); + + headerElement.style.cursor = 'pointer'; + }); +} + +document.getElementById('regenerate-questions').addEventListener('click', generateRandomQuestions); +generateRandomQuestions(); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('quiz-form').addEventListener('submit', function (event) { + event.preventDefault(); + + let answeredQuestions = 0; + + for (let i = 0; i < 10; i++) { + if (document.querySelector(`input[name="q${i}"]:checked`)) { + answeredQuestions++; + } + } + + if (answeredQuestions < 10) { + const confirmSubmit = confirm(`You have only answered ${answeredQuestions} questions. Are you sure you want to submit?`); + if (!confirmSubmit) { + return; + } + } + + calculateAndDisplayResults(); +}); + +function calculateAndDisplayResults() { + let score = 0; + const totalQuestions = 10; + + questionBank.forEach((question, index) => { + const selectedAnswer = document.querySelector(`input[name="q${index}"]:checked`); + if (selectedAnswer && selectedAnswer.value === question.answer) { + score++; + } + }); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || null; + + updateTriviaStats(currentUserEmail, score, totalQuestions); + + displayResults(score); +} + +function displayResults(score) { + let accuracy = (score / 10) * 100; + let progress = 0; + + document.getElementById('progress-circle').style.setProperty('--progress', `${progress}%`); + document.getElementById('correct-answers').textContent = score; + document.getElementById('result-text').textContent = `Your score is ${score} out of 10 (${accuracy.toFixed(1)}% accuracy)`; + + const interval = setInterval(() => { + if (progress < accuracy) { + progress++; + document.getElementById('progress-circle').style.setProperty('--progress', `${progress}%`); + } else { + clearInterval(interval); + } + }, 20); + + showModal(); +} + +function showModal() { + const modal = document.getElementById('result-modal'); + modal.style.display = 'block'; + + modal.querySelector('.close-button').addEventListener('click', function () { + modal.style.display = 'none'; + }); + + window.addEventListener('click', function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } + }); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/ratings-module.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/ratings-module.js new file mode 100644 index 00000000..80d4ec59 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/ratings-module.js @@ -0,0 +1,77 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function loadUserRatings(currentUserEmail) { + if (currentUserEmail) { + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + return docSnap.exists() ? docSnap.data().ratings : {}; + } else { + return JSON.parse(localStorage.getItem('movieRatings')) || {}; + } +} + +export async function updateAverageMovieRating(currentUserEmail, movieId, newRating) { + if (!currentUserEmail) { + console.error('No user signed in, using localStorage to save ratings.'); + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + updateLocalAverage(savedRatings); + } else { + console.log('User signed in, saving ratings to Firebase.'); + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + let ratings = docSnap.exists() ? docSnap.data().ratings || {} : {}; + ratings[movieId] = newRating; + + await setDoc(ratingsRef, { ratings: ratings }, { merge: true }); + updateFirebaseAverage(ratings, ratingsRef); + updateLocalAverage(ratings); + } +} + +function updateLocalAverage(savedRatings) { + let totalRating = 0; + let totalMoviesRated = 0; + Object.values(savedRatings).forEach(rating => { + totalRating += parseFloat(rating); + totalMoviesRated++; + }); + const averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1)); +} + +async function updateFirebaseAverage(ratings, ratingsRef) { + let totalRating = 0; + let totalMoviesRated = 0; + Object.values(ratings).forEach(rating => { + totalRating += parseFloat(rating); + totalMoviesRated++; + }); + const averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + await setDoc(ratingsRef, { averageRating: averageRating }, { merge: true }); +} + +export async function getAverageMovieRating(currentUserEmail) { + if (!currentUserEmail) { + console.error('No user signed in, retrieving average rating from localStorage.'); + return localStorage.getItem('averageMovieRating') || 0; + } else { + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + return docSnap.exists() && docSnap.data().averageRating ? docSnap.data().averageRating : 0; + } +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/reset-password.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/reset-password.js new file mode 100644 index 00000000..78e46da9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/reset-password.js @@ -0,0 +1,128 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, query, where, getDocs, doc, updateDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('resetPasswordForm').addEventListener('submit', async function (event) { + try { + event.preventDefault(); + const resetEmail = document.getElementById('resetEmail').value; + + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', resetEmail)); + const querySnapshot = await getDocs(q); + + if (querySnapshot.empty) { + alert('No account with such credentials exists in our database, or you might have mistyped something. Please try again.'); + return; + } + + document.getElementById('newPasswordFields').style.display = 'block'; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('password-reset-form-container'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +async function updatePassword() { + const resetEmail = document.getElementById('resetEmail').value; + const newPassword = document.getElementById('newPassword').value; + const confirmNewPassword = document.getElementById('confirmNewPassword').value; + + if (!isValidPassword(newPassword)) { + alert( + 'New password does not meet the security requirements.\n\n' + + 'Your password must include:\n' + + '- At least 8 characters\n' + + '- At least one uppercase letter\n' + + '- At least one lowercase letter\n' + + '- At least one number\n' + + '- At least one special character (e.g., !@#$%^&*)' + ); + return; + } + + if (newPassword !== confirmNewPassword) { + alert('Passwords do not match.'); + return; + } + + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', resetEmail)); + const querySnapshot = await getDocs(q); + + if (!querySnapshot.empty) { + querySnapshot.forEach(async docSnapshot => { + await updateDoc(doc(db, 'MovieVerseUsers', docSnapshot.id), { + password: newPassword, + }) + .then(() => { + alert('Password updated successfully!'); + window.location.href = 'sign-in.html'; + }) + .catch(error => { + console.log('Error updating password: ', error); + alert('Failed to update password. Please try again.'); + }); + }); + } else { + alert('Failed to find account. Please try again.'); + } +} + +document.getElementById('updatePasswordButton').addEventListener('click', updatePassword); + +function isValidPassword(password) { + const minLength = 8; + const hasUppercase = /[A-Z]/.test(password); + const hasLowercase = /[a-z]/.test(password); + const hasNumbers = /\d/.test(password); + const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password); + + return password.length >= minLength && hasUppercase && hasLowercase && hasNumbers && hasSpecialChar; +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/root-config.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/root-config.js new file mode 100644 index 00000000..b8083782 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/root-config.js @@ -0,0 +1,34 @@ +import { registerApplication, start } from 'single-spa'; + +// Defines a function that takes a location and returns true if the location should be active +function pathPrefix(prefix) { + return function (location) { + return location.pathname.startsWith(prefix); + }; +} + +// Load React Microfrontend for the homepage +registerApplication('home', () => System.import('http://localhost:8080/home.js'), pathPrefix('/home')); + +// Load React Microfrontend for the about page +registerApplication('about', () => System.import('http://localhost:8083/about.js'), pathPrefix('/about')); + +// Load React Microfrontend for the trivia page +registerApplication('quiz', () => System.import('http://localhost:8084/quiz.js'), pathPrefix('/contact')); + +// Load React Microfrontend for the favorites / watchlist page +registerApplication('favorites', () => System.import('http://localhost:8085/favorites.js'), pathPrefix('/favorites')); + +// Load React Microfrontend for the movie match page +registerApplication('movie-match', () => System.import('http://localhost:8086/movie-match.js'), pathPrefix('/movie-match')); + +// Load React Microfrontend for the movie timeline page +registerApplication('movie-timeline', () => System.import('http://localhost:8087/movie-timeline.js'), pathPrefix('/movie-details')); + +// Load Vue Microfrontend for the movie listing +registerApplication('movies', () => System.import('http://localhost:8081/movies.js'), pathPrefix('/movies')); + +// Load Vue Microfrontend for the navbar +registerApplication('navbar', () => System.import('http://localhost:8082/navbar.js'), pathPrefix('/navbar')); + +start(); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/router.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/router.js new file mode 100644 index 00000000..f78ed621 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/router.js @@ -0,0 +1,51 @@ +import Vue from 'vue'; +import Router from 'vue-router'; + +import HomePage from './components/HomePage.vue'; +import MovieDetails from './components/MovieDetails.vue'; +import AboutPage from './components/AboutPage.vue'; +import MovieMatch from './components/MovieMatch.vue'; +import MovieTimeline from './components/MovieTimeline.vue'; +import MovieOfTheDay from './components/MovieOfTheDay.vue'; + +Vue.use(Router); + +export default new Router({ + mode: 'history', + routes: [ + { + path: '/', + name: 'Home', + component: HomePage, + }, + { + path: '/movie/:id', + name: 'MovieDetails', + component: MovieDetails, + }, + { + path: '/about', + name: 'About', + component: AboutPage, + }, + { + path: '/movie-match', + name: 'MovieMatch', + component: MovieMatch, + }, + { + path: '/movie-timeline', + name: 'MovieTimeline', + component: MovieTimeline, + }, + { + path: '/movie-of-the-day', + name: 'MovieOfTheDay', + component: MovieOfTheDay, + }, + { + path: '*', // This wildcard route is for 404 Not Found pages + redirect: '/', + }, + ], +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/search.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/search.js new file mode 100644 index 00000000..ee46fb1b --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/search.js @@ -0,0 +1,1039 @@ +const form = document.getElementById('form1'); +const IMGPATH = 'https://image.tmdb.org/t/p/w500'; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + attachEventListeners(); + attachArrowKeyNavigation(); + + document.getElementById('form1').addEventListener('submit', function (event) { + event.preventDefault(); + handleSearch(); + }); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +document.addEventListener('DOMContentLoaded', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + attachEventListeners(); + attachArrowKeyNavigation(); + fetchGenreMap(); + fetchTvGenreMap(); + fetchLanguages(); + fetchTvLanguages(); + + document.getElementById('form1').addEventListener('submit', function (event) { + event.preventDefault(); + handleSearch(); + }); +}); + +async function fetchTvLanguages() { + const url = `https://${getMovieVerseData()}/3/configuration/languages?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + let languages = await response.json(); + languages = languages.sort((a, b) => a.english_name.localeCompare(b.english_name)); + populateTvLanguageFilter(languages); + } catch (error) { + console.log('Error fetching languages:', error); + } +} + +function populateTvLanguageFilter(languages) { + const languageFilter = document.getElementById('language-tv-filter'); + languageFilter.innerHTML = ''; + + languages.forEach(language => { + const option = document.createElement('option'); + option.value = language.iso_639_1; + option.textContent = language.english_name; + languageFilter.appendChild(option); + }); +} + +async function fetchLanguages() { + const url = `https://${getMovieVerseData()}/3/configuration/languages?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + let languages = await response.json(); + languages = languages.sort((a, b) => a.english_name.localeCompare(b.english_name)); + populateLanguageFilter(languages); + } catch (error) { + console.log('Error fetching languages:', error); + } +} + +function populateLanguageFilter(languages) { + const languageFilter = document.getElementById('language-filter'); + languageFilter.innerHTML = ''; + + languages.forEach(language => { + const option = document.createElement('option'); + option.value = language.iso_639_1; + option.textContent = language.english_name; + languageFilter.appendChild(option); + }); +} + +async function fetchGenreMap() { + const code = getMovieCode(); + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${code}`; + + try { + const response = await fetch(url); + const data = await response.json(); + localStorage.setItem('genreMap', JSON.stringify(data.genres)); + populateGenreFilter(data.genres); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function fetchTvGenreMap() { + const code = getMovieCode(); + const url = `https://${getMovieVerseData()}/3/genre/tv/list?${generateMovieNames()}${code}`; + + try { + const response = await fetch(url); + const data = await response.json(); + localStorage.setItem('tvGenreMap', JSON.stringify(data.genres)); + populateTvGenreFilter(data.genres); + } catch (error) { + console.log('Error fetching TV genre map:', error); + } +} + +function populateGenreFilter(genres) { + const genreFilter = document.getElementById('genre-filter'); + genreFilter.innerHTML = ''; + + genres.forEach(genre => { + const option = document.createElement('option'); + option.value = genre.id; + option.textContent = genre.name; + genreFilter.appendChild(option); + }); +} + +function populateTvGenreFilter(genres) { + const genreFilter = document.getElementById('genre-tv-filter'); + genreFilter.innerHTML = ''; + + genres.forEach(genre => { + const option = document.createElement('option'); + option.value = genre.id; + option.textContent = genre.name; + genreFilter.appendChild(option); + }); +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let uniqueMoviesViewed = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + + if (!uniqueMoviesViewed.includes(movieId)) { + uniqueMoviesViewed.push(movieId); + } + + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(uniqueMoviesViewed)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function attachEventListeners() { + const movieBtn = document.querySelector('[data-category="movie"]'); + const tvBtn = document.querySelector('[data-category="tv"]'); + const peopleBtn = document.querySelector('[data-category="person"]'); + const toggleFiltersBtn = document.getElementById('toggle-filters-btn'); + + const movieFilters = document.getElementById('movie-tv-filters'); + const tvFilters = document.getElementById('tv-filters'); + const peopleFilters = document.getElementById('people-filters'); + + const genreMovieFilter = document.getElementById('genre-filter'); + const yearMovieFilter = document.getElementById('year-filter'); + const ratingMovieFilter = document.getElementById('rating-filter'); + const languageFilter = document.getElementById('language-filter'); + + const genreTvFilter = document.getElementById('genre-tv-filter'); + const yearTvFilter = document.getElementById('year-tv-filter'); + const ratingTvFilter = document.getElementById('rating-tv-filter'); + const languageTvFilter = document.getElementById('language-tv-filter'); + + const professionFilter = document.getElementById('profession-filter'); + const genderFilter = document.getElementById('gender-filter'); + const popularityFilter = document.getElementById('popularity-filter'); + + const ratingValueSpan = document.getElementById('rating-value'); + const ratingTvValueSpan = document.getElementById('rating-tv-value'); + const popularityValueSpan = document.getElementById('popularity-value'); + + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + + function setFilterDisplayValues() { + ratingValueSpan.textContent = `Rating: ${ratingMovieFilter.value} and above`; + ratingTvValueSpan.textContent = `Rating: ${ratingTvFilter.value} and above`; + popularityValueSpan.textContent = `Popularity: ${popularityFilter.value} and above`; + } + + function showCorrectFilters(category) { + movieFilters.style.display = category === 'movie' ? 'block' : 'none'; + tvFilters.style.display = category === 'tv' ? 'block' : 'none'; + peopleFilters.style.display = category === 'person' ? 'block' : 'none'; + } + + movieBtn.addEventListener('click', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + showCorrectFilters('movie'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + tvBtn.addEventListener('click', () => { + showResults('tv'); + updateCategoryButtonStyles('tv'); + showCorrectFilters('tv'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + peopleBtn.addEventListener('click', () => { + showResults('person'); + updateCategoryButtonStyles('person'); + showCorrectFilters('person'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + toggleFiltersBtn.addEventListener('click', () => { + if (currentCategory === 'movie') { + movieFilters.style.display = movieFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'tv') { + tvFilters.style.display = tvFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'person') { + peopleFilters.style.display = peopleFilters.style.display === 'none' ? 'block' : 'none'; + } + }); + + genreMovieFilter.addEventListener('change', () => showResults('movie')); + yearMovieFilter.addEventListener('change', () => showResults('movie')); + ratingMovieFilter.addEventListener('input', () => { + ratingValueSpan.textContent = `Rating: ${ratingMovieFilter.value} and above`; + showResults('movie'); + }); + languageFilter.addEventListener('change', () => showResults('movie')); + + genreTvFilter.addEventListener('change', () => showResults('tv')); + yearTvFilter.addEventListener('change', () => showResults('tv')); + ratingTvFilter.addEventListener('input', () => { + ratingTvValueSpan.textContent = `Rating: ${ratingTvFilter.value} and above`; + showResults('tv'); + }); + languageTvFilter.addEventListener('change', () => showResults('tv')); + + genderFilter.addEventListener('change', () => showResults('person')); + professionFilter.addEventListener('change', () => showResults('person')); + popularityFilter.addEventListener('input', () => { + popularityValueSpan.textContent = `Popularity: ${popularityFilter.value} and above`; + showResults('person'); + }); + + const resetMovieFiltersBtn = movieFilters.querySelector('button[id="reset-filters"]'); + const resetTvFiltersBtn = tvFilters.querySelector('button[id="reset-filters"]'); + const resetPeopleFiltersBtn = peopleFilters.querySelector('button[id="reset-filters"]'); + + resetMovieFiltersBtn.addEventListener('click', () => { + genreMovieFilter.selectedIndex = 0; + yearMovieFilter.value = ''; + ratingMovieFilter.value = 5; + languageFilter.selectedIndex = 0; + setFilterDisplayValues(); + showResults('movie'); + }); + + resetTvFiltersBtn.addEventListener('click', () => { + genreTvFilter.selectedIndex = 0; + yearTvFilter.value = ''; + ratingTvFilter.value = 5; + languageTvFilter.selectedIndex = 0; + setFilterDisplayValues(); + showResults('tv'); + }); + + resetPeopleFiltersBtn.addEventListener('click', () => { + professionFilter.selectedIndex = 0; + genderFilter.selectedIndex = 0; + popularityFilter.value = 20; + setFilterDisplayValues(); + showResults('person'); + }); + + setFilterDisplayValues(); + showCorrectFilters(localStorage.getItem('selectedCategory')); +} + +let currentCategory = 'movie'; + +document.addEventListener('DOMContentLoaded', function () { + const toggleFiltersBtn = document.getElementById('toggle-filters-btn'); + const movieTvFilters = document.getElementById('movie-tv-filters'); + const peopleFilters = document.getElementById('people-filters'); + const tvFilters = document.getElementById('tv-filters'); + + movieTvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + + toggleFiltersBtn.addEventListener('click', function () { + if (currentCategory === 'movie') { + movieTvFilters.style.display = movieTvFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'person') { + peopleFilters.style.display = peopleFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'tv') { + tvFilters.style.display = tvFilters.style.display === 'none' ? 'block' : 'none'; + } + + if (currentCategory === 'movie' && movieTvFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else if (currentCategory === 'person' && peopleFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else if (currentCategory === 'tv' && tvFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else { + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + } + }); + + document.getElementById('sort-movie').addEventListener('change', () => { + movieSortChanged = true; + showResults('movie'); + }); + + document.getElementById('sort-tv').addEventListener('change', () => { + tvSortChanged = true; + showResults('tv'); + }); + + document.getElementById('sort-people').addEventListener('change', () => { + peopleSortChanged = true; + showResults('person'); + }); + + document.querySelectorAll('.category-buttons button').forEach(button => { + button.addEventListener('click', function () { + currentCategory = this.getAttribute('data-category'); + }); + }); +}); + +let movieSortChanged = false; +let tvSortChanged = false; +let peopleSortChanged = false; + +function attachArrowKeyNavigation() { + const categories = ['movie', 'tv', 'person']; + let currentIndex = 0; + + document.addEventListener('keydown', e => { + switch (e.key) { + case 'ArrowRight': + currentIndex = (currentIndex + 1) % categories.length; + break; + case 'ArrowLeft': + currentIndex = (currentIndex - 1 + categories.length) % categories.length; + break; + default: + return; + } + const selectedCategory = categories[currentIndex]; + showResults(selectedCategory); + updateCategoryButtonStyles(selectedCategory); + e.preventDefault(); + }); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function sortResults(results, sortBy) { + if (!sortBy) return results; + + const [property, order] = sortBy.split('.'); + results.sort((a, b) => { + let propA = property === 'release_date' || property === 'first_air_date' ? new Date(a[property]) : a[property]; + let propB = property === 'release_date' || property === 'first_air_date' ? new Date(b[property]) : b[property]; + + if (order === 'asc') { + return propA > propB ? 1 : propA < propB ? -1 : 0; + } else { + return propA < propB ? 1 : propA > propB ? -1 : 0; + } + }); + return results; +} + +async function showResults(category) { + showSpinner(); + localStorage.setItem('selectedCategory', category); + currentCategory = category; + + const searchQuery = localStorage.getItem('searchQuery') || ''; + document.getElementById('search-results-label').textContent = `Search Results for "${searchQuery}"`; + + const code = getMovieCode(); + const baseApiUrl = `https://${getMovieVerseData()}/3`; + let url = `${baseApiUrl}/search/${category}?${generateMovieNames()}${code}&query=${encodeURIComponent(searchQuery)}`; + let sortValue = ''; + + if (category === 'movie') { + sortValue = document.getElementById('sort-movie').value; + } else if (category === 'tv') { + sortValue = document.getElementById('sort-tv').value; + } else if (category === 'person') { + sortValue = document.getElementById('sort-people').value; + } + + try { + const response = await fetch(url); + let data = await response.json(); + + if (category === 'movie') { + const genre = document.getElementById('genre-filter').value; + const year = category === 'movie' ? document.getElementById('year-filter').value : document.getElementById('year-filter').value; + const rating = parseFloat(document.getElementById('rating-filter').value); + const language = document.getElementById('language-filter').value; + + data.results = data.results.filter(item => { + const itemYear = category === 'movie' ? item.release_date?.substring(0, 4) : item.first_air_date?.substring(0, 4); + const itemRating = item.vote_average; + const itemGenres = item.genre_ids; + const itemLanguage = item.original_language; + + return ( + (!genre || itemGenres.includes(parseInt(genre))) && + (!year || itemYear === year) && + (!rating || itemRating >= rating) && + (!language || itemLanguage === language) + ); + }); + } else if (category === 'person') { + const profession = document.getElementById('profession-filter').value; + const gender = document.getElementById('gender-filter').value; + + if (profession) { + data.results = data.results.filter( + person => person.known_for_department && person.known_for_department.toLowerCase() === profession.toLowerCase() + ); + } + + if (gender) { + data.results = data.results.filter(person => person.gender.toString() === gender); + } + + const popularity = parseFloat(document.getElementById('popularity-filter').value); + if (!isNaN(popularity) && popularity > 0) { + data.results = data.results.filter(person => person.popularity >= popularity); + } + + data.results.sort((a, b) => b.popularity - a.popularity); + + const personDetailsPromises = data.results.map(async person => { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${person.id}?${generateMovieNames()}${code}`; + const personResponse = await fetch(personDetailsUrl); + const personDetails = await personResponse.json(); + person.biography = personDetails.biography || 'Click to view the details of this person.'; + return person; + }); + + data.results = await Promise.all(personDetailsPromises); + } else if (category === 'tv') { + const genre = document.getElementById('genre-tv-filter').value; + const year = document.getElementById('year-tv-filter').value; + const rating = parseFloat(document.getElementById('rating-tv-filter').value); + const language = document.getElementById('language-tv-filter').value; + + data.results = data.results.filter(item => { + const itemYear = item.first_air_date?.substring(0, 4); + const itemRating = item.vote_average; + const itemGenres = item.genre_ids; + const itemLanguage = item.original_language; + + return ( + (!genre || itemGenres.includes(parseInt(genre))) && + (!year || itemYear === year) && + (!rating || itemRating >= rating) && + (!language || itemLanguage === language) + ); + }); + } + + if ((category === 'movie' && movieSortChanged) || (category === 'tv' && tvSortChanged) || (category === 'person' && peopleSortChanged)) { + data.results = sortResults(data.results, sortValue); + } + + displayResults(data.results, category, searchQuery); + } catch (error) { + console.log('Error fetching search results:', error); + } finally { + hideSpinner(); + } +} + +document.querySelector('button[onclick="showResults(\'movie\')"]').addEventListener('click', function () { + showResults('movie'); + localStorage.setItem('selectedCategory', 'movie'); + updateCategoryButtonStyles(); +}); + +document.querySelector('button[onclick="showResults(\'tv\')"]').addEventListener('click', function () { + showResults('tv'); + localStorage.setItem('selectedCategory', 'tv'); + updateCategoryButtonStyles(); +}); + +document.querySelector('button[onclick="showResults(\'person\')"]').addEventListener('click', function () { + showResults('person'); + localStorage.setItem('selectedCategory', 'person'); + updateCategoryButtonStyles(); +}); + +function updateCategoryButtonStyles(selectedCategory) { + const movieBtn = document.querySelector('[data-category="movie"]'); + const tvBtn = document.querySelector('[data-category="tv"]'); + const peopleBtn = document.querySelector('[data-category="person"]'); + + movieBtn.style.backgroundColor = ''; + tvBtn.style.backgroundColor = ''; + peopleBtn.style.backgroundColor = ''; + + if (selectedCategory === 'movie') { + movieBtn.style.backgroundColor = '#ff8623'; + } else if (selectedCategory === 'tv') { + tvBtn.style.backgroundColor = '#ff8623'; + } else if (selectedCategory === 'person') { + peopleBtn.style.backgroundColor = '#ff8623'; + } +} + +function displayResults(results, category, searchTerm) { + const container = document.getElementById('movie-match-container1'); + container.innerHTML = ''; + + const capitalizedCategory = category.charAt(0).toUpperCase() + category.slice(1); + + if (results.length === 0) { + container.innerHTML = `

No results found for "${searchTerm}" in the ${capitalizedCategory} category or no results with the specified filters found. Please try again with a different query or change your filters.

`; + container.style.height = '800px'; + return; + } + + showMovies(results, container, category); +} + +const main = document.getElementById('movie-match-container1'); + +async function getAdditionalImages(itemId, category) { + let endpoint; + if (category === 'movie') { + endpoint = `https://api.themoviedb.org/3/movie/${itemId}/images?api_key=${getMovieCode()}`; + } else if (category === 'person') { + endpoint = `https://api.themoviedb.org/3/person/${itemId}/images?api_key=${getMovieCode()}`; + } else if (category === 'tv') { + endpoint = `https://api.themoviedb.org/3/tv/${itemId}/images?api_key=${getMovieCode()}`; + } + + const response = await fetch(endpoint); + const data = await response.json(); + return data.profiles ? data.profiles.map(image => image.file_path) : data.posters.map(image => image.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +async function showMovies(items, container, category) { + container.innerHTML = ''; + + items.forEach(async item => { + const hasVoteAverage = typeof item.vote_average === 'number'; + const isPerson = !hasVoteAverage; + const isMovie = item.title && hasVoteAverage; + const isTvSeries = item.name && hasVoteAverage && category === 'tv'; + + let title = item.title || item.name || 'N/A'; + const words = title.split(' '); + + if (words.length >= 8) { + words[7] = '...'; + title = words.slice(0, 8).join(' '); + } + + let overview = item.overview || 'Click to view the details of this movie/TV series.'; + const biography = item.biography || 'Click to view the details of this person.'; + + if (overview === '') { + overview = 'Click to view the details of this movie/TV series.'; + } + + const { id, profile_path, poster_path } = item; + const imagePath = profile_path || poster_path ? IMGPATH + (profile_path || poster_path) : null; + + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.zIndex = 10000; + + let movieContentHTML = `
`; + + if (imagePath) { + movieContentHTML += `
`; + movieContentHTML += `${title}`; + movieContentHTML += `
`; + } else { + movieContentHTML += `
Image Unavailable
`; + } + + movieContentHTML += `
`; + movieContentHTML += `

${title}

`; + + if ((isMovie || isTvSeries) && hasVoteAverage) { + const voteAverage = item.vote_average.toFixed(1); + movieContentHTML += `${voteAverage}`; + } + + movieContentHTML += `
`; + + if (isPerson) { + const roleOverview = item.known_for_department === 'Directing' ? 'Director Overview' : 'Actor Overview'; + movieContentHTML += `

${roleOverview}:

${biography}
`; + } else if (isTvSeries) { + movieContentHTML += `

TV Series Overview:

${overview}
`; + } else { + movieContentHTML += `

Movie Overview:

${overview}
`; + } + + movieEl.innerHTML = movieContentHTML; + + movieEl.addEventListener('click', async () => { + if (isPerson) { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + if (personDetails.known_for_department === 'Directing') { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + const uniqueDirectorsViewed = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + + if (!uniqueDirectorsViewed.includes(id)) { + uniqueDirectorsViewed.push(id); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(uniqueDirectorsViewed)); + } + + if (directorVisits[id]) { + directorVisits[id].count++; + } else { + directorVisits[id] = { + count: 1, + name: personDetails.name || 'Unknown', + }; + } + + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); + localStorage.setItem('selectedDirectorId', id); + window.location.href = 'director-details.html?' + id; + } else { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(id)) { + uniqueActorsViewed.push(id); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[id]) { + actorVisits[id].count++; + } else { + actorVisits[id] = { + count: 1, + name: personDetails.name || 'Unknown', + }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + localStorage.setItem('selectedActorId', id); + window.location.href = 'actor-details.html?' + id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else if (isMovie) { + localStorage.setItem('selectedMovieId', id); + window.location.href = 'movie-details.html?' + id; + updateMovieVisitCount(id, title); + } else if (isTvSeries) { + localStorage.setItem('selectedTvSeriesId', id); + window.location.href = 'tv-details.html?' + id; + updateMovieVisitCount(id, title); + } + }); + + container.appendChild(movieEl); + + const additionalImages = await getAdditionalImages(id, category); + let allImages = [profile_path || poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + if (allImages.length > 1) { + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + // Load additional images once the first image is in view + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + } + }); +} + +function handleDirectorClick(directorId, directorName) { + updateUniqueDirectorsViewed(directorId); + updateDirectorVisitCount(directorId, directorName); + localStorage.setItem('selectedDirectorId', directorId); + document.title = `${directorName} - Director's Details`; + window.location.href = 'director-details.html'; +} + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.reload(); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?search_query=' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/service-worker.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/service-worker.js new file mode 100644 index 00000000..5fdc059d --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/service-worker.js @@ -0,0 +1,108 @@ +const CACHE_NAME = 'movieverse-cache-v1'; + +const urlsToCache = [ + '/index.html', + '/MovieVerse-Frontend/css/style.css', + '/MovieVerse-Frontend/css/trivia.css', + '/index.js', + '/manifest.json', + '/MovieVerse-Frontend/js/settings.js', + '/images/favicon.ico', + '/images/image.png', + '/MovieVerse-Frontend/js/chatbot.js', + '/MovieVerse-Frontend/js/movie-details.js', + '/MovieVerse-Frontend/js/movie-timeline.js', + '/MovieVerse-Frontend/js/quiz.js', + '/MovieVerse-Frontend/js/actor-details.js', + '/MovieVerse-Frontend/js/director-details.js', + '/MovieVerse-Frontend/html/about.html', + '/MovieVerse-Frontend/html/actor-details.html', + '/MovieVerse-Frontend/html/director-details.html', + '/MovieVerse-Frontend/html/movie-details.html', + '/MovieVerse-Frontend/html/movie-timeline.html', + '/MovieVerse-Frontend/html/notifications.html', + '/MovieVerse-Frontend/html/trivia.html', + '/MovieVerse-Frontend/html/settings.html', + '/MovieVerse-Frontend/html/favorites.html', + '/MovieVerse-Frontend/html/chat.html', + '/MovieVerse-Frontend/html/chatbot.html', + '/MovieVerse-Frontend/html/privacy-policy.html', + '/MovieVerse-Frontend/html/terms-of-service.html', + '/images/black.webp', + '/images/blue.webp', + '/images/brown.webp', + '/images/green.webp', + '/images/gold.webp', + '/images/grey.webp', + '/images/orange.webp', + '/images/pink.webp', + '/images/purple.webp', + '/images/red.webp', + '/images/rose.webp', + '/images/silver.webp', + '/images/universe.webp', + '/images/universe-1.webp', + '/images/universe-1-small.webp', + '/images/universe-1-medium.webp', + '/images/universe-22.webp', + '/images/universe-2.webp', + '/images/universe-23.webp', + '/images/universe-3.webp', + '/images/universe-4.webp', + '/images/universe-5.webp', + '/images/universe-6.webp', + '/images/universe-7.webp', + '/images/universe-8.webp', + '/images/universe-9.webp', + '/images/universe-10.webp', + '/images/universe-11.webp', + '/images/universe-12.webp', + '/images/universe-13.webp', + '/images/universe-14.webp', + '/images/universe-15.webp', + '/images/universe-16.webp', + '/images/universe-17.webp', + '/images/universe-18.webp', + '/images/universe-19.webp', + '/images/universe-20.webp', + '/images/universe-21.webp', + '/images/yellow.webp', + '/MovieVerse-Frontend/js/analytics.js', + '/MovieVerse-Frontend/html/analytics.html', + '/MovieVerse-Frontend/html/offline.html', +]; + +self.addEventListener('install', event => { + event.waitUntil( + caches.open(CACHE_NAME).then(cache => { + return cache.addAll(urlsToCache); + }) + ); +}); + +self.addEventListener('fetch', event => { + event.respondWith( + caches.match(event.request).then(response => { + if (response) { + return response; + } + return fetch(event.request) + .then(fetchResponse => { + return caches.open(CACHE_NAME).then(cache => { + cache.put(event.request, fetchResponse.clone()); + return fetchResponse; + }); + }) + .catch(() => caches.match('/MovieVerse-Frontend/html/offline.html')); + }) + ); +}); + +self.addEventListener('activate', event => { + const cacheWhitelist = [CACHE_NAME]; + event.waitUntil( + caches.keys().then(cacheNames => { + return Promise.all(cacheNames.filter(cacheName => !cacheWhitelist.includes(cacheName)).map(cacheName => caches.delete(cacheName))); + }) + ); +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/settings.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/settings.js new file mode 100644 index 00000000..d666801a --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/settings.js @@ -0,0 +1,397 @@ +const DEFAULT_BACKGROUND_IMAGE = '../../images/universe-1.webp'; + +document.addEventListener('DOMContentLoaded', () => { + const bgSelect = document.getElementById('background-select'); + const textColorInput = document.getElementById('text-color-input'); + const fontSizeSelect = document.getElementById('font-size-select'); + const resetButton = document.getElementById('reset-button'); + const deleteButton = document.getElementById('delete-uploaded-btn'); + const deleteImagesSection = document.getElementById('delete-images-section'); + const customImagesContainer = document.getElementById('custom-images-container'); + const deleteSelectedImagesBtn = document.getElementById('delete-selected-images-btn'); + + loadCustomBackgrounds(); + loadSettings(); + + if (bgSelect) { + bgSelect.addEventListener('change', function () { + document.body.style.backgroundImage = `url('${this.value}')`; + localStorage.setItem('backgroundImage', this.value); + window.location.reload(); + }); + } + + if (textColorInput) { + textColorInput.addEventListener('input', function () { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = this.value; + }); + localStorage.setItem('textColor', this.value); + }); + } + + if (fontSizeSelect) { + fontSizeSelect.addEventListener('change', function () { + const size = this.value === 'small' ? '12px' : this.value === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + localStorage.setItem('fontSize', this.value); + }); + } + + if (resetButton) { + resetButton.addEventListener('click', function () { + localStorage.removeItem('backgroundImage'); + localStorage.setItem('backgroundImage', '../../images/universe-1.webp'); + localStorage.removeItem('textColor'); + localStorage.removeItem('fontSize'); + window.location.reload(); + }); + } + + if (deleteButton) { + deleteButton.addEventListener('click', function () { + if (deleteImagesSection.style.display === 'block') { + deleteImagesSection.style.display = 'none'; + } else { + deleteImagesSection.style.display = 'block'; + updateCustomImagesDisplay(); + } + }); + } + + if (deleteSelectedImagesBtn) { + deleteSelectedImagesBtn.addEventListener('click', () => { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const selectedIndexes = Array.from(document.querySelectorAll('.delete-checkbox:checked')).map(checkbox => parseInt(checkbox.value)); + + const updatedImages = customImages.filter((_, index) => !selectedIndexes.includes(index)); + localStorage.setItem('customImages', JSON.stringify(updatedImages)); + + updateCustomImagesDisplay(); + updateBackgroundSelectOptions(); + alert('Selected images have been deleted.'); + window.location.reload(); + }); + } + + function updateCustomImagesDisplay() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + customImagesContainer.innerHTML = ''; + + if (customImages.length === 0) { + customImagesContainer.innerHTML = '

No custom images uploaded.

'; + deleteSelectedImagesBtn.style.display = 'none'; + return; + } + + customImages.forEach((image, index) => { + const imageContainer = document.createElement('div'); + imageContainer.classList.add('image-container'); + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.classList.add('delete-checkbox'); + checkbox.value = index; + + const img = document.createElement('img'); + img.src = image.dataURL; + img.alt = image.name; + img.style.width = '100px'; + + const imageName = document.createElement('span'); + imageName.classList.add('image-name'); + imageName.textContent = image.name; + + // Toggle checkbox when image container is clicked + imageContainer.addEventListener('click', e => { + if (e.target !== checkbox) { + // Prevent checkbox click event from toggling twice + checkbox.checked = !checkbox.checked; + } + }); + + imageContainer.appendChild(checkbox); + imageContainer.appendChild(img); + imageContainer.appendChild(imageName); + customImagesContainer.appendChild(imageContainer); + }); + + deleteSelectedImagesBtn.style.display = 'block'; + } + + function loadSettings() { + let savedBg = localStorage.getItem('backgroundImage'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (!savedBg) { + savedBg = DEFAULT_BACKGROUND_IMAGE; + } + + const availableBackgrounds = [ + '../../images/universe-1.webp', + '../../images/universe-2.webp', + '../../images/universe-22.webp', + '../../images/universe-3.webp', + '../../images/universe-4.webp', + '../../images/universe-5.webp', + '../../images/universe-6.webp', + '../../images/universe-7.webp', + '../../images/universe-8.webp', + '../../images/universe-9.webp', + '../../images/universe-10.webp', + '../../images/universe-11.webp', + '../../images/universe-12.webp', + '../../images/universe-13.webp', + '../../images/universe-14.webp', + '../../images/universe-15.webp', + '../../images/universe-16.webp', + '../../images/universe-17.webp', + '../../images/universe-18.webp', + '../../images/universe-19.webp', + '../../images/universe-20.webp', + '../../images/universe-21.webp', + '../../images/universe.webp', + '../../images/universe-23.webp', + '../../images/black.webp', + '../../images/grey.webp', + '../../images/blue.webp', + '../../images/silver.webp', + '../../images/gold.webp', + '../../images/rose.webp', + '../../images/pink.webp', + '../../images/red.webp', + '../../images/green.webp', + '../../images/brown.webp', + '../../images/purple.webp', + '../../images/orange.webp', + '../../images/yellow.webp', + ]; + + if (!availableBackgrounds.includes(savedBg) && !customImages.find(image => image.dataURL === savedBg)) { + savedBg = DEFAULT_BACKGROUND_IMAGE; + localStorage.setItem('backgroundImage', savedBg); + } + + if (savedBg) { + let imageUrl = savedBg; + if (savedBg === DEFAULT_BACKGROUND_IMAGE) { + if (window.innerWidth <= 680) { + imageUrl = '../../images/universe-1-small.webp'; + } else if (window.innerWidth <= 1124) { + imageUrl = '../../images/universe-1-medium.webp'; + } + } + document.body.style.backgroundImage = `url('${imageUrl}')`; + } + + const foundImage = customImages.find(image => image.dataURL === savedBg); + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + textColorInput.value = savedTextColor; + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + fontSizeSelect.value = savedFontSize; + } + + if (bgSelect) { + bgSelect.value = foundImage ? foundImage.dataURL : savedBg; + } + } + + function loadCustomBackgrounds() { + const bgSelect = document.getElementById('background-select'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + + if (bgSelect) { + customImages.forEach(image => { + const newOption = new Option(image.name, image.dataURL); + bgSelect.add(newOption); + }); + } + } +}); + +document.addEventListener('DOMContentLoaded', () => { + const uploadButton = document.getElementById('upload-bg-btn'); + + if (!uploadButton) { + console.log('Upload button not found'); + return; + } + + uploadButton.addEventListener('click', function () { + const fileInput = document.getElementById('custom-bg-upload'); + const imageNameInput = document.getElementById('custom-bg-name'); + const bgSelect = document.getElementById('background-select'); + + if (fileInput && fileInput.files.length > 0) { + const file = fileInput.files[0]; + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const totalSize = customImages.reduce((sum, img) => sum + img.dataURL.length, 0); + const quota = 4.5 * 1024 * 1024; // 4.5 MB + + if (totalSize >= quota) { + handleQuotaExceedance(); + window.location.reload(); + return; + } + + if (file.size > 204800) { + // 200 KB + resizeImage(file, 204800, (resizedDataUrl, err) => { + if (err) { + alert( + `Error resizing the image due to a limitation in your browser. Browser error: ${err.message} Your image might still appear as the background, but it will not be stable. We recommend deleting it and then using a different browser or uploading an image smaller than 1MB.` + ); + return; + } + processImageUpload(resizedDataUrl, imageNameInput, bgSelect); + alert('The uploaded image was resized to fit the size limit of 200KB.'); + window.location.reload(); + }); + } else { + const reader = new FileReader(); + reader.onload = function (e) { + processImageUpload(e.target.result, imageNameInput, bgSelect); + window.location.reload(); + }; + reader.onerror = function () { + alert('Error reading the file.'); + window.location.reload(); + }; + reader.readAsDataURL(file); + } + } else { + alert('Please select an image to upload.'); + } + }); +}); + +function handleQuotaExceedance() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + if (customImages.length > 0) { + alert('Your custom image storage has exceeded the quota. Please delete at least two images to continue.'); + + deleteImagesPrompt(); + } +} + +function deleteImagesPrompt() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + if (customImages.length === 0) { + alert('No custom images to delete.'); + return; + } + + let message = 'Select images to delete:\n'; + customImages.forEach((image, index) => { + message += `${index + 1}. ${image.name}\n`; + }); + message += 'Enter the numbers of the images to delete (e.g., 1,3):'; + + const input = prompt(message); + if (input) { + const indexesToDelete = input.split(',').map(num => parseInt(num.trim()) - 1); + const updatedImages = customImages.filter((_, index) => !indexesToDelete.includes(index)); + localStorage.setItem('customImages', JSON.stringify(updatedImages)); + updateBackgroundSelectOptions(); + alert('Selected images have been deleted.'); + } +} + +function updateBackgroundSelectOptions() { + const bgSelect = document.getElementById('background-select'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + + Array.from(bgSelect.options).forEach(option => { + if (option.value.startsWith('data:image')) { + bgSelect.remove(option.index); + } + }); + + customImages.forEach(image => { + const newOption = new Option(image.name, image.dataURL); + bgSelect.add(newOption); + }); +} + +function processImageUpload(dataUrl, imageNameInput, bgSelect) { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + let imageName = imageNameInput.value.trim(); + + if (!imageName) { + imageName = `User-Added Image ${customImages.length + 1}`; + } + + customImages.push({ name: imageName, dataURL: dataUrl }); + localStorage.setItem('customImages', JSON.stringify(customImages)); + + const newOption = new Option(imageName, dataUrl); + bgSelect.add(newOption); + bgSelect.value = dataUrl; + + document.body.style.backgroundImage = `url('${dataUrl}')`; + localStorage.setItem('backgroundImage', dataUrl); +} + +function resizeImage(file, maxSize, callback) { + if (!(window.FileReader && window.Blob && window.HTMLCanvasElement)) { + callback(null, new Error('Your browser does not support resizing images. Please use a different browser or upload an image smaller than 200KB.')); + return; + } + + const reader = new FileReader(); + reader.onload = function (e) { + const img = new Image(); + img.onload = function () { + try { + let canvas = document.createElement('canvas'); + let ctx = canvas.getContext('2d'); + + let width = img.width; + let height = img.height; + + if (width > height) { + if (width > maxSize) { + height *= maxSize / width; + width = maxSize; + } + } else { + if (height > maxSize) { + width *= maxSize / height; + height = maxSize; + } + } + + canvas.width = width; + canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + + callback(canvas.toDataURL('image/jpeg'), null); + + canvas.height = 0; + canvas.width = 0; + canvas = null; + } catch (error) { + callback(null, error); + } + }; + img.onerror = function () { + callback(null, new Error('Failed to load the image.')); + }; + img.src = e.target.result; + }; + reader.onerror = function () { + callback(null, new Error('Failed to read the image file.')); + }; + + reader.readAsDataURL(file); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/sign-in.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/sign-in.js new file mode 100644 index 00000000..024d4228 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/sign-in.js @@ -0,0 +1,80 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, query, where, getDocs } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('signInForm').addEventListener('submit', async function (event) { + event.preventDefault(); + + try { + const email = document.getElementById('signInEmail').value; + const password = document.getElementById('signInPassword').value; + + const usersRef = collection(db, 'MovieVerseUsers'); + const q = query(usersRef, where('email', '==', email), where('password', '==', password)); + const querySnapshot = await getDocs(q); + + if (!querySnapshot.empty) { + alert('Successfully signed in!'); + localStorage.setItem('isSignedIn', JSON.stringify(true)); + localStorage.setItem('currentlySignedInMovieVerseUser', email); + window.location.href = '../../index.html'; + } else { + alert('Invalid email or password. Ensure that you have entered a correct combination of email and password - one that we have on file.'); + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('signInForm'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +document.getElementById('createAccountBtn').addEventListener('click', function () { + window.location.href = 'create-account.html'; +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/single-spa-config.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/single-spa-config.js new file mode 100644 index 00000000..96ed54cf --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/single-spa-config.js @@ -0,0 +1,16 @@ +import * as singleSpa from 'single-spa'; + +// Function to load microfrontends (apps) +function loadApp(name, path, activeWhen, customProps = {}) { + singleSpa.registerApplication(name, () => System.import(path), activeWhen, customProps); +} + +loadApp('navbar', '/navbar.js', () => true); + +loadApp('home', '/home.js', location => location.pathname === '' || location.pathname === '/'); + +loadApp('movie-details', '/movie-details.js', location => location.pathname.startsWith('/movie')); + +loadApp('about', '/about.js', location => location.pathname.startsWith('/about')); + +singleSpa.start(); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/systemjs-importmap.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/systemjs-importmap.js new file mode 100644 index 00000000..ea5553e9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/systemjs-importmap.js @@ -0,0 +1,25 @@ +let System = (window.System = window.System || {}); +System.import('@system-env').then(env => { + env.production = true; + if (!env.production) { + let System = window.System; + System.importMap({ + imports: { + 'single-spa': 'https://unpkg.com/single-spa/lib/system/single-spa.dev.js', + 'movieverse-navbar': 'http://localhost:8500/movieverse-navbar.js', + 'movieverse-main-content': 'http://localhost:8501/movieverse-main-content.js', + 'movieverse-footer': 'http://localhost:8502/movieverse-footer.js', + }, + }); + } else { + let System = window.System; + System.importMap({ + imports: { + 'single-spa': 'https://unpkg.com/single-spa/lib/system/single-spa.min.js', + 'movieverse-navbar': 'https://your-production-url/movieverse-navbar.js', + 'movieverse-main-content': 'https://your-production-url/movieverse-main-content.js', + 'movieverse-footer': 'https://your-production-url/movieverse-footer.js', + }, + }); + } +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/terms-of-service.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/terms-of-service.js new file mode 100644 index 00000000..7f193db6 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/terms-of-service.js @@ -0,0 +1,814 @@ +document.getElementById('agreement').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('agreement').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('consent').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('consent').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading2').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading3').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading4').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading4').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading5').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading5').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading6').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading6').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading7').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading7').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading8').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading8').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading9').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading9').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading10').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading10').scrollIntoView({ behavior: 'smooth' }); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function toggleNav() { + const sideNav = document.getElementById('side-nav'); + sideNav.classList.toggle('manual-toggle'); + adjustNavBar(); +} + +function removeNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + } + + adjustNavBar(); +} + +function adjustNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0px'; + } else { + sideNav.style.left = '-250px'; + } +} + +document.addEventListener('mousemove', function (event) { + const sideNav = document.getElementById('side-nav'); + if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0'; + } +}); + +document.getElementById('side-nav').addEventListener('mouseleave', function () { + const sideNav = document.getElementById('side-nav'); + if (!sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '-250px'; + } +}); + +document.addEventListener('click', function (event) { + const sideNav = document.getElementById('side-nav'); + const navToggle = document.getElementById('nav-toggle'); + if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + adjustNavBar(); + } +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.webp'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +const movieCode1 = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode1.part1) + atob(movieCode1.part2) + atob(movieCode1.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +window.addEventListener('load', function () { + adjustAnchorHeights(); +}); + +window.addEventListener('resize', adjustAnchorHeights); + +function adjustAnchorHeights() { + const bottomBarAnchors = document.querySelectorAll('.mobile-bottom-bar a'); + let maxHeight = 0; + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = 'auto'; + const anchorHeight = anchor.getBoundingClientRect().height; + maxHeight = Math.max(maxHeight, anchorHeight); + }); + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = `${maxHeight}px`; + }); +} + +let lastScrollY = window.scrollY; + +window.addEventListener('scroll', () => { + const currentScrollY = window.scrollY; + + if (currentScrollY > lastScrollY && currentScrollY > 0) { + document.querySelector('.mobile-bottom-bar').classList.add('hide-bar'); + } else { + document.querySelector('.mobile-bottom-bar').classList.remove('hide-bar'); + } + + lastScrollY = currentScrollY; +}); + +let isAnimating = false; + +document.getElementById('menu-btn').addEventListener('click', () => { + if (isAnimating) return; + + isAnimating = true; + + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach((id, index) => { + const button = document.getElementById(id); + if (button.style.display === 'none' || !button.style.display) { + button.style.display = 'block'; + setTimeout(() => { + button.style.opacity = '1'; + button.style.transform = 'translateY(0)'; + }, 50 * index); + } else { + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + } + + setTimeout( + () => { + button.style.display = button.style.opacity === '1' ? 'block' : 'none'; + if (index === buttonIds.length - 1) { + isAnimating = false; + } + }, + 500 + 50 * index + ); + }); +}); + +window.addEventListener('resize', () => { + if (window.innerWidth < 767) { + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach(id => { + const button = document.getElementById(id); + button.style.display = 'none'; + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + }); + } +}); diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/triviaModule.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/triviaModule.js new file mode 100644 index 00000000..e84a36b9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/triviaModule.js @@ -0,0 +1,79 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +const app = initializeApp(firebaseConfig); + +const db = getFirestore(app); + +export async function updateTriviaStats(currentUserEmail, correctAnswers, totalQuestions) { + if (!currentUserEmail) { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } else { + try { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + const docSnap = await getDoc(statsRef); + let triviaStats = docSnap.exists() ? docSnap.data() : { totalCorrect: 0, totalAttempted: 0 }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + await setDoc(statsRef, triviaStats, { merge: true }); + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } catch (error) { + if (error.code === 'resource-exhausted') { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } + } + } +} + +export async function getTriviaStats(currentUserEmail) { + if (!currentUserEmail) { + return ( + JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + } + ); + } else { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + try { + const docSnap = await getDoc(statsRef); + if (docSnap.exists()) { + return docSnap.data(); + } else { + console.log('No trivia stats found in Firebase for:', currentUserEmail); + return { totalCorrect: 0, totalAttempted: 0 }; + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded, fetching trivia stats from localStorage.'); + return ( + JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + } + ); + } + } + } +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/tv-details.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/tv-details.js new file mode 100644 index 00000000..fa47a025 --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/tv-details.js @@ -0,0 +1,1609 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w780'; +const searchTitle = document.getElementById('search-title'); +let initialMainContent; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function setStarRating(rating) { + const stars = document.querySelectorAll('.rating .star'); + stars.forEach(star => { + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; + }); + + document.getElementById('rating-value').textContent = `${rating}.0/5.0`; +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +document.querySelectorAll('.rating .star').forEach(star => { + star.addEventListener('mouseover', e => { + setStarRating(e.target.dataset.value); + }); + + star.addEventListener('mouseout', () => { + const movieId = localStorage.getItem('selectedTvSeriesId'); + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); + }); + + star.addEventListener('click', e => { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + if (!tvSeriesId) return; + const rating = e.target.dataset.value; + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + savedRatings[tvSeriesId] = rating; + localStorage.setItem('tvSeriesRatings', JSON.stringify(savedRatings)); + setStarRating(rating); + window.location.reload(); + }); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + currentIndex = 0; + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', function () { + applySettings(); +}); + +const tvCode = `${getMovieCode()}`; + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +async function fetchTvDetails(tvSeriesId) { + showSpinner(); + const baseUrl = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}`; + const urlWithAppend = `${baseUrl}?${generateMovieNames()}${tvCode}&append_to_response=credits,keywords,similar,videos,external_ids`; + + try { + const tvDetailsPromise = fetch(urlWithAppend).then(response => { + if (!response.ok) throw new Error('Failed to fetch TV series details'); + return response.json(); + }); + + const tvSeriesDetails = await tvDetailsPromise; + const imdbId = tvSeriesDetails.external_ids.imdb_id; + + if (imdbId) { + const imdbRatingPromise = fetchTVRatings(imdbId); + const imdbRating = await imdbRatingPromise; + populateTvSeriesDetails(tvSeriesDetails, imdbRating); + } else { + populateTvSeriesDetails(tvSeriesDetails, 'IMDb rating'); + } + + updateBrowserURL(tvSeriesDetails.name); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

TV series details currently unavailable - please try again

+
`; + console.log('Error fetching TV series details:', error); + } finally { + hideSpinner(); + } +} + +async function fetchTVRatings(imdbId) { + showSpinner(); + + if (!imdbId) { + return 'IMDb rating'; + } + + const apiKeys = [await getMovieCode2(), '58efe859', '60a09d79', '956e468a', 'bd55ada4', 'cbfc076', 'dc091ff2', '6e367eef', '2a2a3080', 'd20a931f']; + + const baseURL = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}`; + + async function tryFetch(apiKey, timeout = 5000) { + const url = `${baseURL}${apiKey}`; + return new Promise(resolve => { + const timer = setTimeout(() => resolve(null), timeout); + fetch(url) + .then(response => { + if (!response.ok) throw new Error('API limit reached or other error'); + return response.json(); + }) + .then(data => { + clearTimeout(timer); + if (!data || data.Error) throw new Error('Data fetch error'); + resolve(data); + }) + .catch(() => { + clearTimeout(timer); + resolve(null); + }); + }); + } + + const requests = apiKeys.map(key => tryFetch(key)); + const responses = await Promise.all(requests); + const data = responses.find(response => response !== null); + + hideSpinner(); + return data && data.imdbRating ? data.imdbRating : 'View on IMDb'; +} + +function getLanguageName(code) { + const language = twoLetterLangCodes.find(lang => lang.code === code); + return language ? language.name : 'Unknown Language'; +} + +function getCountryName(code) { + const regionNames = new Intl.DisplayNames(['en'], { type: 'region' }); + return regionNames.of(code); +} + +async function populateTvSeriesDetails(tvSeries, imdbRating) { + const title = tvSeries.name || 'Title not available'; + document.getElementById('movie-title').textContent = title; + document.title = tvSeries.name + ' - TV Series Details'; + + const posterPath = `https://image.tmdb.org/t/p/w780${tvSeries.poster_path}`; + if (tvSeries.poster_path) { + document.getElementById('movie-image').src = posterPath; + document.getElementById('movie-image').alt = `Poster of ${title}`; + } else { + const noImageTitle = document.createElement('h2'); + noImageTitle.textContent = 'TV Show Image Not Available'; + noImageTitle.style.textAlign = 'center'; + document.getElementById('movie-image').replaceWith(noImageTitle); + } + + let detailsHTML = `

Overview: ${tvSeries.overview || 'Overview not available.'}

`; + + detailsHTML += `

Original Title: ${tvSeries.original_name || 'Not available'}

`; + + detailsHTML += `

Tagline: ${tvSeries.tagline || 'Not available'}

`; + + const genres = tvSeries.genres && tvSeries.genres.length ? tvSeries.genres.map(genre => genre.name).join(', ') : 'Genres not available'; + detailsHTML += `

Genres: ${genres}

`; + + detailsHTML += `

First Air Date: ${tvSeries.first_air_date || 'Not available'}

`; + + detailsHTML += `

Last Air Date: ${tvSeries.last_air_date || 'Not available'}

`; + + detailsHTML += `

Status: ${tvSeries.status || 'Not available'}

`; + + const type = tvSeries.type || 'Not available'; + detailsHTML += `

Type: ${type}

`; + + const networks = + tvSeries.networks && tvSeries.networks.length ? tvSeries.networks.map(network => network.name).join(', ') : 'Information not available'; + detailsHTML += `

Networks: ${networks}

`; + + const voteAverage = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + const voteCount = tvSeries.vote_count ? tvSeries.vote_count.toLocaleString() : 'N/A'; + detailsHTML += `

MovieVerse User Rating: ${( + voteAverage / 2 + ).toFixed(1)}/5.0 (based on ${voteCount} votes)

`; + + if (tvSeries.external_ids && tvSeries.external_ids.imdb_id) { + const imdbId = tvSeries.external_ids.imdb_id; + const imdbUrl = `https://www.imdb.com/title/${imdbId}/`; + detailsHTML += `

IMDb Rating: ${imdbRating}

`; + } else { + detailsHTML += `

IMDb Rating: IMDb rating not available

`; + } + + let tmdbRating = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + if (tmdbRating === 'N/A') { + detailsHTML += `

TMDB Rating: ${tmdbRating}

`; + } else { + detailsHTML += `

TMDB Rating: ${tmdbRating}/10.0

`; + } + + const homepage = tvSeries.homepage ? `Visit homepage` : 'Not available'; + detailsHTML += `

Homepage: ${homepage}

`; + + if (tvSeries.origin_country && tvSeries.origin_country.length > 0) { + const countryNames = tvSeries.origin_country.map(code => getCountryName(code)).join(', '); + detailsHTML += `

Country of Origin: ${countryNames}

`; + } else { + detailsHTML += `

Country of Origin: Information not available

`; + } + + const languageName = getLanguageName(tvSeries.original_language); + detailsHTML += `

Original Language: ${languageName}

`; + + const productionCountries = + tvSeries.production_countries && tvSeries.production_countries.length > 0 + ? tvSeries.production_countries.map(country => getCountryName(country.iso_3166_1)).join(', ') + : 'Information not available'; + detailsHTML += `

Production Countries: ${productionCountries}

`; + + detailsHTML += `

Seasons: ${tvSeries.number_of_seasons || 0}, Episodes: ${tvSeries.number_of_episodes || 0}

`; + + if (tvSeries.last_episode_to_air) { + const lastEpisode = tvSeries.last_episode_to_air; + + detailsHTML += `
+ Last Episode: ${lastEpisode.name || 'Title not available'} - ${ + lastEpisode.overview || 'Overview not available.' + } +
`; + + if (lastEpisode.still_path) { + detailsHTML += `
+ ${
+                                  lastEpisode.name
+                                } Still Image +
`; + } + } + + if (tvSeries.created_by && tvSeries.created_by.length > 0) { + const creatorsSection = document.createElement('div'); + creatorsSection.classList.add('creators-section'); + + const creatorsTitle = document.createElement('p'); + creatorsTitle.innerHTML = 'Creators:'; + creatorsSection.appendChild(creatorsTitle); + + const creatorsList = document.createElement('div'); + creatorsList.classList.add('creators-list'); + creatorsList.style.display = 'flex'; + creatorsList.style.flexWrap = 'wrap'; + creatorsList.style.justifyContent = 'center'; + creatorsList.style.gap = '2px'; + + tvSeries.created_by.forEach(creator => { + const creatorLink = document.createElement('a'); + creatorLink.classList.add('creator-link'); + creatorLink.href = 'javascript:void(0);'; + creatorLink.setAttribute('onclick', `handleCreatorClick(${creator.id}, '${creator.name.replace(/'/g, "\\'")}');`); + + const creatorItem = document.createElement('div'); + creatorItem.classList.add('creator-item'); + + const creatorImage = document.createElement('img'); + creatorImage.classList.add('creator-image'); + + if (creator.profile_path) { + creatorImage.src = IMGPATH + creator.profile_path; + creatorImage.alt = `${creator.name} Profile Picture`; + } else { + creatorImage.alt = 'Image Not Available'; + creatorImage.style.objectFit = 'cover'; + creatorImage.src = 'https://movie-verse.com/images/user-default.png'; + creatorImage.style.filter = 'grayscale(100%)'; + } + + creatorItem.appendChild(creatorImage); + + const creatorDetails = document.createElement('div'); + creatorDetails.classList.add('creator-details'); + + const creatorName = document.createElement('p'); + creatorName.classList.add('creator-name'); + creatorName.textContent = creator.name; + creatorDetails.appendChild(creatorName); + + creatorItem.appendChild(creatorDetails); + creatorLink.appendChild(creatorItem); + creatorsList.appendChild(creatorLink); + }); + + creatorsSection.appendChild(creatorsList); + detailsHTML += creatorsSection.outerHTML; + } else { + const noCreatorsElement = document.createElement('p'); + noCreatorsElement.innerHTML = `Creators: Information not available`; + detailsHTML += noCreatorsElement.outerHTML; + } + + if (tvSeries.credits && tvSeries.credits.cast && tvSeries.credits.cast.length > 0) { + const castSection = document.createElement('div'); + castSection.classList.add('cast-section'); + + const castTitle = document.createElement('p'); + castTitle.innerHTML = 'Notable Cast:'; + castSection.appendChild(castTitle); + + const castList = document.createElement('div'); + castList.classList.add('cast-list'); + castList.style.display = 'flex'; + castList.style.flexWrap = 'wrap'; + castList.style.justifyContent = 'center'; + castList.style.gap = '2px'; + + tvSeries.credits.cast.slice(0, 12).forEach(castMember => { + const castMemberLink = document.createElement('a'); + castMemberLink.classList.add('cast-member-link'); + castMemberLink.href = 'javascript:void(0);'; + castMemberLink.setAttribute('onclick', `selectActorId(${castMember.id}, '${castMember.name.replace(/'/g, "\\'")}');`); + + const castMemberItem = document.createElement('div'); + castMemberItem.classList.add('cast-member-item'); + + const castMemberImage = document.createElement('img'); + castMemberImage.classList.add('cast-member-image'); + + if (castMember.profile_path) { + castMemberImage.src = IMGPATH + castMember.profile_path; + castMemberImage.alt = `${castMember.name} Profile Picture`; + } else { + castMemberImage.alt = 'Image Not Available'; + castMemberImage.style.objectFit = 'cover'; + castMemberImage.src = 'https://movie-verse.com/images/user-default.png'; + castMemberImage.style.filter = 'grayscale(100%)'; + } + + castMemberItem.appendChild(castMemberImage); + + const castMemberDetails = document.createElement('div'); + castMemberDetails.classList.add('cast-member-details'); + + const castMemberName = document.createElement('p'); + castMemberName.classList.add('cast-member-name'); + castMemberName.textContent = castMember.name; + castMemberDetails.appendChild(castMemberName); + + const castMemberRole = document.createElement('p'); + castMemberRole.classList.add('cast-member-role'); + castMemberRole.textContent = castMember.character ? `(as ${castMember.character})` : ''; + castMemberRole.style.fontStyle = 'italic'; + castMemberDetails.appendChild(castMemberRole); + + castMemberItem.appendChild(castMemberDetails); + castMemberLink.appendChild(castMemberItem); + castList.appendChild(castMemberLink); + }); + + castSection.appendChild(castList); + detailsHTML += castSection.outerHTML; + } else { + const noCastElement = document.createElement('p'); + noCastElement.innerHTML = `Cast: Information not available`; + detailsHTML += noCastElement.outerHTML; + } + + if (tvSeries.similar && tvSeries.similar.results && tvSeries.similar.results.length > 0) { + const similarTvSeriesSection = document.createElement('div'); + similarTvSeriesSection.classList.add('similar-tv-series-section'); + + const similarTvSeriesTitle = document.createElement('p'); + similarTvSeriesTitle.innerHTML = 'Similar TV Series:'; + similarTvSeriesSection.appendChild(similarTvSeriesTitle); + + const similarTvSeriesList = document.createElement('div'); + similarTvSeriesList.classList.add('similar-tv-series-list'); + similarTvSeriesList.style.display = 'flex'; + similarTvSeriesList.style.flexWrap = 'wrap'; + similarTvSeriesList.style.justifyContent = 'center'; + similarTvSeriesList.style.gap = '10px'; + + let similarTvSeries = tvSeries.similar.results.sort((a, b) => b.popularity - a.popularity); + similarTvSeries = similarTvSeries.slice(0, 18); + + similarTvSeries.forEach(similarTv => { + const similarTvLink = document.createElement('a'); + similarTvLink.classList.add('similar-tv-link'); + similarTvLink.href = 'javascript:void(0);'; + similarTvLink.setAttribute('onclick', `selectTvSeriesId(${similarTv.id});`); + + const similarTvItem = document.createElement('div'); + similarTvItem.classList.add('similar-tv-item'); + + const similarTvImage = document.createElement('img'); + similarTvImage.classList.add('similar-tv-image'); + + if (similarTv.poster_path) { + similarTvImage.src = IMGPATH + similarTv.poster_path; + similarTvImage.alt = `${similarTv.name} Poster`; + } else { + similarTvImage.alt = 'Image Not Available'; + similarTvImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + similarTvImage.style.filter = 'grayscale(100%)'; + similarTvImage.style.objectFit = 'cover'; + } + + similarTvItem.appendChild(similarTvImage); + + const similarTvDetails = document.createElement('div'); + similarTvDetails.classList.add('similar-tv-details'); + + const similarTvName = document.createElement('p'); + similarTvName.classList.add('similar-tv-name'); + similarTvName.textContent = similarTv.name; + similarTvDetails.appendChild(similarTvName); + + similarTvItem.appendChild(similarTvDetails); + similarTvLink.appendChild(similarTvItem); + similarTvSeriesList.appendChild(similarTvLink); + }); + + similarTvSeriesSection.appendChild(similarTvSeriesList); + detailsHTML += similarTvSeriesSection.outerHTML; + } else { + const noSimilarTvSeriesElement = document.createElement('p'); + noSimilarTvSeriesElement.innerHTML = `Similar TV Series: Information not available`; + detailsHTML += noSimilarTvSeriesElement.outerHTML; + } + + if (tvSeries.production_companies && tvSeries.production_companies.length) { + const companiesSection = document.createElement('div'); + companiesSection.classList.add('companies-section'); + + const companiesTitle = document.createElement('p'); + companiesTitle.innerHTML = 'Production Companies:'; + companiesSection.appendChild(companiesTitle); + + const companiesList = document.createElement('div'); + companiesList.classList.add('companies-list'); + companiesList.style.display = 'flex'; + companiesList.style.flexWrap = 'wrap'; + companiesList.style.justifyContent = 'center'; + companiesList.style.gap = '5px'; + + let productionCompanies = tvSeries.production_companies.slice(0, 6); + + productionCompanies.forEach(company => { + const companyLink = document.createElement('a'); + companyLink.classList.add('company-link'); + companyLink.href = 'javascript:void(0);'; + companyLink.setAttribute('onclick', `selectCompanyId(${company.id});`); + + const companyItem = document.createElement('div'); + companyItem.classList.add('company-item'); + + const companyLogo = document.createElement('img'); + companyLogo.classList.add('company-logo'); + + if (company.logo_path) { + companyLogo.src = IMGPATH + company.logo_path; + companyLogo.alt = `${company.name} Logo`; + companyLogo.style.backgroundColor = 'white'; + } else { + companyLogo.alt = 'Logo Not Available'; + companyLogo.src = 'https://movie-verse.com/images/company-default.png'; + companyLogo.style.filter = 'grayscale(100%)'; + } + + companyItem.appendChild(companyLogo); + + const companyDetails = document.createElement('div'); + companyDetails.classList.add('company-details'); + + const companyName = document.createElement('p'); + companyName.classList.add('company-name'); + companyName.textContent = company.name; + companyDetails.appendChild(companyName); + + companyItem.appendChild(companyDetails); + companyLink.appendChild(companyItem); + companiesList.appendChild(companyLink); + }); + + companiesSection.appendChild(companiesList); + detailsHTML += companiesSection.outerHTML; + } else { + const noCompaniesElement = document.createElement('p'); + noCompaniesElement.innerHTML = `Production Companies: Information not available`; + detailsHTML += noCompaniesElement.outerHTML; + } + + const tvSeriesTitleEncoded = encodeURIComponent(title); + const streamingProviders = await fetchTvSeriesStreamingLinks(tvSeries.id); + const streamingHTML = + streamingProviders.length > 0 + ? streamingProviders + .map(provider => { + let providerLink = `https://www.google.com/search?q=watch+${tvSeriesTitleEncoded}+on+${encodeURIComponent(provider.provider_name)}`; + switch (provider.provider_name.toLowerCase()) { + case 'netflix': + providerLink = `https://www.netflix.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'disney plus': + providerLink = `https://www.disneyplus.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hbo max': + providerLink = `https://www.hbomax.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hulu': + providerLink = `https://www.hulu.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'amazon prime video': + providerLink = `https://www.amazon.com/s?k=${tvSeriesTitleEncoded}`; + break; + case 'apple tv plus': + providerLink = `https://tv.apple.com/search?term=${tvSeriesTitleEncoded}`; + break; + case 'stan': + providerLink = `https://www.stan.com.au/search?q=${tvSeriesTitleEncoded}`; + break; + case 'player': + providerLink = `https://player.pl/szukaj?search=${tvSeriesTitleEncoded}`; + break; + } + + return ``; + }) + .join('') + + `` + : 'No streaming options available.'; + + detailsHTML += `

Streaming Options: ${streamingHTML}

`; + + let keywordsHTML = tvSeries.keywords + ? tvSeries.keywords.results + .map( + kw => `${kw.name}` + ) + .join(', ') + : 'None Available'; + + if (tvSeries.keywords && tvSeries.keywords.results && tvSeries.keywords.results.length) { + detailsHTML += `

Keywords: ${keywordsHTML}

`; + } else { + detailsHTML += `

Keywords: None Available

`; + } + + const mediaUrl = `https://${getMovieVerseData()}/3/tv/${tvSeries.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; + } + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + document.getElementById('movie-description').innerHTML = detailsHTML; + document.getElementById('movie-description').appendChild(mediaTitle); + document.getElementById('movie-description').appendChild(mediaContainer); + + document.getElementById('last-episode-image').addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + + const modalHtml = ` +
+ Media Image + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + const modal = document.getElementById('image-modal'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + } + }); + }); + + if (tvSeries.videos.results.find(video => video.type === 'Trailer')?.key) { + const trailerKey = tvSeries.videos.results.find(video => video.type === 'Trailer')?.key; + const trailerUrl = trailerKey ? `https://www.youtube.com/embed/${trailerKey}` : null; + + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.id = 'trailer-button'; + trailerButton.style = ` + background-color: #7378c5; + color: white; + padding: 10px 20px; + border: none; + border-radius: 8px; + cursor: pointer; + margin-top: 10px; + font: inherit; + `; + + const iframeContainer = document.createElement('div'); + iframeContainer.id = 'trailer-iframe-container'; + iframeContainer.style = ` + display: none; + overflow: hidden; + margin-top: 10px; + max-height: 0; + transition: max-height 0.5s ease-in-out; + border: none; + border-radius: 8px; + `; + + trailerButton.addEventListener('click', () => { + if (iframeContainer.style.display === 'none') { + if (trailerUrl) { + const iframe = document.createElement('iframe'); + iframe.src = trailerUrl; + iframe.title = 'YouTube video player'; + iframe.frameborder = '0'; + iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'; + iframe.allowFullscreen = true; + iframeContainer.appendChild(iframe); + iframe.style.borderRadius = '16px'; + iframe.style.border = 'none'; + iframe.style.width = '400px'; + iframe.style.height = '315px'; + trailerButton.textContent = 'Close Trailer'; + } else { + iframeContainer.innerHTML = '

Trailer not available.

'; + } + iframeContainer.style.display = 'block'; + setTimeout(() => { + iframeContainer.style.maxHeight = '350px'; + }, 10); + } else { + iframeContainer.style.maxHeight = '0'; + setTimeout(() => { + iframeContainer.style.display = 'none'; + iframeContainer.innerHTML = ''; + trailerButton.textContent = 'Watch Trailer'; + }, 500); + } + }); + + document.getElementById('movie-description').appendChild(trailerButton); + document.getElementById('movie-description').appendChild(iframeContainer); + } +} + +async function fetchTvSeriesStreamingLinks(tvSeriesId) { + const url = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const results = data.results || {}; + let providersMap = {}; + + Object.values(results).forEach(region => { + if (region.flatrate) { + region.flatrate.forEach(provider => { + providersMap[provider.provider_id] = provider; + }); + } + }); + + return Object.values(providersMap).slice(0, 7); + } catch (error) { + console.error('Error fetching TV series streaming links:', error); + return []; + } +} + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + + localStorage.setItem('selectedActorId', actorId); + window.location.href = 'actor-details.html'; +} + +function selectTvSeriesId(tvSeriesId) { + localStorage.setItem('selectedTvSeriesId', tvSeriesId); + window.location.href = 'tv-details.html'; +} + +function selectCompanyId(companyId) { + localStorage.setItem('selectedCompanyId', companyId); + window.location.href = 'company-details.html'; +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +function handleKeywordClick(keyword) { + localStorage.setItem('searchQuery', keyword); + window.location.href = 'search.html'; +} + +function handleCreatorClick(creatorId, creatorName) { + localStorage.setItem('selectedDirectorId', creatorId); + document.title = `${creatorName} - Director's Details`; + updateUniqueDirectorsViewed(creatorId); + updateDirectorVisitCount(creatorId, creatorName); + window.location.href = 'director-details.html'; +} + +document.addEventListener('DOMContentLoaded', () => { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + if (tvSeriesId) { + fetchTvDetails(tvSeriesId); + } else { + fetchTvDetails(100088); + } + + document.getElementById('clear-search-btn').style.display = 'none'; + + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + const movieRating = savedRatings[tvSeriesId] || 0; + setStarRating(movieRating); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function getMovieCode2() { + const encodedKey = 'MmJhOGU1MzY='; + return atob(encodedKey); +} + +function getMovieName() { + const moviename = 'YXBpa2V5PQ=='; + return atob(moviename); +} + +function getMovieActor() { + const actor = 'd3d3Lm9tZGJhcGkuY29t'; + return atob(actor); +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/user-profile.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/user-profile.js new file mode 100644 index 00000000..be5a35ad --- /dev/null +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/js/user-profile.js @@ -0,0 +1,720 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + doc, + getDoc, + setDoc, + query, + collection, + where, + getDocs, + serverTimestamp, + deleteDoc, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { getAverageMovieRating } from './ratings-module.js'; +import { getTriviaStats } from './triviaModule.js'; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.addEventListener('DOMContentLoaded', function () { + showSpinner(); + handleProfileDisplay(); + setupEventListeners(); + setupSearchListeners(); + hideSpinner(); +}); + +function updateProgressCircles(movieRating, triviaScore) { + const movieRatingPercent = movieRating; + const triviaScorePercent = triviaScore; + + setProgress(document.getElementById('avgMovieRatingCircle'), document.getElementById('avgMovieRatingText'), movieRatingPercent); + setProgress(document.getElementById('avgTriviaScoreCircle'), document.getElementById('avgTriviaScoreText'), triviaScorePercent); +} + +function setProgress(circle, text, percent) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (percent / 100) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', percent > 50 ? '#4CAF50' : '#2196F3'); + text.textContent = `${Math.round(percent)}%`; + text.style.opacity = 1; + }, 10); +} + +function handleProfileDisplay() { + showSpinner(); + + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const welcomeMessage = document.getElementById('welcomeMessage'); + const signInPrompt = document.getElementById('signInPrompt'); + const viewMyProfileBtn = document.getElementById('viewMyProfileBtn'); + const profileContainer = document.getElementById('profileContainer'); + profileContainer.style.display = 'none'; + + if (isSignedIn && userEmail) { + loadProfile(userEmail); + viewMyProfileBtn.disabled = false; + viewMyProfileBtn.style.display = 'block'; + } else { + welcomeMessage.textContent = 'Please sign in to view your profile'; + signInPrompt.style.display = 'block'; + viewMyProfileBtn.disabled = true; + viewMyProfileBtn.style.display = 'none'; + } + + document.getElementById('viewMyProfileBtn').addEventListener('click', () => { + loadCurrentUserProfile(); + }); + + function loadCurrentUserProfile() { + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (currentUserEmail) { + loadProfile(currentUserEmail); + } else { + console.error('No user is currently signed in'); + } + } + + hideSpinner(); +} + +function setupSearchListeners() { + try { + const searchUserInput = document.getElementById('searchUserInput'); + const searchUserResults = document.getElementById('searchUserResults'); + + searchUserInput.addEventListener('input', () => { + const searchText = searchUserInput.value.trim(); + + if (searchText) { + performSearch(searchText); + } else { + searchUserResults.innerHTML = ''; + searchUserResults.style.display = 'none'; + } + }); + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + } +} + +async function performSearch(searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + const db = getFirestore(); + showSpinner(); + + try { + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); + const querySnapshot = await getDocs(userQuery); + + searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { + searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; + searchUserResults.style.display = 'block'; + } else { + searchUserResults.style.display = 'block'; + querySnapshot.forEach(doc => { + const user = doc.data(); + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadProfile(doc.id)); + + const img = document.createElement('img'); + img.src = user.profileImage || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.username}

Bio: ${ + user.bio || 'Not Set' + }

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + } + hideSpinner(); + } catch (error) { + console.error('Error during search: ', error); + searchUserResults.innerHTML = `
Error in searching: ${error.message}
`; + searchUserResults.style.display = 'block'; + hideSpinner(); + } +} + +document.getElementById('container1').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlyViewingProfile'); + + if (!userEmail) { + console.error('No user email found'); + return; + } + + try { + const rating = parseInt(localStorage.getItem('currentAverageRating'), 10); + const averageRating = rating.toFixed(1); + + const triviaStats = parseInt(localStorage.getItem('currentAverageTriviaScore'), 10); + const averageTriviaScore = triviaStats.toFixed(1); + + updateProgressCircles(averageRating, averageTriviaScore, 'container1'); + } catch (error) { + console.error('Error updating progress circles:', error); + } +}); + +document.getElementById('container2').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlyViewingProfile'); + + if (!userEmail) { + console.error('No user email found'); + return; + } + + try { + const rating = parseInt(localStorage.getItem('currentAverageRating'), 10); + const averageRating = rating.toFixed(1); + + const triviaStats = parseInt(localStorage.getItem('currentAverageTriviaScore'), 10); + const averageTriviaScore = triviaStats.toFixed(1); + + updateProgressCircles(averageRating, averageTriviaScore, 'container2'); + } catch (error) { + console.error('Error updating progress circles:', error); + } +}); + +async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMovieVerseUser')) { + showSpinner(); + try { + document.getElementById('viewMyProfileBtn').disabled = false; + + if (!userEmail) return; + + const welcomeMessage = document.getElementById('welcomeMessage'); + const profileContainer = document.getElementById('profileContainer'); + const changeProfileImageBtn = document.getElementById('changeProfileImageBtn'); + const editProfileBtn = document.getElementById('editProfileBtn'); + const removeProfileImageBtn = document.getElementById('removeProfileImage'); + const profileImage = document.getElementById('profileImage'); + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) + ) { + changeProfileImageBtn.style.display = 'none'; + editProfileBtn.style.display = 'none'; + profileImage.removeAttribute('onclick'); + profileImage.style.cursor = 'default'; + profileImage.title = 'Sign in to change profile image'; + } else { + changeProfileImageBtn.style.display = ''; + editProfileBtn.style.display = ''; + profileImage.setAttribute('onclick', 'document.getElementById("imageUpload").click()'); + profileImage.style.cursor = 'pointer'; + profileImage.title = 'Click to change profile image'; + } + + const rating = await getAverageMovieRating(userEmail); + const convertRatingToPercent = (rating / 5) * 100; + const averageRating = convertRatingToPercent.toFixed(1); + + const triviaStats = await getTriviaStats(userEmail); + + let averageTriviaScore = 0; + if (triviaStats.totalAttempted > 0) { + averageTriviaScore = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + } + + localStorage.setItem('currentlyViewingProfile', userEmail); + + updateProgressCircles(averageRating, averageTriviaScore); + + localStorage.setItem('currentAverageRating', averageRating); + localStorage.setItem('currentAverageTriviaScore', averageTriviaScore); + + profileContainer.style.display = 'block'; + + const docRef = doc(db, 'profiles', userEmail); + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let followUnfollowBtn = document.getElementById('followUnfollowBtn'); + if (!followUnfollowBtn) { + followUnfollowBtn = document.createElement('button'); + followUnfollowBtn.id = 'followUnfollowBtn'; + followUnfollowBtn.style.width = '100%'; + profileContainer.appendChild(followUnfollowBtn); + } + + if (currentUserEmail && userEmail !== currentUserEmail && isSignedIn) { + const followingRef = doc(db, 'profiles', currentUserEmail, 'following', userEmail); + const followersRef = doc(db, 'profiles', userEmail, 'followers', currentUserEmail); + + const followSnap = await getDoc(followingRef); + let isFollowing = followSnap.exists(); + + followUnfollowBtn.textContent = isFollowing ? 'Unfollow' : 'Follow'; + followUnfollowBtn.style.display = 'block'; + + followUnfollowBtn.onclick = async () => { + if (isFollowing) { + await deleteDoc(followingRef); + await deleteDoc(followersRef); + followUnfollowBtn.textContent = 'Follow'; + isFollowing = false; + await displayUserList('followers', userEmail); + } else { + const timestamp = serverTimestamp(); + await setDoc(followingRef, { timestamp: timestamp }); + await setDoc(followersRef, { timestamp: timestamp }); + followUnfollowBtn.textContent = 'Unfollow'; + isFollowing = true; + await displayUserList('followers', userEmail); + } + }; + } else { + followUnfollowBtn.style.display = 'none'; + } + + try { + const docSnap = await getDoc(docRef); + let profile = { + username: 'N/A', + dob: 'N/A', + bio: 'N/A', + favoriteGenres: 'N/A', + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: 'N/A', + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }; + + if (docSnap.exists()) { + profile = { ...profile, ...docSnap.data() }; + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } + + document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; + document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; + document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } + + hideSpinner(); + + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); + } else { + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } + + document.getElementById('usernameDisplay').innerHTML = `Username: N/A`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: N/A`; + document.getElementById('bioDisplay').innerHTML = `Bio: N/A`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: N/A`; + document.getElementById('locationDisplay').innerHTML = `Location: N/A`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: N/A`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: N/A`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: N/A`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: N/A`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: N/A`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } + + hideSpinner(); + + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); + } + } catch (error) { + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + + document.getElementById('viewMyProfileBtn').disabled = true; + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + + document.getElementById('viewMyProfileBtn').disabled = true; + } +} + +async function displayUserList(listType, userEmail) { + const db = getFirestore(); + const listRef = collection(db, 'profiles', userEmail, listType); + const userListSpan = document.getElementById(`${listType}List`); + + let loadingInterval; + function startLoadingAnimation() { + let dots = ''; + loadingInterval = setInterval(() => { + dots = dots.length < 3 ? dots + '.' : ''; + userListSpan.textContent = `Loading${dots}`; + }, 500); + } + + function stopLoadingAnimation() { + clearInterval(loadingInterval); + userListSpan.innerHTML = ''; + } + + startLoadingAnimation(); + + try { + const snapshot = await getDocs(listRef); + stopLoadingAnimation(); + + if (snapshot.empty) { + userListSpan.textContent = 'N/A'; + } else { + for (let docSnapshot of snapshot.docs) { + const userRef = doc(db, 'profiles', docSnapshot.id); + const userSnap = await getDoc(userRef); + if (userSnap.exists()) { + const userData = userSnap.data(); + + const userLink = document.createElement('a'); + userLink.textContent = userData.username; + userLink.href = '#'; + userLink.id = 'userLink'; + userLink.style.cursor = 'pointer'; + userLink.onclick = () => loadProfile(docSnapshot.id); + + userListSpan.appendChild(userLink); + userListSpan.appendChild(document.createTextNode(', ')); + } + } + + if (userListSpan.lastChild) { + userListSpan.removeChild(userListSpan.lastChild); + } + } + } catch (error) { + console.error('Error fetching user list:', error); + stopLoadingAnimation(); + userListSpan.innerHTML = 'Error loading data'; + } +} + +async function saveProfileChanges() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) return; + + const profileRef = doc(db, 'profiles', userEmail); + const currentDoc = await getDoc(profileRef); + const currentProfile = currentDoc.exists() ? currentDoc.data() : null; + + const newUsername = document.getElementById('editUsername').value.trim(); + + if (currentProfile && currentProfile.username && currentProfile.username !== 'N/A' && !newUsername) { + alert('You cannot delete your username. Please enter a valid username.'); + document.getElementById('editUsername').value = currentProfile.username; + return; + } + + const profile = { + username: newUsername || currentProfile.username, + dob: document.getElementById('editDob').value, + bio: document.getElementById('editBio').value, + favoriteGenres: document + .getElementById('editFavoriteGenres') + .value.split(',') + .map(genre => genre.trim()), + location: document.getElementById('editLocation').value, + favoriteMovie: document.getElementById('editFavoriteMovie').value, + hobbies: document + .getElementById('editHobbies') + .value.split(',') + .map(hobby => hobby.trim()), + favoriteActor: document.getElementById('editFavoriteActor').value, + favoriteDirector: document.getElementById('editFavoriteDirector').value, + personalQuote: document.getElementById('editPersonalQuote').value, + }; + + try { + await setDoc(profileRef, profile, { merge: true }); + console.log('Profile updated successfully.'); + closeModal(); + loadProfile(); + } catch (error) { + console.log('Error updating profile: ', error); + } +} + +async function removeProfileImage() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) return; + + const defaultImageUrl = '../../images/user-default.png'; + + try { + await setDoc(doc(db, 'profiles', userEmail), { profileImage: defaultImageUrl }, { merge: true }); + document.getElementById('profileImage').src = defaultImageUrl; + document.getElementById('removeProfileImage').style.display = 'none'; + } catch (error) { + console.log('Error removing image: ', error); + } +} + +async function uploadImage() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) { + alert("You're not signed in."); + return; + } + + const fileInput = document.getElementById('imageUpload'); + const file = fileInput.files[0]; + if (!file) { + alert('No file selected. Please choose an image.'); + return; + } + + try { + const base64Image = await resizeImageAndConvertToBase64(file, 1024, 1024); + + await setDoc(doc(db, 'profiles', userEmail), { profileImage: base64Image }, { merge: true }); + + document.getElementById('profileImage').src = base64Image; + console.log('Image processed and Firestore updated'); + window.location.reload(); + } catch (error) { + console.log('Error during image processing:', error); + alert('Error during image processing: ' + error.message); + } +} + +function resizeImageAndConvertToBase64(file, maxWidth, maxHeight) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = e => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement('canvas'); + let width = img.width; + let height = img.height; + + if (width > height) { + if (width > maxWidth) { + height *= maxWidth / width; + width = maxWidth; + } + } else { + if (height > maxHeight) { + width *= maxHeight / height; + height = maxHeight; + } + } + + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0, width, height); + const dataUrl = canvas.toDataURL('image/jpeg', 0.7); + resolve(dataUrl); + }; + img.src = e.target.result; + }; + reader.onerror = error => reject(error); + reader.readAsDataURL(file); + }); +} + +function setupEventListeners() { + document.getElementById('saveChanges').addEventListener('click', async () => { + await saveProfileChanges(); + }); + + document.getElementById('cancelEdit').addEventListener('click', () => { + closeModal(); + }); + + const imageUploadInput = document.getElementById('imageUpload'); + imageUploadInput.addEventListener('change', uploadImage); + + document.getElementById('editProfileBtn').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) { + alert("You're not signed in."); + return; + } + + try { + const docRef = doc(db, 'profiles', userEmail); + const docSnap = await getDoc(docRef); + + let profile = { + username: 'N/A', + dob: '', + bio: 'N/A', + favoriteGenres: [], + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: ['N/A'], + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }; + + if (docSnap.exists()) { + profile = docSnap.data(); + profile.hobbies = profile.hobbies.length > 0 ? profile.hobbies : ['N/A']; + } + + document.getElementById('editUsername').value = profile.username; + document.getElementById('editDob').value = profile.dob; + const defaultDOB = new Date(); + defaultDOB.setFullYear(defaultDOB.getFullYear() - 18); + const defaultDOBString = defaultDOB.toISOString().split('T')[0]; + + document.getElementById('editDob').value = profile.dob || defaultDOBString; + document.getElementById('editBio').value = profile.bio; + document.getElementById('editFavoriteGenres').value = profile.favoriteGenres.join(', '); + document.getElementById('editLocation').value = profile.location; + document.getElementById('editFavoriteMovie').value = profile.favoriteMovie; + document.getElementById('editHobbies').value = profile.hobbies.join(', '); + document.getElementById('editFavoriteActor').value = profile.favoriteActor; + document.getElementById('editFavoriteDirector').value = profile.favoriteDirector; + document.getElementById('editPersonalQuote').value = profile.personalQuote; + document.getElementById('profileImage').src = profile.profileImage || '../../images/user-default.png'; + document.getElementById('editProfileModal').style.display = 'block'; + } catch (error) { + console.log('Error accessing Firestore: ', error); + } + }); + + document.getElementById('imageUpload').addEventListener('change', async () => { + await uploadImage(); + }); + + document.getElementById('removeProfileImage').addEventListener('click', async () => { + await removeProfileImage(); + }); +} diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.js b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.js index 2e90def6..68445014 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.js +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/index.js @@ -1,22 +1,22 @@ -const director_main = document.getElementById('director-spotlight'); -const form = document.getElementById('form'); -const search = document.getElementById('search'); -const searchButton = document.getElementById('button-search'); -const searchTitle = document.getElementById('search-title'); -const otherTitle = document.getElementById('other1'); +const director_main = document.getElementById("director-spotlight"); +const form = document.getElementById("form"); +const search = document.getElementById("search"); +const searchButton = document.getElementById("button-search"); +const searchTitle = document.getElementById("search-title"); +const otherTitle = document.getElementById("other1"); function showSpinner() { - document.getElementById('myModal').classList.add('modal-visible'); + document.getElementById("myModal").classList.add("modal-visible"); } function hideSpinner() { - document.getElementById('myModal').classList.remove('modal-visible'); + document.getElementById("myModal").classList.remove("modal-visible"); } -document.addEventListener('DOMContentLoaded', function () { - const pagination = document.getElementById('most-popular-pagination'); - const genresContainer = document.querySelector('.genres'); - const mainContainer = document.getElementById('most-popular'); +document.addEventListener("DOMContentLoaded", function () { + const pagination = document.getElementById("most-popular-pagination"); + const genresContainer = document.querySelector(".genres"); + const mainContainer = document.getElementById("most-popular"); function movePagination() { if (window.innerWidth <= 767) { @@ -27,14 +27,16 @@ document.addEventListener('DOMContentLoaded', function () { } movePagination(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { let currentPageMostPopular = 1; const totalPages = 320; - const mostPopularMain = document.getElementById('most-popular'); - const paginationContainer = document.getElementById('most-popular-pagination'); + const mostPopularMain = document.getElementById("most-popular"); + const paginationContainer = document.getElementById( + "most-popular-pagination", + ); const fetchAndUpdateMostPopular = () => { const mostPopularUrl = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}`; @@ -43,12 +45,16 @@ document.addEventListener('DOMContentLoaded', function () { }; const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageMostPopular > 1, () => { - currentPageMostPopular--; - fetchAndUpdateMostPopular(); - }); + const prevButton = createNavigationButton( + "<", + currentPageMostPopular > 1, + () => { + currentPageMostPopular--; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(prevButton); let startPage = Math.max(currentPageMostPopular - 2, 1); @@ -58,7 +64,8 @@ document.addEventListener('DOMContentLoaded', function () { if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -66,22 +73,27 @@ document.addEventListener('DOMContentLoaded', function () { } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPageMostPopular < totalPages, () => { - currentPageMostPopular++; - fetchAndUpdateMostPopular(); - }); + const nextButton = createNavigationButton( + ">", + currentPageMostPopular < totalPages, + () => { + currentPageMostPopular++; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(nextButton); }; const createNavigationButton = (text, enabled, clickHandler) => { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { button.onclick = clickHandler; @@ -90,12 +102,12 @@ document.addEventListener('DOMContentLoaded', function () { return button; }; - const createPageButton = pageNum => { - const button = document.createElement('button'); + const createPageButton = (pageNum) => { + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { button.onclick = function () { @@ -104,7 +116,7 @@ document.addEventListener('DOMContentLoaded', function () { }; if (pageNum === currentPageMostPopular) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -113,7 +125,12 @@ document.addEventListener('DOMContentLoaded', function () { fetchAndUpdateMostPopular(); }); -function setupPagination(mainElementId, paginationContainerId, genresContainerId, baseUrl) { +function setupPagination( + mainElementId, + paginationContainerId, + genresContainerId, + baseUrl, +) { let currentPage = 1; let totalPages = 10; @@ -168,7 +185,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId mainElement.innerHTML = `

No movies found on this page.

`; } } catch (error) { - console.log('Error fetching data: ', error); + console.log("Error fetching data: ", error); mainElement.innerHTML = `

No movies found on this page.

`; } finally { hideSpinner(); @@ -177,9 +194,9 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPage > 1, () => { + const prevButton = createNavigationButton("<", currentPage > 1, () => { currentPage--; fetchAndUpdate(); }); @@ -194,7 +211,8 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -202,45 +220,50 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPage < totalPages, () => { - currentPage++; - fetchAndUpdate(); - }); + const nextButton = createNavigationButton( + ">", + currentPage < totalPages, + () => { + currentPage++; + fetchAndUpdate(); + }, + ); paginationContainer.appendChild(nextButton); }; function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { - button.addEventListener('click', () => { - currentPage = typeof pageNum === 'number' ? pageNum : currentPage; + button.addEventListener("click", () => { + currentPage = typeof pageNum === "number" ? pageNum : currentPage; fetchAndUpdate(); }); if (pageNum === currentPage) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -250,7 +273,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId fetchAndUpdate(); let resizeTimer; - window.addEventListener('resize', () => { + window.addEventListener("resize", () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(movePagination, 250); }); @@ -265,16 +288,21 @@ async function fetchAndDisplayMovies(url, count, mainElement) { showMovies(movies, mainElement); } -document.addEventListener('DOMContentLoaded', async () => { +document.addEventListener("DOMContentLoaded", async () => { let currentPageRecommended = 1; const totalPagesRecommended = 60; - const recommendedMain = document.getElementById('recommended'); - const paginationContainerRecommended = document.getElementById('recommended-pagination'); - const genresContainer = document.getElementById('recommendedDIV'); + const recommendedMain = document.getElementById("recommended"); + const paginationContainerRecommended = document.getElementById( + "recommended-pagination", + ); + const genresContainer = document.getElementById("recommendedDIV"); function movePagination() { if (window.innerWidth <= 767) { - recommendedMain.parentNode.insertBefore(paginationContainerRecommended, recommendedMain); + recommendedMain.parentNode.insertBefore( + paginationContainerRecommended, + recommendedMain, + ); } else { genresContainer.appendChild(paginationContainerRecommended); } @@ -287,7 +315,7 @@ document.addEventListener('DOMContentLoaded', async () => { const mostCommonGenre = getMostCommonGenre(); const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); - recommendedMain.innerHTML = ''; + recommendedMain.innerHTML = ""; if (!mostVisitedMovieGenre || !mostCommonGenre) { recommendedMain.innerHTML = `
@@ -302,17 +330,29 @@ document.addEventListener('DOMContentLoaded', async () => { const commonGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostCommonGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; const visitedGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostVisitedMovieGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; - await fetchAndDisplayMovies(commonGenreUrl, totalMoviesToDisplay, recommendedMain); - await fetchAndDisplayMovies(visitedGenreUrl, totalMoviesToDisplay, recommendedMain); + await fetchAndDisplayMovies( + commonGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); + await fetchAndDisplayMovies( + visitedGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); updatePaginationDisplayRecommended(); hideSpinner(); } function updatePaginationDisplayRecommended() { - paginationContainerRecommended.innerHTML = ''; + paginationContainerRecommended.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageRecommended > 1, () => generateRecommendations(currentPageRecommended - 1)); + const prevButton = createNavigationButton( + "<", + currentPageRecommended > 1, + () => generateRecommendations(currentPageRecommended - 1), + ); paginationContainerRecommended.appendChild(prevButton); let startPage = Math.max(currentPageRecommended - 2, 1); @@ -321,43 +361,57 @@ document.addEventListener('DOMContentLoaded', async () => { if (endPage === totalPagesRecommended) startPage = Math.max(endPage - 4, 1); if (startPage > 1) { - paginationContainerRecommended.appendChild(createPageButton(1, generateRecommendations)); - if (startPage > 2) paginationContainerRecommended.appendChild(createPageButton('...')); + paginationContainerRecommended.appendChild( + createPageButton(1, generateRecommendations), + ); + if (startPage > 2) + paginationContainerRecommended.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { - paginationContainerRecommended.appendChild(createPageButton(i, generateRecommendations, i === currentPageRecommended)); + paginationContainerRecommended.appendChild( + createPageButton( + i, + generateRecommendations, + i === currentPageRecommended, + ), + ); } if (endPage < totalPagesRecommended) { - if (endPage < totalPagesRecommended - 1) paginationContainerRecommended.appendChild(createPageButton('...')); - paginationContainerRecommended.appendChild(createPageButton(totalPagesRecommended, generateRecommendations)); + if (endPage < totalPagesRecommended - 1) + paginationContainerRecommended.appendChild(createPageButton("...")); + paginationContainerRecommended.appendChild( + createPageButton(totalPagesRecommended, generateRecommendations), + ); } - const nextButton = createNavigationButton('>', currentPageRecommended < totalPagesRecommended, () => - generateRecommendations(currentPageRecommended + 1) + const nextButton = createNavigationButton( + ">", + currentPageRecommended < totalPagesRecommended, + () => generateRecommendations(currentPageRecommended + 1), ); paginationContainerRecommended.appendChild(nextButton); } function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum, fetchFunction, isActive) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button' + (isActive ? ' active' : ''); + button.className = "page-button" + (isActive ? " active" : ""); - if (pageNum !== '...') { - button.addEventListener('click', () => fetchFunction(pageNum)); + if (pageNum !== "...") { + button.addEventListener("click", () => fetchFunction(pageNum)); } else { button.disabled = true; } @@ -367,7 +421,7 @@ document.addEventListener('DOMContentLoaded', async () => { movePagination(); await generateRecommendations(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); async function getMovies(url, mainElement, page = 1) { @@ -398,102 +452,149 @@ async function getMovies(url, mainElement, page = 1) { } async function getAdditionalPosters(movieId) { - const response = await fetch(`https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`); + const response = await fetch( + `https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`, + ); const data = await response.json(); - return data.posters.map(poster => poster.file_path); + return data.posters.map((poster) => poster.file_path); } function rotateImages(imageElements, interval = 3000) { - const uniqueImageElements = Array.from(imageElements).filter((el, index, self) => index === self.findIndex(e => e.src === el.src)); + const uniqueImageElements = Array.from(imageElements).filter( + (el, index, self) => index === self.findIndex((e) => e.src === el.src), + ); if (uniqueImageElements.length <= 1) return; let currentIndex = 0; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; setTimeout(() => { setInterval(() => { - uniqueImageElements[currentIndex].style.opacity = '0'; + uniqueImageElements[currentIndex].style.opacity = "0"; currentIndex = (currentIndex + 1) % uniqueImageElements.length; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; }, interval); }, 0); } async function showMovies(movies, mainElement) { - mainElement.innerHTML = ''; + mainElement.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - const observer = new IntersectionObserver( + // Observer for background image loading and rotation setup + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch additional posters and set up rotation in the background const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); + const movieImageContainer = movieEl.querySelector(".movie-images"); allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); - const imagePromises = allPosters.map((poster, index) => { + // Load images in the background + allPosters.forEach((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; - img.loading = index === 0 ? 'eager' : 'lazy'; + img.loading = index === 0 ? "eager" : "lazy"; img.alt = `${movieEl.dataset.title} poster ${index + 1}`; img.width = 300; img.height = 435; - img.style.position = 'absolute'; + img.style.position = "absolute"; img.style.top = 0; img.style.left = 0; - img.style.transition = 'opacity 1s ease-in-out'; - img.style.opacity = '0'; - img.classList.add('poster-img'); + img.style.transition = "opacity 1s ease-in-out"; + img.style.opacity = "0"; + img.classList.add("poster-img"); movieImageContainer.appendChild(img); - return new Promise(resolve => { - img.onload = () => resolve(img); - }); + img.onload = () => { + if (index === 0) img.style.opacity = "1"; // Show the first image + }; }); - const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); - await Promise.race([Promise.all(imagePromises), maxWait]); - - movieImageContainer.querySelector('.poster-img').style.opacity = '1'; - + // Start rotating images in the background rotateImages(Array.from(movieImageContainer.children)); observer.unobserve(movieEl); } } }, { - rootMargin: '50px 0px', + rootMargin: "50px 0px", threshold: 0.1, - } + }, ); - movies.forEach(movie => { - let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; - - const movieEl = document.createElement('div'); - movieEl.style.zIndex = '1000'; - movieEl.classList.add('movie'); + movies.forEach((movie, index) => { + let { + id, + poster_path, + title, + vote_average, + vote_count, + overview, + genre_ids, + } = movie; + + const movieEl = document.createElement("div"); + movieEl.style.zIndex = "1000"; + movieEl.classList.add("movie"); movieEl.dataset.id = id; movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; - const words = title.split(' '); + const words = title.split(" "); if (words.length >= 8) { - words[7] = '...'; - title = words.slice(0, 8).join(' '); + words[7] = "..."; + title = words.slice(0, 8).join(" "); } - const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); - const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); + const voteAvg = vote_count === 0 ? "Unrated" : vote_average.toFixed(1); + const ratingClass = + vote_count === 0 ? "unrated" : getClassByRate(vote_average); - if (overview === '') { - overview = 'No overview available.'; + if (overview === "") { + overview = "No overview available."; } movieEl.innerHTML = ` @@ -511,37 +612,44 @@ async function showMovies(movies, mainElement) { ${overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); + + // Observe for background image loading and rotation + imageObserver.observe(movieEl); }); } function updateFavoriteGenre(genre_ids) { if (genre_ids && genre_ids.length > 0) { - const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenres = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; favoriteGenres.push(genre_ids[0]); - localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + localStorage.setItem("favoriteGenres", JSON.stringify(favoriteGenres)); } } function updateUniqueMoviesViewed(movieId) { - let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + let viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; if (!viewedMovies.includes(movieId)) { viewedMovies.push(movieId); - localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); + localStorage.setItem("uniqueMoviesViewed", JSON.stringify(viewedMovies)); } } async function ensureGenreMapIsAvailable() { - if (!localStorage.getItem('genreMap')) { + if (!localStorage.getItem("genreMap")) { await fetchGenreMap(); } } @@ -556,9 +664,9 @@ async function fetchGenreMap() { map[genre.id] = genre.name; return map; }, {}); - localStorage.setItem('genreMap', JSON.stringify(genreMap)); + localStorage.setItem("genreMap", JSON.stringify(genreMap)); } catch (error) { - console.log('Error fetching genre map:', error); + console.log("Error fetching genre map:", error); } } @@ -567,49 +675,51 @@ async function rotateUserStats() { const stats = [ { - label: 'Your Current Time', + label: "Your Current Time", getValue: () => { const now = new Date(); let hours = now.getHours(); let minutes = now.getMinutes(); - hours = hours < 10 ? '0' + hours : hours; - minutes = minutes < 10 ? '0' + minutes : minutes; + hours = hours < 10 ? "0" + hours : hours; + minutes = minutes < 10 ? "0" + minutes : minutes; return `${hours}:${minutes}`; }, }, - { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, - { label: 'Most Visited Director', getValue: getMostVisitedDirector }, - { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { label: "Most Visited Movie", getValue: getMostVisitedMovie }, + { label: "Most Visited Director", getValue: getMostVisitedDirector }, + { label: "Most Visited Actor", getValue: getMostVisitedActor }, { - label: 'Movies Discovered', + label: "Movies Discovered", getValue: () => { - const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + const viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; return viewedMovies.length; }, }, { - label: 'Favorite Movies', + label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritedMovies = + JSON.parse(localStorage.getItem("moviesFavorited")) || []; return favoritedMovies.length; }, }, { - label: 'Favorite Genre', + label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMapString = localStorage.getItem('genreMap'); + const genreMapString = localStorage.getItem("genreMap"); if (!genreMapString) { - console.log('No genre map found in localStorage.'); - return 'Not Available'; + console.log("No genre map found in localStorage."); + return "Not Available"; } let genreMap; try { genreMap = JSON.parse(genreMapString); } catch (e) { - console.log('Error parsing genre map:', e); - return 'Not Available'; + console.log("Error parsing genre map:", e); + return "Not Available"; } let genreObject; @@ -618,74 +728,81 @@ async function rotateUserStats() { acc[genre.id] = genre.name; return acc; }, {}); - } else if (typeof genreMap === 'object' && genreMap !== null) { + } else if (typeof genreMap === "object" && genreMap !== null) { genreObject = genreMap; } else { - console.log('genreMap is neither an array nor a proper object:', genreMap); - return 'Not Available'; + console.log( + "genreMap is neither an array nor a proper object:", + genreMap, + ); + return "Not Available"; } - return genreObject[mostCommonGenreCode] || 'Not Available'; + return genreObject[mostCommonGenreCode] || "Not Available"; }, }, { - label: 'Watchlists Created', - getValue: () => localStorage.getItem('watchlistsCreated') || 0, + label: "Watchlists Created", + getValue: () => localStorage.getItem("watchlistsCreated") || 0, }, { - label: 'Average Movie Rating', - getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + label: "Average Movie Rating", + getValue: () => localStorage.getItem("averageMovieRating") || "Not Rated", }, { - label: 'Directors Discovered', + label: "Directors Discovered", getValue: () => { - const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + const viewedDirectors = + JSON.parse(localStorage.getItem("uniqueDirectorsViewed")) || []; return viewedDirectors.length; }, }, { - label: 'Actors Discovered', + label: "Actors Discovered", getValue: () => { - const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + const viewedActors = + JSON.parse(localStorage.getItem("uniqueActorsViewed")) || []; return viewedActors.length; }, }, - { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + { label: "Your Trivia Accuracy", getValue: getTriviaAccuracy }, ]; let currentStatIndex = 0; function updateStatDisplay() { const currentStat = stats[currentStatIndex]; - document.getElementById('stats-label').textContent = currentStat.label + ':'; - document.getElementById('stats-display').textContent = currentStat.getValue(); + document.getElementById("stats-label").textContent = + currentStat.label + ":"; + document.getElementById("stats-display").textContent = + currentStat.getValue(); currentStatIndex = (currentStatIndex + 1) % stats.length; } updateStatDisplay(); - const localTimeDiv = document.getElementById('local-time'); + const localTimeDiv = document.getElementById("local-time"); let statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.addEventListener('click', () => { + localTimeDiv.addEventListener("click", () => { clearInterval(statRotationInterval); updateStatDisplay(); statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + localTimeDiv.scrollIntoView({ behavior: "smooth" }); }); } function updateMovieVisitCount(movieId, movieTitle) { - let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; if (!movieVisits[movieId]) { movieVisits[movieId] = { count: 0, title: movieTitle }; } movieVisits[movieId].count += 1; - localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem("movieVisits", JSON.stringify(movieVisits)); } function getMostVisitedMovie() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; - let mostVisitedMovie = ''; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; + let mostVisitedMovie = ""; let maxVisits = 0; for (const movieId in movieVisits) { @@ -695,11 +812,11 @@ function getMostVisitedMovie() { } } - return mostVisitedMovie || 'Not Available'; + return mostVisitedMovie || "Not Available"; } async function getMostVisitedMovieGenre() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; let mostVisitedGenre = null; let maxVisits = 0; @@ -722,8 +839,8 @@ async function fetchGenreForMovie(movieId) { } function getMostVisitedActor() { - const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; - let mostVisitedActor = ''; + const actorVisits = JSON.parse(localStorage.getItem("actorVisits")) || {}; + let mostVisitedActor = ""; let maxVisits = 0; for (const actorId in actorVisits) { @@ -733,12 +850,13 @@ function getMostVisitedActor() { } } - return mostVisitedActor || 'Not Available'; + return mostVisitedActor || "Not Available"; } function getMostVisitedDirector() { - const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; - let mostVisitedDirector = ''; + const directorVisits = + JSON.parse(localStorage.getItem("directorVisits")) || {}; + let mostVisitedDirector = ""; let maxVisits = 0; for (const directorId in directorVisits) { @@ -747,16 +865,16 @@ function getMostVisitedDirector() { maxVisits = directorVisits[directorId].count; } } - return mostVisitedDirector || 'Not Available'; + return mostVisitedDirector || "Not Available"; } function getTriviaAccuracy() { - let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + let triviaStats = JSON.parse(localStorage.getItem("triviaStats")) || { totalCorrect: 0, totalAttempted: 0, }; if (triviaStats.totalAttempted === 0) { - return 'No trivia attempted'; + return "No trivia attempted"; } let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; @@ -764,13 +882,14 @@ function getTriviaAccuracy() { } function getMostCommonGenre() { - const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenresArray = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; const genreCounts = favoriteGenresArray.reduce((acc, genre) => { acc[genre] = (acc[genre] || 0) + 1; return acc; }, {}); - let mostCommonGenre = ''; + let mostCommonGenre = ""; let maxCount = 0; for (const genre in genreCounts) { @@ -780,16 +899,16 @@ function getMostCommonGenre() { } } - return mostCommonGenre || 'Not Available'; + return mostCommonGenre || "Not Available"; } const movieCode = { - part1: 'YzVhMjBjODY=', - part2: 'MWFjZjdiYjg=', - part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', + part1: "YzVhMjBjODY=", + part2: "MWFjZjdiYjg=", + part3: "ZDllOTg3ZGNjN2YxYjU1OA==", }; -document.addEventListener('DOMContentLoaded', rotateUserStats); +document.addEventListener("DOMContentLoaded", rotateUserStats); async function showMovieOfTheDay() { const year = new Date().getFullYear(); @@ -802,26 +921,28 @@ async function showMovieOfTheDay() { if (movies.length > 0) { const randomMovie = movies[Math.floor(Math.random() * movies.length)]; - localStorage.setItem('selectedMovieId', randomMovie.id); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomMovie.id); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } else { fallbackMovieSelection(); } } catch (error) { - console.log('Error fetching movie:', error); + console.log("Error fetching movie:", error); fallbackMovieSelection(); } } function fallbackMovieSelection() { const fallbackMovies = [ - 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, - 424, 98, + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, + 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, 424, + 98, ]; - const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + const randomFallbackMovie = + fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; - localStorage.setItem('selectedMovieId', randomFallbackMovie); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomFallbackMovie); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } function calculateMoviesToDisplay() { @@ -855,71 +976,75 @@ function calculateMoviesToDisplay() { function getClassByRate(vote) { if (vote >= 8) { - return 'green'; + return "green"; } else if (vote >= 5) { - return 'orange'; + return "orange"; } else { - return 'red'; + return "red"; } } -form.addEventListener('submit', e => { +form.addEventListener("submit", (e) => { e.preventDefault(); - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; }); function toggleNav() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - sideNav.classList.toggle('manual-toggle'); + sideNav.classList.toggle("manual-toggle"); adjustNavBar(); } function removeNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if (sideNav.classList.contains("manual-toggle")) { + sideNav.classList.remove("manual-toggle"); } adjustNavBar(); } function adjustNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0px'; + if (sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0px"; } else { - sideNav.style.left = '-250px'; + sideNav.style.left = "-250px"; } } -document.addEventListener('mousemove', function (event) { - const sideNav = document.getElementById('side-nav'); +document.addEventListener("mousemove", function (event) { + const sideNav = document.getElementById("side-nav"); - if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0'; + if (event.clientX < 10 && !sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0"; } }); -document.addEventListener('click', function (event) { - const sideNav = document.getElementById('side-nav'); - const navToggle = document.getElementById('nav-toggle'); +document.addEventListener("click", function (event) { + const sideNav = document.getElementById("side-nav"); + const navToggle = document.getElementById("nav-toggle"); - if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if ( + !sideNav.contains(event.target) && + !navToggle.contains(event.target) && + sideNav.classList.contains("manual-toggle") + ) { + sideNav.classList.remove("manual-toggle"); adjustNavBar(); } }); -document.getElementById('side-nav').addEventListener('mouseleave', function () { - const sideNav = document.getElementById('side-nav'); +document.getElementById("side-nav").addEventListener("mouseleave", function () { + const sideNav = document.getElementById("side-nav"); - if (!sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '-250px'; + if (!sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "-250px"; } }); @@ -928,32 +1053,32 @@ const IMGPATH = `https://image.tmdb.org/t/p/w500`; const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; const directors = [ - { name: 'Alfred Hitchcock', id: '2636' }, - { name: 'Steven Spielberg', id: '488' }, - { name: 'Martin Scorsese', id: '1032' }, - { name: 'Quentin Tarantino', id: '138' }, - { name: 'Christopher Nolan', id: '525' }, - { name: 'Stanley Kubrick', id: '240' }, - { name: 'Bong Joon-ho', id: '21684' }, - { name: 'David Fincher', id: '7467' }, - { name: 'James Cameron', id: '2710' }, - { name: 'Francis Ford Coppola', id: '1776' }, - { name: 'Tim Burton', id: '510' }, - { name: 'Ridley Scott', id: '578' }, - { name: 'Joel Coen', id: '1223' }, - { name: 'Spike Lee', id: '5281' }, - { name: 'Woody Allen', id: '1243' }, - { name: 'Peter Jackson', id: '108' }, - { name: 'Oliver Stone', id: '1152' }, - { name: 'David Lynch', id: '5602' }, - { name: 'Roman Polanski', id: '3556' }, - { name: 'Wes Anderson', id: '5655' }, - { name: 'Sergio Leone', id: '4385' }, - { name: 'Akira Kurosawa', id: '5026' }, - { name: 'Federico Fellini', id: '4415' }, - { name: 'John Ford', id: '8500' }, - { name: 'Fritz Lang', id: '68' }, - { name: 'Frank Capra', id: '2662' }, + { name: "Alfred Hitchcock", id: "2636" }, + { name: "Steven Spielberg", id: "488" }, + { name: "Martin Scorsese", id: "1032" }, + { name: "Quentin Tarantino", id: "138" }, + { name: "Christopher Nolan", id: "525" }, + { name: "Stanley Kubrick", id: "240" }, + { name: "Bong Joon-ho", id: "21684" }, + { name: "David Fincher", id: "7467" }, + { name: "James Cameron", id: "2710" }, + { name: "Francis Ford Coppola", id: "1776" }, + { name: "Tim Burton", id: "510" }, + { name: "Ridley Scott", id: "578" }, + { name: "Joel Coen", id: "1223" }, + { name: "Spike Lee", id: "5281" }, + { name: "Woody Allen", id: "1243" }, + { name: "Peter Jackson", id: "108" }, + { name: "Oliver Stone", id: "1152" }, + { name: "David Lynch", id: "5602" }, + { name: "Roman Polanski", id: "3556" }, + { name: "Wes Anderson", id: "5655" }, + { name: "Sergio Leone", id: "4385" }, + { name: "Akira Kurosawa", id: "5026" }, + { name: "Federico Fellini", id: "4415" }, + { name: "John Ford", id: "8500" }, + { name: "Fritz Lang", id: "68" }, + { name: "Frank Capra", id: "2662" }, ]; let currentDirectorIndex = 0; @@ -972,7 +1097,8 @@ setInterval(changeDirector, 3600000); function updateDirectorSpotlight() { const director = directors[currentDirectorIndex]; - document.getElementById('spotlight-director-name').textContent = director.name; + document.getElementById("spotlight-director-name").textContent = + director.name; const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_people=${ director.id @@ -981,7 +1107,26 @@ function updateDirectorSpotlight() { } function getMovieVerseData(input) { - return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); + return String.fromCharCode( + 97, + 112, + 105, + 46, + 116, + 104, + 101, + 109, + 111, + 118, + 105, + 101, + 100, + 98, + 46, + 111, + 114, + 103, + ); } function generateMovieNames(input) { @@ -1005,21 +1150,59 @@ async function getDirectorSpotlight(url) { } function showMoviesDirectorSpotlight(movies) { - director_main.innerHTML = ''; + director_main.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - movies.forEach(movie => { + movies.forEach((movie, index) => { const { id, poster_path, title, vote_average, genre_ids } = movie; - const movieEl = document.createElement('div'); + const movieEl = document.createElement("div"); - movieEl.classList.add('movie'); - movieEl.style.zIndex = '1000'; + movieEl.classList.add("movie"); + movieEl.style.zIndex = "1000"; + // Movie image and fallback in case the image is unavailable const movieImage = poster_path ? `${title}` : `
Image Not Available
`; - const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : 'Unrated'; - const ratingClass = vote_average > 0 ? getClassByRate(vote_average) : 'unrated'; + const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : "Unrated"; + const ratingClass = + vote_average > 0 ? getClassByRate(vote_average) : "unrated"; movieEl.innerHTML = ` ${movieImage} @@ -1032,26 +1215,29 @@ function showMoviesDirectorSpotlight(movies) { ${movie.overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); director_main.appendChild(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); }); } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); + localStorage.setItem("isSignedIn", JSON.stringify(false)); + alert("You have been signed out."); } else { - window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; + window.location.href = "MovieVerse-Frontend/html/sign-in.html"; return; } @@ -1059,213 +1245,215 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const signInText = document.getElementById("signInOutText"); + const signInIcon = document.getElementById("signInIcon"); + const signOutIcon = document.getElementById("signOutIcon"); if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; + signInText.textContent = "Sign Out"; + signInIcon.style.display = "none"; + signOutIcon.style.display = "inline-block"; } else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; + signInText.textContent = "Sign In"; + signInIcon.style.display = "inline-block"; + signOutIcon.style.display = "none"; } - const mobileSignInText = document.getElementById('mobileSignInOutText'); - const mobileSignInIcon = document.getElementById('mobileSignInIcon'); - const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); + const mobileSignInText = document.getElementById("mobileSignInOutText"); + const mobileSignInIcon = document.getElementById("mobileSignInIcon"); + const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); if (isSignedIn) { - mobileSignInText.textContent = 'Sign Out'; - mobileSignInIcon.style.display = 'none'; - mobileSignOutIcon.style.display = 'inline-block'; + mobileSignInText.textContent = "Sign Out"; + mobileSignInIcon.style.display = "none"; + mobileSignOutIcon.style.display = "inline-block"; } else { - mobileSignInText.textContent = 'Sign In'; - mobileSignInIcon.style.display = 'inline-block'; - mobileSignOutIcon.style.display = 'none'; + mobileSignInText.textContent = "Sign In"; + mobileSignInIcon.style.display = "inline-block"; + mobileSignOutIcon.style.display = "none"; } } setupPagination( - 'award-winning', - 'award-winning-pagination', - 'award-winning-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` + "award-winning", + "award-winning-pagination", + "award-winning-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, ); setupPagination( - 'hidden-gems', - 'hidden-gems-pagination', - 'hidden-gems-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` + "hidden-gems", + "hidden-gems-pagination", + "hidden-gems-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, ); setupPagination( - 'western', - 'western-pagination', - 'western-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` + "western", + "western-pagination", + "western-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'war', - 'war-pagination', - 'war-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` + "war", + "war-pagination", + "war-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'vietnamese', - 'vietnamese-pagination', - 'vietnamese-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` + "vietnamese", + "vietnamese-pagination", + "vietnamese-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, ); setupPagination( - 'korean', - 'korean-pagination', - 'korean-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` + "korean", + "korean-pagination", + "korean-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, ); setupPagination( - 'musical', - 'musical-pagination', - 'musical-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` + "musical", + "musical-pagination", + "musical-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'drama', - 'drama-pagination', - 'drama-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` + "drama", + "drama-pagination", + "drama-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'indian', - 'indian-pagination', - 'indian-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` + "indian", + "indian-pagination", + "indian-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, ); setupPagination( - 'action', - 'action-pagination', - 'action-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` + "action", + "action-pagination", + "action-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'horror', - 'horror-pagination', - 'horror-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` + "horror", + "horror-pagination", + "horror-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'documentary', - 'documentary-pagination', - 'documentary-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` + "documentary", + "documentary-pagination", + "documentary-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'animation', - 'animation-pagination', - 'animation-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` + "animation", + "animation-pagination", + "animation-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'sci-fi', - 'sci-fi-pagination', - 'sci-fi-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` + "sci-fi", + "sci-fi-pagination", + "sci-fi-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'romantic', - 'romantic-pagination', - 'romantic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` + "romantic", + "romantic-pagination", + "romantic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'thriller', - 'thriller-pagination', - 'thriller-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` + "thriller", + "thriller-pagination", + "thriller-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'mystery', - 'mystery-pagination', - 'mystery-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` + "mystery", + "mystery-pagination", + "mystery-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'comedy', - 'comedy-pagination', - 'comedy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` + "comedy", + "comedy-pagination", + "comedy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'fantasy', - 'fantasy-pagination', - 'fantasy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` + "fantasy", + "fantasy-pagination", + "fantasy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'family', - 'family-pagination', - 'family-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` + "family", + "family-pagination", + "family-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'tv-series', - 'tv-series-pagination', - 'tv-series-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` + "tv-series", + "tv-series-pagination", + "tv-series-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'crime', - 'crime-pagination', - 'crime-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` + "crime", + "crime-pagination", + "crime-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'classic', - 'classic-pagination', - 'classic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` + "classic", + "classic-pagination", + "classic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, ); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + document + .getElementById("googleSignInBtn") + .addEventListener("click", handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; } -document.addEventListener('DOMContentLoaded', () => { - const notificationBtn = document.getElementById('notificationBtn'); +document.addEventListener("DOMContentLoaded", () => { + const notificationBtn = document.getElementById("notificationBtn"); - notificationBtn.addEventListener('click', () => { - window.location.href = 'MovieVerse-Frontend/html/notifications.html'; + notificationBtn.addEventListener("click", () => { + window.location.href = "MovieVerse-Frontend/html/notifications.html"; }); }); diff --git a/MovieVerse-Mobile/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist b/MovieVerse-Mobile/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist index abace984..2c8b6bbd 100644 --- a/MovieVerse-Mobile/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/MovieVerse-Mobile/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ Cordova.xcscheme_^#shared#^_ orderHint - 3 + 2 CordovaLib.xcscheme_^#shared#^_ orderHint - 2 + 3 diff --git a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj index 83d34d28..cf58da16 100644 --- a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj +++ b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.pbxproj @@ -10,14 +10,14 @@ 0207DA581B56EA530066E2B4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0207DA571B56EA530066E2B4 /* Assets.xcassets */; }; 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* AppDelegate.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; + 27A2DEACD9D94F98B1247AD4 /* CDVStatusBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 07138ADA063247E8BF47E9A8 /* CDVStatusBar.m */; }; 301BF552109A68D80062928A /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF535109A57CC0062928A /* libCordova.a */; settings = {ATTRIBUTES = (Required, ); }; }; 302D95F114D2391D003F00A1 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 302D95EF14D2391D003F00A1 /* MainViewController.m */; }; 302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 302D95F014D2391D003F00A1 /* MainViewController.xib */; }; 4E7CA2B6272ABB0D00177EF9 /* config.xml in Copy Staging Resources */ = {isa = PBXBuildFile; fileRef = F840E1F0165FE0F500CFE078 /* config.xml */; }; 4E7CA2B7272ABB0D00177EF9 /* www in Copy Staging Resources */ = {isa = PBXBuildFile; fileRef = 301BF56E109A69640062928A /* www */; }; 6AFF5BF91D6E424B00AB3073 /* CDVLaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */; }; - 7EDF4474DC664F60982A9C91 /* CDVStatusBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 348F1B3BF7A741D2A1FABE94 /* CDVStatusBar.m */; }; - FAB2CA4BF32FAD80281BD54C /* libPods-MovieVerse.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AFFCB7BDACFE8795BCE49B8 /* libPods-MovieVerse.a */; }; + FEBDFCEB9B237EF1821566EB /* libPods-MovieVerse.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 30D9EECC9AF3AF27EEE2A5AB /* libPods-MovieVerse.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,14 +60,13 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 00587CF35A37E059FDF56BCB /* Pods-MovieVerse.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.debug.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.debug.xcconfig"; sourceTree = ""; }; 0207DA571B56EA530066E2B4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 061897145ED0469594427BC2 /* CDVStatusBar.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVStatusBar.h; path = "cordova-plugin-statusbar/CDVStatusBar.h"; sourceTree = ""; }; + 07138ADA063247E8BF47E9A8 /* CDVStatusBar.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVStatusBar.m; path = "cordova-plugin-statusbar/CDVStatusBar.m"; sourceTree = ""; }; 1D3623240D0F684500981E51 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 1D3623250D0F684500981E51 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 1D6058910D05DD3D006BFB54 /* MovieVerse.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MovieVerse.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 244D96C9BB72428F90309DA5 /* CDVStatusBar.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVStatusBar.h; path = "cordova-plugin-statusbar/CDVStatusBar.h"; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 2AFFCB7BDACFE8795BCE49B8 /* libPods-MovieVerse.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MovieVerse.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = ""; }; 301BF56E109A69640062928A /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = SOURCE_ROOT; }; 302D95EE14D2391D003F00A1 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; @@ -76,15 +75,16 @@ 3047A50F1AB8059700498E2A /* build-debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "build-debug.xcconfig"; path = "cordova/build-debug.xcconfig"; sourceTree = SOURCE_ROOT; }; 3047A5101AB8059700498E2A /* build-release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "build-release.xcconfig"; path = "cordova/build-release.xcconfig"; sourceTree = SOURCE_ROOT; }; 3047A5111AB8059700498E2A /* build.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = build.xcconfig; path = cordova/build.xcconfig; sourceTree = SOURCE_ROOT; }; + 30D9EECC9AF3AF27EEE2A5AB /* libPods-MovieVerse.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MovieVerse.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 32CA4F630368D1EE00C91783 /* MovieVerse-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MovieVerse-Prefix.pch"; sourceTree = ""; }; - 348F1B3BF7A741D2A1FABE94 /* CDVStatusBar.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVStatusBar.m; path = "cordova-plugin-statusbar/CDVStatusBar.m"; sourceTree = ""; }; 6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = CDVLaunchScreen.storyboard; sourceTree = ""; }; + 7DCF64699203705E500290F3 /* Pods-MovieVerse.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.debug.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.debug.xcconfig"; sourceTree = ""; }; 8D1107310486CEB800E47090 /* MovieVerse-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MovieVerse-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; EB87FDF31871DA8E0020F90C /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; name = www; path = ../../www; sourceTree = ""; }; EB87FDF41871DAF40020F90C /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = ../../config.xml; sourceTree = ""; }; ED33DF2A687741AEAF9F8254 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; - F1B3F6EBC86DD063E443E536 /* Pods-MovieVerse.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.release.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.release.xcconfig"; sourceTree = ""; }; F840E1F0165FE0F500CFE078 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = MovieVerse/config.xml; sourceTree = ""; }; + F87681A4CF4C2D098636680F /* Pods-MovieVerse.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieVerse.release.xcconfig"; path = "Target Support Files/Pods-MovieVerse/Pods-MovieVerse.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -93,7 +93,7 @@ buildActionMask = 2147483647; files = ( 301BF552109A68D80062928A /* libCordova.a in Frameworks */, - FAB2CA4BF32FAD80281BD54C /* libPods-MovieVerse.a in Frameworks */, + FEBDFCEB9B237EF1821566EB /* libPods-MovieVerse.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -121,7 +121,7 @@ 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, - C1791719849883EAA89C12E5 /* Pods */, + AAB3B044EE8E899C2A7D1691 /* Pods */, ); name = CustomTemplate; sourceTree = ""; @@ -155,7 +155,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( - 2AFFCB7BDACFE8795BCE49B8 /* libPods-MovieVerse.a */, + 30D9EECC9AF3AF27EEE2A5AB /* libPods-MovieVerse.a */, ); name = Frameworks; sourceTree = ""; @@ -182,18 +182,18 @@ 307C750510C5A3420062BCA9 /* Plugins */ = { isa = PBXGroup; children = ( - 348F1B3BF7A741D2A1FABE94 /* CDVStatusBar.m */, - 061897145ED0469594427BC2 /* CDVStatusBar.h */, + 07138ADA063247E8BF47E9A8 /* CDVStatusBar.m */, + 244D96C9BB72428F90309DA5 /* CDVStatusBar.h */, ); name = Plugins; path = MovieVerse/Plugins; sourceTree = SOURCE_ROOT; }; - C1791719849883EAA89C12E5 /* Pods */ = { + AAB3B044EE8E899C2A7D1691 /* Pods */ = { isa = PBXGroup; children = ( - 00587CF35A37E059FDF56BCB /* Pods-MovieVerse.debug.xcconfig */, - F1B3F6EBC86DD063E443E536 /* Pods-MovieVerse.release.xcconfig */, + 7DCF64699203705E500290F3 /* Pods-MovieVerse.debug.xcconfig */, + F87681A4CF4C2D098636680F /* Pods-MovieVerse.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -214,7 +214,7 @@ isa = PBXNativeTarget; buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MovieVerse" */; buildPhases = ( - 4CB5EA24819FB654057E26C5 /* [CP] Check Pods Manifest.lock */, + AB60C0609D77CBC9E2C84F12 /* [CP] Check Pods Manifest.lock */, 857339E32710CC9700A1C74C /* Copy Staging Resources */, 1D60588D0D05DD3D006BFB54 /* Resources */, 1D60588E0D05DD3D006BFB54 /* Sources */, @@ -298,7 +298,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 4CB5EA24819FB654057E26C5 /* [CP] Check Pods Manifest.lock */ = { + AB60C0609D77CBC9E2C84F12 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -330,7 +330,7 @@ 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */, 302D95F114D2391D003F00A1 /* MainViewController.m in Sources */, - 7EDF4474DC664F60982A9C91 /* CDVStatusBar.m in Sources */, + 27A2DEACD9D94F98B1247AD4 /* CDVStatusBar.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -353,7 +353,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; diff --git a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate index f74e8182..448f8886 100644 Binary files a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate and b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/MovieVerse-Mobile/platforms/ios/Pods/Pods.xcodeproj/project.pbxproj b/MovieVerse-Mobile/platforms/ios/Pods/Pods.xcodeproj/project.pbxproj index 08e7c66f..d906a9a0 100644 --- a/MovieVerse-Mobile/platforms/ios/Pods/Pods.xcodeproj/project.pbxproj +++ b/MovieVerse-Mobile/platforms/ios/Pods/Pods.xcodeproj/project.pbxproj @@ -125,6 +125,7 @@ en, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; + minimizedProjectReferenceProxies = 0; productRefGroup = C31A5A0C8077DD46B78807811092B45E /* Products */; projectDirPath = ""; projectRoot = ""; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/README.md b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/README.md index 1a216e41..0fcbf3e5 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/README.md +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/README.md @@ -158,7 +158,7 @@ Contributions to MovieVerse are always welcome. Whether it's bug reports, featur ## License -This project is licensed under MIT license. Refer to the `LICENSE` file in each subdirectory for more information. +This project is licensed under CC BY-NC 4.0 license. Refer to the [LICENSE](LICENSE.md) file for more information. --- diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js index 44af428a..d3841f0a 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-timeline.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-timeline.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/search.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/search.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/about.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/about.js new file mode 100644 index 00000000..916bbac0 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/about.js @@ -0,0 +1,336 @@ +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/actor-details.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/actor-details.js new file mode 100644 index 00000000..b3d7fe24 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/actor-details.js @@ -0,0 +1,824 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +let initialMainContent = ''; + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + currentIndex = 0; + + const actorId = localStorage.getItem('selectedActorId'); + if (actorId) { + fetchActorDetails(actorId); + } else { + fetchActorDetails(2037); + } +}); + +async function fetchActorDetails(actorId) { + showSpinner(); + const actorUrl = `https://${getMovieVerseData()}/3/person/${actorId}?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/${actorId}/movie_credits?${generateMovieNames()}${getMovieCode()}`; + + try { + const [actorResponse, creditsResponse] = await Promise.all([fetch(actorUrl), fetch(creditsUrl)]); + + const actor = await actorResponse.json(); + const credits = await creditsResponse.json(); + if (actor.success === false) { + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details currently unavailable - please try again

+
`; + } else { + updateBrowserURL(actor.name); + populateActorDetails(actor, credits); + } + hideSpinner(); + } catch (error) { + console.log('Error fetching actor details:', error); + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details currently unavailable - please try again

+
`; + hideSpinner(); + } +} + +async function populateActorDetails(actor, credits) { + const actorImage = document.getElementById('actor-image'); + const actorName = document.getElementById('actor-name'); + const actorDescription = document.getElementById('actor-description'); + + if (actor.profile_path) { + actorImage.src = `https://image.tmdb.org/t/p/w1280${actor.profile_path}`; + actorName.textContent = actor.name; + document.title = `${actor.name} - Actor's Details`; + } else { + actorImage.style.display = 'none'; + actorName.textContent = actor.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.actor-left').appendChild(noImageText); + } + + let ageOrStatus; + if (actor.birthday) { + if (actor.deathday) { + ageOrStatus = calculateAge(actor.birthday, actor.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(actor.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + actorDescription.innerHTML = ` +

Biography: ${actor.biography || 'Information Unavailable'}

+

Also Known As: ${actor.also_known_as.join(', ') || 'Information Unavailable'}

+

Date of Birth: ${actor.birthday || 'Information Unavailable'}

+

Date of Death: ${actor.deathday || 'Information Unavailable'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${actor.place_of_birth || 'Information Unavailable'}

+

Known For: ${actor.known_for_department || 'Information Unavailable'}

+

Height: ${actor.height || 'Information Unavailable'}

+ `; + + const gender = document.createElement('div'); + gender.innerHTML = `

Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'Information Unavailable'}

`; + actorDescription.appendChild(gender); + + const popularity = document.createElement('div'); + popularity.innerHTML = `

Popularity Score: ${actor.popularity.toFixed(2)}

`; + actorDescription.appendChild(popularity); + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + actorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + movieList.style.display = 'flex'; + movieList.style.flexWrap = 'wrap'; + movieList.style.justifyContent = 'center'; + movieList.style.gap = '5px'; + + let filmsToDisplay = credits.cast; + filmsToDisplay = filmsToDisplay.sort((a, b) => b.popularity - a.popularity); + + filmsToDisplay.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + movieList.appendChild(movieLink); + + if (index < credits.cast.length - 1) { + movieList.appendChild(document.createTextNode('')); + } + }); + + filmographyHeading.appendChild(movieList); + + const mediaUrl = `https://${getMovieVerseData()}/3/person/${actor.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + const detailsContainer = document.getElementById('actor-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + const imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + applySettings(); +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +function calculateAge(birthday, deathday = null) { + const birthDate = new Date(birthday); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const diff = referenceDate - birthDate.getTime(); + const ageDate = new Date(diff); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + applySettings(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/add-to-favorites.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/add-to-favorites.js new file mode 100644 index 00000000..eae22b78 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/add-to-favorites.js @@ -0,0 +1,252 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + query, + where, + getDocs, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function checkAndUpdateFavoriteButton() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const movieId = localStorage.getItem('selectedMovieId'); + + if (!movieId) { + console.log('Movie ID is missing'); + return; + } + + try { + if (!userEmail) { + console.log('User is not signed in. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + if (querySnapshot.empty) { + console.log('No user found with that email'); + return; + } + + const userData = querySnapshot.docs[0].data(); + const favorites = userData.favoritesMovies || []; + + updateFavoriteButton(movieId, favorites); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + } else { + console.error('An error occurred:', error); + } + } +} + +function updateFavoriteButton(movieId, favorites) { + const favoriteButton = document.getElementById('favorite-btn'); + + if (favorites.includes(movieId)) { + favoriteButton.classList.add('favorited'); + favoriteButton.style.backgroundColor = 'grey'; + favoriteButton.title = 'Remove from favorites'; + } else { + favoriteButton.classList.remove('favorited'); + favoriteButton.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + favoriteButton.title = 'Add to favorites'; + } +} + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +async function getMovieGenre(movieId) { + const tmdbUrl = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(tmdbUrl); + const movieData = await response.json(); + return movieData.genres.length > 0 ? movieData.genres[0].name : 'Unknown'; +} + +export async function toggleFavorite() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const movieId = localStorage.getItem('selectedMovieId'); + + if (!movieId) { + console.log('Movie ID is missing'); + return; + } + + const movieGenre = await getMovieGenre(movieId); + + try { + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + let userDocRef; + + if (querySnapshot.empty && userEmail === '') { + const newUserRef = doc(collection(db, 'MovieVerseUsers')); + userDocRef = newUserRef; + await setDoc(newUserRef, { + email: userEmail, + favoritesMovies: [movieId], + }); + console.log('New user created with favorite movie.'); + } else if (!querySnapshot.empty) { + userDocRef = doc(db, 'MovieVerseUsers', querySnapshot.docs[0].id); + } else { + console.log('No user found with that email and user is supposed to be signed in.'); + return; + } + + if (userDocRef) { + const userData = querySnapshot.empty ? { favoritesMovies: [] } : querySnapshot.docs[0].data(); + let favoritesMovies = userData.favoritesMovies || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + await updateDoc(userDocRef, { favoritesMovies }); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in Firestore'); + } + + updateMoviesFavorited(movieId); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; + } else { + console.error('An error occurred:', error); + } + + updateMoviesFavorited(movieId); + } + window.location.reload(); +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js new file mode 100644 index 00000000..704efa91 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js @@ -0,0 +1,169 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + query, + where, + getDocs, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function toggleFavoriteTVSeries() { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } + + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + await checkAndUpdateFavoriteButtonTVSeries(); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + let userDocRef; + if (querySnapshot.empty) { + console.log('Signed-in user does not have a Firestore document.'); + return; + } else { + userDocRef = doc(db, 'MovieVerseUsers', querySnapshot.docs[0].id); + } + + const userData = querySnapshot.docs[0].data(); + let favoritesTVSeries = userData.favoritesTVSeries || []; + + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + + await updateDoc(userDocRef, { favoritesTVSeries }); + console.log('Favorites TV Series updated successfully in Firestore'); + await checkAndUpdateFavoriteButtonTVSeries(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + } else { + console.error('An error occurred:', error); + } + window.location.reload(); + } +} + +export async function checkAndUpdateFavoriteButtonTVSeries() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } + + let favoritesTVSeries = []; + + if (userEmail) { + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + if (!querySnapshot.empty) { + const userData = querySnapshot.docs[0].data(); + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); + } else { + console.error('An error occurred:', error); + } + } +} + +function updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries) { + const favoriteBtn = document.getElementById('favorite-btn'); + + if (favoritesTVSeries.includes(tvSeriesId)) { + favoriteBtn.classList.add('favorited'); + favoriteBtn.title = 'Remove from Favorites'; + favoriteBtn.style.backgroundColor = 'grey'; + } else { + favoriteBtn.classList.remove('favorited'); + favoriteBtn.title = 'Add to Favorites'; + favoriteBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + } +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/analytics.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/analytics.js new file mode 100644 index 00000000..f8e4b2dd --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/analytics.js @@ -0,0 +1,867 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const string = `${getMovieCode()}`; + +async function fetchData(url) { + try { + const response = await fetch(url); + return await response.json(); + } catch (error) { + console.log('Error fetching data:', error); + return null; + } +} + +function createChart(canvasId, chartType, data, options = {}) { + const ctx = document.getElementById(canvasId).getContext('2d'); + new Chart(ctx, { + type: chartType, + data: data, + options: options, + }); +} + +async function loadMoviesByYearChart() { + showSpinner(); + const years = []; + const movieCounts = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + movieCounts.push(response.total_results); + } + + createChart('chart1', 'line', { + labels: years, + datasets: [ + { + label: 'Number of Movies Released', + data: movieCounts, + backgroundColor: 'rgba(0,148,255,1)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadGenrePopularityChart() { + showSpinner(); + const genresResponse = await fetchData(`${BASE_URL}/genre/movie/list?${generateMovieNames()}=${string}`); + const genres = genresResponse.genres; + + const genreNames = []; + const genrePopularity = []; + + for (const genre of genres) { + genreNames.push(genre.name); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_genres=${genre.id}`); + genrePopularity.push(response.results.reduce((acc, movie) => acc + movie.popularity, 0) / response.results.length); + } + + createChart('chart2', 'bar', { + labels: genreNames, + datasets: [ + { + label: 'Average Popularity', + data: genrePopularity, + backgroundColor: 'rgba(255, 99, 132, 1)', + borderColor: 'rgba(255, 99, 132, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMoviesByCertificationChart() { + showSpinner(); + const certifications = ['G', 'PG', 'PG-13', 'R']; + const movieCounts = []; + + for (const certification of certifications) { + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&certification_country=US&certification=${certification}` + ); + movieCounts.push(response.total_results); + } + + createChart('chart3', 'bar', { + labels: certifications, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(75, 192, 192, 1)', + borderColor: 'rgba(75, 192, 192, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadAveragePopularityChart() { + showSpinner(); + const years = []; + const averagePopularity = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 4; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + const totalPopularity = response.results.reduce((sum, movie) => sum + movie.popularity, 0); + averagePopularity.push(totalPopularity / response.results.length); + } + + createChart('chart4', 'line', { + labels: years, + datasets: [ + { + label: 'Average Popularity', + data: averagePopularity, + backgroundColor: 'rgba(255, 159, 64, 1)', + borderColor: 'rgba(255, 159, 64, 1)', + borderWidth: 1, + }, + ], + }); + showSpinner(); +} + +Chart.defaults.color = 'black'; +Chart.defaults.scale.grid.borderColor = 'black'; + +async function loadMoviesByLanguageChart() { + showSpinner(); + const languages = ['en', 'es', 'fr', 'de', 'it']; + const movieCounts = []; + + for (const language of languages) { + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_original_language=${language}`); + movieCounts.push(response.total_results); + } + + createChart('chart5', 'bar', { + labels: languages.map(lang => lang.toUpperCase()), + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(153, 102, 255, 1)', + borderColor: 'rgba(153, 102, 255, 1)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + }, + }); + + hideSpinner(); +} + +async function loadVoteCountByGenreChart() { + showSpinner(); + const genreResponse = await fetchData(`${BASE_URL}/genre/movie/list?${generateMovieNames()}=${string}`); + const genres = genreResponse.genres.slice(0, 5); + const genreNames = []; + const averageVoteCounts = []; + + for (const genre of genres) { + genreNames.push(genre.name); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_genres=${genre.id}`); + const totalVotes = response.results.reduce((sum, movie) => sum + movie.vote_count, 0); + averageVoteCounts.push(totalVotes / response.results.length); + } + + createChart('chart6', 'bar', { + labels: genreNames, + datasets: [ + { + label: 'Average Vote Count', + data: averageVoteCounts, + backgroundColor: 'rgba(255, 206, 86, 1)', + borderColor: 'rgba(255, 206, 86, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMovieReleaseDatesByMonthChart() { + showSpinner(); + const months = Array.from({ length: 12 }, (_, i) => new Date(0, i).toLocaleString('en', { month: 'long' })); + const movieCounts = Array(12).fill(0); + const currentYear = new Date().getFullYear(); + + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${currentYear}`); + response.results.forEach(movie => { + const releaseDate = new Date(movie.release_date); + movieCounts[releaseDate.getMonth()]++; + }); + + createChart('chart7', 'bar', { + labels: months, + datasets: [ + { + label: 'Movies Released', + data: movieCounts, + backgroundColor: 'rgba(123, 239, 178, 1)', + borderColor: 'rgba(123, 239, 178, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMoviesByDecadeChart() { + showSpinner(); + const decades = ['1980s', '1990s', '2000s', '2010s', '2020s']; + const decadeStartYears = [1980, 1990, 2000, 2010, 2020]; + const movieCounts = []; + + for (const startYear of decadeStartYears) { + const endYear = startYear + 9; + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31` + ); + movieCounts.push(response.total_results); + } + + createChart('chart8', 'bar', { + labels: decades, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgb(255,0,0)', + borderColor: 'rgb(255,0,0)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + ticks: { + color: 'black', + }, + }, + y: { + ticks: { + color: 'black', + }, + }, + }, + plugins: { + legend: { + position: 'right', + labels: { + color: 'black', + }, + }, + }, + }, + }); + + hideSpinner(); +} + +async function loadMoviesByProductionCountriesChart() { + showSpinner(); + const countries = ['US', 'GB', 'CA', 'FR', 'DE']; + const countryNames = ['USA', 'UK', 'Canada', 'France', 'Germany']; + const movieCounts = []; + + for (const country of countries) { + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_original_language=en®ion=${country}`); + movieCounts.push(response.total_results); + } + + createChart('chart9', 'bar', { + labels: countryNames, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(0,32,255,0.75)', + borderColor: 'rgb(0,21,255)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + ticks: { + color: 'black', + }, + }, + y: { + ticks: { + color: 'black', + }, + }, + }, + plugins: { + legend: { + position: 'right', + labels: { + color: 'black', + }, + }, + }, + }, + }); + + hideSpinner(); +} + +async function loadTopRatedMoviesPerYearChart() { + const years = []; + const topMovies = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&sort_by=vote_average.desc&vote_count.gte=100` + ); + if (response.results.length > 0) { + topMovies.push(response.results[0].vote_average); + } else { + topMovies.push(0); + } + } + + createChart('chart11', 'bar', { + labels: years, + datasets: [ + { + label: 'Top Rated Movie Score', + data: topMovies, + backgroundColor: 'rgba(255, 159, 64, 1)', + borderColor: 'rgba(255, 159, 64, 1)', + borderWidth: 1, + }, + ], + }); +} + +async function loadTotalMovieVotesOverYearsChart() { + const years = []; + const totalVoteCounts = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + const yearlyTotalVotes = response.results.reduce((sum, movie) => sum + movie.vote_count, 0); + totalVoteCounts.push(yearlyTotalVotes); + } + + createChart('chartVotesOverYears', 'line', { + labels: years, + datasets: [ + { + label: 'Total Movie Votes', + data: totalVoteCounts, + backgroundColor: 'rgba(255, 193, 7, 1)', + borderColor: 'rgba(255, 193, 7, 1)', + borderWidth: 1, + }, + ], + }); +} + +async function loadHighlyRatedMoviesOverYearsChart() { + const years = []; + const highRatedMovieCounts = []; + const currentYear = new Date().getFullYear(); + const startYear = currentYear - 10; + + for (let year = startYear; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&vote_average.gte=8`); + highRatedMovieCounts.push(response.total_results); + } + + createChart('chartHighlyRatedMovies', 'line', { + labels: years, + datasets: [ + { + label: 'Highly Rated Movies (Rating >= 8)', + data: highRatedMovieCounts, + backgroundColor: 'rgba(0, 206, 209, 1)', + borderColor: 'rgba(0, 206, 209, 1)', + borderWidth: 1, + }, + ], + }); +} + +function loadAllCharts() { + showSpinner(); + loadMoviesByYearChart(); + loadGenrePopularityChart(); + loadMoviesByCertificationChart(); + loadAveragePopularityChart(); + loadMoviesByLanguageChart(); + loadVoteCountByGenreChart(); + loadMovieReleaseDatesByMonthChart(); + loadMoviesByDecadeChart(); + loadMoviesByProductionCountriesChart(); + loadTopRatedMoviesPerYearChart(); + loadTotalMovieVotesOverYearsChart(); + loadHighlyRatedMoviesOverYearsChart(); + hideSpinner(); +} + +document.addEventListener('DOMContentLoaded', loadAllCharts); + +const BASE_URL = `https://${getMovieVerseData()}/3`; + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}=${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.png'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +document.getElementById('chart-title1').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title1').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title2').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title3').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title4').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title4').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title5').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title5').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title6').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title6').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title7').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title7').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title8').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title8').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title9').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title9').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title11').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title11').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title10').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title10').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title12').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title12').scrollIntoView({ behavior: 'smooth' }); +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chat-auxiliary.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chat-auxiliary.js new file mode 100644 index 00000000..165d6e5b --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chat-auxiliary.js @@ -0,0 +1,268 @@ +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chat.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chat.js new file mode 100644 index 00000000..b3a0da63 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chat.js @@ -0,0 +1,496 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + collection, + addDoc, + doc, + startAfter, + getDocs, + query, + where, + orderBy, + onSnapshot, + documentId, + serverTimestamp, + limit, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +document.addEventListener('DOMContentLoaded', () => { + const mainElement = document.getElementById('main'); + const isLoggedIn = localStorage.getItem('isSignedIn'); + + if (!isLoggedIn || isLoggedIn !== 'true') { + mainElement.style.display = 'none'; + + const signInMessage = document.createElement('div'); + signInMessage.innerHTML = '

You must be signed in to access MovieVerse chat services.

'; + signInMessage.style.display = 'flex'; + signInMessage.style.justifyContent = 'center'; + signInMessage.style.alignItems = 'center'; + signInMessage.style.height = '100vh'; + signInMessage.style.borderRadius = '12px'; + signInMessage.style.margin = '10px auto'; + signInMessage.style.marginRight = '20px'; + signInMessage.style.marginLeft = '20px'; + signInMessage.style.marginBottom = '20px'; + signInMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'; + document.getElementById('footer').style.display = 'none'; + + const adContainer2 = document.getElementById('ad-container2'); + if (adContainer2) { + document.body.insertBefore(signInMessage, adContainer2); + } else { + document.body.appendChild(signInMessage); + } + } else { + mainElement.style.display = ''; + loadUserList(); + setupSearchListeners(); + } +}); + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +initializeApp(firebaseConfig); +const db = getFirestore(); + +const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); +let selectedUserEmail = null; + +const messagesDiv = document.getElementById('messages'); +const userListDiv = document.getElementById('userList'); +const messageInput = document.getElementById('messageInput'); +const sendButton = document.getElementById('sendButton'); + +sendButton.addEventListener('click', async () => { + const text = messageInput.value.trim(); + if (text && selectedUserEmail) { + try { + await addDoc(collection(db, 'messages'), { + sender: currentUserEmail, + recipient: selectedUserEmail, + message: text, + timestamp: serverTimestamp(), + readBy: [currentUserEmail], + }); + messageInput.value = ''; + + const userElement = document.querySelector(`.user[data-email="${selectedUserEmail}"]`); + + if (!userElement) { + const newUserElement = await createUserElement(selectedUserEmail); + userListDiv.prepend(newUserElement); + selectUser(newUserElement); + } else { + userListDiv.prepend(userElement); + selectUser(userElement); + } + } catch (error) { + console.error('Error adding message: ', error); + } + } +}); + +async function createUserElement(email) { + const userElement = document.createElement('div'); + userElement.classList.add('user'); + userElement.setAttribute('data-email', email); + userElement.addEventListener('click', () => loadMessages(email)); + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '50px'; + img.style.borderRadius = '25px'; + img.style.marginRight = '10px'; + userElement.appendChild(img); + + const emailDiv = document.createElement('div'); + emailDiv.textContent = email; + userElement.appendChild(emailDiv); + + return userElement; +} + +function selectUser(userElement) { + if (previouslySelectedUserElement) { + previouslySelectedUserElement.classList.remove('selected'); + previouslySelectedUserElement.style.backgroundColor = ''; + } + userElement.classList.add('selected'); + userElement.style.backgroundColor = '#ff8623'; + previouslySelectedUserElement = userElement; +} + +document.getElementById('messageInput').addEventListener('keydown', function (event) { + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault(); + sendButton.click(); + } +}); + +function formatMessage(message, isCurrentUser, timestamp) { + const messageElement = document.createElement('div'); + messageElement.classList.add('message'); + messageElement.textContent = isCurrentUser ? `You: ${message}` : `${selectedUserEmail}: ${message}`; + + if (timestamp && timestamp.toDate) { + messageElement.dataset.timestamp = timestamp.toDate().toISOString(); + } else { + console.log('Timestamp is not in the expected format:', timestamp); + messageElement.dataset.timestamp = 'Unknown time'; + } + + messageElement.classList.add(isCurrentUser ? 'my-message' : 'other-message'); + messageElement.addEventListener('mouseover', showTooltip); + messageElement.addEventListener('click', showTooltip); + + return messageElement; +} + +function showTooltip(event) { + const messageElement = event.target.closest('.message'); + const timestampString = messageElement.dataset.timestamp; + + const date = new Date(timestampString); + const tooltipText = isNaN(date.getTime()) + ? 'Unknown time' + : date.toLocaleString('default', { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + }); + + const tooltip = document.createElement('div'); + tooltip.className = 'tooltip'; + tooltip.textContent = tooltipText; + document.body.appendChild(tooltip); + + const rect = messageElement.getBoundingClientRect(); + const tooltipRect = tooltip.getBoundingClientRect(); + + const leftPosition = rect.left + rect.width / 2 - tooltipRect.width / 2; + tooltip.style.position = 'fixed'; + tooltip.style.top = `${rect.top - tooltipRect.height - 5}px`; + tooltip.style.left = `${Math.max(leftPosition, 0) - 12}px`; + + function removeTooltip() { + tooltip.remove(); + } + messageElement.addEventListener('mouseout', removeTooltip); + setTimeout(removeTooltip, 5000); +} + +const chatSection = document.getElementById('chatSection'); +const noUserSelected = document.getElementById('noUserSelected'); + +chatSection.style.display = 'none'; +noUserSelected.style.display = 'flex'; + +async function loadMessages(userEmail) { + selectedUserEmail = userEmail; + messagesDiv.innerHTML = ''; + + chatSection.style.display = 'flex'; + noUserSelected.style.display = 'none'; + + const userEmailDisplay = document.getElementById('userEmailDisplay'); + if (userEmailDisplay) { + userEmailDisplay.textContent = `Chatting with: ${selectedUserEmail}`; + } + + document.querySelectorAll('.user').forEach(user => user.classList.remove('selected')); + const selectedUser = document.querySelector(`.user[data-email="${selectedUserEmail}"]`); + if (selectedUser) { + selectedUser.classList.add('selected'); + } + + const messagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp'), + where('sender', 'in', [currentUserEmail, selectedUserEmail]), + where('recipient', 'in', [currentUserEmail, selectedUserEmail]) + ); + + onSnapshot(messagesQuery, snapshot => { + messagesDiv.innerHTML = ''; + snapshot.docs.forEach(doc => { + const messageData = doc.data(); + const isCurrentUser = messageData.sender === currentUserEmail; + const timestamp = messageData.timestamp; + const messageElement = formatMessage(messageData.message, isCurrentUser, timestamp); + messagesDiv.appendChild(messageElement); + + if (!isCurrentUser && (!messageData.readBy || !messageData.readBy.includes(currentUserEmail))) { + updateReadStatus(doc.id); + } + }); + + messagesDiv.scrollTop = messagesDiv.scrollHeight; + }); +} + +async function updateReadStatus(messageId) { + const messageRef = doc(db, 'messages', messageId); + await updateDoc(messageRef, { + readBy: arrayUnion(currentUserEmail), + }); +} + +let searchDebounceTimeout; +let lastVisible = null; +const initialFetchLimit = 5; +const maxTotalFetch = 20; + +function setupSearchListeners() { + const searchUserInput = document.getElementById('searchUserInput'); + const searchUserResults = document.getElementById('searchUserResults'); + + searchUserInput.addEventListener('input', () => { + clearTimeout(searchDebounceTimeout); + const searchText = searchUserInput.value.trim(); + + if (searchText) { + searchDebounceTimeout = setTimeout(() => { + lastVisible = null; + performSearch(searchText, true); + }, 300); + } else { + searchUserResults.innerHTML = ''; + searchUserResults.style.display = 'none'; + } + }); +} + +async function performSearch(searchText, isNewSearch = false) { + const searchUserResults = document.getElementById('searchUserResults'); + + try { + showSpinner(); + animateLoadingDots(); + + let userQuery = query( + collection(db, 'MovieVerseUsers'), + where('email', '>=', searchText), + where('email', '<=', searchText + '\uf8ff'), + orderBy('email'), + limit(initialFetchLimit) + ); + + if (!isNewSearch && lastVisible) { + userQuery = query(userQuery, startAfter(lastVisible)); + } + + const querySnapshot = await getDocs(userQuery); + + if (isNewSearch) { + searchUserResults.innerHTML = ''; + } + + if (!querySnapshot.empty) { + lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; + } + + for (const doc of querySnapshot.docs) { + const user = doc.data(); + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadMessages(user.email)); + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.email}

${user.bio || ''}

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + } + + searchUserResults.style.display = 'block'; + hideSpinner(); + + if (isNewSearch || (!querySnapshot.empty && querySnapshot.size === initialFetchLimit)) { + const loadMoreButton = document.createElement('button'); + loadMoreButton.textContent = 'Load More'; + loadMoreButton.id = 'loadMoreButton'; + loadMoreButton.style.marginBottom = '20px'; + loadMoreButton.addEventListener('click', () => performSearch(searchText)); + searchUserResults.appendChild(loadMoreButton); + + if (searchUserResults.children.length >= maxTotalFetch) { + loadMoreButton.style.display = 'none'; + } + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.margin = '25px auto'; + } + hideSpinner(); + } + } +} + +let previouslySelectedUserElement = null; + +async function loadUserList() { + try { + showSpinner(); + animateLoadingDots(); + + const userLimit = 5; + const messageLimit = 30; + + const sentMessagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp', 'desc'), + where('sender', '==', currentUserEmail), + limit(messageLimit) + ); + const receivedMessagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp', 'desc'), + where('recipient', '==', currentUserEmail), + limit(messageLimit) + ); + + const [sentMessagesSnapshot, receivedMessagesSnapshot] = await Promise.all([getDocs(sentMessagesQuery), getDocs(receivedMessagesQuery)]); + + let userEmails = new Set(); + sentMessagesSnapshot.forEach(doc => userEmails.add(doc.data().recipient)); + receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); + + let users = []; + for (let email of userEmails) { + if (email) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + let userData = doc.data(); + if (userData.email) { + users.push(userData); + } + }); + } + } + + users.sort((a, b) => { + const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( + doc => doc.data().sender === a.email || doc.data().recipient === a.email + ); + const bLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( + doc => doc.data().sender === b.email || doc.data().recipient === b.email + ); + return (bLastMessage?.data().timestamp.toDate() || 0) - (aLastMessage?.data().timestamp.toDate() || 0); + }); + + users = users.slice(0, userLimit); + + userListDiv.innerHTML = ''; + for (const user of users) { + const userElement = document.createElement('div'); + userElement.classList.add('user'); + userElement.setAttribute('data-email', user.email); + userElement.onclick = () => { + if (previouslySelectedUserElement) { + previouslySelectedUserElement.classList.remove('selected'); + previouslySelectedUserElement.style.backgroundColor = ''; + } + selectedUserEmail = user.email; + loadMessages(user.email); + document.querySelectorAll('.user').forEach(u => u.classList.remove('selected')); + userElement.classList.add('selected'); + userElement.style.backgroundColor = '#ff8623'; + previouslySelectedUserElement = userElement; + }; + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '50px'; + img.style.borderRadius = '25px'; + img.style.marginRight = '10px'; + userElement.appendChild(img); + + const emailDiv = document.createElement('div'); + emailDiv.textContent = user.email; + userElement.appendChild(emailDiv); + + userListDiv.appendChild(userElement); + } + + hideSpinner(); + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + } + hideSpinner(); + } + } +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chatbot.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chatbot.js new file mode 100644 index 00000000..db8687e8 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/chatbot.js @@ -0,0 +1,501 @@ +import { GoogleGenerativeAI, HarmBlockThreshold, HarmCategory } from '@google/generative-ai'; + +const chatbotBody = document.getElementById('chatbotBody'); +const movieee = `https://${getMovieVerseData()}/3`; + +let initialMainContent; +let conversationHistory = []; + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +document.addEventListener('DOMContentLoaded', function () { + initialMainContent = document.getElementById('main').innerHTML; + initializeChatbot(); + document.getElementById('clear-search-btn').style.display = 'none'; +}); + +const searchTitle = document.getElementById('search-title'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function initializeChatbot() { + const chatbotInput = document.getElementById('chatbotInput'); + sendInitialInstructions(); + chatbotInput.addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + sendMessage(chatbotInput.value); + chatbotInput.value = ''; + } + }); + + const sendButton = document.getElementById('sendButton'); + sendButton.addEventListener('click', function () { + sendMessage(chatbotInput.value); + chatbotInput.value = ''; + }); +} + +async function sendMessage(message) { + chatbotBody.innerHTML += `
You: ${message}
`; + const botReply = await movieVerseResponse(message); + setTimeout(() => { + chatbotBody.innerHTML += `
MovieVerse Assistant: ${botReply}
`; + scrollToBottom(); + }, 1000); + scrollToBottom(); +} + +function sendInitialInstructions() { + const initialMessage = ` +
+ MovieVerse Assistant: + + Welcome to MovieVerse Assistant 🍿! Here's how to get started: + +
+
    +
  • To quickly find the trailer of a movie, type "Show trailer for [movie name]".
  • +
  • You can also ask about genres, top-rated movies, latest movies, get a recommended movie, and any general questions!
  • +
  • 💡Tip: To get the best results, try to avoid phrasing requests like "Show trailer for ...", as they might trigger specific functions instead of a broader search.
  • +
+
How may I assist you today? 🎬🍿
+ `; + chatbotBody.innerHTML += `
${initialMessage}
`; + scrollToBottom(); +} + +function scrollToBottom() { + chatbotBody.scrollTop = chatbotBody.scrollHeight; +} + +document.getElementById('clear-search-btn').addEventListener('click', function () { + document.getElementById('main').innerHTML = initialMainContent; + initializeChatbot(); + searchTitle.innerHTML = ''; + this.style.display = 'none'; +}); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +async function fetchMovieTrailer(movieName) { + const searchUrl = SEARCHPATH + encodeURIComponent(movieName); + try { + const response = await fetch(searchUrl); + const data = await response.json(); + const movie = data.results[0]; + if (movie) { + const trailerUrl = await getTrailerUrl(movie.id); + if (trailerUrl) { + createTrailerButton(trailerUrl, movie.title); + } else { + chatbotBody.innerHTML += '
No trailer available for this movie.
'; + } + } else { + chatbotBody.innerHTML += '
Movie not found. Please try another search.
'; + } + } catch (error) { + console.log('Error fetching movie trailer:', error); + } +} + +async function getTrailerUrl(movieId) { + const trailerApiUrl = `https://${getMovieVerseData()}/3/movie/${movieId}/videos?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(trailerApiUrl); + const data = await response.json(); + const trailer = data.results.find(video => video.type === 'Trailer' && video.site === 'YouTube'); + return trailer ? `https://www.youtube.com/watch?v=${trailer.key}` : null; + } catch (error) { + console.log('Error fetching trailer:', error); + return null; + } +} + +function createTrailerButton(trailerUrl, movieTitle) { + const buttonId = 'trailerButton'; + chatbotBody.innerHTML += ` + + `; + chatbotBody.addEventListener('click', function (event) { + if (event.target && event.target.id === buttonId) { + window.open(trailerUrl, '_blank'); + } + }); +} + +async function movieVerseResponse(message) { + const lowerMessage = message.toLowerCase(); + + if (lowerMessage.startsWith('show trailer for ')) { + const movieName = lowerMessage.replace('show trailer for ', ''); + fetchMovieTrailer(movieName); + return `Searching for the trailer of "${movieName}". Please wait...`; + } + + if (lowerMessage.startsWith('hello') || lowerMessage.startsWith('hi') || lowerMessage.startsWith('hey')) { + return 'Hello! How can I assist you with MovieVerse today?'; + } else if (lowerMessage.startsWith('bye') || lowerMessage.startsWith('goodbye')) { + return 'Goodbye! Thank you for using MovieVerse Assistant and have a nice day!'; + } else { + showSpinner(); + animateLoadingDots(); + + let fullResponse = ''; + try { + const genAI = new GoogleGenerativeAI(getAIResponse()); + const model = genAI.getGenerativeModel({ + model: 'gemini-1.5-flash', + systemInstruction: + 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + }); + + conversationHistory.push({ role: 'user', parts: [{ text: message }] }); + + const chatSession = model.startChat({ + generationConfig: { + temperature: 1, + topP: 0.95, + topK: 64, + maxOutputTokens: 8192, + responseMimeType: 'text/plain', + }, + safetySettings: [ + { + category: HarmCategory.HARM_CATEGORY_HARASSMENT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + ], + history: conversationHistory, + }); + + const result = await chatSession.sendMessage(message); + fullResponse = result.response.text(); + conversationHistory.push({ + role: 'model', + parts: [{ text: fullResponse }], + }); + } catch (error) { + console.error('Error fetching response:', error.message); + fullResponse = + 'An error occurred while generating the response, possibly due to high traffic or safety concerns. Please understand that I am trained by MovieVerse to provide safe and helpful responses within my limitations. I apologize for any inconvenience caused. Please try again with a different query or contact MovieVerse support for further assistance.'; + } + + hideSpinner(); + return removeMarkdown(fullResponse); + } +} + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading response${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + +function removeMarkdown(text) { + const converter = new showdown.Converter(); + const html = converter.makeHtml(text); + + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = html; + return tempDiv.textContent || tempDiv.innerText || ''; +} + +function getAIResponse() { + const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + return atob(response); +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/christopher-nolan.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/christopher-nolan.js new file mode 100644 index 00000000..ddddd17a --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/christopher-nolan.js @@ -0,0 +1,488 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const searchTitle = document.getElementById('search-title'); + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function showMovies(movies) { + main.innerHTML = ''; + movies.forEach(movie => { + const { id, poster_path, title, vote_average, overview } = movie; + const movieE1 = document.createElement('div'); + const voteAverage = vote_average.toFixed(1); + movieE1.classList.add('movie'); + const movieImage = poster_path + ? `${title}` + : `
Image Not Available
`; + movieE1.innerHTML = ` + ${movieImage} +
+

${title}

+ ${voteAverage} +
+
+

Movie Overview:

+ ${overview} +
`; + movieE1.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); + window.location.href = 'movie-details.html'; + updateMovieVisitCount(id, title); + }); + main.appendChild(movieE1); + }); + applySettings(); +} + +function clearMovieDetails() { + const movieDetailsContainer = document.getElementById('director-details-container'); + if (movieDetailsContainer) { + movieDetailsContainer.innerHTML = ''; + } +} + +document.addEventListener('DOMContentLoaded', () => { + const directorId = '525'; + if (directorId) { + fetchDirectorDetails(directorId); + } else { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details not found.

+
`; + } +}); + +async function fetchDirectorDetails(directorId) { + const directorUrl = `https://${getMovieVerseData()}/3/person/525?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/525/movie_credits?${generateMovieNames()}${getMovieCode()}`; + try { + const [directorResponse, creditsResponse] = await Promise.all([fetch(directorUrl), fetch(creditsUrl)]); + + const director = await directorResponse.json(); + const credits = await creditsResponse.json(); + + if (director.success === false) { + document.getElementById('director-details-container').innerHTML = '

No Information is Available for this Director

'; + } else { + updateBrowserURL(director.name); + populateDirectorDetails(director, credits); + } + } catch (error) { + console.log('Error fetching director details:', error); + document.getElementById('director-details-container').innerHTML = '

Error fetching director details

'; + } +} + +function populateDirectorDetails(director, credits) { + const directorImage = document.getElementById('director-image'); + const directorName = document.getElementById('director-name'); + const directorDescription = document.getElementById('director-description'); + + if (director.profile_path) { + directorImage.src = `https://image.tmdb.org/t/p/w1280${director.profile_path}`; + directorName.textContent = director.name; + document.title = `${director.name} - Director's Details`; + } else { + directorImage.style.display = 'none'; + directorName.textContent = director.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.director-left').appendChild(noImageText); + } + + let ageOrStatus; + if (director.birthday) { + if (director.deathday) { + ageOrStatus = calculateAge(director.birthday, director.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(director.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + directorDescription.innerHTML = ` +

Biography: ${director.biography || 'N/A'}

+

Date of Birth: ${director.birthday || 'N/A'}

+

Date of Death: ${director.deathday || 'N/A'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${director.place_of_birth || 'N/A'}

+

Known For: Directing

+ `; + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + directorDescription.appendChild(filmographyHeading); + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + credits.crew.forEach(movie => { + if (movie.job === 'Director') { + const movieLink = document.createElement('span'); + movieLink.textContent = movie.title; + movieLink.classList.add('movie-link'); + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + window.location.href = 'movie-details.html'; + }); + movieList.appendChild(movieLink); + movieList.appendChild(document.createTextNode(', ')); + } + }); + filmographyHeading.appendChild(movieList); + + applySettings(); +} + +function calculateAge(dob, deathday = null) { + const birthDate = new Date(dob); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const ageDifMs = referenceDate - birthDate.getTime(); + const ageDate = new Date(ageDifMs); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + applyTextColor(savedTextColor); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/comments-tv.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/comments-tv.js new file mode 100644 index 00000000..9217424f --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/comments-tv.js @@ -0,0 +1,156 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, addDoc, getDocs, query, orderBy, where } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { app, db } from './firebase.js'; + +const commentForm = document.getElementById('comment-form'); +commentForm.addEventListener('submit', async e => { + e.preventDefault(); + const userName = document.getElementById('user-name').value; + const userComment = document.getElementById('user-comment').value; + const commentDate = new Date(); + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + await addDoc(collection(db, 'comments'), { + userName, + userComment, + commentDate, + tvSeriesId, + }); + commentForm.reset(); + fetchComments(); + } catch (error) { + console.log('Error adding comment: ', error); + } +}); + +let modal = document.getElementById('comment-modal'); +let btn = document.getElementById('toggle-comment-modal'); +let span = document.getElementsByClassName('close')[0]; + +btn.onclick = function () { + modal.style.display = 'block'; +}; + +span.onclick = function () { + modal.style.display = 'none'; +}; + +document.getElementById('post-comment-btn').onclick = function () { + modal.style.display = 'none'; +}; + +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } +}; + +let currentPage = 1; +const commentsPerPage = 3; +let totalComments = 0; +let totalPages = 1; + +async function fetchComments() { + try { + const commentsContainer = document.getElementById('comments-container'); + commentsContainer.innerHTML = ''; + commentsContainer.style.maxWidth = '100%'; + const movieId = localStorage.getItem('selectedTvSeriesId'); + + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', movieId), orderBy('commentDate', 'desc')); + const querySnapshot = await getDocs(q); + + totalComments = querySnapshot.size; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let index = 0; + let displayedComments = 0; + + if (querySnapshot.empty) { + const noCommentsMsg = document.createElement('p'); + noCommentsMsg.textContent = 'No comments for this TV series yet.'; + commentsContainer.appendChild(noCommentsMsg); + } else { + querySnapshot.forEach(doc => { + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { + const comment = doc.data(); + const commentDate = comment.commentDate.toDate(); + + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; + } + hideSpinner(); + } + } +} + +function formatCommentDate(commentDate) { + const formattedDate = commentDate.toLocaleString('default', { month: 'short' }) + ' ' + commentDate.getDate() + 'th, ' + commentDate.getFullYear(); + return formattedDate; +} + +function formatAMPM(date) { + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours || 12; + minutes = minutes < 10 ? '0' + minutes : minutes; + const strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +document.getElementById('prev-page').addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + fetchComments(); + } +}); + +document.getElementById('next-page').addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage++; + fetchComments(); + } +}); + +fetchComments(); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/comments.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/comments.js new file mode 100644 index 00000000..1d2e97a9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/comments.js @@ -0,0 +1,156 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, addDoc, getDocs, query, orderBy, where } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { app, db } from './firebase.js'; + +const commentForm = document.getElementById('comment-form'); +commentForm.addEventListener('submit', async e => { + e.preventDefault(); + const userName = document.getElementById('user-name').value; + const userComment = document.getElementById('user-comment').value; + const commentDate = new Date(); + const movieId = localStorage.getItem('selectedMovieId'); + + try { + await addDoc(collection(db, 'comments'), { + userName, + userComment, + commentDate, + movieId, + }); + commentForm.reset(); + fetchComments(); + } catch (error) { + console.log('Error adding comment: ', error); + } +}); + +let modal = document.getElementById('comment-modal'); +let btn = document.getElementById('toggle-comment-modal'); +let span = document.getElementsByClassName('close')[0]; + +btn.onclick = function () { + modal.style.display = 'block'; +}; + +span.onclick = function () { + modal.style.display = 'none'; +}; + +document.getElementById('post-comment-btn').onclick = function () { + modal.style.display = 'none'; +}; + +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } +}; + +let currentPage = 1; +const commentsPerPage = 3; +let totalComments = 0; +let totalPages = 1; + +async function fetchComments() { + try { + const commentsContainer = document.getElementById('comments-container'); + commentsContainer.innerHTML = ''; + commentsContainer.style.maxWidth = '100%'; + const movieId = localStorage.getItem('selectedMovieId'); + + const q = query(collection(db, 'comments'), where('movieId', '==', movieId), orderBy('commentDate', 'desc')); + const querySnapshot = await getDocs(q); + + totalComments = querySnapshot.size; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let index = 0; + let displayedComments = 0; + + if (querySnapshot.empty) { + const noCommentsMsg = document.createElement('p'); + noCommentsMsg.textContent = 'No comments for this movie yet.'; + commentsContainer.appendChild(noCommentsMsg); + } else { + querySnapshot.forEach(doc => { + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { + const comment = doc.data(); + const commentDate = comment.commentDate.toDate(); + + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; + } + hideSpinner(); + } + } +} + +function formatCommentDate(commentDate) { + const formattedDate = commentDate.toLocaleString('default', { month: 'short' }) + ' ' + commentDate.getDate() + 'th, ' + commentDate.getFullYear(); + return formattedDate; +} + +function formatAMPM(date) { + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours || 12; + minutes = minutes < 10 ? '0' + minutes : minutes; + const strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +document.getElementById('prev-page').addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + fetchComments(); + } +}); + +document.getElementById('next-page').addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage++; + fetchComments(); + } +}); + +fetchComments(); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/company-details.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/company-details.js new file mode 100644 index 00000000..b87c3bcf --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/company-details.js @@ -0,0 +1,742 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +document.addEventListener('DOMContentLoaded', () => { + const companyId = localStorage.getItem('selectedCompanyId'); + if (companyId) { + fetchCompanyDetails(companyId); + fetchCompanyMovies(companyId); + } else { + fetchCompanyDetails(521); + fetchCompanyMovies(521); + } +}); + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function fetchCompanyDetails(companyId) { + showSpinner(); + const url = `https://${getMovieVerseData()}/3/company/${companyId}?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const company = await response.json(); + const logoImg = document.getElementById('company-logo'); + + if (company.logo_path) { + logoImg.src = `https://image.tmdb.org/t/p/w500${company.logo_path}`; + } else { + logoImg.style.display = 'none'; + const logoFallbackText = document.createElement('p'); + logoFallbackText.textContent = 'Logo Not Available'; + logoImg.parentNode.insertBefore(logoFallbackText, logoImg); + } + + const fullCountryName = twoLetterCountryCodes.find(country => country.code === company.origin_country)?.name; + + document.getElementById('company-name').textContent = company.name || 'Information Unavailable'; + document.getElementById('company-headquarters').textContent = company.headquarters || 'Information Unavailable'; + document.getElementById('company-country').textContent = fullCountryName || 'Information Unavailable'; + document.title = `${company.name} - Company Details`; + + const homepage = company.homepage || '#'; + const companyWebsite = document.getElementById('company-website'); + + if (homepage !== '#') { + companyWebsite.href = homepage; + companyWebsite.textContent = homepage; + } else { + companyWebsite.textContent = 'Information Unavailable'; + } + + updateBrowserURL(company.name); + hideSpinner(); + } catch (error) { + console.log('Error fetching company details:', error); + const companyDetailsContainer = document.getElementById('company-details-container'); + companyDetailsContainer.innerHTML = ` +
+

Company details currently unavailable - please try again

+
`; + hideSpinner(); + } +} + +async function fetchCompanyMovies(companyId) { + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_companies=${companyId}`; + try { + const response = await fetch(url); + const data = await response.json(); + + if (data.results.length === 0) { + const companyMoviesContainer = document.getElementById('company-movies-container'); + companyMoviesContainer.innerHTML = `

No movies found for this company.

`; + return; + } + displayCompanyMovies(data.results); + } catch (error) { + console.log('Error fetching movies:', error); + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +const twoLetterCountryCodes = [ + { name: 'Afghanistan', code: 'AF' }, + { name: 'Albania', code: 'AL' }, + { name: 'Algeria', code: 'DZ' }, + { name: 'American Samoa', code: 'AS' }, + { name: 'Andorra', code: 'AD' }, + { name: 'Angola', code: 'AO' }, + { name: 'Anguilla', code: 'AI' }, + { name: 'Antarctica', code: 'AQ' }, + { name: 'Antigua and Barbuda', code: 'AG' }, + { name: 'Argentina', code: 'AR' }, + { name: 'Armenia', code: 'AM' }, + { name: 'Aruba', code: 'AW' }, + { name: 'Australia', code: 'AU' }, + { name: 'Austria', code: 'AT' }, + { name: 'Azerbaijan', code: 'AZ' }, + { name: 'Bahamas', code: 'BS' }, + { name: 'Bahrain', code: 'BH' }, + { name: 'Bangladesh', code: 'BD' }, + { name: 'Barbados', code: 'BB' }, + { name: 'Belarus', code: 'BY' }, + { name: 'Belgium', code: 'BE' }, + { name: 'Belize', code: 'BZ' }, + { name: 'Benin', code: 'BJ' }, + { name: 'Bermuda', code: 'BM' }, + { name: 'Bhutan', code: 'BT' }, + { name: 'Bolivia', code: 'BO' }, + { name: 'Bonaire', code: 'BQ' }, + { name: 'Bosnia and Herzegovina', code: 'BA' }, + { name: 'Botswana', code: 'BW' }, + { name: 'Bouvet Island', code: 'BV' }, + { name: 'Brazil', code: 'BR' }, + { name: 'British Indian Ocean Territory', code: 'IO' }, + { name: 'Brunei Darussalam', code: 'BN' }, + { name: 'Bulgaria', code: 'BG' }, + { name: 'Burkina Faso', code: 'BF' }, + { name: 'Burundi', code: 'BI' }, + { name: 'Cambodia', code: 'KH' }, + { name: 'Cameroon', code: 'CM' }, + { name: 'Canada', code: 'CA' }, + { name: 'Cape Verde', code: 'CV' }, + { name: 'Cayman Islands', code: 'KY' }, + { name: 'Central African Republic', code: 'CF' }, + { name: 'Chad', code: 'TD' }, + { name: 'Chile', code: 'CL' }, + { name: 'China', code: 'CN' }, + { name: 'Christmas Island', code: 'CX' }, + { name: 'Cocos (Keeling) Islands', code: 'CC' }, + { name: 'Colombia', code: 'CO' }, + { name: 'Comoros', code: 'KM' }, + { name: 'Congo', code: 'CG' }, + { name: 'Congo, The Democratic Republic of the', code: 'CD' }, + { name: 'Cook Islands', code: 'CK' }, + { name: 'Costa Rica', code: 'CR' }, + { name: 'Cote D Ivoire', code: 'CI' }, + { name: 'Croatia', code: 'HR' }, + { name: 'Cuba', code: 'CU' }, + { name: 'Curacao', code: 'CW' }, + { name: 'Cyprus', code: 'CY' }, + { name: 'Czech Republic', code: 'CZ' }, + { name: 'Denmark', code: 'DK' }, + { name: 'Djibouti', code: 'DJ' }, + { name: 'Dominica', code: 'DM' }, + { name: 'Dominican Republic', code: 'DO' }, + { name: 'Ecuador', code: 'EC' }, + { name: 'Egypt', code: 'EG' }, + { name: 'El Salvador', code: 'SV' }, + { name: 'Equatorial Guinea', code: 'GQ' }, + { name: 'Eritrea', code: 'ER' }, + { name: 'Estonia', code: 'EE' }, + { name: 'Eswatini', code: 'SZ' }, + { name: 'Ethiopia', code: 'ET' }, + { name: 'Falkland Islands (Malvinas)', code: 'FK' }, + { name: 'Faroe Islands', code: 'FO' }, + { name: 'Fiji', code: 'FJ' }, + { name: 'Finland', code: 'FI' }, + { name: 'France', code: 'FR' }, + { name: 'French Guiana', code: 'GF' }, + { name: 'French Polynesia', code: 'PF' }, + { name: 'French Southern Territories', code: 'TF' }, + { name: 'Gabon', code: 'GA' }, + { name: 'Gambia', code: 'GM' }, + { name: 'Georgia', code: 'GE' }, + { name: 'Germany', code: 'DE' }, + { name: 'Ghana', code: 'GH' }, + { name: 'Gibraltar', code: 'GI' }, + { name: 'Greece', code: 'GR' }, + { name: 'Greenland', code: 'GL' }, + { name: 'Grenada', code: 'GD' }, + { name: 'Guadeloupe', code: 'GP' }, + { name: 'Guam', code: 'GU' }, + { name: 'Guatemala', code: 'GT' }, + { name: 'Guernsey', code: 'GG' }, + { name: 'Guinea', code: 'GN' }, + { name: 'Guinea-Bissau', code: 'GW' }, + { name: 'Guyana', code: 'GY' }, + { name: 'Haiti', code: 'HT' }, + { name: 'Heard Island and Mcdonald Islands', code: 'HM' }, + { name: 'Holy See (Vatican City State)', code: 'VA' }, + { name: 'Honduras', code: 'HN' }, + { name: 'Hong Kong', code: 'HK' }, + { name: 'Hungary', code: 'HU' }, + { name: 'Iceland', code: 'IS' }, + { name: 'India', code: 'IN' }, + { name: 'Indonesia', code: 'ID' }, + { name: 'Iran, Islamic Republic Of', code: 'IR' }, + { name: 'Iraq', code: 'IQ' }, + { name: 'Ireland', code: 'IE' }, + { name: 'Isle of Man', code: 'IM' }, + { name: 'Israel', code: 'IL' }, + { name: 'Italy', code: 'IT' }, + { name: 'Ivory Coast', code: 'CI' }, + { name: 'Jamaica', code: 'JM' }, + { name: 'Japan', code: 'JP' }, + { name: 'Jersey', code: 'JE' }, + { name: 'Jordan', code: 'JO' }, + { name: 'Kazakhstan', code: 'KZ' }, + { name: 'Kenya', code: 'KE' }, + { name: 'Kiribati', code: 'KI' }, + { name: 'DPR Korea', code: 'KP' }, + { name: 'South Korea', code: 'KR' }, + { name: 'Kuwait', code: 'KW' }, + { name: 'Kyrgyzstan', code: 'KG' }, + { name: 'Laos', code: 'LA' }, + { name: 'Latvia', code: 'LV' }, + { name: 'Lebanon', code: 'LB' }, + { name: 'Lesotho', code: 'LS' }, + { name: 'Liberia', code: 'LR' }, + { name: 'Libyan Arab Jamahiriya', code: 'LY' }, + { name: 'Liechtenstein', code: 'LI' }, + { name: 'Lithuania', code: 'LT' }, + { name: 'Luxembourg', code: 'LU' }, + { name: 'Macao', code: 'MO' }, + { name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK' }, + { name: 'Madagascar', code: 'MG' }, + { name: 'Malawi', code: 'MW' }, + { name: 'Malaysia', code: 'MY' }, + { name: 'Maldives', code: 'MV' }, + { name: 'Mali', code: 'ML' }, + { name: 'Malta', code: 'MT' }, + { name: 'Marshall Islands', code: 'MH' }, + { name: 'Martinique', code: 'MQ' }, + { name: 'Mauritania', code: 'MR' }, + { name: 'Mauritius', code: 'MU' }, + { name: 'Mayotte', code: 'YT' }, + { name: 'Mexico', code: 'MX' }, + { name: 'Micronesia, Federated States of', code: 'FM' }, + { name: 'Moldova, Republic of', code: 'MD' }, + { name: 'Monaco', code: 'MC' }, + { name: 'Mongolia', code: 'MN' }, + { name: 'Montenegro', code: 'ME' }, + { name: 'Montserrat', code: 'MS' }, + { name: 'Morocco', code: 'MA' }, + { name: 'Mozambique', code: 'MZ' }, + { name: 'Myanmar', code: 'MM' }, + { name: 'Namibia', code: 'NA' }, + { name: 'Nauru', code: 'NR' }, + { name: 'Nepal', code: 'NP' }, + { name: 'Netherlands', code: 'NL' }, + { name: 'Netherlands Antilles', code: 'AN' }, + { name: 'New Caledonia', code: 'NC' }, + { name: 'New Zealand', code: 'NZ' }, + { name: 'Nicaragua', code: 'NI' }, + { name: 'Niger', code: 'NE' }, + { name: 'Nigeria', code: 'NG' }, + { name: 'Niue', code: 'NU' }, + { name: 'Norfolk Island', code: 'NF' }, + { name: 'Northern Mariana Islands', code: 'MP' }, + { name: 'Norway', code: 'NO' }, + { name: 'Oman', code: 'OM' }, + { name: 'Pakistan', code: 'PK' }, + { name: 'Palau', code: 'PW' }, + { name: 'Palestinian Territory, Occupied', code: 'PS' }, + { name: 'Panama', code: 'PA' }, + { name: 'Papua New Guinea', code: 'PG' }, + { name: 'Paraguay', code: 'PY' }, + { name: 'Peru', code: 'PE' }, + { name: 'Philippines', code: 'PH' }, + { name: 'Pitcairn', code: 'PN' }, + { name: 'Poland', code: 'PL' }, + { name: 'Portugal', code: 'PT' }, + { name: 'Puerto Rico', code: 'PR' }, + { name: 'Qatar', code: 'QA' }, + { name: 'RWANDA', code: 'RW' }, + { name: 'Reunion', code: 'RE' }, + { name: 'Romania', code: 'RO' }, + { name: 'Russian Federation', code: 'RU' }, + { name: 'Saint Barthelemy', code: 'BL' }, + { name: 'Saint Helena', code: 'SH' }, + { name: 'Saint Kitts and Nevis', code: 'KN' }, + { name: 'Saint Lucia', code: 'LC' }, + { name: 'Saint Martin', code: 'MF' }, + { name: 'Saint Pierre and Miquelon', code: 'PM' }, + { name: 'Saint Vincent and the Grenadines', code: 'VC' }, + { name: 'Samoa', code: 'WS' }, + { name: 'San Marino', code: 'SM' }, + { name: 'Sao Tome and Principe', code: 'ST' }, + { name: 'Saudi Arabia', code: 'SA' }, + { name: 'Senegal', code: 'SN' }, + { name: 'Serbia', code: 'RS' }, + { name: 'Seychelles', code: 'SC' }, + { name: 'Sierra Leone', code: 'SL' }, + { name: 'Singapore', code: 'SG' }, + { name: 'Sint Maarten', code: 'SX' }, + { name: 'Slovakia', code: 'SK' }, + { name: 'Slovenia', code: 'SI' }, + { name: 'Solomon Islands', code: 'SB' }, + { name: 'Somalia', code: 'SO' }, + { name: 'South Africa', code: 'ZA' }, + { name: 'South Georgia and the South Sandwich Islands', code: 'GS' }, + { name: 'South Sudan', code: 'SS' }, + { name: 'Spain', code: 'ES' }, + { name: 'Sri Lanka', code: 'LK' }, + { name: 'Sudan', code: 'SD' }, + { name: 'Suriname', code: 'SR' }, + { name: 'Svalbard and Jan Mayen', code: 'SJ' }, + { name: 'Swaziland', code: 'SZ' }, + { name: 'Sweden', code: 'SE' }, + { name: 'Switzerland', code: 'CH' }, + { name: 'Syrian Arab Republic', code: 'SY' }, + { name: 'Taiwan', code: 'TW' }, + { name: 'Tajikistan', code: 'TJ' }, + { name: 'Tanzania, United Republic of', code: 'TZ' }, + { name: 'Thailand', code: 'TH' }, + { name: 'Timor-Leste', code: 'TL' }, + { name: 'Togo', code: 'TG' }, + { name: 'Tokelau', code: 'TK' }, + { name: 'Tonga', code: 'TO' }, + { name: 'Trinidad and Tobago', code: 'TT' }, + { name: 'Tunisia', code: 'TN' }, + { name: 'Turkey', code: 'TR' }, + { name: 'Turkmenistan', code: 'TM' }, + { name: 'Turks and Caicos Islands', code: 'TC' }, + { name: 'Tuvalu', code: 'TV' }, + { name: 'Uganda', code: 'UG' }, + { name: 'Ukraine', code: 'UA' }, + { name: 'United Arab Emirates', code: 'AE' }, + { name: 'United Kingdom', code: 'GB' }, + { name: 'United States', code: 'US' }, + { name: 'United States Minor Outlying Islands', code: 'UM' }, + { name: 'Uruguay', code: 'UY' }, + { name: 'Uzbekistan', code: 'UZ' }, + { name: 'Vanuatu', code: 'VU' }, + { name: 'Venezuela', code: 'VE' }, + { name: 'Viet Nam', code: 'VN' }, + { name: 'Vietnam', code: 'VN' }, + { name: 'Virgin Islands, British', code: 'VG' }, + { name: 'Virgin Islands, U.S.', code: 'VI' }, + { name: 'Wallis and Futuna', code: 'WF' }, + { name: 'Western Sahara', code: 'EH' }, + { name: 'Yemen', code: 'YE' }, + { name: 'Zambia', code: 'ZM' }, + { name: 'Zimbabwe', code: 'ZW' }, + { name: 'Åland Islands', code: 'AX' }, +]; + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function displayCompanyMovies(movies) { + const moviesList = document.getElementById('company-movies-list'); + moviesList.style.display = 'flex'; + moviesList.style.flexWrap = 'wrap'; + moviesList.style.justifyContent = 'center'; + moviesList.style.gap = '5px'; + + let moviesToDisplay = movies.sort((a, b) => b.popularity - a.popularity); + + moviesToDisplay.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + moviesList.appendChild(movieLink); + + if (index < movies.length - 1) { + const separator = document.createTextNode(' '); + moviesList.appendChild(separator); + } + }); +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/create-account.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/create-account.js new file mode 100644 index 00000000..33047f26 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/create-account.js @@ -0,0 +1,140 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + collection, + addDoc, + getDocs, + query, + where, + doc, + setDoc, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function isValidPassword(password) { + const minLength = 8; + const hasUppercase = /[A-Z]/.test(password); + const hasLowercase = /[a-z]/.test(password); + const hasNumbers = /\d/.test(password); + const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password); + + return password.length >= minLength && hasUppercase && hasLowercase && hasNumbers && hasSpecialChar; +} + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('createAccountForm').addEventListener('submit', async e => { + try { + e.preventDefault(); + const email = document.getElementById('newEmail').value; + const password = document.getElementById('newPassword').value; + const confirmPassword = document.getElementById('confirmPassword').value; + + if (!isValidPassword(password)) { + alert( + 'Password does not meet the security requirements.\n\n' + + 'Your password must include:\n' + + '- At least 8 characters\n' + + '- At least one uppercase letter\n' + + '- At least one lowercase letter\n' + + '- At least one number\n' + + '- At least one special character (e.g., !@#$%^&*)' + ); + return; + } + + if (password !== confirmPassword) { + alert('Passwords do not match.'); + return; + } + + const exists = await accountExists(email); + if (exists) { + alert('An account with this email already exists.'); + return; + } + + try { + await addDoc(collection(db, 'MovieVerseUsers'), { + email: email, + password: password, + }); + + const profileRef = doc(db, 'profiles', email); // Using email as document ID for simplicity + await setDoc(profileRef, { + username: 'N/A', + dob: 'N/A', + bio: 'N/A', + favoriteGenres: ['N/A'], + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: ['N/A'], + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }); + + alert('Account created successfully! Now please sign in on the sign in page to proceed.'); + window.location.href = 'sign-in.html'; + } catch (error) { + console.log('Error creating account: ', error); + alert('Failed to create account. Please try again later.'); + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('account-creation-form-container'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +async function accountExists(email) { + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); + const querySnapshot = await getDocs(q); + return !querySnapshot.empty; +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/director-details.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/director-details.js new file mode 100644 index 00000000..4a0dfc46 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/director-details.js @@ -0,0 +1,781 @@ +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + currentIndex = 0; + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', () => { + const directorId = localStorage.getItem('selectedDirectorId'); + + if (directorId) { + fetchDirectorDetails(directorId); + } else { + fetchDirectorDetails(488); + } +}); + +async function fetchDirectorDetails(directorId) { + showSpinner(); + + const directorUrl = `https://${getMovieVerseData()}/3/person/${directorId}?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/${directorId}/movie_credits?${generateMovieNames()}${getMovieCode()}`; + + try { + const [directorResponse, creditsResponse] = await Promise.all([fetch(directorUrl), fetch(creditsUrl)]); + + const director = await directorResponse.json(); + const credits = await creditsResponse.json(); + + if (director.success === false) { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details currently unavailable - please try again

+
`; + } else { + updateBrowserURL(director.name); + populateDirectorDetails(director, credits); + } + hideSpinner(); + } catch (error) { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details currently unavailable - please try again

+
`; + console.log('Error fetching director details:', error); + hideSpinner(); + } +} + +async function populateDirectorDetails(director, credits) { + const directorImage = document.getElementById('director-image'); + const directorName = document.getElementById('director-name'); + const directorDescription = document.getElementById('director-description'); + + if (director.profile_path) { + directorImage.src = `https://image.tmdb.org/t/p/w1280${director.profile_path}`; + directorName.textContent = director.name; + document.title = `${director.name} - Director's Details`; + } else { + directorImage.style.display = 'none'; + directorName.textContent = director.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.director-left').appendChild(noImageText); + } + + let ageOrStatus; + if (director.birthday) { + if (director.deathday) { + ageOrStatus = calculateAge(director.birthday, director.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(director.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + directorDescription.innerHTML = ` +

Biography: ${director.biography || 'Information Unavailable'}

+

Also Known As: ${director.also_known_as.join(', ') || 'Information Unavailable'}

+

Date of Birth: ${director.birthday || 'Information Unavailable'}

+

Date of Death: ${director.deathday || 'Information Unavailable'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${director.place_of_birth || 'Information Unavailable'}

+

Known For: Directing

+ `; + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + directorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + movieList.style.display = 'flex'; + movieList.style.flexWrap = 'wrap'; + movieList.style.justifyContent = 'center'; + movieList.style.gap = '5px'; + + let directedMovies = credits.crew.filter(movie => movie.job === 'Director'); + directedMovies = directedMovies.sort((a, b) => b.popularity - a.popularity); + + directedMovies.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + movieList.appendChild(movieLink); + + if (index < directedMovies.length - 1) { + movieList.appendChild(document.createTextNode('')); + } + }); + + filmographyHeading.appendChild(movieList); + + const mediaUrl = `https://${getMovieVerseData()}/3/person/${director.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + + const detailsContainer = document.getElementById('director-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + let modalOpen = false; + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + imageElement.addEventListener('click', function () { + const imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 380); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + applySettings(); +} + +function calculateAge(dob, deathday = null) { + const birthDate = new Date(dob); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const ageDifMs = referenceDate - birthDate.getTime(); + const ageDate = new Date(ageDifMs); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + applyTextColor(savedTextColor); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/favorites.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/favorites.js new file mode 100644 index 00000000..fcb4771a --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/favorites.js @@ -0,0 +1,2062 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + getDocs, + getDoc, + query, + where, + orderBy, + writeBatch, + deleteDoc, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +let initialMoviesSelection = []; +let initialTVSeriesSelection = []; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.addEventListener('DOMContentLoaded', function () { + loadWatchLists(); +}); + +const tvCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(tvCode.part1) + atob(tvCode.part2) + atob(tvCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +document.addEventListener('DOMContentLoaded', function () { + adjustButtonMargin(); + document.getElementById('how-to-use-btn').addEventListener('click', function () { + let howToUseSection = document.getElementById('how-to-use-section'); + if (howToUseSection.style.display === 'none') { + howToUseSection.style.display = 'block'; + window.location.href = '#how-to-use-section'; + document.getElementById('how-to-use-btn').textContent = 'Hide Tutorial'; + document.getElementById('how-to-use-btn').style.marginBottom = '0'; + } else { + howToUseSection.style.display = 'none'; + document.getElementById('how-to-use-btn').textContent = 'How to Use'; + document.getElementById('how-to-use-btn').style.marginBottom = '180px'; + } + }); +}); + +function adjustButtonMargin() { + let howToUseSection = document.getElementById('how-to-use-section'); + if (howToUseSection.style.display === 'none' || !howToUseSection.style.display) { + document.getElementById('how-to-use-btn').style.marginBottom = '200px'; + } else { + document.getElementById('how-to-use-btn').style.marginBottom = '0'; + } +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function openModal(modalId) { + document.getElementById(modalId).style.display = 'block'; +} + +document.addEventListener('DOMContentLoaded', () => { + const closeButtons = document.querySelectorAll('.close-button'); + + closeButtons.forEach(button => { + button.addEventListener('click', function () { + const modalId = this.closest('.modal').id; + closeModal(modalId); + }); + }); +}); + +function closeModal(modalId) { + document.getElementById(modalId).style.display = 'none'; +} + +document.getElementById('delete-watchlist-btn').addEventListener('click', () => openModal('delete-watchlist-modal')); + +async function getMovieTitle(movieId) { + const apiKey = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${apiKey}`; + + try { + const response = await fetch(url); + const movie = await response.json(); + return movie.title; + } catch (error) { + return 'Unknown Movie'; + } +} + +async function populateCreateModalWithFavorites() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || ''; + + if (!currentUserEmail) { + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + + const createForm = document.getElementById('create-watchlist-form'); + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + createForm.insertBefore(container, createForm.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + const moviesFavorited = userData.favoritesMovies || []; + const favoritesTVSeries = userData.favoritesTVSeries || []; + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + } else { + container.innerHTML = '

No favorites found. Please add some favorites first.

'; + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('create-watchlist-modal'); + } + }); +} + +document.getElementById('create-watchlist-form').addEventListener('submit', async function (e) { + e.preventDefault(); + showSpinner(); + + const name = document.getElementById('new-watchlist-name').value.trim(); + const description = document.getElementById('new-watchlist-description').value; + const selectedMovies = Array.from(document.querySelectorAll('#movies-container input:checked')).map(checkbox => checkbox.value); + const selectedTVSeries = Array.from(document.querySelectorAll('#tvseries-container input:checked')).map(checkbox => checkbox.value); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let isDuplicate = false; + let maxOrder = 0; + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + try { + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + maxOrder = querySnapshot.docs.reduce((max, docSnapshot) => Math.max(max, docSnapshot.data().order || 0), 0); + isDuplicate = querySnapshot.docs.some(doc => doc.data().name.toLowerCase() === name.toLowerCase()); + } else { + isDuplicate = localWatchlists.some(watchlist => watchlist.name.toLowerCase() === name.toLowerCase()); + } + + if (isDuplicate) { + alert('A watchlist with this name already exists. Please choose a different name.'); + hideSpinner(); + return; + } + + if (currentUserEmail) { + const newWatchlistRef = doc(collection(db, 'watchlists')); + await setDoc(newWatchlistRef, { + userEmail: currentUserEmail, + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + order: maxOrder + 1, + }); + } else { + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: '', + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: '', + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } else { + console.error('An error occurred while creating a watchlist:', error); + alert('Failed to create the watchlist due to an error.'); + } + } + + closeModal('create-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); +}); + +async function getTVSeriesTitle(seriesId) { + const apiKey = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/tv/${seriesId}?${generateMovieNames()}${apiKey}`; + + try { + const response = await fetch(url); + const series = await response.json(); + return series.name; + } catch (error) { + return 'Unknown Series'; + } +} + +function appendCheckbox(container, id, title, name, isChecked = false) { + const item = document.createElement('div'); + item.classList.add('favorite-item'); + item.style.display = 'flex'; + item.style.alignItems = 'center'; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `${name}-${id}`; + checkbox.value = id; + checkbox.name = name; + checkbox.checked = isChecked; + + const label = document.createElement('label'); + label.htmlFor = `${name}-${id}`; + label.textContent = title; + label.style.marginTop = '12px'; + label.style.marginLeft = '10px'; + + item.appendChild(checkbox); + item.appendChild(label); + container.appendChild(item); +} + +document.getElementById('create-watchlist-btn').addEventListener('click', function () { + document.getElementById('create-watchlist-form').reset(); + populateCreateModalWithFavorites(); + openModal('create-watchlist-modal'); + updateWatchlistsCreated(); +}); + +function generateUniqueId() { + return Date.now().toString(36) + Math.random().toString(36).substr(2); +} + +document.getElementById('edit-watchlist-btn').addEventListener('click', async function () { + await populateEditModal(); + openModal('edit-watchlist-modal'); +}); + +async function populateEditModal() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let watchlists = []; + let moviesFavorited = []; + let favoritesTVSeries = []; + + if (currentUserEmail) { + const qWatchlists = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const qUsers = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + + const [watchlistsSnapshot, usersSnapshot] = await Promise.all([getDocs(qWatchlists), getDocs(qUsers)]); + + watchlists = watchlistsSnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + if (!usersSnapshot.empty) { + const userData = usersSnapshot.docs[0].data(); + moviesFavorited = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; + + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } + + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute('for', 'watchlist-select'); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach(watchlist => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); + + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; + + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); + + const updateForm = async watchlist => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; + + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } + } + + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; + + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); + + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } + + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; + + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } + + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute('for', 'watchlist-select'); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach(watchlist => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); + + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; + + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); + + const updateForm = async watchlist => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; + + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } + } + + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; + + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); + + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } + + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('edit-watchlist-modal'); + } + }); +} + +document.getElementById('edit-watchlist-form').addEventListener('submit', async function (e) { + try { + showSpinner(); + e.preventDefault(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; + + let selectedMovies; + let selectedTVSeries; + + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + + const moviesSelectionChanged = !( + initialMoviesSelection.length === currentMoviesSelection.length && initialMoviesSelection.every(value => currentMoviesSelection.includes(value)) + ); + const tvSeriesSelectionChanged = !( + initialTVSeriesSelection.length === currentTVSeriesSelection.length && + initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value)) + ); + + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } else { + selectedMovies = initialMoviesSelection; + } + + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } else { + selectedTVSeries = initialTVSeriesSelection; + } + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + + const watchlistRef = doc(db, 'watchlists', watchlistId); + await updateDoc(watchlistRef, { + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }); + } else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); + + e.preventDefault(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; + + let selectedMovies; + let selectedTVSeries; + + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + + const moviesSelectionChanged = !( + initialMoviesSelection.length === currentMoviesSelection.length && + initialMoviesSelection.every(value => currentMoviesSelection.includes(value)) + ); + const tvSeriesSelectionChanged = !( + initialTVSeriesSelection.length === currentTVSeriesSelection.length && + initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value)) + ); + + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } else { + selectedMovies = initialMoviesSelection; + } + + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } else { + selectedTVSeries = initialTVSeriesSelection; + } + + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } +}); + +async function populateDeleteModal() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; + + let watchlists = []; + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + } else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + } + + if (watchlists.length === 0) { + deleteForm.innerHTML = '

No Watchlists Available to Delete.

'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); + + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; + + if (watchlists.length === 0) { + deleteForm.innerHTML = '

No Watchlists Available to Delete.

'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); + + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('delete-watchlist-modal'); + } + }); +} + +async function deleteSelectedWatchlists() { + try { + showSpinner(); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + + for (const id of selectedIds) { + await deleteDoc(doc(db, 'watchlists', id)); + } + } else { + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + } + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); + + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } +} + +document.getElementById('delete-watchlist-btn').addEventListener('click', populateDeleteModal); + +async function fetchMovieDetails(movieId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + + try { + const response = await fetch(url); + const movie = await response.json(); + const movieCard = await createMovieCard(movie); + movieCard.setAttribute('data-movie-title', movie.title); + return movieCard; + } catch (error) { + const errorDiv = document.createElement('div'); + errorDiv.textContent = 'Error loading movie card. Please try refreshing the page.'; + return errorDiv; + } +} + +async function getAdditionalMovieImages(movieId) { + const response = await fetch(`https://api.themoviedb.org/3/movie/${movieId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +async function createMovieCard(movie) { + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = movie.title; + const words = movieTitle.split(' '); + if (words.length >= 9) { + words[8] = '...'; + movieTitle = words.slice(0, 9).join(' '); + } + + const ratingClass = movie.vote_count === 0 ? 'unrated' : getClassByRate(movie.vote_average); + const voteAvg = movie.vote_count === 0 ? 'Unrated' : movie.vote_average.toFixed(1); + + let overview = movie.overview; + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+ ${movie.title} +
+
+

${movieTitle}

+ ${voteAvg} +
+
+

Movie Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + updateUniqueMoviesViewed(movie.id); + updateFavoriteGenre(movie.genre_ids); + updateMovieVisitCount(movie.id, movie.title); + window.location.href = 'movie-details.html'; + }); + + const additionalImages = await getAdditionalMovieImages(movie.id); + let allImages = [movie.poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + + return movieEl; +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +const searchForm = document.getElementById('form'); + +searchForm.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function loadWatchLists() { + const displaySection = document.getElementById('watchlists-display-section'); + + try { + showSpinner(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + const watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + if (watchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Click on "Create Watch Lists" to start adding movies.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += + '

Your Watch Lists

'; + document.getElementById('watchlist-header').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); + }); + watchlists.sort((a, b) => a.order - b.order); + watchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of watchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + } else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + if (localWatchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += '

Your Watch Lists

'; + localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + } + + let favorites = []; + let favoritesTVSeries = []; + + if (currentUserEmail) { + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + if (favorites.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite Movies'; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite movies.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const movieId of favorites) { + const movieCard = await fetchMovieDetails(movieId); + moviesContainer.appendChild(movieCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + favoritesDiv.innerHTML = + '

Favorite Movies

No favorite movies added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + if (favoritesTVSeries.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite TV Series'; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite TV series.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const tvSeriesId of favoritesTVSeries) { + const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); + moviesContainer.appendChild(tvSeriesCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + favoritesDiv.innerHTML = + '

Favorite TV Series

No favorite TV series added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + hideSpinner(); + } catch (error) { + if (error.code === 'resource-exhausted') { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + if (localWatchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += '

Your Watch Lists

'; + localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + + let favorites = []; + let favoritesTVSeries = []; + + favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + if (favorites.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite Movies'; + title.className = 'watchlist-title'; + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite movies.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const movieId of favorites) { + const movieCard = await fetchMovieDetails(movieId); + moviesContainer.appendChild(movieCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + favoritesDiv.innerHTML = + '

Favorite Movies

No favorite movies added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + if (favoritesTVSeries.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite TV Series'; + title.className = 'watchlist-title'; + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite TV series.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const tvSeriesId of favoritesTVSeries) { + const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); + moviesContainer.appendChild(tvSeriesCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + hideSpinner(); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + favoritesDiv.innerHTML = + '

Favorite TV Series

No favorite TV series added yet.

'; + displaySection.appendChild(favoritesDiv); + hideSpinner(); + } + } else { + console.error('An error occurred:', error); + } + } +} + +async function fetchTVSeriesDetails(tvSeriesId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + + try { + const response = await fetch(url); + const series = await response.json(); + const seriesCard = await createTVSeriesCard(series); + seriesCard.setAttribute('data-series-title', series.name); + return seriesCard; + } catch (error) { + const errorDiv = document.createElement('div'); + errorDiv.textContent = 'Error loading series details. Please try refreshing the page.'; + return errorDiv; + } +} + +async function getAdditionalTVSeriesImages(tvSeriesId) { + const response = await fetch(`https://api.themoviedb.org/3/tv/${tvSeriesId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +async function createTVSeriesCard(tvSeries) { + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = tvSeries.name; + const words = movieTitle.split(' '); + if (words.length >= 9) { + words[8] = '...'; + movieTitle = words.slice(0, 9).join(' '); + } + + const ratingClass = tvSeries.vote_count === 0 ? 'unrated' : getClassByRate(tvSeries.vote_average); + const voteAvg = tvSeries.vote_count === 0 ? 'Unrated' : tvSeries.vote_average.toFixed(1); + + let overview = tvSeries.overview; + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+ ${tvSeries.name} +
+
+

${movieTitle}

+ ${voteAvg} +
+
+

TV Series Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedTvSeriesId', tvSeries.id); + updateMovieVisitCount(tvSeries.id, tvSeries.name); + updateUniqueMoviesViewed(tvSeries.id); + updateFavoriteGenre(tvSeries.genres_ids); + window.location.href = 'tv-details.html'; + }); + + const additionalImages = await getAdditionalTVSeriesImages(tvSeries.id); + let allImages = [tvSeries.poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + + return movieEl; +} + +function updateFavoriteGenre(genre_ids) { + if (genre_ids && genre_ids.length > 0) { + const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + favoriteGenres.push(genre_ids[0]); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + } +} + +function updateUniqueMoviesViewed(movieId) { + let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + if (!viewedMovies.includes(movieId)) { + viewedMovies.push(movieId); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); + } +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +async function isListPinned(watchlistId) { + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (currentUserEmail) { + try { + const watchlistRef = doc(db, 'watchlists', watchlistId); + const watchlistDoc = await getDoc(watchlistRef); + + if (watchlistDoc.exists()) { + const watchlistData = watchlistDoc.data(); + return watchlistData.pinned || false; + } else { + return false; + } + } catch (error) { + return false; + } + } else { + const watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + const watchlist = watchlists.find(watchlist => watchlist.id === watchlistId); + return watchlist ? watchlist.pinned : false; + } +} + +function addWatchListControls(watchlistDiv, watchlistId) { + if (!watchlistId) { + return; + } + + const controlContainer = document.createElement('div'); + controlContainer.className = 'watchlist-controls'; + + const pinBtn = document.createElement('button'); + pinBtn.innerHTML = ''; + pinBtn.classList.add('pin-btn'); + + isListPinned(watchlistId).then(isPinned => { + pinBtn.title = isPinned ? 'Unpin this watch list' : 'Pin this watch list'; + if (isPinned) { + pinBtn.classList.add('pinned'); + } else { + pinBtn.classList.remove('pinned'); + } + pinBtn.onclick = function () { + pinWatchList(watchlistDiv, watchlistId); + }; + }); + + const moveUpBtn = document.createElement('button'); + moveUpBtn.innerHTML = ''; + moveUpBtn.onclick = function () { + moveWatchList(watchlistDiv, true); + }; + moveUpBtn.title = 'Move this watch list up'; + + const moveDownBtn = document.createElement('button'); + moveDownBtn.innerHTML = ''; + moveDownBtn.onclick = function () { + moveWatchList(watchlistDiv, false); + }; + moveDownBtn.title = 'Move this watch list down'; + + const shareBtn = document.createElement('button'); + shareBtn.innerHTML = ''; + shareBtn.title = 'Share this watch list'; + shareBtn.onclick = function () { + shareWatchList(watchlistDiv); + }; + + controlContainer.appendChild(pinBtn); + controlContainer.appendChild(moveUpBtn); + controlContainer.appendChild(moveDownBtn); + controlContainer.appendChild(shareBtn); + watchlistDiv.appendChild(controlContainer); +} + +function shareWatchList(watchlistDiv) { + const watchlistTitle = watchlistDiv.querySelector('.watchlist-title').textContent; + let itemsToShare = `Explore my curated watchlist, "${watchlistTitle}", which contains:\n`; + let finalLine = 'Happy Watching! 🍿🎬🎥\n\n'; + const movieCards = watchlistDiv.querySelectorAll('[data-movie-title]'); + const tvSeriesCards = watchlistDiv.querySelectorAll('[data-series-title]'); + + movieCards.forEach(movieCard => { + itemsToShare += `- ${movieCard.getAttribute('data-movie-title')}\n`; + }); + + tvSeriesCards.forEach(seriesCard => { + itemsToShare += `- ${seriesCard.getAttribute('data-series-title')}\n`; + }); + + itemsToShare += finalLine; + + if (navigator.share) { + navigator + .share({ + title: `Share Watchlist: ${watchlistTitle}`, + text: itemsToShare, + }) + .catch(err => { + console.error('Error sharing the watchlist:', err); + }); + } else { + downloadWatchlist(watchlistTitle, itemsToShare); + } +} + +function downloadWatchlist(title, content) { + const encodedContent = encodeURIComponent(content); + const dataUri = `data:text/plain;charset=utf-8,${encodedContent}`; + + const element = document.createElement('a'); + element.setAttribute('href', dataUri); + element.setAttribute('download', `${title.replace(/[\s]+/g, '_')}.txt`); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + document.body.removeChild(element); +} + +function createWatchListDiv(watchlist) { + const watchlistDiv = document.createElement('div'); + watchlistDiv.className = 'watchlist'; + watchlistDiv.setAttribute('data-watchlist-id', watchlist.id); + + const title = document.createElement('h3'); + title.textContent = watchlist.name; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + watchlistDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = watchlist.description; + description.className = 'watchlist-description'; + + watchlistDiv.appendChild(title); + watchlistDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + moviesContainer.style.flexWrap = 'wrap'; + + if (watchlist.movies === undefined) { + moviesContainer.innerHTML = ''; + } else { + watchlist.movies.forEach(movieId => { + fetchMovieDetails(movieId).then(movieCard => moviesContainer.appendChild(movieCard)); + }); + } + + if (watchlist.tvSeries === undefined) { + moviesContainer.innerHTML = ''; + } else { + watchlist.tvSeries.forEach(tvSeriesId => { + fetchTVSeriesDetails(tvSeriesId).then(tvSeriesCard => moviesContainer.appendChild(tvSeriesCard)); + }); + } + + watchlistDiv.appendChild(moviesContainer); + addWatchListControls(watchlistDiv, watchlist.id); + return watchlistDiv; +} + +function updateWatchlistsOrderInLS() { + const watchlistsDivs = document.querySelectorAll('#watchlists-display-section > .watchlist'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + const newOrder = Array.from(watchlistsDivs).map(div => div.getAttribute('data-watchlist-id')); + + watchlists.sort((a, b) => newOrder.indexOf(a.id) - newOrder.indexOf(b.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); +} + +async function moveWatchList(watchlistDiv, moveUp) { + showSpinner(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const watchlistId = watchlistDiv.getAttribute('data-watchlist-id'); + + if (currentUserEmail) { + try { + const watchlistsQuery = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail), orderBy('order', 'asc')); + const snapshot = await getDocs(watchlistsQuery); + let watchlists = snapshot.docs.map(doc => { + return { docId: doc.id, ...doc.data() }; + }); + + const index = watchlists.findIndex(watchlist => watchlist.docId === watchlistId); + if (index === -1 || watchlists.length < 2) { + hideSpinner(); + return; + } + + const swapIndex = moveUp ? index - 1 : index + 1; + if (swapIndex < 0 || swapIndex >= watchlists.length) { + hideSpinner(); + return; + } + + let currentOrder = watchlists[index].order; + let swapOrder = watchlists[swapIndex].order; + + const batch = writeBatch(db); + batch.update(doc(db, 'watchlists', watchlists[index].docId), { + order: swapOrder, + }); + batch.update(doc(db, 'watchlists', watchlists[swapIndex].docId), { + order: currentOrder, + }); + + await batch.commit(); + } catch (error) { + hideSpinner(); + } + hideSpinner(); + } else { + const sibling = moveUp ? watchlistDiv.previousElementSibling : watchlistDiv.nextElementSibling; + if (sibling) { + const parent = watchlistDiv.parentNode; + if (moveUp) { + parent.insertBefore(watchlistDiv, sibling); + } else { + parent.insertBefore(sibling, watchlistDiv); + } + updateWatchlistsOrderInLS(); + } + hideSpinner(); + } + + loadWatchLists(); + window.location.reload(); +} + +async function pinWatchList(watchlistDiv, watchlistId) { + showSpinner(); + + const isPinned = watchlistDiv.classList.contains('pinned'); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (currentUserEmail) { + const watchlistRef = doc(db, 'watchlists', watchlistId); + await updateDoc(watchlistRef, { + pinned: !isPinned, + }); + hideSpinner(); + } else { + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists.forEach(watchlist => { + if (watchlist.id === watchlistId) { + watchlist.pinned = !isPinned; + } + }); + + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + hideSpinner(); + } + + loadWatchLists(); + window.location.reload(); +} + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +function updateWatchlistsCreated() { + let watchlistsCount = parseInt(localStorage.getItem('watchlistsCreated')) || 0; + watchlistsCount++; + localStorage.setItem('watchlistsCreated', watchlistsCount.toString()); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/firebase.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/firebase.js new file mode 100644 index 00000000..bddd3301 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/firebase.js @@ -0,0 +1,43 @@ +import { initializeApp, getApps, getApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +export const app = !getApps().length ? initializeApp(firebaseConfig) : getApp(); +export const db = getFirestore(app); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/inception.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/inception.js new file mode 100644 index 00000000..cf9779e6 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/inception.js @@ -0,0 +1,1265 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const favoriteButton = document.getElementById('favorite-btn'); +const searchTitle = document.getElementById('search-title'); + +let trailerUrlGlobal; +let initialMainContent; +let trailerButton; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function setStarRating(rating) { + const stars = document.querySelectorAll('.rating .star'); + stars.forEach(star => { + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; + }); + + document.getElementById('rating-value').textContent = `${rating}.0/5.0`; +} + +document.querySelectorAll('.rating .star').forEach(star => { + star.addEventListener('mouseover', e => { + setStarRating(e.target.dataset.value); + }); + + star.addEventListener('mouseout', () => { + const movieId = localStorage.getItem('selectedMovieId'); + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); + }); + + star.addEventListener('click', e => { + const movieId = localStorage.getItem('selectedMovieId'); + const rating = e.target.dataset.value; + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + savedRatings[movieId] = rating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + setStarRating(rating); + updateAverageMovieRating(movieId, rating); + window.location.reload(); + }); +}); + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + + const movieId = localStorage.getItem('selectedMovieId'); + if (movieId) { + fetchMovieDetails(movieId); + } else { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details not found.

+
`; + } + + document.getElementById('clear-search-btn').style.display = 'none'; + + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButton(); + initClient(); + applySettings(); +}); + +async function fetchMovieDetails(movieId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + const url2 = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=videos`; + const imdbUrl = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=external_ids`; + + try { + const response = await fetch(url); + const movie = await response.json(); + const imdbId = movie.imdb_id; + + fetchMovieRatings(imdbId, movie); + + const response2 = await fetch(url2); + const movie2 = await response2.json(); + const trailers = movie2.videos.results.filter(video => video.type === 'Trailer'); + + if (trailers.length > 0) { + const trailerUrl = `https://www.youtube.com/watch?v=${trailers[0].key}`; + trailerButton = createTrailerButton(trailerUrl); + positionTrailerButton(); + } + updateBrowserURL(movie.title); + } catch (error) { + console.log('Error fetching movie details:', error); + } +} + +function getRatingDetails(rating) { + let details = { color: 'black', text: rating, description: '' }; + + switch (rating) { + case 'R': + details = { + color: 'red', + text: 'R (Restricted)', + description: ' - No one 17 and under admitted', + }; + break; + case 'PG-13': + details = { + color: 'yellow', + text: 'PG-13 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 13', + }; + break; + case 'PG': + details = { + color: 'orange', + text: 'PG (Parental Guidance Suggested)', + description: ' - May not be suitable for children', + }; + break; + case 'G': + details = { + color: 'green', + text: 'G (General Audiences)', + description: ' - All ages admitted', + }; + break; + case 'NC-17': + details = { + color: 'darkred', + text: 'NC-17 (Adults Only)', + description: ' - No one 17 and under admitted', + }; + break; + case 'TV-Y': + details = { + color: 'lightgreen', + text: 'TV-Y (All Children)', + description: ' - Appropriate for all children', + }; + break; + case 'TV-Y7': + details = { + color: 'lightblue', + text: 'TV-Y7 (Directed to Older Children)', + description: ' - Suitable for children ages 7 and up', + }; + break; + case 'TV-G': + details = { + color: 'green', + text: 'TV-G (General Audience)', + description: ' - Suitable for all ages', + }; + break; + case 'TV-PG': + details = { + color: 'orange', + text: 'TV-PG (Parental Guidance Suggested)', + description: ' - May not be suitable for younger children', + }; + break; + case 'TV-14': + details = { + color: 'yellow', + text: 'TV-14 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 14', + }; + break; + case 'TV-MA': + details = { + color: 'red', + text: 'TV-MA (Mature Audience Only)', + description: ' - Specifically designed to be viewed by adults', + }; + break; + case 'NR': + details = { + color: 'grey', + text: 'NR (Not Rated)', + description: ' - Movie has not been officially rated', + }; + break; + case 'UR': + case 'Unrated': + details = { + color: 'grey', + text: 'UR (Unrated)', + description: ' - Contains content not used in the rated version', + }; + break; + default: + details = { + color: 'white', + text: rating, + description: ' - Rating information not available', + }; + break; + } + + return details; +} + +async function fetchMovieRatings(imdbId, tmdbMovieData) { + const omdbApiKey = '2ba8e536'; + const omdbUrl = `https://www.omdbapi.com/?i=${imdbId}&apikey=${omdbApiKey}`; + + try { + const response = await fetch(omdbUrl); + const data = await response.json(); + + let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + + if (imdbRating === 'N/A' && tmdbMovieData.vote_average) { + imdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; + } + + const rtRatingObj = data.Ratings.find(rating => rating.Source === 'Rotten Tomatoes'); + let rtRating = rtRatingObj ? rtRatingObj.Value : 'N/A'; + + let metascore = data.Metascore ? `${data.Metascore}/100` : 'N/A'; + let awards = data.Awards; + let rated = data.Rated ? data.Rated : 'Rating information unavailable'; + + if (awards === 'N/A') { + awards = 'No awards information available'; + } + + if (metascore === 'N/A/100') { + const metacriticsRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + metascore = calculateFallbackMetacriticsRating(metacriticsRatingValue, tmdbMovieData.vote_average) + '/100'; + } + + if (rtRating === 'N/A') { + const imdbRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + rtRating = calculateFallbackRTRating(imdbRatingValue, tmdbMovieData.vote_average); + } + populateMovieDetails(tmdbMovieData, imdbRating, rtRating, metascore, awards, rated); + } catch (error) { + console.log('Error fetching movie ratings:', error); + const fallbackImdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; + populateMovieDetails(tmdbMovieData, fallbackImdbRating, 'N/A', 'No metascore information available', 'No awards information available'); + } +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +function calculateFallbackRTRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0) + '%'; // Calculate fallback RT rating out of 100% scale (in case data is not available from OMDB) +} + +function calculateFallbackMetacriticsRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0); // Calculate fallback Metacritics rating out of 100 scale (in case data is not available from OMDB) +} + +let trailerIframeDisplayed = false; + +function createTrailerButton(trailerUrl) { + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + + trailerButton.addEventListener('click', function () { + if (!trailerIframeDisplayed) { + showTrailerIframe(trailerUrl); + trailerButton.textContent = 'Close Trailer'; + trailerButton.title = 'Click to close the trailer'; + } else { + closeTrailerIframe(); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + } + }); + + trailerButton.classList.add('trailer-button'); + trailerButton.style.font = 'inherit'; + + return trailerButton; +} + +function closeTrailerIframe() { + const iframeContainer = document.querySelector('.trailer-button + div'); + + if (iframeContainer) { + iframeContainer.style.height = '0'; + setTimeout(() => iframeContainer.remove(), 500); + } + trailerIframeDisplayed = false; +} + +function getYouTubeVideoId(url) { + const urlObj = new URL(url); + return urlObj.searchParams.get('v'); +} + +function positionTrailerButton() { + if (!trailerButton) return; + + if (window.innerWidth <= 900) { + const movieDescription = document.getElementById('movie-description'); + movieDescription.parentNode.insertBefore(trailerButton, movieDescription); + } else { + const movieRating = document.getElementById('movie-rating'); + movieRating.parentNode.insertBefore(trailerButton, movieRating.nextSibling); + } +} + +document.addEventListener('DOMContentLoaded', positionTrailerButton); + +function showTrailerIframe(trailerUrl) { + trailerUrlGlobal = trailerUrl; + + const iframeContainer = document.createElement('div'); + iframeContainer.style.position = 'relative'; + iframeContainer.style.width = '400px'; + iframeContainer.style.margin = '0 auto'; + iframeContainer.style.overflow = 'hidden'; + iframeContainer.style.height = '0'; + iframeContainer.style.transition = 'height 0.5s ease-in-out'; + + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', `https://www.youtube.com/embed/${getYouTubeVideoId(trailerUrl)}?autoplay=1`); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('height', '315'); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'); + iframe.setAttribute('allowfullscreen', true); + + iframeContainer.appendChild(iframe); + + const trailerButton = document.querySelector('.trailer-button'); + trailerButton.parentNode.insertBefore(iframeContainer, trailerButton.nextSibling); + + setTimeout(() => (iframeContainer.style.height = '315px'), 50); + + trailerIframeDisplayed = true; +} + +function toggleFavorite(movie) { + let favorites = JSON.parse(localStorage.getItem('favorites')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || {}; + + if (favorites.includes(movie.id)) { + favorites = favorites.filter(favId => favId !== movie.id); + movie.genres.forEach(genre => { + favoriteGenres[genre.name] = favoriteGenres[genre.name] ? favoriteGenres[genre.name] - 1 : 0; + }); + } else { + favorites.push(movie.id); + movie.genres.forEach(genre => { + favoriteGenres[genre.name] = favoriteGenres[genre.name] ? favoriteGenres[genre.name] + 1 : 1; + }); + } + + localStorage.setItem('favorites', JSON.stringify(favorites)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + + updateFavoriteButton(movie.id); +} + +function updateFavoriteButton(movieId) { + const favorites = JSON.parse(localStorage.getItem('favorites')) || []; + const favoriteButton = document.getElementById('favorite-btn'); + + if (favorites.includes(movieId)) { + favoriteButton.classList.add('favorited'); + favoriteButton.style.backgroundColor = 'grey'; + favoriteButton.title = 'Remove from favorites'; + } else { + favoriteButton.classList.remove('favorited'); + favoriteButton.style.background = 'transparent'; + favoriteButton.title = 'Add to favorites'; + } +} + +function getRtSlug(title) { + return title + .toLowerCase() + .replace(/:/g, '') + .replace(/part one/g, 'part_1') + .replace(/-/g, '') + .replace(/&/g, 'and') + .replace(/ /g, '_') + .replace(/[^\w-]/g, ''); +} + +function createMetacriticSlug(title) { + return title + .toLowerCase() + .replace(/part\sone/g, 'part-1') + .replace(/:|_|-|\s/g, '-') + .replace(/&/g, 'and') + .replace(/--+/g, '-') + .replace(/[^\w-]/g, ''); +} + +function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, rated) { + document.getElementById('movie-image').src = `https://image.tmdb.org/t/p/w1280${movie.poster_path}`; + document.getElementById('movie-title').textContent = movie.title; + + const movieRating = movie.vote_average.toFixed(1); + const imdbLink = `https://www.imdb.com/title/${movie.imdb_id}`; + + const rtLink = rtRating !== 'N/A' ? `https://www.rottentomatoes.com/m/${getRtSlug(movie.title)}` : '#'; + const metaCriticsLink = metascore !== 'N/A' ? `https://www.metacritic.com/movie/${createMetacriticSlug(movie.title)}` : '#'; + + const ratingDetails = getRatingDetails(rated); + const ratedElement = rated + ? `

Rated: ${ratingDetails.text}${ratingDetails.description}

` + : ''; + + document.getElementById('movie-rating').innerHTML = ` + IMDB Rating: ${imdbRating} + `; + document.getElementById('movie-rating').style.marginTop = '120px'; + document.title = movie.title + ' - Movie Details'; + + const movieImage = document.getElementById('movie-image'); + const movieDescription = document.getElementById('movie-description'); + + const metascoreElement = metascore ? `

Metascore: ${metascore}

` : ''; + const awardsElement = awards ? `

Awards: ${awards}

` : ''; + + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + } else { + movieImage.style.display = 'none'; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.movie-left').appendChild(noImageText); + } + + const fullLanguage = twoLetterLangCodes.find(lang => lang.code === movie.original_language).name; + const overview = movie.overview; + const genres = movie.genres.map(genre => genre.name).join(', '); + const releaseDate = movie.release_date; + + const budget = movie.budget === 0 ? 'Information Not Available' : `$${movie.budget.toLocaleString()}`; + const revenue = movie.revenue <= 1000 ? 'Information Not Available' : `$${movie.revenue.toLocaleString()}`; + const tagline = movie.tagline ? movie.tagline : 'No tagline found'; + const languages = movie.spoken_languages.map(lang => lang.name).join(', '); + + const countries = movie.production_countries.map(country => country.name).join(', '); + const originalLanguage = fullLanguage; + const popularityScore = movie.popularity.toFixed(0); + const status = movie.status; + + const voteCount = movie.vote_count.toLocaleString(); + let keywords = movie.keywords ? movie.keywords.keywords.map(kw => kw.name).join(', ') : 'None Available'; + const similarTitles = movie.similar ? movie.similar.results.map(m => m.title).join(', ') : 'None Available'; + const scaledRating = (movie.vote_average / 2).toFixed(1); + + if (keywords.length === 0) { + keywords = 'None Available'; + } + + const popularityThreshold = 80; + const isPopular = movie.popularity >= popularityThreshold; + const popularityText = isPopular ? `${popularityScore} (This movie is popular)` : `${popularityScore} (This movie is unpopular)`; + + const adultContentIndicator = movie.adult + ? `Adult Content` + : `General Audience`; + + const movieStatus = `

Status: ${movie.status}

`; + + const runtime = movie.runtime > 0 ? movie.runtime + ' minutes' : 'Runtime Info Not Available'; + + document.getElementById('movie-description').innerHTML += ` +

Description: ${overview}

+

Genres: ${genres}

+ ${ratedElement} + ${movieStatus} +

Release Date: ${releaseDate}

+

Runtime: ${runtime}

+

Budget: ${budget}

+

Revenue: ${revenue}

+

Languages: ${languages}

+

Countries of Production: ${countries}

+

Original Language: ${originalLanguage}

+

Popularity Score: ${popularityText}

+

Averaged User Ratings: ${scaledRating}/5.0 (based on ${ + movie.vote_count + } votes)

+ ${awardsElement} + ${metascoreElement} +

Rotten Tomatoes: ${rtRating}

+

Tagline: ${tagline}

+ `; + + if (movie.credits && movie.credits.crew) { + const director = movie.credits.crew.find(member => member.job === 'Director'); + if (director) { + const directorAge = director.birthday ? calculateAge(director.birthday) : 'N/A'; + const directorElement = document.createElement('p'); + directorElement.innerHTML = `Director: ${director.name}`; + directorElement.querySelector('.director-link').addEventListener('click', e => { + e.preventDefault(); + localStorage.setItem('selectedDirectorId', director.id); + document.title = `${director.name} - Director's Details`; + window.location.href = 'director-details.html'; + updateUniqueDirectorsViewed(director.id); + updateDirectorVisitCount(director.id, director.name); + }); + document.getElementById('movie-description').appendChild(directorElement); + } + } + + const castHeading = document.createElement('p'); + castHeading.innerHTML = 'Cast: '; + document.getElementById('movie-description').appendChild(castHeading); + + if (movie.credits && movie.credits.cast.length > 0) { + const topTenCast = movie.credits.cast.slice(0, 10); + topTenCast.forEach((actor, index) => { + const actorLink = document.createElement('span'); + actorLink.textContent = actor.name; + actorLink.classList.add('actor-link'); + actorLink.addEventListener('click', () => { + localStorage.setItem('selectedActorId', actor.id); + window.location.href = 'actor-details.html'; + updateUniqueActorsViewed(actor.id); + updateActorVisitCount(actor.id, actor.name); + }); + + castHeading.appendChild(actorLink); + + if (index < topTenCast.length - 1) { + castHeading.appendChild(document.createTextNode(', ')); + } + }); + } else { + castHeading.appendChild(document.createTextNode('None available.')); + } + + const productionCompanies = movie.production_companies; + const productionCompaniesElement = document.createElement('p'); + productionCompaniesElement.innerHTML = 'Production Companies: '; + + if (productionCompanies.length === 0) { + productionCompaniesElement.innerHTML += 'None available.'; + } + productionCompanies.forEach((company, index) => { + const companyLink = document.createElement('a'); + companyLink.textContent = company.name; + companyLink.style.cursor = 'pointer'; + companyLink.style.textDecoration = 'underline'; + companyLink.href = '#'; + companyLink.classList.add('company-link'); + companyLink.addEventListener('click', e => { + e.preventDefault(); + localStorage.setItem('selectedCompanyId', company.id); + window.location.href = 'company-details.html'; + updateUniqueCompaniesViewed(company.id); + }); + + productionCompaniesElement.appendChild(companyLink); + + if (index < productionCompanies.length - 1) { + productionCompaniesElement.appendChild(document.createTextNode(', ')); + } + }); + + document.getElementById('movie-description').appendChild(productionCompaniesElement); + const similarMoviesHeading = document.createElement('p'); + + similarMoviesHeading.innerHTML = 'Similar Movies: '; + document.getElementById('movie-description').appendChild(similarMoviesHeading); + + if (movie.similar && movie.similar.results.length > 0) { + movie.similar.results.forEach((similarMovie, index) => { + const movieLink = document.createElement('span'); + movieLink.textContent = similarMovie.title; + movieLink.style.cursor = 'pointer'; + movieLink.style.textDecoration = 'underline'; + movieLink.addEventListener('mouseenter', () => { + movieLink.style.color = '#f509d9'; + }); + + movieLink.addEventListener('mouseleave', () => { + movieLink.style.color = getSavedTextColor(); + }); + + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', similarMovie.id); + window.location.href = 'movie-details.html'; + }); + + similarMoviesHeading.appendChild(movieLink); + + if (index < movie.similar.results.length - 1) { + similarMoviesHeading.appendChild(document.createTextNode(', ')); + } + }); + } else { + similarMoviesHeading.appendChild(document.createTextNode('None available.')); + } + + const keywordsElement = document.createElement('p'); + keywordsElement.innerHTML = `Keywords: ${keywords}`; + + movieDescription.appendChild(keywordsElement); + updateFavoriteButton(movie.id); + + favoriteButton.addEventListener('click', () => { + toggleFavorite(movie); + updateMoviesFavorited(movie.id); + window.location.reload(); + }); + + updateMoviesFavorited(movie.id); + applySettings(); +} + +function getSavedTextColor() { + return localStorage.getItem('textColor') || 'white'; +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} + +function updateAverageMovieRating(movieId, newRating) { + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + + let totalRating = 0; + let totalMoviesRated = 0; + + for (let id in savedRatings) { + totalRating += parseFloat(savedRatings[id]); + totalMoviesRated++; + } + let averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1).toString()); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function updateUniqueActorsViewed(actorId) { + let viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + if (!viewedActors.includes(actorId)) { + viewedActors.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(viewedActors)); + } +} + +function updateUniqueCompaniesViewed(companyId) { + let viewedCompanies = JSON.parse(localStorage.getItem('uniqueCompaniesViewed')) || []; + if (!viewedCompanies.includes(companyId)) { + viewedCompanies.push(companyId); + localStorage.setItem('uniqueCompaniesViewed', JSON.stringify(viewedCompanies)); + } +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js new file mode 100644 index 00000000..0628d210 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js @@ -0,0 +1,486 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const searchTitle = document.getElementById('search-title'); + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +let initialMainContent = ''; + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + + const actorId = 6193; + if (actorId) { + fetchActorDetails(actorId); + } else { + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details not found.

+
`; + } + + document.getElementById('clear-search-btn').style.display = 'none'; +}); + +async function fetchActorDetails(actorId) { + const actorUrl = `https://${getMovieVerseData()}/3/person/6193?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/6193/movie_credits?${generateMovieNames()}${getMovieCode()}`; + try { + const [actorResponse, creditsResponse] = await Promise.all([fetch(actorUrl), fetch(creditsUrl)]); + + const actor = await actorResponse.json(); + const credits = await creditsResponse.json(); + if (actor.success === false) { + document.getElementById('actor-details-container').innerHTML = '

No Information is Available for this Actor

'; + } else { + updateBrowserURL(actor.name); + populateActorDetails(actor, credits); + } + } catch (error) { + console.log('Error fetching actor details:', error); + document.getElementById('actor-details-container').innerHTML = '

Error fetching actor details

'; + } +} + +function populateActorDetails(actor, credits) { + const actorImage = document.getElementById('actor-image'); + const actorName = document.getElementById('actor-name'); + const actorDescription = document.getElementById('actor-description'); + + if (actor.profile_path) { + actorImage.src = `https://image.tmdb.org/t/p/w1280${actor.profile_path}`; + actorName.textContent = actor.name; + document.title = `${actor.name} - Actor's Details`; + } else { + actorImage.style.display = 'none'; + actorName.textContent = actor.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.actor-left').appendChild(noImageText); + } + + let ageOrStatus; + if (actor.birthday) { + if (actor.deathday) { + ageOrStatus = calculateAge(actor.birthday, actor.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(actor.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + actorDescription.innerHTML = ` +

Biography: ${actor.biography || 'N/A'}

+

Date of Birth: ${actor.birthday || 'N/A'}

+

Date of Death: ${actor.deathday || 'N/A'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${actor.place_of_birth || 'N/A'}

+

Known For: ${actor.known_for_department || 'N/A'}

+

Height: ${actor.height || 'N/A'}

+ `; + + const gender = document.createElement('div'); + gender.innerHTML = `

Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'N/A'}

`; + actorDescription.appendChild(gender); + + const popularity = document.createElement('div'); + popularity.innerHTML = `

Popularity Score: ${actor.popularity.toFixed(2)}

`; + actorDescription.appendChild(popularity); + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + actorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + credits.cast.forEach(movie => { + const movieLink = document.createElement('span'); + movieLink.textContent = movie.title; + movieLink.classList.add('movie-link'); + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + window.location.href = 'movie-details.html'; + }); + movieList.appendChild(movieLink); + movieList.appendChild(document.createTextNode(', ')); + }); + + filmographyHeading.appendChild(movieList); + applySettings(); +} + +function calculateAge(birthday, deathday = null) { + const birthDate = new Date(birthday); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const diff = referenceDate - birthDate.getTime(); + const ageDate = new Date(diff); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + applySettings(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-details.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-details.js new file mode 100644 index 00000000..dcaa4028 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-details.js @@ -0,0 +1,1902 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w780'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const favoriteButton = document.getElementById('favorite-btn'); +const searchTitle = document.getElementById('search-title'); + +let trailerUrlGlobal; +let initialMainContent; +let trailerButton; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + console.log(genreMap); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let uniqueMoviesViewed = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + + if (!uniqueMoviesViewed.includes(movieId)) { + uniqueMoviesViewed.push(movieId); + } + + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(uniqueMoviesViewed)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +document.addEventListener('DOMContentLoaded', () => { + showSpinner(); + initialMainContent = document.getElementById('main').innerHTML; + currentIndex = 0; + + const movieId = localStorage.getItem('selectedMovieId'); + if (movieId) { + fetchMovieDetails(movieId); + } else { + fetchMovieDetails(1011985); + } + + hideSpinner(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + showSpinner(); + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + hideSpinner(); +}); + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +document.addEventListener('DOMContentLoaded', function () { + applySettings(); +}); + +async function fetchMovieDetails(movieId) { + showSpinner(); + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + const url2 = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=videos`; + + try { + showSpinner(); + const response = await fetch(url); + const movie = await response.json(); + const imdbId = movie.imdb_id; + + fetchMovieRatings(imdbId, movie); + updateBrowserURL(movie.title); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details currently unavailable - please try again

+
`; + console.log('Error fetching movie details:', error); + } finally { + hideSpinner(); + } +} + +function getRatingDetails(rating) { + let details = { color: 'black', text: rating, description: '' }; + + switch (rating) { + case 'R': + details = { + color: 'red', + text: 'R (Restricted)', + description: ' - No one 17 and under admitted', + }; + break; + case 'PG-13': + details = { + color: 'yellow', + text: 'PG-13 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 13', + }; + break; + case 'PG': + details = { + color: 'orange', + text: 'PG (Parental Guidance Suggested)', + description: ' - May not be suitable for children', + }; + break; + case 'G': + details = { + color: 'green', + text: 'G (General Audiences)', + description: ' - All ages admitted', + }; + break; + case 'NC-17': + details = { + color: 'darkred', + text: 'NC-17 (Adults Only)', + description: ' - No one 17 and under admitted', + }; + break; + case 'TV-Y': + details = { + color: 'lightgreen', + text: 'TV-Y (All Children)', + description: ' - Appropriate for all children', + }; + break; + case 'TV-Y7': + details = { + color: 'lightblue', + text: 'TV-Y7 (Directed to Older Children)', + description: ' - Suitable for children ages 7 and up', + }; + break; + case 'TV-G': + details = { + color: 'green', + text: 'TV-G (General Audience)', + description: ' - Suitable for all ages', + }; + break; + case 'TV-PG': + details = { + color: 'orange', + text: 'TV-PG (Parental Guidance Suggested)', + description: ' - May not be suitable for younger children', + }; + break; + case 'TV-14': + details = { + color: 'yellow', + text: 'TV-14 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 14', + }; + break; + case 'TV-MA': + details = { + color: 'red', + text: 'TV-MA (Mature Audience Only)', + description: ' - Specifically designed to be viewed by adults', + }; + break; + case 'NR': + details = { + color: 'white', + text: 'NR (Not Rated)', + description: ' - Movie has not been officially rated', + }; + break; + case 'UR': + case 'Unrated': + details = { + color: 'white', + text: 'UR (Unrated)', + description: ' - Contains content not used in the rated version', + }; + break; + default: + details = { + color: 'white', + text: rating, + description: ' - Rating information not available', + }; + break; + } + + return details; +} + +async function fetchMovieRatings(imdbId, tmdbMovieData) { + showSpinner(); + document.body.offsetHeight; + + const req = [await getMovieCode2(), '58efe859', '60a09d79', '956e468a', 'bd55ada4', 'cbfc076', 'dc091ff2', '6e367eef', '2a2a3080', 'd20a931f']; + const baseURL = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}`; + + async function tryFetch(apiKey) { + const url = `${baseURL}${apiKey}`; + + try { + const response = await fetch(url); + if (!response.ok) throw new Error('API limit reached or other error'); + return await response.json(); + } catch (error) { + return null; + } + } + + async function fetchWithTimeout(apiKey, timeout = 5000) { + return new Promise(resolve => { + const timer = setTimeout(() => resolve(null), timeout); + tryFetch(apiKey) + .then(data => { + clearTimeout(timer); + resolve(data); + }) + .catch(() => { + clearTimeout(timer); + resolve(null); + }); + }); + } + + const requests = req.map(key => fetchWithTimeout(key)); + const responses = await Promise.all(requests); + const data = responses.find(response => response !== null); + + if (!data) { + populateMovieDetails(tmdbMovieData, tmdbMovieData.vote_average, 'N/A', 'View on Metacritics', 'Awards information unavailable'); + return; + } + + let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + if (imdbRating === 'N/A' || imdbRating === '0.0' || imdbRating === null) { + imdbRating = 'N/A'; + } + + let rtRating = 'N/A'; + let metascore = data.Metascore ? `${data.Metascore}/100` : 'N/A'; + let awards = data.Awards; + let rated = data.Rated ? data.Rated : 'Rating information unavailable'; + + if (awards === 'N/A') { + awards = 'Awards information unavailable'; + } + if (metascore === 'N/A/100') { + const metacriticsRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + metascore = calculateFallbackMetacriticsRating(metacriticsRatingValue, tmdbMovieData.vote_average) + '/100'; + } + if (rtRating === 'N/A') { + const imdbRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + rtRating = calculateFallbackRTRating(imdbRatingValue, tmdbMovieData.vote_average); + } + + populateMovieDetails(tmdbMovieData, imdbRating, rtRating, metascore, awards, rated); + hideSpinner(); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +function calculateFallbackRTRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0) + '%'; +} + +function calculateFallbackMetacriticsRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0); +} + +let trailerIframeDisplayed = false; + +function createTrailerButton(trailerUrl) { + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + trailerButton.id = 'trailerButton'; + + trailerButton.addEventListener('click', function () { + if (!trailerIframeDisplayed) { + showTrailerIframe(trailerUrl); + trailerButton.textContent = 'Close Trailer'; + trailerButton.title = 'Click to close the trailer'; + } else { + closeTrailerIframe(); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + } + }); + + trailerButton.classList.add('trailer-button'); + trailerButton.style.font = 'inherit'; + + return trailerButton; +} + +function closeTrailerIframe() { + const iframeContainer = document.querySelector('.trailer-button + div'); + + if (iframeContainer) { + iframeContainer.style.height = '0'; + setTimeout(() => iframeContainer.remove(), 500); + } + trailerIframeDisplayed = false; +} + +function getYouTubeVideoId(url) { + const urlObj = new URL(url); + return urlObj.searchParams.get('v'); +} + +function showTrailerIframe(trailerUrl) { + trailerUrlGlobal = trailerUrl; + + const iframeContainer = document.createElement('div'); + iframeContainer.style.position = 'relative'; + iframeContainer.style.width = '400px'; + iframeContainer.style.margin = '0 auto'; + iframeContainer.style.overflow = 'hidden'; + iframeContainer.style.height = '0'; + iframeContainer.style.transition = 'height 0.5s ease-in-out'; + iframeContainer.style.borderRadius = '8px'; + + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', `https://www.youtube.com/embed/${getYouTubeVideoId(trailerUrl)}?autoplay=1`); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('height', '315'); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'); + iframe.setAttribute('allowfullscreen', true); + + iframeContainer.appendChild(iframe); + + const trailerButton = document.querySelector('.trailer-button'); + trailerButton.parentNode.insertBefore(iframeContainer, trailerButton.nextSibling); + trailerButton.id = 'trailerButton'; + + setTimeout(() => (iframeContainer.style.height = '315px'), 50); + + trailerIframeDisplayed = true; +} + +function getRtSlug(title) { + return title + .toLowerCase() + .replace(/:/g, '') + .replace(/part one/g, 'part_1') + .replace(/-/g, '') + .replace(/&/g, 'and') + .replace(/ /g, '_') + .replace(/[^\w-]/g, ''); +} + +function createMetacriticSlug(title) { + return title + .toLowerCase() + .replace(/part\sone/g, 'part-1') + .replace(/:|_|-|\s/g, '-') + .replace(/&/g, 'and') + .replace(/--+/g, '-') + .replace(/[^\w-]/g, ''); +} + +async function fetchStreamingLinks(movieId) { + const url = `https://${getMovieVerseData()}/3/movie/${movieId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const results = data.results || {}; + let providersMap = {}; + + Object.values(results).forEach(region => { + if (region.flatrate) { + region.flatrate.forEach(provider => { + providersMap[provider.provider_id] = provider; + }); + } + }); + + return Object.values(providersMap).slice(0, 7); + } catch (error) { + console.error('Error fetching streaming links:', error); + } +} + +async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, rated) { + showSpinner(); + document.getElementById('movie-title').textContent = movie.title; + + const imdbLink = `https://www.imdb.com/title/${movie.imdb_id}`; + const streamingProviders = await fetchStreamingLinks(movie.id); + const movieTitleEncoded = encodeURIComponent(movie.title); + + const streamingHTML = + streamingProviders.length > 0 + ? streamingProviders + .map(provider => { + let providerLink; + switch (provider.provider_name.toLowerCase()) { + case 'netflix': + providerLink = `https://www.netflix.com/search?q=${movieTitleEncoded}`; + break; + case 'disney plus': + providerLink = `https://www.disneyplus.com/search?q=${movieTitleEncoded}`; + break; + case 'hbo max': + providerLink = `https://www.hbomax.com/search?q=${movieTitleEncoded}`; + break; + case 'hulu': + providerLink = `https://www.hulu.com/search?q=${movieTitleEncoded}`; + break; + case 'amazon prime video': + providerLink = `https://www.amazon.com/s?k=${movieTitleEncoded}`; + break; + case 'apple tv plus': + providerLink = `https://tv.apple.com/search?term=${movieTitleEncoded}`; + break; + case 'stan': + providerLink = `https://www.stan.com.au/search?q=${movieTitleEncoded}`; + break; + case 'player': + providerLink = `https://player.pl/szukaj?search=${movieTitleEncoded}`; + break; + default: + providerLink = `https://www.google.com/search?q=watch+${movieTitleEncoded}+on+${encodeURIComponent(provider.provider_name)}`; + break; + } + + return ``; + }) + .join('') + + `` + : 'No streaming options available.'; + + const metaCriticsLink = metascore !== 'N/A' ? `https://www.metacritic.com/search/${createMetacriticSlug(movie.title)}` : '#'; + const ratingDetails = getRatingDetails(rated); + const ratedElement = rated + ? `

Rated: ${ratingDetails.text}${ratingDetails.description}

` + : ''; + + document.getElementById('movie-rating').innerHTML = ``; + document.title = movie.title + ' - Movie Details'; + + const movieDescription = document.getElementById('movie-description'); + const metascoreElement = metascore + ? `

Metascore: ${metascore}

` + : ''; + const awardsElement = awards ? `

Awards: ${awards}

` : ''; + + const overview = movie.overview ? movie.overview : 'No overview available'; + const genres = movie.genres.map(genre => genre.name).join(', '); + + const releaseDate = movie.release_date || 'Release date not available'; + const releaseDateObj = new Date(releaseDate); + const currentDate = new Date(); + + let timeAgoString = ''; + if (releaseDateObj > currentDate) { + timeAgoString = '0 months'; + } else { + const timeDiff = currentDate - releaseDateObj; + let years = Math.floor(timeDiff / (1000 * 60 * 60 * 24 * 365.25)); + let remainingMonths = Math.round((timeDiff % (1000 * 60 * 60 * 24 * 365.25)) / (1000 * 60 * 60 * 24 * 30.44)); + + if (remainingMonths >= 12) { + years += 1; + remainingMonths -= 12; + } + if (years > 0) { + timeAgoString += `${years} year${years > 1 ? 's' : ''}`; + if (remainingMonths > 0) { + timeAgoString += ` and `; + } + } + if (remainingMonths > 0 || years === 0) { + timeAgoString += `${remainingMonths} month${remainingMonths > 1 ? 's' : ''}`; + } + } + + const releaseDateWithTimeAgo = `${releaseDate} (${timeAgoString} ago)`; + const budget = movie.budget === 0 ? 'Information Not Available' : `$${movie.budget.toLocaleString()}`; + const revenue = movie.revenue <= 1000 ? 'Information Not Available' : `$${movie.revenue.toLocaleString()}`; + const tagline = movie.tagline ? movie.tagline : 'No tagline found'; + const languages = movie.spoken_languages.map(lang => lang.name).join(', '); + + const countries = movie.production_countries.map(country => country.name).join(', '); + const popularityScore = movie.popularity.toFixed(0); + + let keywords = movie.keywords + ? movie.keywords.keywords + .map( + kw => `${kw.name}` + ) + .join(', ') + : 'None Available'; + + if (keywords.length === 0) { + keywords = 'No keywords have been added'; + } + + const scaledRating = (movie.vote_average / 2).toFixed(1); + const popularityThreshold = 80; + const isPopular = movie.popularity >= popularityThreshold; + const popularityText = isPopular + ? `${popularityScore} (This movie is popular)` + : `${popularityScore} (This movie is unpopular)`; + + const movieStatus = `

Status: ${movie.status}

`; + const runtime = movie.runtime > 0 ? movie.runtime + ' minutes' : 'Runtime Info Not Available'; + + const originalTitle = + movie.original_title !== movie.title + ? `

Original Title: ${movie.original_title}

` + : `

Original Title: ${movie.title}

`; + const tmdbRating = movie.vote_average.toFixed(1); + + document.getElementById('movie-description').innerHTML += ` +

Description: ${overview}

+ ${originalTitle} +

Tagline: ${tagline}

+

Genres: ${genres}

+ ${ratedElement} + ${movieStatus} +

Release Date: ${releaseDateWithTimeAgo}

+

Runtime: ${runtime}

+

Budget: ${budget}

+

Revenue: ${revenue}

+

Languages: ${languages}

+

Countries of Production: ${countries}

+

Popularity Score: ${popularityText}

+

MovieVerse User Rating: ${scaledRating}/5.0 (based on ${ + movie.vote_count + } votes)

+ ${awardsElement} +

TMDb Rating: ${tmdbRating}/10.0

+ ${metascoreElement} + `; + + if (movie.credits && movie.credits.crew) { + const directors = movie.credits.crew.filter(member => member.job === 'Director'); + + if (directors.length > 0) { + const directorSection = document.createElement('div'); + directorSection.classList.add('director-section'); + directorSection.style.textAlign = 'center'; + + const directorTitle = document.createElement('p'); + directorTitle.innerHTML = 'Director:'; + directorTitle.style.padding = '0'; + directorSection.appendChild(directorTitle); + + const directorList = document.createElement('div'); + directorList.classList.add('director-list'); + + directors.forEach(director => { + const directorLink = document.createElement('a'); + directorLink.classList.add('director-link'); + directorLink.href = 'javascript:void(0);'; + directorLink.style.textDecoration = 'none'; + directorLink.setAttribute('onclick', `handleDirectorClick(${director.id}, '${director.name.replace(/'/g, "\\'")}');`); + + const directorItem = document.createElement('div'); + directorItem.classList.add('cast-item'); + + const directorImage = document.createElement('img'); + directorImage.classList.add('cast-image'); + + if (director.profile_path) { + directorImage.src = IMGPATH2 + director.profile_path; + directorImage.alt = `${director.name} Profile Picture`; + } else { + directorImage.alt = 'Image Not Available'; + directorImage.src = 'https://movie-verse.com/images/user-default.png'; + directorImage.style.filter = 'grayscale(100%)'; + directorImage.style.objectFit = 'cover'; + } + + directorItem.appendChild(directorImage); + + const directorDetails = document.createElement('div'); + directorDetails.classList.add('cast-details'); + + const directorName = document.createElement('p'); + directorName.classList.add('actor-name'); + directorName.textContent = director.name; + directorDetails.appendChild(directorName); + + directorItem.appendChild(directorDetails); + directorLink.appendChild(directorItem); + directorList.appendChild(directorLink); + }); + + directorSection.appendChild(directorList); + document.getElementById('movie-description').appendChild(directorSection); + } else { + const noDirectorsElement = document.createElement('p'); + noDirectorsElement.innerHTML = `Director: Information not available`; + document.getElementById('movie-description').appendChild(noDirectorsElement); + } + } + + const castSection = document.createElement('div'); + castSection.classList.add('cast-section'); + + const castTitle = document.createElement('p'); + castTitle.innerHTML = 'Notable Cast:'; + castSection.appendChild(castTitle); + + if (movie.credits && movie.credits.cast.length > 0) { + const castList = document.createElement('div'); + castList.classList.add('cast-list'); + castList.style.display = 'flex'; + castList.style.flexWrap = 'wrap'; + castList.style.justifyContent = 'center'; + castList.style.gap = '3px'; + const topTwelveCast = movie.credits.cast.slice(0, 12); + + topTwelveCast.forEach(actor => { + const castItemLink = document.createElement('a'); + castItemLink.classList.add('actor-link'); + castItemLink.href = 'javascript:void(0);'; + castItemLink.setAttribute('onclick', `selectActorId(${actor.id}, '${actor.name.replace(/'/g, "\\'")}');`); + + const castItem = document.createElement('div'); + castItem.classList.add('cast-item'); + + const actorImage = document.createElement('img'); + actorImage.classList.add('cast-image'); + + if (actor.profile_path) { + actorImage.src = IMGPATH2 + actor.profile_path; + actorImage.alt = `${actor.name} Profile Picture`; + } else { + actorImage.alt = 'Image Not Available'; + actorImage.src = 'https://movie-verse.com/images/user-default.png'; + actorImage.style.filter = 'grayscale(100%)'; + actorImage.style.objectFit = 'cover'; + } + + castItem.appendChild(actorImage); + + const actorDetails = document.createElement('div'); + actorDetails.classList.add('cast-details'); + + const actorName = document.createElement('p'); + actorName.classList.add('actor-name'); + actorName.textContent = actor.name; + actorDetails.appendChild(actorName); + + const character = actor.character ? ` (as ${actor.character})` : ''; + const actorRole = document.createElement('p'); + actorRole.classList.add('actor-role'); + actorRole.textContent = character; + actorDetails.appendChild(actorRole); + + castItem.appendChild(actorDetails); + castItemLink.appendChild(castItem); + castList.appendChild(castItemLink); + }); + + castSection.appendChild(castList); + } else { + castSection.appendChild(document.createTextNode('None available.')); + } + + document.getElementById('movie-description').appendChild(castSection); + + if (movie.similar && movie.similar.results && movie.similar.results.length > 0) { + const similarMoviesSection = document.createElement('div'); + similarMoviesSection.classList.add('similar-movies-section'); + + const similarMoviesTitle = document.createElement('p'); + similarMoviesTitle.innerHTML = 'Similar Movies:'; + similarMoviesSection.appendChild(similarMoviesTitle); + + const similarMoviesList = document.createElement('div'); + similarMoviesList.classList.add('similar-movies-list'); + similarMoviesList.style.display = 'flex'; + similarMoviesList.style.flexWrap = 'wrap'; + similarMoviesList.style.justifyContent = 'center'; + similarMoviesList.style.gap = '3px'; + + let topTenSimilarMovies = movie.similar.results; + topTenSimilarMovies = topTenSimilarMovies.sort((a, b) => b.popularity - a.popularity); + topTenSimilarMovies = topTenSimilarMovies.slice(0, 18); + topTenSimilarMovies.forEach(similarMovie => { + const similarMovieLink = document.createElement('a'); + similarMovieLink.classList.add('similar-movie-link'); + similarMovieLink.href = 'javascript:void(0);'; + similarMovieLink.setAttribute('onclick', `handleSimilarMovieClick(${similarMovie.id}, '${similarMovie.title.replace(/'/g, "\\'")}');`); + + const similarMovieItem = document.createElement('div'); + similarMovieItem.classList.add('cast-item'); + + const similarMovieImage = document.createElement('img'); + similarMovieImage.classList.add('cast-image'); + + if (similarMovie.poster_path) { + similarMovieImage.src = IMGPATH2 + similarMovie.poster_path; + similarMovieImage.alt = `${similarMovie.title} Poster`; + similarMovieImage.style.objectFit = 'fill'; + } else { + similarMovieImage.alt = 'Image Not Available'; + similarMovieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + similarMovieImage.style.filter = 'grayscale(100%)'; + similarMovieImage.style.objectFit = 'cover'; + } + + similarMovieItem.appendChild(similarMovieImage); + + const similarMovieDetails = document.createElement('div'); + similarMovieDetails.classList.add('cast-details'); + + const similarMovieTitle = document.createElement('p'); + similarMovieTitle.classList.add('actor-name'); + similarMovieTitle.textContent = similarMovie.title; + similarMovieDetails.appendChild(similarMovieTitle); + + similarMovieItem.appendChild(similarMovieDetails); + similarMovieLink.appendChild(similarMovieItem); + similarMoviesList.appendChild(similarMovieLink); + }); + + similarMoviesSection.appendChild(similarMoviesList); + document.getElementById('movie-description').appendChild(similarMoviesSection); + } else { + const noSimilarMoviesElement = document.createElement('p'); + noSimilarMoviesElement.innerHTML = `Similar Movies: None available`; + document.getElementById('movie-description').appendChild(noSimilarMoviesElement); + } + + if (movie.production_companies && movie.production_companies.length > 0) { + const companiesSection = document.createElement('div'); + companiesSection.classList.add('companies-section'); + + const companiesTitle = document.createElement('p'); + companiesTitle.innerHTML = 'Production Companies:'; + companiesSection.appendChild(companiesTitle); + + const companiesList = document.createElement('div'); + companiesList.classList.add('companies-list'); + companiesList.style.display = 'flex'; + companiesList.style.flexWrap = 'wrap'; + companiesList.style.justifyContent = 'center'; + companiesList.style.gap = '5px'; + + let productionCompanies = movie.production_companies.slice(0, 6); + + productionCompanies.forEach(company => { + const companyLink = document.createElement('a'); + companyLink.classList.add('company-link'); + companyLink.href = 'javascript:void(0);'; + companyLink.setAttribute('onclick', `handleCompanyClick(${company.id}, '${company.name.replace(/'/g, "\\'")}');`); + + const companyItem = document.createElement('div'); + companyItem.classList.add('company-item'); + + const companyLogo = document.createElement('img'); + companyLogo.classList.add('company-logo'); + + const IMGPATH3 = 'https://image.tmdb.org/t/p/w300'; + + if (company.logo_path) { + companyLogo.src = IMGPATH3 + company.logo_path; + companyLogo.alt = `${company.name} Logo`; + companyLogo.style.backgroundColor = 'white'; + } else { + companyLogo.alt = 'Logo Not Available'; + companyLogo.src = 'https://movie-verse.com/images/company-default.png'; + companyLogo.style.filter = 'grayscale(100%)'; + companyLogo.style.objectFit = 'cover'; + } + + companyItem.appendChild(companyLogo); + + const companyDetails = document.createElement('div'); + companyDetails.classList.add('company-details'); + + const companyName = document.createElement('p'); + companyName.classList.add('company-name'); + companyName.textContent = company.name; + companyDetails.appendChild(companyName); + + companyItem.appendChild(companyDetails); + companyLink.appendChild(companyItem); + companiesList.appendChild(companyLink); + }); + + companiesSection.appendChild(companiesList); + document.getElementById('movie-description').appendChild(companiesSection); + } else { + const noCompaniesElement = document.createElement('p'); + noCompaniesElement.innerHTML = `Production Companies: Information not available`; + document.getElementById('movie-description').appendChild(noCompaniesElement); + } + + document.getElementById('movie-description').innerHTML += ` +

Streaming Options: ${streamingHTML}

`; + + const homepage = document.createElement('p'); + homepage.innerHTML = movie.homepage + ? `Homepage: Visit homepage` + : `Homepage: Information unavailable`; + movieDescription.appendChild(homepage); + + const keywordsElement = document.createElement('p'); + keywordsElement.innerHTML = `Keywords: ${keywords}`; + movieDescription.appendChild(keywordsElement); + + createImdbRatingCircle(imdbRating, imdbLink); + + const mediaUrl = `https://${getMovieVerseData()}/3/movie/${movie.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + const mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 90vw; + max-width: 450px; + margin: 20px auto; + overflow: hidden; + box-sizing: border-box; + border-radius: 16px; + `; + + const mediaTitle = document.createElement('p'); + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + const imageWrapper = document.createElement('div'); + imageWrapper.style = ` + width: 100%; + max-height: 210px; + border-radius: 16px; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + position: relative; + `; + + const imageElement = document.createElement('img'); + imageElement.style = ` + width: 100%; + height: auto; + transition: opacity 0.5s ease-in-out; + opacity: 1; + cursor: pointer; + object-fit: contain; + border-radius: 16px; + `; + + imageWrapper.appendChild(imageElement); + mediaContainer.appendChild(imageWrapper); + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Movie Image + + × +
+ `; + + document.body.insertAdjacentHTML('beforeend', modalHtml); + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const prevButton = document.createElement('button'); + prevButton.innerHTML = ''; + prevButton.style = ` + position: absolute; + left: 5px; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + z-index: 10; + `; + prevButton.onmouseover = () => (prevButton.style.backgroundColor = '#ff8623'); + prevButton.onmouseout = () => (prevButton.style.backgroundColor = '#7378c5'); + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + imageWrapper.appendChild(prevButton); + + const nextButton = document.createElement('button'); + nextButton.innerHTML = ''; + nextButton.style = ` + position: absolute; + right: 5px; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + z-index: 10; + `; + nextButton.onmouseover = () => (nextButton.style.backgroundColor = '#ff8623'); + nextButton.onmouseout = () => (nextButton.style.backgroundColor = '#7378c5'); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + imageWrapper.appendChild(nextButton); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + const movieImage = document.getElementById('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + movieImage.loading = 'lazy'; + } else { + const noImageContainer = document.createElement('div'); + noImageContainer.id = 'no-image-container'; + noImageContainer.style.textAlign = 'center'; + + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageContainer.appendChild(noImageText); + + if (movieImage.parentNode) { + movieImage.parentNode.replaceChild(noImageContainer, movieImage); + } else { + document.body.appendChild(noImageContainer); + } + } + + const movieId = movie.id; + const code = `${getMovieCode()}`; + const url2 = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=videos`; + + try { + const response2 = await fetch(url2); + const movie2 = await response2.json(); + const trailers = movie2.videos.results.filter(video => video.type === 'Trailer'); + + if (trailers.length > 0) { + const trailerUrl = `https://www.youtube.com/watch?v=${trailers[0].key}`; + trailerButton = createTrailerButton(trailerUrl); + detailsContainer.appendChild(trailerButton); + } + + updateBrowserURL(movie.title); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details not found - Try again with a different movie

+
`; + console.log('Error fetching movie details:', error); + } + + hideSpinner(); +} + +function createImdbRatingCircle(imdbRating, imdbId) { + if (imdbRating === 'N/A' || imdbRating === null || imdbRating === undefined) { + imdbRating = 'N/A'; + } else { + imdbRating = parseFloat(imdbRating); + if (!isNaN(imdbRating)) { + imdbRating = imdbRating.toFixed(1); + } else { + imdbRating = 'N/A'; + } + } + + let circleContainer = document.getElementById('imdbRatingCircleContainer'); + if (!circleContainer) { + circleContainer = document.createElement('div'); + circleContainer.id = 'imdbRatingCircleContainer'; + circleContainer.className = 'progress-container'; + const imdbLink = `${imdbId}`; + circleContainer.innerHTML = ` + +
IMDb Rating
+
+ + + + ${imdbRating} + + `; + + if (imdbRating === 'N/A') { + circleContainer.innerHTML += `

Rating information currently unavailable

`; + } + + document.getElementById('movie-description').appendChild(circleContainer); + } else { + const text = document.getElementById('imdbRatingText'); + text.textContent = `${imdbRating}`; + } + + const circle = circleContainer.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); +} + +function setProgress(circle, text, rating) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (rating / 10) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', rating <= 5 ? '#FF0000' : rating >= 7.5 ? '#4CAF50' : '#2196F3'); + text.textContent = `${rating}`; + }, 10); +} + +function retriggerAnimation(imdbRating) { + const circle = document.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); +} + +function getSavedTextColor() { + return localStorage.getItem('textColor') || 'white'; +} + +function handleKeywordClick(keyword) { + localStorage.setItem('searchQuery', keyword); + window.location.href = 'search.html'; +} + +function handleActorClick(actorId, actorName) { + selectActorId(actorId, actorName); +} + +function handleDirectorClick(directorId, directorName) { + localStorage.setItem('selectedDirectorId', directorId); + document.title = `${directorName} - Director's Details`; + updateUniqueDirectorsViewed(directorId); + updateDirectorVisitCount(directorId, directorName); + window.location.href = 'director-details.html'; +} + +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + localStorage.setItem('selectedActorId', actorId); + window.location.href = 'actor-details.html'; +} + +function handleCompanyClick(companyId, companyName) { + localStorage.setItem('selectedCompanyId', companyId); + document.title = `${companyName} - Company Details`; + window.location.href = 'company-details.html'; + updateUniqueCompaniesViewed(companyId); +} + +function handleSimilarMovieClick(movieId, movieTitle) { + localStorage.setItem('selectedMovieId', movieId); + document.title = `${movieTitle} - Movie Details`; + window.location.href = 'movie-details.html'; + updateMovieVisitCount(movieId, movieTitle); +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} + +function getMovieCode2() { + const codeOfMovie = 'MmJhOGU1MzY='; + return atob(codeOfMovie); +} + +function getMovieName() { + const moviename = 'YXBpa2V5PQ=='; + return atob(moviename); +} + +function getMovieActor() { + const actor = 'd3d3Lm9tZGJhcGkuY29t'; + return atob(actor); +} + +function updateAverageMovieRating(movieId, newRating) { + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + + let totalRating = 0; + let totalMoviesRated = 0; + + for (let id in savedRatings) { + totalRating += parseFloat(savedRatings[id]); + totalMoviesRated++; + } + let averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1).toString()); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + fallbackMovieSelection(); + } +} + +function updateUniqueActorsViewed(actorId) { + let viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + if (!viewedActors.includes(actorId)) { + viewedActors.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(viewedActors)); + } +} + +function updateUniqueCompaniesViewed(companyId) { + let viewedCompanies = JSON.parse(localStorage.getItem('uniqueCompaniesViewed')) || []; + if (!viewedCompanies.includes(companyId)) { + viewedCompanies.push(companyId); + localStorage.setItem('uniqueCompaniesViewed', JSON.stringify(viewedCompanies)); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-match.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-match.js new file mode 100644 index 00000000..069f5c82 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-match.js @@ -0,0 +1,1378 @@ +const main = document.getElementById('movie-match-form'); +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const searchTitle = document.getElementById('search-title'); +const otherTitle = document.getElementById('other1'); + +document.getElementById('movie-match-form').addEventListener('submit', function (event) { + event.preventDefault(); + const mood = document.getElementById('mood').value; + const genre = document.getElementById('genre').value; + const period = document.getElementById('period').value; + findMovieMatch(mood, genre, period); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://api.themoviedb.org/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function findMovieMatch(mood, genre, period) { + const movieDatabase = [ + // Movies starting with the mood "happy" + { + id: '432413', + title: 'The Avengers', + mood: 'happy', + genre: 'action', + period: '2010s', + }, + { + id: '299534', + title: 'Avengers: Endgame', + mood: 'happy', + genre: 'action', + period: '2020s', + }, + { + id: '1726', + title: 'Iron Man', + mood: 'happy', + genre: 'action', + period: '2000s', + }, + { + id: '562', + title: 'Die Hard', + mood: 'happy', + genre: 'action', + period: '90s', + }, + { + id: '89', + title: 'Indiana Jones and the Last Crusade', + mood: 'happy', + genre: 'action', + period: '80s', + }, + + { + id: '620', + title: 'Ghostbusters', + mood: 'happy', + genre: 'comedy', + period: '80s', + }, + { + id: '105', + title: 'Back to the Future', + mood: 'happy', + genre: 'comedy', + period: '90s', + }, + { + id: '18785', + title: 'The Hangover', + mood: 'happy', + genre: 'comedy', + period: '2000s', + }, + { + id: '284053', + title: 'Thor: Ragnarok', + mood: 'happy', + genre: 'comedy', + period: '2010s', + }, + { + id: '515001', + title: 'Jojo Rabbit', + mood: 'happy', + genre: 'comedy', + period: '2020s', + }, + + { + id: '773', + title: 'Little Miss Sunshine', + mood: 'happy', + genre: 'drama', + period: '2000s', + }, + { + id: '1402', + title: 'The Pursuit of Happyness', + mood: 'happy', + genre: 'drama', + period: '2010s', + }, + { + id: '508442', + title: 'Soul', + mood: 'happy', + genre: 'drama', + period: '2020s', + }, + { + id: '489', + title: 'Good Will Hunting', + mood: 'happy', + genre: 'drama', + period: '90s', + }, + { + id: '207', + title: 'Dead Poets Society', + mood: 'happy', + genre: 'drama', + period: '80s', + }, + + { + id: '118340', + title: 'Guardians of the Galaxy', + mood: 'happy', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '607', + title: 'Men in Black', + mood: 'happy', + genre: 'sci-fi', + period: '90s', + }, + { + id: '601', + title: 'E.T. the Extra-Terrestrial', + mood: 'happy', + genre: 'sci-fi', + period: '80s', + }, + { + id: '333339', + title: 'Ready Player One', + mood: 'happy', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '438631', + title: 'Dune', + mood: 'happy', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '50646', + title: 'Crazy Stupid Love', + mood: 'happy', + genre: 'romance', + period: '2010s', + }, + { + id: '1581', + title: 'The Holiday', + mood: 'happy', + genre: 'romance', + period: '2000s', + }, + { + id: '114', + title: 'Pretty Woman', + mood: 'happy', + genre: 'romance', + period: '90s', + }, + { + id: '2028', + title: 'Say Anything...', + mood: 'happy', + genre: 'romance', + period: '80s', + }, + { + id: '614409', + title: 'To All the Boys: Always and Forever', + mood: 'happy', + genre: 'romance', + period: '2020s', + }, + + // Movies starting with the mood "sad" + { + id: '424', + title: "Schindler's List", + mood: 'sad', + genre: 'drama', + period: '90s', + }, + { + id: '334541', + title: 'Manchester by the Sea', + mood: 'sad', + genre: 'drama', + period: '2010s', + }, + { + id: '4148', + title: 'Revolutionary Road', + mood: 'sad', + genre: 'drama', + period: '2000s', + }, + { + id: '16619', + title: 'Ordinary People', + mood: 'sad', + genre: 'drama', + period: '80s', + }, + { + id: '1135095', + title: 'Pieces of a Woman', + mood: 'sad', + genre: 'drama', + period: '2020s', + }, + + { + id: '38', + title: 'Eternal Sunshine of the Spotless Mind', + mood: 'sad', + genre: 'romance', + period: '2000s', + }, + { + id: '46705', + title: 'Blue Valentine', + mood: 'sad', + genre: 'romance', + period: '2010s', + }, + { + id: '222935', + title: 'The Fault in Our Stars', + mood: 'sad', + genre: 'romance', + period: '2010s', + }, + { + id: '142', + title: 'Brokeback Mountain', + mood: 'sad', + genre: 'romance', + period: '2000s', + }, + { + id: '589049', + title: 'The Photograph', + mood: 'sad', + genre: 'romance', + period: '2020s', + }, + + { + id: '335984', + title: 'Blade Runner 2049', + mood: 'sad', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '644', + title: 'A.I. Artificial Intelligence', + mood: 'sad', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '152601', + title: 'Her', + mood: 'sad', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '9426', + title: 'The Fly', + mood: 'sad', + genre: 'sci-fi', + period: '80s', + }, + { + id: '419704', + title: 'Ad Astra', + mood: 'sad', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '637', + title: 'Life Is Beautiful', + mood: 'sad', + genre: 'comedy', + period: '90s', + }, + { + id: '9428', + title: 'The Royal Tenenbaums', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '153', + title: 'Lost in Translation', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '9675', + title: 'Sideways', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '7326', + title: 'Juno', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + + { + id: '263115', + title: 'Logan', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '70', + title: 'Million Dollar Baby', + mood: 'sad', + genre: 'action', + period: '2000s', + }, + { + id: '49026', + title: 'The Dark Knight Rises', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '475557', + title: 'Joker', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '98', + title: 'Gladiator', + mood: 'sad', + genre: 'action', + period: '2000s', + }, + + // Movies starting with the mood "adventurous" + { + id: '85', + title: 'Indiana Jones and the Raiders of the Lost Ark', + mood: 'adventurous', + genre: 'action', + period: '80s', + }, + { + id: '76341', + title: 'Mad Max: Fury Road', + mood: 'adventurous', + genre: 'action', + period: '2010s', + }, + { + id: '98', + title: 'Gladiator', + mood: 'adventurous', + genre: 'action', + period: '2000s', + }, + { + id: '562', + title: 'Die Hard', + mood: 'adventurous', + genre: 'action', + period: '90s', + }, + { + id: '438631', + title: 'Dune', + mood: 'adventurous', + genre: 'action', + period: '2020s', + }, + + { + id: '620', + title: 'Ghostbusters', + mood: 'adventurous', + genre: 'comedy', + period: '80s', + }, + { + id: '353486', + title: 'Jumanji: Welcome to the Jungle', + mood: 'adventurous', + genre: 'comedy', + period: '2010s', + }, + { + id: '22', + title: 'Pirates of the Caribbean', + mood: 'adventurous', + genre: 'comedy', + period: '2000s', + }, + { + id: '607', + title: 'Men in Black', + mood: 'adventurous', + genre: 'comedy', + period: '90s', + }, + { + id: '550988', + title: 'Free Guy', + mood: 'adventurous', + genre: 'comedy', + period: '2020s', + }, + + { + id: '281957', + title: 'The Revenant', + mood: 'adventurous', + genre: 'drama', + period: '2010s', + }, + { + id: '8358', + title: 'Cast Away', + mood: 'adventurous', + genre: 'drama', + period: '2000s', + }, + { + id: '947', + title: 'Lawrence of Arabia', + mood: 'adventurous', + genre: 'drama', + period: '80s', + }, + { + id: '13', + title: 'Forrest Gump', + mood: 'adventurous', + genre: 'drama', + period: '90s', + }, + { + id: '581734', + title: 'Nomadland', + mood: 'adventurous', + genre: 'drama', + period: '2020s', + }, + + { + id: '11', + title: 'Star Wars', + mood: 'adventurous', + genre: 'sci-fi', + period: '80s', + }, + { + id: '19995', + title: 'Avatar', + mood: 'adventurous', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '27205', + title: 'Inception', + mood: 'adventurous', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '335984', + title: 'Blade Runner', + mood: 'adventurous', + genre: 'sci-fi', + period: '90s', + }, + { + id: '438631', + title: 'Dune', + mood: 'adventurous', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '2493', + title: 'The Princess Bride', + mood: 'adventurous', + genre: 'romance', + period: '80s', + }, + { + id: '313369', + title: 'La La Land', + mood: 'adventurous', + genre: 'romance', + period: '2010s', + }, + { + id: '24420', + title: "The Time Traveler's Wife", + mood: 'adventurous', + genre: 'romance', + period: '2000s', + }, + { + id: '597', + title: 'Titanic', + mood: 'adventurous', + genre: 'romance', + period: '90s', + }, + { + id: '672647', + title: 'The Map of Tiny Perfect Things', + mood: 'adventurous', + genre: 'romance', + period: '2020s', + }, + + // Movies starting with the mood "romantic" + { + id: '11036', + title: 'The Notebook', + mood: 'romantic', + genre: 'drama', + period: '2000s', + }, + { + id: '332562', + title: 'A Star is Born', + mood: 'romantic', + genre: 'drama', + period: '2010s', + }, + { + id: '4348', + title: 'Pride and Prejudice', + mood: 'romantic', + genre: 'drama', + period: '2000s', + }, + { + id: '289', + title: 'Casablanca', + mood: 'romantic', + genre: 'drama', + period: 'classic', + }, + { + id: '398818', + title: 'Call Me by Your Name', + mood: 'romantic', + genre: 'drama', + period: '2010s', + }, + + { + id: '194', + title: 'Amélie', + mood: 'romantic', + genre: 'romance', + period: '2000s', + }, + { + id: '313369', + title: 'La La Land', + mood: 'romantic', + genre: 'romance', + period: '2010s', + }, + { + id: '76', + title: 'Before Sunrise', + mood: 'romantic', + genre: 'romance', + period: '90s', + }, + { + id: '416477', + title: 'The Big Sick', + mood: 'romantic', + genre: 'romance', + period: '2010s', + }, + { + id: '531428', + title: 'Portrait of a Lady on Fire', + mood: 'romantic', + genre: 'romance', + period: '2020s', + }, + + { + id: '152601', + title: 'Her', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '38050', + title: 'The Adjustment Bureau', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '38', + title: 'Eternal Sunshine of the Spotless Mind', + mood: 'romantic', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '274870', + title: 'Passengers', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '122906', + title: 'About Time', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + + { + id: '639', + title: 'When Harry Met Sally', + mood: 'romantic', + genre: 'comedy', + period: '80s', + }, + { + id: '455207', + title: 'Crazy Rich Asians', + mood: 'romantic', + genre: 'comedy', + period: '2010s', + }, + { + id: '509', + title: 'Notting Hill', + mood: 'romantic', + genre: 'comedy', + period: '90s', + }, + { + id: '4951', + title: '10 Things I Hate About You', + mood: 'romantic', + genre: 'comedy', + period: '90s', + }, + { + id: '18240', + title: 'The Proposal', + mood: 'romantic', + genre: 'comedy', + period: '2000s', + }, + + { + id: '787', + title: 'Mr. & Mrs. Smith', + mood: 'romantic', + genre: 'action', + period: '2000s', + }, + { + id: '36955', + title: 'True Lies', + mood: 'romantic', + genre: 'action', + period: '90s', + }, + { + id: '10529', + title: 'Outlander', + mood: 'romantic', + genre: 'action', + period: '2000s', + }, + { + id: '2493', + title: 'The Princess Bride', + mood: 'romantic', + genre: 'action', + period: '80s', + }, + { + id: '547016', + title: 'The Old Guard', + mood: 'romantic', + genre: 'action', + period: '2020s', + }, + + // Movies starting with the mood "scary" + { + id: '493922', + title: 'Hereditary', + mood: 'scary', + genre: 'drama', + period: '2010s', + }, + { + id: '274', + title: 'The Silence of the Lambs', + mood: 'scary', + genre: 'drama', + period: '90s', + }, + { + id: '539', + title: 'Psycho', + mood: 'scary', + genre: 'drama', + period: 'classic', + }, + { + id: '44214', + title: 'Black Swan', + mood: 'scary', + genre: 'drama', + period: '2000s', + }, + { + id: '503919', + title: 'The Lighthouse', + mood: 'scary', + genre: 'drama', + period: '2020s', + }, + + { + id: '310131', + title: 'The Witch', + mood: 'scary', + genre: 'horror', + period: '2010s', + }, + { + id: '694', + title: 'The Shining', + mood: 'scary', + genre: 'horror', + period: '80s', + }, + { + id: '377', + title: 'A Nightmare on Elm Street', + mood: 'scary', + genre: 'horror', + period: '80s', + }, + { + id: '419430', + title: 'Get Out', + mood: 'scary', + genre: 'horror', + period: '2010s', + }, + { + id: '565', + title: 'The Ring', + mood: 'scary', + genre: 'horror', + period: '2000s', + }, + + { + id: '8413', + title: 'Event Horizon', + mood: 'scary', + genre: 'sci-fi', + period: '90s', + }, + { + id: '348', + title: 'Alien', + mood: 'scary', + genre: 'sci-fi', + period: '80s', + }, + { + id: '300668', + title: 'Annihilation', + mood: 'scary', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '447332', + title: 'A Quiet Place', + mood: 'scary', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '443791', + title: 'Underwater', + mood: 'scary', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '747', + title: 'Shaun of the Dead', + mood: 'scary', + genre: 'comedy', + period: '2000s', + }, + { + id: '19908', + title: 'Zombieland', + mood: 'scary', + genre: 'comedy', + period: '2000s', + }, + { + id: '4011', + title: 'Beetlejuice', + mood: 'scary', + genre: 'comedy', + period: '80s', + }, + { + id: '22970', + title: 'The Cabin in the Woods', + mood: 'scary', + genre: 'comedy', + period: '2010s', + }, + { + id: '425909', + title: 'Ghostbusters: Afterlife', + mood: 'scary', + genre: 'comedy', + period: '2020s', + }, + + { + id: '72190', + title: 'World War Z', + mood: 'scary', + genre: 'action', + period: '2010s', + }, + { + id: '6479', + title: 'I Am Legend', + mood: 'scary', + genre: 'action', + period: '2000s', + }, + { + id: '106', + title: 'Predator', + mood: 'scary', + genre: 'action', + period: '80s', + }, + { + id: '396535', + title: 'Train to Busan', + mood: 'scary', + genre: 'action', + period: '2010s', + }, + { + id: '503736', + title: 'Army of the Dead', + mood: 'scary', + genre: 'action', + period: '2020s', + }, + + // Movies starting with the mood "thoughtful" + { + id: '8967', + title: 'The Tree of Life', + mood: 'thoughtful', + genre: 'drama', + period: '2010s', + }, + { + id: '14', + title: 'American Beauty', + mood: 'thoughtful', + genre: 'drama', + period: '90s', + }, + { + id: '453', + title: 'A Beautiful Mind', + mood: 'thoughtful', + genre: 'drama', + period: '2000s', + }, + { + id: '595', + title: 'To Kill a Mockingbird', + mood: 'thoughtful', + genre: 'drama', + period: 'classic', + }, + { + id: '581734', + title: 'Nomadland', + mood: 'thoughtful', + genre: 'drama', + period: '2020s', + }, + + { + id: '419430', + title: 'Get Out', + mood: 'thoughtful', + genre: 'horror', + period: '2010s', + }, + { + id: '1933', + title: 'The Others', + mood: 'thoughtful', + genre: 'horror', + period: '2000s', + }, + { + id: '745', + title: 'The Sixth Sense', + mood: 'thoughtful', + genre: 'horror', + period: '90s', + }, + { + id: '805', + title: "Rosemary's Baby", + mood: 'thoughtful', + genre: 'horror', + period: 'classic', + }, + { + id: '530385', + title: 'Midsommar', + mood: 'thoughtful', + genre: 'horror', + period: '2020s', + }, + + { + id: '335984', + title: 'Blade Runner 2049', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '27205', + title: 'Inception', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '141', + title: 'Donnie Darko', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '62', + title: '2001: A Space Odyssey', + mood: 'thoughtful', + genre: 'sci-fi', + period: 'classic', + }, + { + id: '264660', + title: 'Ex Machina', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '120467', + title: 'The Grand Budapest Hotel', + mood: 'thoughtful', + genre: 'comedy', + period: '2010s', + }, + { + id: '153', + title: 'Lost in Translation', + mood: 'thoughtful', + genre: 'comedy', + period: '2000s', + }, + { + id: '137', + title: 'Groundhog Day', + mood: 'thoughtful', + genre: 'comedy', + period: '90s', + }, + { + id: '935', + title: 'Dr. Strangelove', + mood: 'thoughtful', + genre: 'comedy', + period: 'classic', + }, + { + id: '515001', + title: 'Jojo Rabbit', + mood: 'thoughtful', + genre: 'comedy', + period: '2020s', + }, + + { + id: '603', + title: 'The Matrix', + mood: 'thoughtful', + genre: 'action', + period: '90s', + }, + { + id: '76341', + title: 'Mad Max: Fury Road', + mood: 'thoughtful', + genre: 'action', + period: '2010s', + }, + { + id: '9693', + title: 'Children of Men', + mood: 'thoughtful', + genre: 'action', + period: '2000s', + }, + { + id: '577922', + title: 'Tenet', + mood: 'thoughtful', + genre: 'action', + period: '2020s', + }, + { + id: '335984', + title: 'Blade Runner', + mood: 'thoughtful', + genre: 'action', + period: '80s', + }, + ]; + + const filteredMovies = movieDatabase.filter(movie => movie.mood === mood && movie.genre === genre && movie.period === period); + + if (filteredMovies.length > 0) { + const randomIndex = Math.floor(Math.random() * filteredMovies.length); + const matchedMovie = filteredMovies[randomIndex]; + + localStorage.setItem('selectedMovieId', matchedMovie.id); + window.location.href = 'movie-details.html'; + } else { + alert('No match found. Try different criteria.'); + } +} + +const form = document.getElementById('form1'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-timeline.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-timeline.js new file mode 100644 index 00000000..5d947c26 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/movie-timeline.js @@ -0,0 +1,647 @@ +let alertShown = false; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.getElementById('start-year').addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + event.preventDefault(); + updateMovies(); + } +}); + +document.getElementById('end-year').addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + event.preventDefault(); + updateMovies(); + } +}); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const IMGPATH = 'https://image.tmdb.org/t/p/w500'; +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const searchTitle = document.getElementById('select-text'); +const searchButton = document.getElementById('button-search'); +const search = document.getElementById('search'); +const main = document.getElementById('results'); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +async function getMovies(url) { + clearMovieDetails(); + const numberOfMovies = calculateMoviesToDisplay(); + const pagesToFetch = numberOfMovies <= 20 ? 1 : 2; + let allMovies = []; + + for (let page = 1; page <= pagesToFetch; page++) { + const response = await fetch(`${url}&page=${page}`); + const data = await response.json(); + allMovies = allMovies.concat(data.results); + } + + const popularityThreshold = 0.5; + + allMovies.sort((a, b) => { + const popularityDifference = Math.abs(a.popularity - b.popularity); + if (popularityDifference < popularityThreshold) { + return b.vote_average - a.vote_average; + } + return b.popularity - a.popularity; + }); + + if (allMovies.length > 0) { + showMovies(allMovies.slice(0, numberOfMovies), main); + } else { + main.innerHTML = `

No movie with the specified search term found. Please try again.

`; + } +} + +function clearMovieDetails() { + const movieDetailsContainer = document.getElementById('movie-details-container'); + if (movieDetailsContainer) { + movieDetailsContainer.innerHTML = ''; + } +} + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function updateMovies() { + showSpinner(); + let startYear = document.getElementById('start-year').value; + let endYear = document.getElementById('end-year').value; + let currentYear = new Date().getFullYear(); + if (startYear && endYear && startYear <= endYear && endYear <= currentYear && startYear >= 1900 && startYear <= currentYear) { + fetchMoviesByTimePeriod(startYear, endYear); + hideSpinner(); + alertShown = false; + } else { + if (!alertShown) { + alert( + 'Please ensure the start year is before the end year, the start year is later than the year 1900, and both are not later than the current year.' + ); + alertShown = true; + } + hideSpinner(); + } +} + +async function getAdditionalPosters(movieId) { + const response = await fetch(`https://api.themoviedb.org/3/movie/${movieId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +function showMovies(movies, mainElement, startYear, endYear, append) { + showSpinner(); + + if (!append) { + mainElement.innerHTML = ''; + const header = document.createElement('h2'); + header.style.textAlign = 'center'; + header.style.marginTop = '20px'; + header.style.marginBottom = '20px'; + header.style.color = '#ff8623'; + header.style.fontSize = '23px'; + if (startYear === endYear) { + header.textContent = `Movies released in ${startYear}`; + } else { + header.textContent = `Movies released between ${startYear} and ${endYear}`; + } + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.innerHTML = ''; + centerContainer1.appendChild(header); + centerContainer1.appendChild(mainElement); + } + + const observer = new IntersectionObserver( + async (entries, observer) => { + for (const entry of entries) { + if (entry.isIntersecting) { + const movieEl = entry.target; + const movieId = movieEl.dataset.id; + + const additionalPosters = await getAdditionalPosters(movieId); + let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; + + const movieImageContainer = movieEl.querySelector('.movie-images'); + + allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imagePromises = allPosters.map((poster, index) => { + const img = new Image(); + img.src = `${IMGPATH + poster}`; + img.loading = index === 0 ? 'eager' : 'lazy'; + img.alt = `${movieEl.dataset.title} poster ${index + 1}`; + img.width = 300; + img.height = 435; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = '0'; + img.classList.add('poster-img'); + movieImageContainer.appendChild(img); + + return new Promise(resolve => { + img.onload = () => resolve(img); + }); + }); + + const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); + await Promise.race([Promise.all(imagePromises), maxWait]); + + movieImageContainer.querySelector('.poster-img').style.opacity = '1'; + + rotateImages(Array.from(movieImageContainer.children)); + observer.unobserve(movieEl); + } + } + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + movies.forEach(movie => { + let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; + + const movieEl = document.createElement('div'); + movieEl.style.zIndex = '1000'; + movieEl.classList.add('movie'); + movieEl.dataset.id = id; + movieEl.dataset.posterPath = poster_path; + movieEl.dataset.title = title; + + const words = title.split(' '); + if (words.length >= 8) { + words[7] = '...'; + title = words.slice(0, 8).join(' '); + } + + const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); + const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); + + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+
+ ${title} poster +
+
+
+

${title}

+ ${voteAvg} +
+
+

Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); + updateUniqueMoviesViewed(id); + updateFavoriteGenre(genre_ids); + updateMovieVisitCount(id, title); + window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + }); + + mainElement.appendChild(movieEl); + observer.observe(movieEl); + }); + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.appendChild(mainElement); + + createLoadMoreButton(startYear, endYear, mainElement); + hideSpinner(); +} + +function createLoadMoreButton(startYear, endYear, mainElement) { + const existingButtonDiv = mainElement.querySelector('.load-more-container'); + if (existingButtonDiv) { + mainElement.removeChild(existingButtonDiv); + } + + const buttonContainer = document.createElement('div'); + buttonContainer.className = 'load-more-container'; + buttonContainer.style.width = '100%'; + buttonContainer.style.textAlign = 'center'; + buttonContainer.style.marginTop = '20px'; + + const moreButton = document.createElement('button'); + moreButton.textContent = 'Get More Movies in this Period'; + moreButton.style.margin = '10px auto'; + + moreButton.addEventListener('click', function () { + currentPage++; + fetchMoviesByTimePeriod(startYear, endYear, true); + }); + + buttonContainer.appendChild(moreButton); + mainElement.appendChild(buttonContainer); +} + +let currentPage = 1; + +async function fetchMoviesByTimePeriod(startYear, endYear, append = false) { + showSpinner(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31&page=${currentPage}`; + const response = await fetch(url); + const data = await response.json(); + const moviesToShow = data.results; + + if (append) { + showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, true); + } else { + showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, false); + } + hideSpinner(); +} + +document.getElementById('load-movies').addEventListener('click', () => { + showSpinner(); + updateMovies(); + alertShown = false; + hideSpinner(); +}); + +function calculateMoviesToDisplay() { + const screenWidth = window.innerWidth; + if (screenWidth <= 689.9) return 10; // 1 movie per row + if (screenWidth <= 1021.24) return 20; // 2 movies per row + if (screenWidth <= 1353.74) return 21; // 3 movies per row + if (screenWidth <= 1684.9) return 20; // 4 movies per row + if (screenWidth <= 2017.49) return 20; // 5 movies per row + if (screenWidth <= 2349.99) return 18; // 6 movies per row + if (screenWidth <= 2681.99) return 21; // 7 movies per row + if (screenWidth <= 3014.49) return 24; // 8 movies per row + if (screenWidth <= 3345.99) return 27; // 9 movies per row + if (screenWidth <= 3677.99) return 20; // 10 movies per row + if (screenWidth <= 4009.99) return 22; // 11 movies per row + if (screenWidth <= 4340.99) return 24; // 12 movies per row + if (screenWidth <= 4673.49) return 26; // 13 movies per row + if (screenWidth <= 5005.99) return 28; // 14 movies per row + if (screenWidth <= 5337.99) return 30; // 15 movies per row + if (screenWidth <= 5669.99) return 32; // 16 movies per row + if (screenWidth <= 6001.99) return 34; // 17 movies per row + if (screenWidth <= 6333.99) return 36; // 18 movies per row + if (screenWidth <= 6665.99) return 38; // 19 movies per row + if (screenWidth <= 6997.99) return 40; // 20 movies per row + if (screenWidth <= 7329.99) return 42; // 21 movies per row + if (screenWidth <= 7661.99) return 44; // 22 movies per row + if (screenWidth <= 7993.99) return 46; // 23 movies per row + if (screenWidth <= 8325.99) return 48; // 24 movies per row + return 20; +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/notifications.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/notifications.js new file mode 100644 index 00000000..4ea7acef --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/notifications.js @@ -0,0 +1,176 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +document.addEventListener('DOMContentLoaded', () => { + const today = new Date(); + fetchReleasesByCategory('releasesSinceLastVisit', new Date(localStorage.getItem('lastVisit')), today, true); + fetchReleasesByCategory('releasesThisMonth', new Date(today.getFullYear(), today.getMonth(), 1), today, false); + fetchReleasesByCategory('releasesThisYear', new Date(today.getFullYear(), 0, 1), today, false); + fetchRecommendedReleases(); +}); + +async function fetchReleasesByCategory(elementId, startDate, endDate, isLastVisit) { + const list = document.getElementById(elementId); + list.innerHTML = ''; + + let movies = await fetchMovies(startDate, endDate); + + movies = movies.sort((a, b) => new Date(b.release_date) - new Date(a.release_date)); + + populateList(elementId, movies.slice(0, 5)); +} + +async function fetchMovies(startDate, endDate) { + const formattedStartDate = `${startDate.getFullYear()}-${(startDate.getMonth() + 1) + .toString() + .padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`; + const formattedEndDate = `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`; + + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&release_date.gte=${formattedStartDate}&release_date.lte=${formattedEndDate}`; + + try { + const response = await fetch(url); + const data = await response.json(); + return data.results; + } catch (error) { + console.log('Failed to fetch movies for', elementId + ':', error); + return []; + } +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +async function getMostVisitedMovieGenre() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedGenre = null; + let maxVisits = 0; + for (const movieId in movieVisits) { + const visits = movieVisits[movieId]; + if (visits.count > maxVisits) { + maxVisits = visits.count; + mostVisitedGenre = await fetchGenreForMovie(movieId); + } + } + return mostVisitedGenre; +} + +async function fetchGenreForMovie(movieId) { + const movieDetailsUrl = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(movieDetailsUrl); + const movieDetails = await response.json(); + return movieDetails.genres[0] ? movieDetails.genres[0].id : null; +} + +async function fetchRecommendedReleases() { + let url; + + const mostCommonGenre = getMostCommonGenre(); + const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); + + try { + const genreId = mostVisitedMovieGenre || mostCommonGenre; + if (!genreId) { + throw new Error('Genre ID is not valid.'); + } + url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${genreId}`; + } catch (error) { + console.log('Fetching recommended movies failed or data issues:', error); + url = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}&language=en-US&page=1`; + } + + try { + const response = await fetch(url); + const data = await response.json(); + populateList('recommendedReleases', data.results.slice(0, 5)); + } catch (error) { + console.log('Failed to fetch movies:', error); + } +} + +function populateList(elementId, movies) { + const list = document.getElementById(elementId); + list.innerHTML = ''; + movies.forEach(movie => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id.toString()); + window.location.href = 'movie-details.html'; + }); + + const title = document.createElement('span'); + title.textContent = movie.title; + title.style.color = 'black'; + li.appendChild(title); + list.appendChild(li); + }); +} + +document.addEventListener('DOMContentLoaded', () => { + populateActors(); + populateDirectors(); +}); + +function populateActors() { + const actors = [ + { name: 'Robert Downey Jr.', id: 3223 }, + { name: 'Scarlett Johansson', id: 1245 }, + { name: 'Denzel Washington', id: 5292 }, + { name: 'Meryl Streep', id: 5064 }, + { name: 'Leonardo DiCaprio', id: 6193 }, + { name: 'Sandra Bullock', id: 18277 }, + { name: 'Tom Hanks', id: 31 }, + ]; + + const list = document.getElementById('popularActors').querySelector('ul'); + actors.forEach(actor => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedActorId', actor.id.toString()); + window.location.href = 'actor-details.html'; + }); + + const name = document.createElement('span'); + name.textContent = actor.name; + li.appendChild(name); + list.appendChild(li); + }); +} + +function populateDirectors() { + const directors = [ + { name: 'Steven Spielberg', id: 488 }, + { name: 'Martin Scorsese', id: 1032 }, + { name: 'Christopher Nolan', id: 525 }, + { name: 'Quentin Tarantino', id: 138 }, + { name: 'Kathryn Bigelow', id: 14392 }, + { name: 'James Cameron', id: 2710 }, + { name: 'Sofia Coppola', id: 1776 }, + ]; + + const list = document.getElementById('popularDirectors').querySelector('ul'); + directors.forEach(director => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedDirectorId', director.id.toString()); + window.location.href = 'director-details.html'; + }); + + const name = document.createElement('span'); + name.textContent = director.name; + li.appendChild(name); + + list.appendChild(li); + }); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/privacy-policy.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/privacy-policy.js new file mode 100644 index 00000000..7f4afb2d --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/privacy-policy.js @@ -0,0 +1,789 @@ +function toggleNav() { + const sideNav = document.getElementById('side-nav'); + sideNav.classList.toggle('manual-toggle'); + adjustNavBar(); +} + +function removeNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + } + + adjustNavBar(); +} + +function adjustNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0px'; + } else { + sideNav.style.left = '-250px'; + } +} + +document.addEventListener('mousemove', function (event) { + const sideNav = document.getElementById('side-nav'); + if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0'; + } +}); + +document.getElementById('side-nav').addEventListener('mouseleave', function () { + const sideNav = document.getElementById('side-nav'); + if (!sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '-250px'; + } +}); + +document.addEventListener('click', function (event) { + const sideNav = document.getElementById('side-nav'); + const navToggle = document.getElementById('nav-toggle'); + if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + adjustNavBar(); + } +}); + +document.getElementById('introduction').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('introduction').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('consent').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('consent').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading2').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading3').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading4').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading4').scrollIntoView({ behavior: 'smooth' }); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.webp'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +window.addEventListener('load', function () { + adjustAnchorHeights(); +}); + +window.addEventListener('resize', adjustAnchorHeights); + +function adjustAnchorHeights() { + const bottomBarAnchors = document.querySelectorAll('.mobile-bottom-bar a'); + let maxHeight = 0; + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = 'auto'; + const anchorHeight = anchor.getBoundingClientRect().height; + maxHeight = Math.max(maxHeight, anchorHeight); + }); + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = `${maxHeight}px`; + }); +} + +let lastScrollY = window.scrollY; + +window.addEventListener('scroll', () => { + const currentScrollY = window.scrollY; + + if (currentScrollY > lastScrollY && currentScrollY > 0) { + document.querySelector('.mobile-bottom-bar').classList.add('hide-bar'); + } else { + document.querySelector('.mobile-bottom-bar').classList.remove('hide-bar'); + } + + lastScrollY = currentScrollY; +}); + +let isAnimating = false; + +document.getElementById('menu-btn').addEventListener('click', () => { + if (isAnimating) return; + + isAnimating = true; + + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach((id, index) => { + const button = document.getElementById(id); + if (button.style.display === 'none' || !button.style.display) { + button.style.display = 'block'; + setTimeout(() => { + button.style.opacity = '1'; + button.style.transform = 'translateY(0)'; + }, 50 * index); + } else { + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + } + + setTimeout( + () => { + button.style.display = button.style.opacity === '1' ? 'block' : 'none'; + if (index === buttonIds.length - 1) { + isAnimating = false; + } + }, + 500 + 50 * index + ); + }); +}); + +window.addEventListener('resize', () => { + if (window.innerWidth < 767) { + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach(id => { + const button = document.getElementById(id); + button.style.display = 'none'; + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + }); + } +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/quiz.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/quiz.js new file mode 100644 index 00000000..c5adcd57 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/quiz.js @@ -0,0 +1,859 @@ +import { updateTriviaStats } from './triviaModule.js'; + +const questionBank = [ + { + question: 'What movie won the Academy Award for Best Picture in 2020?', + options: ['Joker', '1917', 'Parasite'], + answer: 'Parasite', + }, + { + question: "Who directed the movie 'The Godfather'?", + options: ['Steven Spielberg', 'Francis Ford Coppola', 'Martin Scorsese'], + answer: 'Francis Ford Coppola', + }, + { + question: 'What was the first feature-length animated movie ever released?', + options: ['Snow White and the Seven Dwarfs', 'Bambi', 'Pinocchio'], + answer: 'Snow White and the Seven Dwarfs', + }, + { + question: "What was the highest-grossing movie of all time before the release of 'Avatar'?", + options: ['Titanic', 'Star Wars: The Force Awakens', 'Avengers: Endgame'], + answer: 'Titanic', + }, + { + question: "Who played the lead role in the movie 'Forrest Gump'?", + options: ['Tom Hanks', 'Brad Pitt', 'Leonardo DiCaprio'], + answer: 'Tom Hanks', + }, + { + question: 'What movie won the Academy Award for Best Picture in 2019?', + options: ['Bohemian Rhapsody', 'Green Book', 'Roma'], + answer: 'Green Book', + }, + { + question: 'Who played the character of John McClane in the Die Hard movie series?', + options: ['Arnold Schwarzenegger', 'Sylvester Stallone', 'Bruce Willis'], + answer: 'Bruce Willis', + }, + { + question: 'What movie is based on a novel by Stephen King and features a character named Jack Torrance?', + options: ['Carrie', 'The Shining', 'Misery'], + answer: 'The Shining', + }, + { + question: "Who directed the movie 'Forrest Gump'?", + options: ['Steven Spielberg', 'Robert Zemeckis', 'Martin Scorsese'], + answer: 'Robert Zemeckis', + }, + { + question: 'What is the highest-grossing movie of all time (as of 2021)?', + options: ['Avatar', 'Avengers: Endgame', 'Titanic'], + answer: 'Avatar', + }, + { + question: "What movie features the line 'You can't handle the truth!'?", + options: ['The Shawshank Redemption', 'A Few Good Men', 'Goodfellas'], + answer: 'A Few Good Men', + }, + { + question: 'Who played the character of Tony Stark/Iron Man in the Marvel Cinematic Universe?', + options: ['Chris Hemsworth', 'Mark Ruffalo', 'Robert Downey Jr.'], + answer: 'Robert Downey Jr.', + }, + { + question: "In which movie did Tom Hanks say, 'Houston, we have a problem'?", + options: ['Apollo 13', 'Cast Away', 'The Terminal'], + answer: 'Apollo 13', + }, + { + question: 'What is the name of the hobbit played by Elijah Wood in the Lord of the Rings movies?', + options: ['Frodo', 'Sam', 'Merry'], + answer: 'Frodo', + }, + { + question: "What is the name of the kingdom where the 2013 animated movie 'Frozen' is set?", + options: ['Arendelle', 'Genovia', 'DunBroch'], + answer: 'Arendelle', + }, + { + question: 'Which 1997 science fiction movie stars Will Smith and Tommy Lee Jones?', + options: ['Independence Day', 'Men in Black', 'Wild Wild West'], + answer: 'Men in Black', + }, + { + question: 'Which movie features Bruce Willis as a child psychologist?', + options: ['Die Hard', 'The Sixth Sense', 'Unbreakable'], + answer: 'The Sixth Sense', + }, + { + question: "In 'The Matrix', does Neo take the blue pill or the red pill?", + options: ['Blue', 'Red', 'Green'], + answer: 'Red', + }, + { + question: "Which actress played Katniss Everdeen in 'The Hunger Games' movies?", + options: ['Jennifer Lawrence', 'Emma Watson', 'Shailene Woodley'], + answer: 'Jennifer Lawrence', + }, + { + question: "Who directed 'Jurassic Park'?", + options: ['James Cameron', 'Steven Spielberg', 'George Lucas'], + answer: 'Steven Spielberg', + }, + { + question: 'What 1980s movie was the highest grossing film of the decade?', + options: ['E.T. the Extra-Terrestrial', 'Star Wars: Episode V', 'Back to the Future'], + answer: 'E.T. the Extra-Terrestrial', + }, + { + question: "Which movie features the song 'My Heart Will Go On'?", + options: ['The Bodyguard', 'Titanic', 'Romeo + Juliet'], + answer: 'Titanic', + }, + { + question: 'What was the first Pixar movie?', + options: ['Toy Story', "A Bug's Life", 'Monsters, Inc.'], + answer: 'Toy Story', + }, + { + question: 'Who played Wolverine in the X-Men movies?', + options: ['Hugh Jackman', 'Liam Hemsworth', 'Chris Evans'], + answer: 'Hugh Jackman', + }, + { + question: 'Which film did NOT win the Academy Award for Best Picture?', + options: ['The Shawshank Redemption', 'The Godfather', 'Forrest Gump'], + answer: 'The Shawshank Redemption', + }, + { + question: "What is Indiana Jones' real first name?", + options: ['Henry', 'John', 'Walter'], + answer: 'Henry', + }, + { + question: "In 'The Wizard of Oz', what did the Scarecrow want from the wizard?", + options: ['Heart', 'Brain', 'Courage'], + answer: 'Brain', + }, + { + question: 'Who is the only actor to receive an Oscar nomination for acting in a Lord of the Rings movie?', + options: ['Viggo Mortensen', 'Ian McKellen', 'Elijah Wood'], + answer: 'Ian McKellen', + }, + { + question: 'Which movie features an iconic dance scene between Uma Thurman and John Travolta?', + options: ['Pulp Fiction', 'Kill Bill', 'Saturday Night Fever'], + answer: 'Pulp Fiction', + }, + { + question: 'What is the highest-grossing R-rated movie of all time?', + options: ['Deadpool', 'Joker', 'The Matrix'], + answer: 'Joker', + }, + { + question: 'Which Alfred Hitchcock movie is notorious for its shower scene?', + options: ['Vertigo', 'Psycho', 'Rear Window'], + answer: 'Psycho', + }, + { + question: "What is Darth Vader's real name?", + options: ['Anakin Skywalker', 'Luke Skywalker', 'Obi-Wan Kenobi'], + answer: 'Anakin Skywalker', + }, + { + question: "Who directed 'Schindler's List'?", + options: ['Martin Scorsese', 'Steven Spielberg', 'Ridley Scott'], + answer: 'Steven Spielberg', + }, + { + question: 'In which movie does Tom Cruise perform his own stunts climbing the Burj Khalifa?', + options: ['Mission: Impossible - Rogue Nation', 'Mission: Impossible - Ghost Protocol', 'Edge of Tomorrow'], + answer: 'Mission: Impossible - Ghost Protocol', + }, + { + question: "What is the name of the fictional African country where 'Black Panther' is set?", + options: ['Wakanda', 'Genovia', 'Zamunda'], + answer: 'Wakanda', + }, + { + question: "Who directed 'Inception' and 'Interstellar'?", + options: ['Christopher Nolan', 'James Cameron', 'Steven Spielberg'], + answer: 'Christopher Nolan', + }, + { + question: "In 'The Hunger Games', what district do Katniss and Peeta represent?", + options: ['District 12', 'District 9', 'District 7'], + answer: 'District 12', + }, + { + question: 'Which movie features a character named Tyler Durden?', + options: ['Fight Club', 'Gone Girl', 'Seven'], + answer: 'Fight Club', + }, + { + question: "What is the name of the island in 'Jurassic Park'?", + options: ['Isla Nublar', 'Isla Sorna', 'Skull Island'], + answer: 'Isla Nublar', + }, + { + question: "Who played the Joker in 'The Dark Knight'?", + options: ['Heath Ledger', 'Joaquin Phoenix', 'Jared Leto'], + answer: 'Heath Ledger', + }, + { + question: 'In which movie is the fictional company Initech featured?', + options: ['Office Space', 'The Social Network', 'Wall Street'], + answer: 'Office Space', + }, + { + question: "What year was the first 'Harry Potter' movie released?", + options: ['2001', '2003', '1999'], + answer: '2001', + }, + { + question: "What fictional country is 'Wonder Woman' from?", + options: ['Themyscira', 'Asgard', 'Genovia'], + answer: 'Themyscira', + }, + { + question: "Which movie is known for the quote 'Here's looking at you, kid'?", + options: ['Casablanca', 'Gone with the Wind', 'The Maltese Falcon'], + answer: 'Casablanca', + }, + { + question: "In 'The Lion King', what is Simba's mother's name?", + options: ['Nala', 'Sarabi', 'Shenzi'], + answer: 'Sarabi', + }, + { + question: "Who directed 'Avengers: Endgame'?", + options: ['The Russo Brothers', 'Joss Whedon', 'Jon Favreau'], + answer: 'The Russo Brothers', + }, + { + question: "What is the name of the kingdom in 'Tangled'?", + options: ['Corona', 'Far Far Away', 'Arendelle'], + answer: 'Corona', + }, + { + question: 'Which film features a famous dance scene with Uma Thurman and John Travolta?', + options: ['Pulp Fiction', 'Saturday Night Fever', 'Kill Bill'], + answer: 'Pulp Fiction', + }, + { + question: "Who played Jack Dawson in 'Titanic'?", + options: ['Leonardo DiCaprio', 'Brad Pitt', 'Johnny Depp'], + answer: 'Leonardo DiCaprio', + }, + { + question: 'What is the highest-grossing film of all time?', + options: ['Avengers: Endgame', 'Avatar', 'Titanic'], + answer: 'Avatar', + }, + { + question: 'In which movie does the character Neo appear?', + options: ['The Matrix', 'John Wick', 'Speed'], + answer: 'The Matrix', + }, + { + question: 'What is the real name of the Black Panther in the Marvel Cinematic Universe?', + options: ["T'Challa", "M'Baku", "N'Jadaka"], + answer: "T'Challa", + }, + { + question: "Who directed 'Mad Max: Fury Road'?", + options: ['George Miller', 'Ridley Scott', 'Peter Jackson'], + answer: 'George Miller', + }, + { + question: "What animated film features a character named 'Hiccup'?", + options: ['Brave', 'How to Train Your Dragon', 'Shrek'], + answer: 'How to Train Your Dragon', + }, + { + question: "In which film is the fictional mineral 'Unobtainium' sought after?", + options: ['Avatar', 'The Core', 'Transformers'], + answer: 'Avatar', + }, + { + question: 'What is the name of the fictional city where the Batman movies take place?', + options: ['Gotham City', 'Metropolis', 'Star City'], + answer: 'Gotham City', + }, + { + question: "Who directed 'The Dark Knight'?", + options: ['Christopher Nolan', 'Martin Scorsese', 'Steven Spielberg'], + answer: 'Christopher Nolan', + }, + { + question: 'Who won the Best Actress award at the Oscars in 2021?', + options: ['Viola Davis', 'Frances McDormand', 'Carey Mulligan'], + answer: 'Frances McDormand', + }, + { + question: 'Which movie features a dystopian future divided into faction-based societies?', + options: ['The Hunger Games', 'Divergent', 'The Maze Runner'], + answer: 'Divergent', + }, + { + question: "What is the name of the spaceship in 'Alien' (1979)?", + options: ['Nostromo', 'Serenity', 'Millennium Falcon'], + answer: 'Nostromo', + }, + { + question: "Which director is known for the 'Dark Knight' trilogy?", + options: ['Christopher Nolan', 'Tim Burton', 'Joel Schumacher'], + answer: 'Christopher Nolan', + }, + { + question: "In 'The Terminator', what is the name of the company that created Skynet?", + options: ['Cyberdyne Systems', 'Wayland Industries', 'Oscorp'], + answer: 'Cyberdyne Systems', + }, + { + question: "What 1994 film revitalized John Travolta's career?", + options: ['Get Shorty', 'Pulp Fiction', 'Face/Off'], + answer: 'Pulp Fiction', + }, + { + question: 'Which movie was incorrectly announced as the Best Picture winner at the 2017 Academy Awards?', + options: ['La La Land', 'Moonlight', 'Manchester by the Sea'], + answer: 'La La Land', + }, + { + question: "What animated film was Disney's first ever full-length feature?", + options: ['Snow White and the Seven Dwarfs', 'Cinderella', 'The Little Mermaid'], + answer: 'Snow White and the Seven Dwarfs', + }, + { + question: "Who directed 'E.T. the Extra-Terrestrial'?", + options: ['Steven Spielberg', 'George Lucas', 'Ridley Scott'], + answer: 'Steven Spielberg', + }, + { + question: "Which film contains the quote, 'There's no place like home'?", + options: ['The Wizard of Oz', 'Gone with the Wind', 'Casablanca'], + answer: 'The Wizard of Oz', + }, + { + question: 'What is the highest grossing film of all time (not adjusted for inflation) as of 2023?', + options: ['Avengers: Endgame', 'Avatar', 'Titanic'], + answer: 'Avatar', + }, + { + question: "Who composed the score for 'The Lion King' (1994)?", + options: ['John Williams', 'Hans Zimmer', 'Alan Menken'], + answer: 'Hans Zimmer', + }, + { + question: 'Which movie did Leonardo DiCaprio win his first Oscar for Best Actor?', + options: ['The Revenant', 'The Wolf of Wall Street', 'Inception'], + answer: 'The Revenant', + }, + { + question: 'In which film does the character Maximus Decimus Meridius appear?', + options: ['300', 'Gladiator', 'Troy'], + answer: 'Gladiator', + }, + { + question: 'What is the name of the fictional British spy in the film series created by Ian Fleming?', + options: ['James Bond', 'Jason Bourne', 'Jack Ryan'], + answer: 'James Bond', + }, + { + question: 'Which movie won the Academy Award for Best Animated Feature in 2021?', + options: ['Onward', 'Soul', 'Wolfwalkers'], + answer: 'Soul', + }, + { + question: "Who played the role of Michael Corleone in 'The Godfather'?", + options: ['Al Pacino', 'Robert De Niro', 'Marlon Brando'], + answer: 'Al Pacino', + }, + { + question: 'What 2009 film is known for pioneering modern 3D cinema technology?', + options: ['Inception', 'Avatar', 'The Hurt Locker'], + answer: 'Avatar', + }, + { + question: 'Which 2012 film features a protagonist who survives a shipwreck with a tiger?', + options: ['Life of Pi', 'Cast Away', 'The Revenant'], + answer: 'Life of Pi', + }, + { + question: "What is the main theme of the movie 'Inception'?", + options: ['Time travel', 'Dream manipulation', 'Space exploration'], + answer: 'Dream manipulation', + }, + { + question: 'Which film features the character Sarah Connor, who is central to the plot?', + options: ['The Terminator', 'Aliens', 'Jurassic Park'], + answer: 'The Terminator', + }, + { + question: "What 1999 movie is famous for the quote, 'I see dead people'?", + options: ['The Sixth Sense', 'Ghost', 'The Others'], + answer: 'The Sixth Sense', + }, + { + question: "Who directed 'Titanic', which won the Academy Award for Best Picture in 1997?", + options: ['James Cameron', 'Steven Spielberg', 'Martin Scorsese'], + answer: 'James Cameron', + }, + { + question: 'Which film did NOT feature Leonardo DiCaprio?', + options: ['Titanic', 'The Great Gatsby', 'The Prestige'], + answer: 'The Prestige', + }, + { + question: "In which movie do characters compete in the 'Hunger Games'?", + options: ['Catching Fire', 'The Hunger Games', 'Battle Royale'], + answer: 'The Hunger Games', + }, + { + question: 'What film, released in 1982, features a character named E.T.?', + options: ['Star Wars', 'Close Encounters of the Third Kind', 'E.T. the Extra-Terrestrial'], + answer: 'E.T. the Extra-Terrestrial', + }, + { + question: "Who starred as the lead in the 2018 film 'Black Panther'?", + options: ['Chadwick Boseman', 'Michael B. Jordan', 'Denzel Washington'], + answer: 'Chadwick Boseman', + }, + { + question: "What iconic 1980s movie features the quote, 'Say hello to my little friend!'?", + options: ['Scarface', 'The Godfather', 'Goodfellas'], + answer: 'Scarface', + }, + { + question: 'Which film features a unique spinning top in its final scene?', + options: ['Inception', 'Minority Report', 'The Matrix'], + answer: 'Inception', + }, + { + question: 'What movie, featuring a journey to Mordor, won the Academy Award for Best Picture in 2003?', + options: [ + 'The Lord of the Rings: The Two Towers', + 'The Lord of the Rings: The Return of the King', + 'The Lord of the Rings: The Fellowship of the Ring', + ], + answer: 'The Lord of the Rings: The Return of the King', + }, + { + question: 'Which movie features a giant monster known as Godzilla?', + options: ['Pacific Rim', 'Godzilla', 'Cloverfield'], + answer: 'Godzilla', + }, + { + question: 'What classic film was remade in 2005 starring Naomi Watts and Jack Black?', + options: ['King Kong', 'Godzilla', 'Planet of the Apes'], + answer: 'King Kong', + }, + { + question: "Who directed the 1994 crime film 'Pulp Fiction'?", + options: ['Quentin Tarantino', 'Steven Spielberg', 'Martin Scorsese'], + answer: 'Quentin Tarantino', + }, + { + question: 'Which movie includes a character named Norman Bates?', + options: ['Psycho', 'Rebecca', 'The Birds'], + answer: 'Psycho', + }, + { + question: "What is the name of the fictional theme park in 'Jurassic Park'?", + options: ['Dinosaur Land', 'Jurassic World', 'Isla Nublar'], + answer: 'Isla Nublar', + }, + { + question: "Who played the role of Clarice Starling in the film 'The Silence of the Lambs'?", + options: ['Jodie Foster', 'Julianne Moore', 'Sigourney Weaver'], + answer: 'Jodie Foster', + }, + { + question: "Which film is famous for the line, 'May the Force be with you'?", + options: ['Star Trek', 'Star Wars', 'Guardians of the Galaxy'], + answer: 'Star Wars', + }, + { + question: 'What 1975 thriller is known for its menacing shark and famous soundtrack?', + options: ['Deep Blue Sea', 'Jaws', 'Sharknado'], + answer: 'Jaws', + }, + { + question: 'Which film did Tom Hanks win his first Academy Award for Best Actor?', + options: ['Big', 'Philadelphia', 'Forrest Gump'], + answer: 'Philadelphia', + }, + { + question: "What is the name of the ring in 'The Lord of the Rings'?", + options: ['The Ring of Power', 'The One Ring', 'The Master Ring'], + answer: 'The One Ring', + }, + { + question: "Who directed 'Avatar', the groundbreaking sci-fi movie released in 2009?", + options: ['James Cameron', 'George Lucas', 'Steven Spielberg'], + answer: 'James Cameron', + }, + { + question: 'Which 1988 animated film features a dystopian future and psychic powers?', + options: ['Ghost in the Shell', 'Akira', 'Blade Runner'], + answer: 'Akira', + }, + { + question: 'Who played the role of Hermione Granger in the Harry Potter films?', + options: ['Emma Watson', 'Emma Stone', 'Emily Blunt'], + answer: 'Emma Watson', + }, + { + question: "Which film features a group of friends who use a map to find a pirate's treasure?", + options: ['The Goonies', 'Treasure Island', 'Pirates of the Caribbean'], + answer: 'The Goonies', + }, + { + question: 'What was the first animated film to receive a Best Picture nomination at the Oscars?', + options: ['Beauty and the Beast', 'The Lion King', 'Up'], + answer: 'Beauty and the Beast', + }, + { + question: "What is the fictional sport played in the 'Harry Potter' series?", + options: ['Quidditch', 'Bludgers', 'Snitchball'], + answer: 'Quidditch', + }, + { + question: "Who composed the iconic score for 'Star Wars'?", + options: ['Hans Zimmer', 'John Williams', 'Danny Elfman'], + answer: 'John Williams', + }, + { + question: 'What 2000 film, directed by Ridley Scott, features a Roman general turned gladiator?', + options: ['Spartacus', 'Gladiator', 'Ben-Hur'], + answer: 'Gladiator', + }, + { + question: "Which movie's plot centers around a unique wooden board game?", + options: ['Clue', 'Jumanji', 'Zathura'], + answer: 'Jumanji', + }, + { + question: "Who directed the 1980 horror film 'The Shining'?", + options: ['Stanley Kubrick', 'Alfred Hitchcock', 'Stephen King'], + answer: 'Stanley Kubrick', + }, + { + question: 'What 1993 science fiction film directed by Steven Spielberg features dinosaurs brought back to life through cloning?', + options: ['Jurassic Park', 'The Lost World', 'Dinosaur'], + answer: 'Jurassic Park', + }, + { + question: "Who voiced the character of Woody in the 'Toy Story' movies?", + options: ['Tom Hanks', 'Tim Allen', 'Billy Crystal'], + answer: 'Tom Hanks', + }, + { + question: 'Which 2010 film directed by Christopher Nolan explores dream-sharing technology?', + options: ['Inception', 'Interstellar', 'Memento'], + answer: 'Inception', + }, + { + question: 'What film series features a secret British spy agency known as Kingsman?', + options: ['James Bond', 'Kingsman', 'Johnny English'], + answer: 'Kingsman', + }, + { + question: "Who played the role of Jack Sparrow in the 'Pirates of the Caribbean' film series?", + options: ['Johnny Depp', 'Orlando Bloom', 'Keira Knightley'], + answer: 'Johnny Depp', + }, + { + question: "Which 2001 film, based on a J.R.R. Tolkien novel, follows a hobbit's quest to destroy a powerful ring?", + options: ['The Hobbit', 'The Lord of the Rings: The Fellowship of the Ring', 'The Lord of the Rings: The Two Towers'], + answer: 'The Lord of the Rings: The Fellowship of the Ring', + }, + { + question: 'What 2003 animated film features a fish named Nemo?', + options: ['Shark Tale', 'Finding Nemo', 'The Little Mermaid'], + answer: 'Finding Nemo', + }, + { + question: 'Which 2017 film is based on a DC Comics character and set during World War I?', + options: ['Wonder Woman', 'Captain America: The First Avenger', 'Justice League'], + answer: 'Wonder Woman', + }, + { + question: "Who directed the 1994 film 'Pulp Fiction'?", + options: ['Quentin Tarantino', 'Martin Scorsese', 'Ridley Scott'], + answer: 'Quentin Tarantino', + }, + { + question: 'What movie introduced the character of Hannibal Lecter?', + options: ['Silence of the Lambs', 'Hannibal', 'Manhunter'], + answer: 'Manhunter', + }, + { + question: 'Which 2016 film tells the story of a group of rebels who plan to steal plans for the Death Star?', + options: ['Star Wars: The Force Awakens', 'Rogue One: A Star Wars Story', 'Star Wars: The Last Jedi'], + answer: 'Rogue One: A Star Wars Story', + }, + { + question: "What is the name of the fictional African kingdom in 'Coming to America'?", + options: ['Wakanda', 'Zamunda', 'Genovia'], + answer: 'Zamunda', + }, + { + question: "Who directed the 2017 movie 'Get Out'?", + options: ['Jordan Peele', 'Spike Lee', 'John Singleton'], + answer: 'Jordan Peele', + }, + { + question: 'Which movie features an AI character named HAL 9000?', + options: ['Blade Runner', 'Ex Machina', '2001: A Space Odyssey'], + answer: '2001: A Space Odyssey', + }, + { + question: "What 1980s movie is known for the quote 'Nobody puts Baby in a corner'?", + options: ['Dirty Dancing', 'Footloose', 'Flashdance'], + answer: 'Dirty Dancing', + }, + { + question: 'What 1995 film directed by Michael Mann stars Robert De Niro and Al Pacino?', + options: ['Heat', 'The Godfather', 'Scarface'], + answer: 'Heat', + }, + { + question: "Who starred as the titular character in the 2014 film 'Maleficent'?", + options: ['Angelina Jolie', 'Charlize Theron', 'Nicole Kidman'], + answer: 'Angelina Jolie', + }, + { + question: 'Which film is about a board game that becomes real for the players?', + options: ['Zathura', 'Jumanji', 'The Game'], + answer: 'Jumanji', + }, + { + question: 'In which movie does a group of archaeologists find a frozen prehistoric man?', + options: ['Encino Man', 'Ice Age', 'The Thing'], + answer: 'Encino Man', + }, + { + question: 'What movie features a theme park filled with cloned dinosaurs?', + options: ['Jurassic Park', 'Westworld', 'Prehistoric Park'], + answer: 'Jurassic Park', + }, +]; + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function generateRandomQuestions() { + const questionsToDisplay = 10; + const shuffledQuestions = questionBank.sort(() => 0.5 - Math.random()); + let selectedQuestions = shuffledQuestions.slice(0, questionsToDisplay); + + const quizContainer = document.getElementById('quiz-container'); + quizContainer.innerHTML = ''; + + selectedQuestions.forEach((question, index) => { + const questionElement = document.createElement('div'); + questionElement.innerHTML = ` +

Question ${index + 1}:

+

${question.question}

+ ${question.options.map((option, i) => `
`).join('')} +
`; + quizContainer.appendChild(questionElement); + + const headerElement = questionElement.querySelector(`h2`); + + headerElement.addEventListener('click', function (e) { + e.preventDefault(); + + headerElement.scrollIntoView({ behavior: 'smooth' }); + }); + + headerElement.addEventListener('mouseover', function () { + headerElement.style.color = 'orange'; + }); + + headerElement.addEventListener('mouseout', function () { + headerElement.style.color = '#ff8623'; + }); + + headerElement.style.cursor = 'pointer'; + }); +} + +document.getElementById('regenerate-questions').addEventListener('click', generateRandomQuestions); +generateRandomQuestions(); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('quiz-form').addEventListener('submit', function (event) { + event.preventDefault(); + + let answeredQuestions = 0; + + for (let i = 0; i < 10; i++) { + if (document.querySelector(`input[name="q${i}"]:checked`)) { + answeredQuestions++; + } + } + + if (answeredQuestions < 10) { + const confirmSubmit = confirm(`You have only answered ${answeredQuestions} questions. Are you sure you want to submit?`); + if (!confirmSubmit) { + return; + } + } + + calculateAndDisplayResults(); +}); + +function calculateAndDisplayResults() { + let score = 0; + const totalQuestions = 10; + + questionBank.forEach((question, index) => { + const selectedAnswer = document.querySelector(`input[name="q${index}"]:checked`); + if (selectedAnswer && selectedAnswer.value === question.answer) { + score++; + } + }); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || null; + + updateTriviaStats(currentUserEmail, score, totalQuestions); + + displayResults(score); +} + +function displayResults(score) { + let accuracy = (score / 10) * 100; + let progress = 0; + + document.getElementById('progress-circle').style.setProperty('--progress', `${progress}%`); + document.getElementById('correct-answers').textContent = score; + document.getElementById('result-text').textContent = `Your score is ${score} out of 10 (${accuracy.toFixed(1)}% accuracy)`; + + const interval = setInterval(() => { + if (progress < accuracy) { + progress++; + document.getElementById('progress-circle').style.setProperty('--progress', `${progress}%`); + } else { + clearInterval(interval); + } + }, 20); + + showModal(); +} + +function showModal() { + const modal = document.getElementById('result-modal'); + modal.style.display = 'block'; + + modal.querySelector('.close-button').addEventListener('click', function () { + modal.style.display = 'none'; + }); + + window.addEventListener('click', function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } + }); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/ratings-module.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/ratings-module.js new file mode 100644 index 00000000..80d4ec59 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/ratings-module.js @@ -0,0 +1,77 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function loadUserRatings(currentUserEmail) { + if (currentUserEmail) { + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + return docSnap.exists() ? docSnap.data().ratings : {}; + } else { + return JSON.parse(localStorage.getItem('movieRatings')) || {}; + } +} + +export async function updateAverageMovieRating(currentUserEmail, movieId, newRating) { + if (!currentUserEmail) { + console.error('No user signed in, using localStorage to save ratings.'); + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + updateLocalAverage(savedRatings); + } else { + console.log('User signed in, saving ratings to Firebase.'); + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + let ratings = docSnap.exists() ? docSnap.data().ratings || {} : {}; + ratings[movieId] = newRating; + + await setDoc(ratingsRef, { ratings: ratings }, { merge: true }); + updateFirebaseAverage(ratings, ratingsRef); + updateLocalAverage(ratings); + } +} + +function updateLocalAverage(savedRatings) { + let totalRating = 0; + let totalMoviesRated = 0; + Object.values(savedRatings).forEach(rating => { + totalRating += parseFloat(rating); + totalMoviesRated++; + }); + const averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1)); +} + +async function updateFirebaseAverage(ratings, ratingsRef) { + let totalRating = 0; + let totalMoviesRated = 0; + Object.values(ratings).forEach(rating => { + totalRating += parseFloat(rating); + totalMoviesRated++; + }); + const averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + await setDoc(ratingsRef, { averageRating: averageRating }, { merge: true }); +} + +export async function getAverageMovieRating(currentUserEmail) { + if (!currentUserEmail) { + console.error('No user signed in, retrieving average rating from localStorage.'); + return localStorage.getItem('averageMovieRating') || 0; + } else { + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + return docSnap.exists() && docSnap.data().averageRating ? docSnap.data().averageRating : 0; + } +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/reset-password.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/reset-password.js new file mode 100644 index 00000000..78e46da9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/reset-password.js @@ -0,0 +1,128 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, query, where, getDocs, doc, updateDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('resetPasswordForm').addEventListener('submit', async function (event) { + try { + event.preventDefault(); + const resetEmail = document.getElementById('resetEmail').value; + + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', resetEmail)); + const querySnapshot = await getDocs(q); + + if (querySnapshot.empty) { + alert('No account with such credentials exists in our database, or you might have mistyped something. Please try again.'); + return; + } + + document.getElementById('newPasswordFields').style.display = 'block'; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('password-reset-form-container'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +async function updatePassword() { + const resetEmail = document.getElementById('resetEmail').value; + const newPassword = document.getElementById('newPassword').value; + const confirmNewPassword = document.getElementById('confirmNewPassword').value; + + if (!isValidPassword(newPassword)) { + alert( + 'New password does not meet the security requirements.\n\n' + + 'Your password must include:\n' + + '- At least 8 characters\n' + + '- At least one uppercase letter\n' + + '- At least one lowercase letter\n' + + '- At least one number\n' + + '- At least one special character (e.g., !@#$%^&*)' + ); + return; + } + + if (newPassword !== confirmNewPassword) { + alert('Passwords do not match.'); + return; + } + + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', resetEmail)); + const querySnapshot = await getDocs(q); + + if (!querySnapshot.empty) { + querySnapshot.forEach(async docSnapshot => { + await updateDoc(doc(db, 'MovieVerseUsers', docSnapshot.id), { + password: newPassword, + }) + .then(() => { + alert('Password updated successfully!'); + window.location.href = 'sign-in.html'; + }) + .catch(error => { + console.log('Error updating password: ', error); + alert('Failed to update password. Please try again.'); + }); + }); + } else { + alert('Failed to find account. Please try again.'); + } +} + +document.getElementById('updatePasswordButton').addEventListener('click', updatePassword); + +function isValidPassword(password) { + const minLength = 8; + const hasUppercase = /[A-Z]/.test(password); + const hasLowercase = /[a-z]/.test(password); + const hasNumbers = /\d/.test(password); + const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password); + + return password.length >= minLength && hasUppercase && hasLowercase && hasNumbers && hasSpecialChar; +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/root-config.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/root-config.js new file mode 100644 index 00000000..b8083782 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/root-config.js @@ -0,0 +1,34 @@ +import { registerApplication, start } from 'single-spa'; + +// Defines a function that takes a location and returns true if the location should be active +function pathPrefix(prefix) { + return function (location) { + return location.pathname.startsWith(prefix); + }; +} + +// Load React Microfrontend for the homepage +registerApplication('home', () => System.import('http://localhost:8080/home.js'), pathPrefix('/home')); + +// Load React Microfrontend for the about page +registerApplication('about', () => System.import('http://localhost:8083/about.js'), pathPrefix('/about')); + +// Load React Microfrontend for the trivia page +registerApplication('quiz', () => System.import('http://localhost:8084/quiz.js'), pathPrefix('/contact')); + +// Load React Microfrontend for the favorites / watchlist page +registerApplication('favorites', () => System.import('http://localhost:8085/favorites.js'), pathPrefix('/favorites')); + +// Load React Microfrontend for the movie match page +registerApplication('movie-match', () => System.import('http://localhost:8086/movie-match.js'), pathPrefix('/movie-match')); + +// Load React Microfrontend for the movie timeline page +registerApplication('movie-timeline', () => System.import('http://localhost:8087/movie-timeline.js'), pathPrefix('/movie-details')); + +// Load Vue Microfrontend for the movie listing +registerApplication('movies', () => System.import('http://localhost:8081/movies.js'), pathPrefix('/movies')); + +// Load Vue Microfrontend for the navbar +registerApplication('navbar', () => System.import('http://localhost:8082/navbar.js'), pathPrefix('/navbar')); + +start(); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/router.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/router.js new file mode 100644 index 00000000..f78ed621 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/router.js @@ -0,0 +1,51 @@ +import Vue from 'vue'; +import Router from 'vue-router'; + +import HomePage from './components/HomePage.vue'; +import MovieDetails from './components/MovieDetails.vue'; +import AboutPage from './components/AboutPage.vue'; +import MovieMatch from './components/MovieMatch.vue'; +import MovieTimeline from './components/MovieTimeline.vue'; +import MovieOfTheDay from './components/MovieOfTheDay.vue'; + +Vue.use(Router); + +export default new Router({ + mode: 'history', + routes: [ + { + path: '/', + name: 'Home', + component: HomePage, + }, + { + path: '/movie/:id', + name: 'MovieDetails', + component: MovieDetails, + }, + { + path: '/about', + name: 'About', + component: AboutPage, + }, + { + path: '/movie-match', + name: 'MovieMatch', + component: MovieMatch, + }, + { + path: '/movie-timeline', + name: 'MovieTimeline', + component: MovieTimeline, + }, + { + path: '/movie-of-the-day', + name: 'MovieOfTheDay', + component: MovieOfTheDay, + }, + { + path: '*', // This wildcard route is for 404 Not Found pages + redirect: '/', + }, + ], +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/search.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/search.js new file mode 100644 index 00000000..ee46fb1b --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/search.js @@ -0,0 +1,1039 @@ +const form = document.getElementById('form1'); +const IMGPATH = 'https://image.tmdb.org/t/p/w500'; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + attachEventListeners(); + attachArrowKeyNavigation(); + + document.getElementById('form1').addEventListener('submit', function (event) { + event.preventDefault(); + handleSearch(); + }); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +document.addEventListener('DOMContentLoaded', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + attachEventListeners(); + attachArrowKeyNavigation(); + fetchGenreMap(); + fetchTvGenreMap(); + fetchLanguages(); + fetchTvLanguages(); + + document.getElementById('form1').addEventListener('submit', function (event) { + event.preventDefault(); + handleSearch(); + }); +}); + +async function fetchTvLanguages() { + const url = `https://${getMovieVerseData()}/3/configuration/languages?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + let languages = await response.json(); + languages = languages.sort((a, b) => a.english_name.localeCompare(b.english_name)); + populateTvLanguageFilter(languages); + } catch (error) { + console.log('Error fetching languages:', error); + } +} + +function populateTvLanguageFilter(languages) { + const languageFilter = document.getElementById('language-tv-filter'); + languageFilter.innerHTML = ''; + + languages.forEach(language => { + const option = document.createElement('option'); + option.value = language.iso_639_1; + option.textContent = language.english_name; + languageFilter.appendChild(option); + }); +} + +async function fetchLanguages() { + const url = `https://${getMovieVerseData()}/3/configuration/languages?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + let languages = await response.json(); + languages = languages.sort((a, b) => a.english_name.localeCompare(b.english_name)); + populateLanguageFilter(languages); + } catch (error) { + console.log('Error fetching languages:', error); + } +} + +function populateLanguageFilter(languages) { + const languageFilter = document.getElementById('language-filter'); + languageFilter.innerHTML = ''; + + languages.forEach(language => { + const option = document.createElement('option'); + option.value = language.iso_639_1; + option.textContent = language.english_name; + languageFilter.appendChild(option); + }); +} + +async function fetchGenreMap() { + const code = getMovieCode(); + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${code}`; + + try { + const response = await fetch(url); + const data = await response.json(); + localStorage.setItem('genreMap', JSON.stringify(data.genres)); + populateGenreFilter(data.genres); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function fetchTvGenreMap() { + const code = getMovieCode(); + const url = `https://${getMovieVerseData()}/3/genre/tv/list?${generateMovieNames()}${code}`; + + try { + const response = await fetch(url); + const data = await response.json(); + localStorage.setItem('tvGenreMap', JSON.stringify(data.genres)); + populateTvGenreFilter(data.genres); + } catch (error) { + console.log('Error fetching TV genre map:', error); + } +} + +function populateGenreFilter(genres) { + const genreFilter = document.getElementById('genre-filter'); + genreFilter.innerHTML = ''; + + genres.forEach(genre => { + const option = document.createElement('option'); + option.value = genre.id; + option.textContent = genre.name; + genreFilter.appendChild(option); + }); +} + +function populateTvGenreFilter(genres) { + const genreFilter = document.getElementById('genre-tv-filter'); + genreFilter.innerHTML = ''; + + genres.forEach(genre => { + const option = document.createElement('option'); + option.value = genre.id; + option.textContent = genre.name; + genreFilter.appendChild(option); + }); +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let uniqueMoviesViewed = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + + if (!uniqueMoviesViewed.includes(movieId)) { + uniqueMoviesViewed.push(movieId); + } + + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(uniqueMoviesViewed)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function attachEventListeners() { + const movieBtn = document.querySelector('[data-category="movie"]'); + const tvBtn = document.querySelector('[data-category="tv"]'); + const peopleBtn = document.querySelector('[data-category="person"]'); + const toggleFiltersBtn = document.getElementById('toggle-filters-btn'); + + const movieFilters = document.getElementById('movie-tv-filters'); + const tvFilters = document.getElementById('tv-filters'); + const peopleFilters = document.getElementById('people-filters'); + + const genreMovieFilter = document.getElementById('genre-filter'); + const yearMovieFilter = document.getElementById('year-filter'); + const ratingMovieFilter = document.getElementById('rating-filter'); + const languageFilter = document.getElementById('language-filter'); + + const genreTvFilter = document.getElementById('genre-tv-filter'); + const yearTvFilter = document.getElementById('year-tv-filter'); + const ratingTvFilter = document.getElementById('rating-tv-filter'); + const languageTvFilter = document.getElementById('language-tv-filter'); + + const professionFilter = document.getElementById('profession-filter'); + const genderFilter = document.getElementById('gender-filter'); + const popularityFilter = document.getElementById('popularity-filter'); + + const ratingValueSpan = document.getElementById('rating-value'); + const ratingTvValueSpan = document.getElementById('rating-tv-value'); + const popularityValueSpan = document.getElementById('popularity-value'); + + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + + function setFilterDisplayValues() { + ratingValueSpan.textContent = `Rating: ${ratingMovieFilter.value} and above`; + ratingTvValueSpan.textContent = `Rating: ${ratingTvFilter.value} and above`; + popularityValueSpan.textContent = `Popularity: ${popularityFilter.value} and above`; + } + + function showCorrectFilters(category) { + movieFilters.style.display = category === 'movie' ? 'block' : 'none'; + tvFilters.style.display = category === 'tv' ? 'block' : 'none'; + peopleFilters.style.display = category === 'person' ? 'block' : 'none'; + } + + movieBtn.addEventListener('click', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + showCorrectFilters('movie'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + tvBtn.addEventListener('click', () => { + showResults('tv'); + updateCategoryButtonStyles('tv'); + showCorrectFilters('tv'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + peopleBtn.addEventListener('click', () => { + showResults('person'); + updateCategoryButtonStyles('person'); + showCorrectFilters('person'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + toggleFiltersBtn.addEventListener('click', () => { + if (currentCategory === 'movie') { + movieFilters.style.display = movieFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'tv') { + tvFilters.style.display = tvFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'person') { + peopleFilters.style.display = peopleFilters.style.display === 'none' ? 'block' : 'none'; + } + }); + + genreMovieFilter.addEventListener('change', () => showResults('movie')); + yearMovieFilter.addEventListener('change', () => showResults('movie')); + ratingMovieFilter.addEventListener('input', () => { + ratingValueSpan.textContent = `Rating: ${ratingMovieFilter.value} and above`; + showResults('movie'); + }); + languageFilter.addEventListener('change', () => showResults('movie')); + + genreTvFilter.addEventListener('change', () => showResults('tv')); + yearTvFilter.addEventListener('change', () => showResults('tv')); + ratingTvFilter.addEventListener('input', () => { + ratingTvValueSpan.textContent = `Rating: ${ratingTvFilter.value} and above`; + showResults('tv'); + }); + languageTvFilter.addEventListener('change', () => showResults('tv')); + + genderFilter.addEventListener('change', () => showResults('person')); + professionFilter.addEventListener('change', () => showResults('person')); + popularityFilter.addEventListener('input', () => { + popularityValueSpan.textContent = `Popularity: ${popularityFilter.value} and above`; + showResults('person'); + }); + + const resetMovieFiltersBtn = movieFilters.querySelector('button[id="reset-filters"]'); + const resetTvFiltersBtn = tvFilters.querySelector('button[id="reset-filters"]'); + const resetPeopleFiltersBtn = peopleFilters.querySelector('button[id="reset-filters"]'); + + resetMovieFiltersBtn.addEventListener('click', () => { + genreMovieFilter.selectedIndex = 0; + yearMovieFilter.value = ''; + ratingMovieFilter.value = 5; + languageFilter.selectedIndex = 0; + setFilterDisplayValues(); + showResults('movie'); + }); + + resetTvFiltersBtn.addEventListener('click', () => { + genreTvFilter.selectedIndex = 0; + yearTvFilter.value = ''; + ratingTvFilter.value = 5; + languageTvFilter.selectedIndex = 0; + setFilterDisplayValues(); + showResults('tv'); + }); + + resetPeopleFiltersBtn.addEventListener('click', () => { + professionFilter.selectedIndex = 0; + genderFilter.selectedIndex = 0; + popularityFilter.value = 20; + setFilterDisplayValues(); + showResults('person'); + }); + + setFilterDisplayValues(); + showCorrectFilters(localStorage.getItem('selectedCategory')); +} + +let currentCategory = 'movie'; + +document.addEventListener('DOMContentLoaded', function () { + const toggleFiltersBtn = document.getElementById('toggle-filters-btn'); + const movieTvFilters = document.getElementById('movie-tv-filters'); + const peopleFilters = document.getElementById('people-filters'); + const tvFilters = document.getElementById('tv-filters'); + + movieTvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + + toggleFiltersBtn.addEventListener('click', function () { + if (currentCategory === 'movie') { + movieTvFilters.style.display = movieTvFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'person') { + peopleFilters.style.display = peopleFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'tv') { + tvFilters.style.display = tvFilters.style.display === 'none' ? 'block' : 'none'; + } + + if (currentCategory === 'movie' && movieTvFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else if (currentCategory === 'person' && peopleFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else if (currentCategory === 'tv' && tvFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else { + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + } + }); + + document.getElementById('sort-movie').addEventListener('change', () => { + movieSortChanged = true; + showResults('movie'); + }); + + document.getElementById('sort-tv').addEventListener('change', () => { + tvSortChanged = true; + showResults('tv'); + }); + + document.getElementById('sort-people').addEventListener('change', () => { + peopleSortChanged = true; + showResults('person'); + }); + + document.querySelectorAll('.category-buttons button').forEach(button => { + button.addEventListener('click', function () { + currentCategory = this.getAttribute('data-category'); + }); + }); +}); + +let movieSortChanged = false; +let tvSortChanged = false; +let peopleSortChanged = false; + +function attachArrowKeyNavigation() { + const categories = ['movie', 'tv', 'person']; + let currentIndex = 0; + + document.addEventListener('keydown', e => { + switch (e.key) { + case 'ArrowRight': + currentIndex = (currentIndex + 1) % categories.length; + break; + case 'ArrowLeft': + currentIndex = (currentIndex - 1 + categories.length) % categories.length; + break; + default: + return; + } + const selectedCategory = categories[currentIndex]; + showResults(selectedCategory); + updateCategoryButtonStyles(selectedCategory); + e.preventDefault(); + }); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function sortResults(results, sortBy) { + if (!sortBy) return results; + + const [property, order] = sortBy.split('.'); + results.sort((a, b) => { + let propA = property === 'release_date' || property === 'first_air_date' ? new Date(a[property]) : a[property]; + let propB = property === 'release_date' || property === 'first_air_date' ? new Date(b[property]) : b[property]; + + if (order === 'asc') { + return propA > propB ? 1 : propA < propB ? -1 : 0; + } else { + return propA < propB ? 1 : propA > propB ? -1 : 0; + } + }); + return results; +} + +async function showResults(category) { + showSpinner(); + localStorage.setItem('selectedCategory', category); + currentCategory = category; + + const searchQuery = localStorage.getItem('searchQuery') || ''; + document.getElementById('search-results-label').textContent = `Search Results for "${searchQuery}"`; + + const code = getMovieCode(); + const baseApiUrl = `https://${getMovieVerseData()}/3`; + let url = `${baseApiUrl}/search/${category}?${generateMovieNames()}${code}&query=${encodeURIComponent(searchQuery)}`; + let sortValue = ''; + + if (category === 'movie') { + sortValue = document.getElementById('sort-movie').value; + } else if (category === 'tv') { + sortValue = document.getElementById('sort-tv').value; + } else if (category === 'person') { + sortValue = document.getElementById('sort-people').value; + } + + try { + const response = await fetch(url); + let data = await response.json(); + + if (category === 'movie') { + const genre = document.getElementById('genre-filter').value; + const year = category === 'movie' ? document.getElementById('year-filter').value : document.getElementById('year-filter').value; + const rating = parseFloat(document.getElementById('rating-filter').value); + const language = document.getElementById('language-filter').value; + + data.results = data.results.filter(item => { + const itemYear = category === 'movie' ? item.release_date?.substring(0, 4) : item.first_air_date?.substring(0, 4); + const itemRating = item.vote_average; + const itemGenres = item.genre_ids; + const itemLanguage = item.original_language; + + return ( + (!genre || itemGenres.includes(parseInt(genre))) && + (!year || itemYear === year) && + (!rating || itemRating >= rating) && + (!language || itemLanguage === language) + ); + }); + } else if (category === 'person') { + const profession = document.getElementById('profession-filter').value; + const gender = document.getElementById('gender-filter').value; + + if (profession) { + data.results = data.results.filter( + person => person.known_for_department && person.known_for_department.toLowerCase() === profession.toLowerCase() + ); + } + + if (gender) { + data.results = data.results.filter(person => person.gender.toString() === gender); + } + + const popularity = parseFloat(document.getElementById('popularity-filter').value); + if (!isNaN(popularity) && popularity > 0) { + data.results = data.results.filter(person => person.popularity >= popularity); + } + + data.results.sort((a, b) => b.popularity - a.popularity); + + const personDetailsPromises = data.results.map(async person => { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${person.id}?${generateMovieNames()}${code}`; + const personResponse = await fetch(personDetailsUrl); + const personDetails = await personResponse.json(); + person.biography = personDetails.biography || 'Click to view the details of this person.'; + return person; + }); + + data.results = await Promise.all(personDetailsPromises); + } else if (category === 'tv') { + const genre = document.getElementById('genre-tv-filter').value; + const year = document.getElementById('year-tv-filter').value; + const rating = parseFloat(document.getElementById('rating-tv-filter').value); + const language = document.getElementById('language-tv-filter').value; + + data.results = data.results.filter(item => { + const itemYear = item.first_air_date?.substring(0, 4); + const itemRating = item.vote_average; + const itemGenres = item.genre_ids; + const itemLanguage = item.original_language; + + return ( + (!genre || itemGenres.includes(parseInt(genre))) && + (!year || itemYear === year) && + (!rating || itemRating >= rating) && + (!language || itemLanguage === language) + ); + }); + } + + if ((category === 'movie' && movieSortChanged) || (category === 'tv' && tvSortChanged) || (category === 'person' && peopleSortChanged)) { + data.results = sortResults(data.results, sortValue); + } + + displayResults(data.results, category, searchQuery); + } catch (error) { + console.log('Error fetching search results:', error); + } finally { + hideSpinner(); + } +} + +document.querySelector('button[onclick="showResults(\'movie\')"]').addEventListener('click', function () { + showResults('movie'); + localStorage.setItem('selectedCategory', 'movie'); + updateCategoryButtonStyles(); +}); + +document.querySelector('button[onclick="showResults(\'tv\')"]').addEventListener('click', function () { + showResults('tv'); + localStorage.setItem('selectedCategory', 'tv'); + updateCategoryButtonStyles(); +}); + +document.querySelector('button[onclick="showResults(\'person\')"]').addEventListener('click', function () { + showResults('person'); + localStorage.setItem('selectedCategory', 'person'); + updateCategoryButtonStyles(); +}); + +function updateCategoryButtonStyles(selectedCategory) { + const movieBtn = document.querySelector('[data-category="movie"]'); + const tvBtn = document.querySelector('[data-category="tv"]'); + const peopleBtn = document.querySelector('[data-category="person"]'); + + movieBtn.style.backgroundColor = ''; + tvBtn.style.backgroundColor = ''; + peopleBtn.style.backgroundColor = ''; + + if (selectedCategory === 'movie') { + movieBtn.style.backgroundColor = '#ff8623'; + } else if (selectedCategory === 'tv') { + tvBtn.style.backgroundColor = '#ff8623'; + } else if (selectedCategory === 'person') { + peopleBtn.style.backgroundColor = '#ff8623'; + } +} + +function displayResults(results, category, searchTerm) { + const container = document.getElementById('movie-match-container1'); + container.innerHTML = ''; + + const capitalizedCategory = category.charAt(0).toUpperCase() + category.slice(1); + + if (results.length === 0) { + container.innerHTML = `

No results found for "${searchTerm}" in the ${capitalizedCategory} category or no results with the specified filters found. Please try again with a different query or change your filters.

`; + container.style.height = '800px'; + return; + } + + showMovies(results, container, category); +} + +const main = document.getElementById('movie-match-container1'); + +async function getAdditionalImages(itemId, category) { + let endpoint; + if (category === 'movie') { + endpoint = `https://api.themoviedb.org/3/movie/${itemId}/images?api_key=${getMovieCode()}`; + } else if (category === 'person') { + endpoint = `https://api.themoviedb.org/3/person/${itemId}/images?api_key=${getMovieCode()}`; + } else if (category === 'tv') { + endpoint = `https://api.themoviedb.org/3/tv/${itemId}/images?api_key=${getMovieCode()}`; + } + + const response = await fetch(endpoint); + const data = await response.json(); + return data.profiles ? data.profiles.map(image => image.file_path) : data.posters.map(image => image.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +async function showMovies(items, container, category) { + container.innerHTML = ''; + + items.forEach(async item => { + const hasVoteAverage = typeof item.vote_average === 'number'; + const isPerson = !hasVoteAverage; + const isMovie = item.title && hasVoteAverage; + const isTvSeries = item.name && hasVoteAverage && category === 'tv'; + + let title = item.title || item.name || 'N/A'; + const words = title.split(' '); + + if (words.length >= 8) { + words[7] = '...'; + title = words.slice(0, 8).join(' '); + } + + let overview = item.overview || 'Click to view the details of this movie/TV series.'; + const biography = item.biography || 'Click to view the details of this person.'; + + if (overview === '') { + overview = 'Click to view the details of this movie/TV series.'; + } + + const { id, profile_path, poster_path } = item; + const imagePath = profile_path || poster_path ? IMGPATH + (profile_path || poster_path) : null; + + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.zIndex = 10000; + + let movieContentHTML = `
`; + + if (imagePath) { + movieContentHTML += `
`; + movieContentHTML += `${title}`; + movieContentHTML += `
`; + } else { + movieContentHTML += `
Image Unavailable
`; + } + + movieContentHTML += `
`; + movieContentHTML += `

${title}

`; + + if ((isMovie || isTvSeries) && hasVoteAverage) { + const voteAverage = item.vote_average.toFixed(1); + movieContentHTML += `${voteAverage}`; + } + + movieContentHTML += `
`; + + if (isPerson) { + const roleOverview = item.known_for_department === 'Directing' ? 'Director Overview' : 'Actor Overview'; + movieContentHTML += `

${roleOverview}:

${biography}
`; + } else if (isTvSeries) { + movieContentHTML += `

TV Series Overview:

${overview}
`; + } else { + movieContentHTML += `

Movie Overview:

${overview}
`; + } + + movieEl.innerHTML = movieContentHTML; + + movieEl.addEventListener('click', async () => { + if (isPerson) { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + if (personDetails.known_for_department === 'Directing') { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + const uniqueDirectorsViewed = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + + if (!uniqueDirectorsViewed.includes(id)) { + uniqueDirectorsViewed.push(id); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(uniqueDirectorsViewed)); + } + + if (directorVisits[id]) { + directorVisits[id].count++; + } else { + directorVisits[id] = { + count: 1, + name: personDetails.name || 'Unknown', + }; + } + + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); + localStorage.setItem('selectedDirectorId', id); + window.location.href = 'director-details.html?' + id; + } else { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(id)) { + uniqueActorsViewed.push(id); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[id]) { + actorVisits[id].count++; + } else { + actorVisits[id] = { + count: 1, + name: personDetails.name || 'Unknown', + }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + localStorage.setItem('selectedActorId', id); + window.location.href = 'actor-details.html?' + id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else if (isMovie) { + localStorage.setItem('selectedMovieId', id); + window.location.href = 'movie-details.html?' + id; + updateMovieVisitCount(id, title); + } else if (isTvSeries) { + localStorage.setItem('selectedTvSeriesId', id); + window.location.href = 'tv-details.html?' + id; + updateMovieVisitCount(id, title); + } + }); + + container.appendChild(movieEl); + + const additionalImages = await getAdditionalImages(id, category); + let allImages = [profile_path || poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + if (allImages.length > 1) { + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + // Load additional images once the first image is in view + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + } + }); +} + +function handleDirectorClick(directorId, directorName) { + updateUniqueDirectorsViewed(directorId); + updateDirectorVisitCount(directorId, directorName); + localStorage.setItem('selectedDirectorId', directorId); + document.title = `${directorName} - Director's Details`; + window.location.href = 'director-details.html'; +} + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.reload(); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?search_query=' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/service-worker.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/service-worker.js new file mode 100644 index 00000000..5fdc059d --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/service-worker.js @@ -0,0 +1,108 @@ +const CACHE_NAME = 'movieverse-cache-v1'; + +const urlsToCache = [ + '/index.html', + '/MovieVerse-Frontend/css/style.css', + '/MovieVerse-Frontend/css/trivia.css', + '/index.js', + '/manifest.json', + '/MovieVerse-Frontend/js/settings.js', + '/images/favicon.ico', + '/images/image.png', + '/MovieVerse-Frontend/js/chatbot.js', + '/MovieVerse-Frontend/js/movie-details.js', + '/MovieVerse-Frontend/js/movie-timeline.js', + '/MovieVerse-Frontend/js/quiz.js', + '/MovieVerse-Frontend/js/actor-details.js', + '/MovieVerse-Frontend/js/director-details.js', + '/MovieVerse-Frontend/html/about.html', + '/MovieVerse-Frontend/html/actor-details.html', + '/MovieVerse-Frontend/html/director-details.html', + '/MovieVerse-Frontend/html/movie-details.html', + '/MovieVerse-Frontend/html/movie-timeline.html', + '/MovieVerse-Frontend/html/notifications.html', + '/MovieVerse-Frontend/html/trivia.html', + '/MovieVerse-Frontend/html/settings.html', + '/MovieVerse-Frontend/html/favorites.html', + '/MovieVerse-Frontend/html/chat.html', + '/MovieVerse-Frontend/html/chatbot.html', + '/MovieVerse-Frontend/html/privacy-policy.html', + '/MovieVerse-Frontend/html/terms-of-service.html', + '/images/black.webp', + '/images/blue.webp', + '/images/brown.webp', + '/images/green.webp', + '/images/gold.webp', + '/images/grey.webp', + '/images/orange.webp', + '/images/pink.webp', + '/images/purple.webp', + '/images/red.webp', + '/images/rose.webp', + '/images/silver.webp', + '/images/universe.webp', + '/images/universe-1.webp', + '/images/universe-1-small.webp', + '/images/universe-1-medium.webp', + '/images/universe-22.webp', + '/images/universe-2.webp', + '/images/universe-23.webp', + '/images/universe-3.webp', + '/images/universe-4.webp', + '/images/universe-5.webp', + '/images/universe-6.webp', + '/images/universe-7.webp', + '/images/universe-8.webp', + '/images/universe-9.webp', + '/images/universe-10.webp', + '/images/universe-11.webp', + '/images/universe-12.webp', + '/images/universe-13.webp', + '/images/universe-14.webp', + '/images/universe-15.webp', + '/images/universe-16.webp', + '/images/universe-17.webp', + '/images/universe-18.webp', + '/images/universe-19.webp', + '/images/universe-20.webp', + '/images/universe-21.webp', + '/images/yellow.webp', + '/MovieVerse-Frontend/js/analytics.js', + '/MovieVerse-Frontend/html/analytics.html', + '/MovieVerse-Frontend/html/offline.html', +]; + +self.addEventListener('install', event => { + event.waitUntil( + caches.open(CACHE_NAME).then(cache => { + return cache.addAll(urlsToCache); + }) + ); +}); + +self.addEventListener('fetch', event => { + event.respondWith( + caches.match(event.request).then(response => { + if (response) { + return response; + } + return fetch(event.request) + .then(fetchResponse => { + return caches.open(CACHE_NAME).then(cache => { + cache.put(event.request, fetchResponse.clone()); + return fetchResponse; + }); + }) + .catch(() => caches.match('/MovieVerse-Frontend/html/offline.html')); + }) + ); +}); + +self.addEventListener('activate', event => { + const cacheWhitelist = [CACHE_NAME]; + event.waitUntil( + caches.keys().then(cacheNames => { + return Promise.all(cacheNames.filter(cacheName => !cacheWhitelist.includes(cacheName)).map(cacheName => caches.delete(cacheName))); + }) + ); +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/settings.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/settings.js new file mode 100644 index 00000000..d666801a --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/settings.js @@ -0,0 +1,397 @@ +const DEFAULT_BACKGROUND_IMAGE = '../../images/universe-1.webp'; + +document.addEventListener('DOMContentLoaded', () => { + const bgSelect = document.getElementById('background-select'); + const textColorInput = document.getElementById('text-color-input'); + const fontSizeSelect = document.getElementById('font-size-select'); + const resetButton = document.getElementById('reset-button'); + const deleteButton = document.getElementById('delete-uploaded-btn'); + const deleteImagesSection = document.getElementById('delete-images-section'); + const customImagesContainer = document.getElementById('custom-images-container'); + const deleteSelectedImagesBtn = document.getElementById('delete-selected-images-btn'); + + loadCustomBackgrounds(); + loadSettings(); + + if (bgSelect) { + bgSelect.addEventListener('change', function () { + document.body.style.backgroundImage = `url('${this.value}')`; + localStorage.setItem('backgroundImage', this.value); + window.location.reload(); + }); + } + + if (textColorInput) { + textColorInput.addEventListener('input', function () { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = this.value; + }); + localStorage.setItem('textColor', this.value); + }); + } + + if (fontSizeSelect) { + fontSizeSelect.addEventListener('change', function () { + const size = this.value === 'small' ? '12px' : this.value === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + localStorage.setItem('fontSize', this.value); + }); + } + + if (resetButton) { + resetButton.addEventListener('click', function () { + localStorage.removeItem('backgroundImage'); + localStorage.setItem('backgroundImage', '../../images/universe-1.webp'); + localStorage.removeItem('textColor'); + localStorage.removeItem('fontSize'); + window.location.reload(); + }); + } + + if (deleteButton) { + deleteButton.addEventListener('click', function () { + if (deleteImagesSection.style.display === 'block') { + deleteImagesSection.style.display = 'none'; + } else { + deleteImagesSection.style.display = 'block'; + updateCustomImagesDisplay(); + } + }); + } + + if (deleteSelectedImagesBtn) { + deleteSelectedImagesBtn.addEventListener('click', () => { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const selectedIndexes = Array.from(document.querySelectorAll('.delete-checkbox:checked')).map(checkbox => parseInt(checkbox.value)); + + const updatedImages = customImages.filter((_, index) => !selectedIndexes.includes(index)); + localStorage.setItem('customImages', JSON.stringify(updatedImages)); + + updateCustomImagesDisplay(); + updateBackgroundSelectOptions(); + alert('Selected images have been deleted.'); + window.location.reload(); + }); + } + + function updateCustomImagesDisplay() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + customImagesContainer.innerHTML = ''; + + if (customImages.length === 0) { + customImagesContainer.innerHTML = '

No custom images uploaded.

'; + deleteSelectedImagesBtn.style.display = 'none'; + return; + } + + customImages.forEach((image, index) => { + const imageContainer = document.createElement('div'); + imageContainer.classList.add('image-container'); + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.classList.add('delete-checkbox'); + checkbox.value = index; + + const img = document.createElement('img'); + img.src = image.dataURL; + img.alt = image.name; + img.style.width = '100px'; + + const imageName = document.createElement('span'); + imageName.classList.add('image-name'); + imageName.textContent = image.name; + + // Toggle checkbox when image container is clicked + imageContainer.addEventListener('click', e => { + if (e.target !== checkbox) { + // Prevent checkbox click event from toggling twice + checkbox.checked = !checkbox.checked; + } + }); + + imageContainer.appendChild(checkbox); + imageContainer.appendChild(img); + imageContainer.appendChild(imageName); + customImagesContainer.appendChild(imageContainer); + }); + + deleteSelectedImagesBtn.style.display = 'block'; + } + + function loadSettings() { + let savedBg = localStorage.getItem('backgroundImage'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (!savedBg) { + savedBg = DEFAULT_BACKGROUND_IMAGE; + } + + const availableBackgrounds = [ + '../../images/universe-1.webp', + '../../images/universe-2.webp', + '../../images/universe-22.webp', + '../../images/universe-3.webp', + '../../images/universe-4.webp', + '../../images/universe-5.webp', + '../../images/universe-6.webp', + '../../images/universe-7.webp', + '../../images/universe-8.webp', + '../../images/universe-9.webp', + '../../images/universe-10.webp', + '../../images/universe-11.webp', + '../../images/universe-12.webp', + '../../images/universe-13.webp', + '../../images/universe-14.webp', + '../../images/universe-15.webp', + '../../images/universe-16.webp', + '../../images/universe-17.webp', + '../../images/universe-18.webp', + '../../images/universe-19.webp', + '../../images/universe-20.webp', + '../../images/universe-21.webp', + '../../images/universe.webp', + '../../images/universe-23.webp', + '../../images/black.webp', + '../../images/grey.webp', + '../../images/blue.webp', + '../../images/silver.webp', + '../../images/gold.webp', + '../../images/rose.webp', + '../../images/pink.webp', + '../../images/red.webp', + '../../images/green.webp', + '../../images/brown.webp', + '../../images/purple.webp', + '../../images/orange.webp', + '../../images/yellow.webp', + ]; + + if (!availableBackgrounds.includes(savedBg) && !customImages.find(image => image.dataURL === savedBg)) { + savedBg = DEFAULT_BACKGROUND_IMAGE; + localStorage.setItem('backgroundImage', savedBg); + } + + if (savedBg) { + let imageUrl = savedBg; + if (savedBg === DEFAULT_BACKGROUND_IMAGE) { + if (window.innerWidth <= 680) { + imageUrl = '../../images/universe-1-small.webp'; + } else if (window.innerWidth <= 1124) { + imageUrl = '../../images/universe-1-medium.webp'; + } + } + document.body.style.backgroundImage = `url('${imageUrl}')`; + } + + const foundImage = customImages.find(image => image.dataURL === savedBg); + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + textColorInput.value = savedTextColor; + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + fontSizeSelect.value = savedFontSize; + } + + if (bgSelect) { + bgSelect.value = foundImage ? foundImage.dataURL : savedBg; + } + } + + function loadCustomBackgrounds() { + const bgSelect = document.getElementById('background-select'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + + if (bgSelect) { + customImages.forEach(image => { + const newOption = new Option(image.name, image.dataURL); + bgSelect.add(newOption); + }); + } + } +}); + +document.addEventListener('DOMContentLoaded', () => { + const uploadButton = document.getElementById('upload-bg-btn'); + + if (!uploadButton) { + console.log('Upload button not found'); + return; + } + + uploadButton.addEventListener('click', function () { + const fileInput = document.getElementById('custom-bg-upload'); + const imageNameInput = document.getElementById('custom-bg-name'); + const bgSelect = document.getElementById('background-select'); + + if (fileInput && fileInput.files.length > 0) { + const file = fileInput.files[0]; + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const totalSize = customImages.reduce((sum, img) => sum + img.dataURL.length, 0); + const quota = 4.5 * 1024 * 1024; // 4.5 MB + + if (totalSize >= quota) { + handleQuotaExceedance(); + window.location.reload(); + return; + } + + if (file.size > 204800) { + // 200 KB + resizeImage(file, 204800, (resizedDataUrl, err) => { + if (err) { + alert( + `Error resizing the image due to a limitation in your browser. Browser error: ${err.message} Your image might still appear as the background, but it will not be stable. We recommend deleting it and then using a different browser or uploading an image smaller than 1MB.` + ); + return; + } + processImageUpload(resizedDataUrl, imageNameInput, bgSelect); + alert('The uploaded image was resized to fit the size limit of 200KB.'); + window.location.reload(); + }); + } else { + const reader = new FileReader(); + reader.onload = function (e) { + processImageUpload(e.target.result, imageNameInput, bgSelect); + window.location.reload(); + }; + reader.onerror = function () { + alert('Error reading the file.'); + window.location.reload(); + }; + reader.readAsDataURL(file); + } + } else { + alert('Please select an image to upload.'); + } + }); +}); + +function handleQuotaExceedance() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + if (customImages.length > 0) { + alert('Your custom image storage has exceeded the quota. Please delete at least two images to continue.'); + + deleteImagesPrompt(); + } +} + +function deleteImagesPrompt() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + if (customImages.length === 0) { + alert('No custom images to delete.'); + return; + } + + let message = 'Select images to delete:\n'; + customImages.forEach((image, index) => { + message += `${index + 1}. ${image.name}\n`; + }); + message += 'Enter the numbers of the images to delete (e.g., 1,3):'; + + const input = prompt(message); + if (input) { + const indexesToDelete = input.split(',').map(num => parseInt(num.trim()) - 1); + const updatedImages = customImages.filter((_, index) => !indexesToDelete.includes(index)); + localStorage.setItem('customImages', JSON.stringify(updatedImages)); + updateBackgroundSelectOptions(); + alert('Selected images have been deleted.'); + } +} + +function updateBackgroundSelectOptions() { + const bgSelect = document.getElementById('background-select'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + + Array.from(bgSelect.options).forEach(option => { + if (option.value.startsWith('data:image')) { + bgSelect.remove(option.index); + } + }); + + customImages.forEach(image => { + const newOption = new Option(image.name, image.dataURL); + bgSelect.add(newOption); + }); +} + +function processImageUpload(dataUrl, imageNameInput, bgSelect) { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + let imageName = imageNameInput.value.trim(); + + if (!imageName) { + imageName = `User-Added Image ${customImages.length + 1}`; + } + + customImages.push({ name: imageName, dataURL: dataUrl }); + localStorage.setItem('customImages', JSON.stringify(customImages)); + + const newOption = new Option(imageName, dataUrl); + bgSelect.add(newOption); + bgSelect.value = dataUrl; + + document.body.style.backgroundImage = `url('${dataUrl}')`; + localStorage.setItem('backgroundImage', dataUrl); +} + +function resizeImage(file, maxSize, callback) { + if (!(window.FileReader && window.Blob && window.HTMLCanvasElement)) { + callback(null, new Error('Your browser does not support resizing images. Please use a different browser or upload an image smaller than 200KB.')); + return; + } + + const reader = new FileReader(); + reader.onload = function (e) { + const img = new Image(); + img.onload = function () { + try { + let canvas = document.createElement('canvas'); + let ctx = canvas.getContext('2d'); + + let width = img.width; + let height = img.height; + + if (width > height) { + if (width > maxSize) { + height *= maxSize / width; + width = maxSize; + } + } else { + if (height > maxSize) { + width *= maxSize / height; + height = maxSize; + } + } + + canvas.width = width; + canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + + callback(canvas.toDataURL('image/jpeg'), null); + + canvas.height = 0; + canvas.width = 0; + canvas = null; + } catch (error) { + callback(null, error); + } + }; + img.onerror = function () { + callback(null, new Error('Failed to load the image.')); + }; + img.src = e.target.result; + }; + reader.onerror = function () { + callback(null, new Error('Failed to read the image file.')); + }; + + reader.readAsDataURL(file); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/sign-in.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/sign-in.js new file mode 100644 index 00000000..024d4228 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/sign-in.js @@ -0,0 +1,80 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, query, where, getDocs } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('signInForm').addEventListener('submit', async function (event) { + event.preventDefault(); + + try { + const email = document.getElementById('signInEmail').value; + const password = document.getElementById('signInPassword').value; + + const usersRef = collection(db, 'MovieVerseUsers'); + const q = query(usersRef, where('email', '==', email), where('password', '==', password)); + const querySnapshot = await getDocs(q); + + if (!querySnapshot.empty) { + alert('Successfully signed in!'); + localStorage.setItem('isSignedIn', JSON.stringify(true)); + localStorage.setItem('currentlySignedInMovieVerseUser', email); + window.location.href = '../../index.html'; + } else { + alert('Invalid email or password. Ensure that you have entered a correct combination of email and password - one that we have on file.'); + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('signInForm'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +document.getElementById('createAccountBtn').addEventListener('click', function () { + window.location.href = 'create-account.html'; +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/single-spa-config.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/single-spa-config.js new file mode 100644 index 00000000..96ed54cf --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/single-spa-config.js @@ -0,0 +1,16 @@ +import * as singleSpa from 'single-spa'; + +// Function to load microfrontends (apps) +function loadApp(name, path, activeWhen, customProps = {}) { + singleSpa.registerApplication(name, () => System.import(path), activeWhen, customProps); +} + +loadApp('navbar', '/navbar.js', () => true); + +loadApp('home', '/home.js', location => location.pathname === '' || location.pathname === '/'); + +loadApp('movie-details', '/movie-details.js', location => location.pathname.startsWith('/movie')); + +loadApp('about', '/about.js', location => location.pathname.startsWith('/about')); + +singleSpa.start(); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/systemjs-importmap.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/systemjs-importmap.js new file mode 100644 index 00000000..ea5553e9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/systemjs-importmap.js @@ -0,0 +1,25 @@ +let System = (window.System = window.System || {}); +System.import('@system-env').then(env => { + env.production = true; + if (!env.production) { + let System = window.System; + System.importMap({ + imports: { + 'single-spa': 'https://unpkg.com/single-spa/lib/system/single-spa.dev.js', + 'movieverse-navbar': 'http://localhost:8500/movieverse-navbar.js', + 'movieverse-main-content': 'http://localhost:8501/movieverse-main-content.js', + 'movieverse-footer': 'http://localhost:8502/movieverse-footer.js', + }, + }); + } else { + let System = window.System; + System.importMap({ + imports: { + 'single-spa': 'https://unpkg.com/single-spa/lib/system/single-spa.min.js', + 'movieverse-navbar': 'https://your-production-url/movieverse-navbar.js', + 'movieverse-main-content': 'https://your-production-url/movieverse-main-content.js', + 'movieverse-footer': 'https://your-production-url/movieverse-footer.js', + }, + }); + } +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/terms-of-service.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/terms-of-service.js new file mode 100644 index 00000000..7f193db6 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/terms-of-service.js @@ -0,0 +1,814 @@ +document.getElementById('agreement').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('agreement').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('consent').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('consent').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading2').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading3').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading4').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading4').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading5').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading5').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading6').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading6').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading7').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading7').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading8').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading8').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading9').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading9').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading10').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading10').scrollIntoView({ behavior: 'smooth' }); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function toggleNav() { + const sideNav = document.getElementById('side-nav'); + sideNav.classList.toggle('manual-toggle'); + adjustNavBar(); +} + +function removeNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + } + + adjustNavBar(); +} + +function adjustNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0px'; + } else { + sideNav.style.left = '-250px'; + } +} + +document.addEventListener('mousemove', function (event) { + const sideNav = document.getElementById('side-nav'); + if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0'; + } +}); + +document.getElementById('side-nav').addEventListener('mouseleave', function () { + const sideNav = document.getElementById('side-nav'); + if (!sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '-250px'; + } +}); + +document.addEventListener('click', function (event) { + const sideNav = document.getElementById('side-nav'); + const navToggle = document.getElementById('nav-toggle'); + if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + adjustNavBar(); + } +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.webp'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +const movieCode1 = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode1.part1) + atob(movieCode1.part2) + atob(movieCode1.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +window.addEventListener('load', function () { + adjustAnchorHeights(); +}); + +window.addEventListener('resize', adjustAnchorHeights); + +function adjustAnchorHeights() { + const bottomBarAnchors = document.querySelectorAll('.mobile-bottom-bar a'); + let maxHeight = 0; + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = 'auto'; + const anchorHeight = anchor.getBoundingClientRect().height; + maxHeight = Math.max(maxHeight, anchorHeight); + }); + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = `${maxHeight}px`; + }); +} + +let lastScrollY = window.scrollY; + +window.addEventListener('scroll', () => { + const currentScrollY = window.scrollY; + + if (currentScrollY > lastScrollY && currentScrollY > 0) { + document.querySelector('.mobile-bottom-bar').classList.add('hide-bar'); + } else { + document.querySelector('.mobile-bottom-bar').classList.remove('hide-bar'); + } + + lastScrollY = currentScrollY; +}); + +let isAnimating = false; + +document.getElementById('menu-btn').addEventListener('click', () => { + if (isAnimating) return; + + isAnimating = true; + + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach((id, index) => { + const button = document.getElementById(id); + if (button.style.display === 'none' || !button.style.display) { + button.style.display = 'block'; + setTimeout(() => { + button.style.opacity = '1'; + button.style.transform = 'translateY(0)'; + }, 50 * index); + } else { + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + } + + setTimeout( + () => { + button.style.display = button.style.opacity === '1' ? 'block' : 'none'; + if (index === buttonIds.length - 1) { + isAnimating = false; + } + }, + 500 + 50 * index + ); + }); +}); + +window.addEventListener('resize', () => { + if (window.innerWidth < 767) { + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach(id => { + const button = document.getElementById(id); + button.style.display = 'none'; + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + }); + } +}); diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/triviaModule.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/triviaModule.js new file mode 100644 index 00000000..e84a36b9 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/triviaModule.js @@ -0,0 +1,79 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +const app = initializeApp(firebaseConfig); + +const db = getFirestore(app); + +export async function updateTriviaStats(currentUserEmail, correctAnswers, totalQuestions) { + if (!currentUserEmail) { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } else { + try { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + const docSnap = await getDoc(statsRef); + let triviaStats = docSnap.exists() ? docSnap.data() : { totalCorrect: 0, totalAttempted: 0 }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + await setDoc(statsRef, triviaStats, { merge: true }); + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } catch (error) { + if (error.code === 'resource-exhausted') { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } + } + } +} + +export async function getTriviaStats(currentUserEmail) { + if (!currentUserEmail) { + return ( + JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + } + ); + } else { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + try { + const docSnap = await getDoc(statsRef); + if (docSnap.exists()) { + return docSnap.data(); + } else { + console.log('No trivia stats found in Firebase for:', currentUserEmail); + return { totalCorrect: 0, totalAttempted: 0 }; + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded, fetching trivia stats from localStorage.'); + return ( + JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + } + ); + } + } + } +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/tv-details.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/tv-details.js new file mode 100644 index 00000000..fa47a025 --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/tv-details.js @@ -0,0 +1,1609 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w780'; +const searchTitle = document.getElementById('search-title'); +let initialMainContent; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function setStarRating(rating) { + const stars = document.querySelectorAll('.rating .star'); + stars.forEach(star => { + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; + }); + + document.getElementById('rating-value').textContent = `${rating}.0/5.0`; +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +document.querySelectorAll('.rating .star').forEach(star => { + star.addEventListener('mouseover', e => { + setStarRating(e.target.dataset.value); + }); + + star.addEventListener('mouseout', () => { + const movieId = localStorage.getItem('selectedTvSeriesId'); + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); + }); + + star.addEventListener('click', e => { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + if (!tvSeriesId) return; + const rating = e.target.dataset.value; + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + savedRatings[tvSeriesId] = rating; + localStorage.setItem('tvSeriesRatings', JSON.stringify(savedRatings)); + setStarRating(rating); + window.location.reload(); + }); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + currentIndex = 0; + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', function () { + applySettings(); +}); + +const tvCode = `${getMovieCode()}`; + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +async function fetchTvDetails(tvSeriesId) { + showSpinner(); + const baseUrl = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}`; + const urlWithAppend = `${baseUrl}?${generateMovieNames()}${tvCode}&append_to_response=credits,keywords,similar,videos,external_ids`; + + try { + const tvDetailsPromise = fetch(urlWithAppend).then(response => { + if (!response.ok) throw new Error('Failed to fetch TV series details'); + return response.json(); + }); + + const tvSeriesDetails = await tvDetailsPromise; + const imdbId = tvSeriesDetails.external_ids.imdb_id; + + if (imdbId) { + const imdbRatingPromise = fetchTVRatings(imdbId); + const imdbRating = await imdbRatingPromise; + populateTvSeriesDetails(tvSeriesDetails, imdbRating); + } else { + populateTvSeriesDetails(tvSeriesDetails, 'IMDb rating'); + } + + updateBrowserURL(tvSeriesDetails.name); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

TV series details currently unavailable - please try again

+
`; + console.log('Error fetching TV series details:', error); + } finally { + hideSpinner(); + } +} + +async function fetchTVRatings(imdbId) { + showSpinner(); + + if (!imdbId) { + return 'IMDb rating'; + } + + const apiKeys = [await getMovieCode2(), '58efe859', '60a09d79', '956e468a', 'bd55ada4', 'cbfc076', 'dc091ff2', '6e367eef', '2a2a3080', 'd20a931f']; + + const baseURL = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}`; + + async function tryFetch(apiKey, timeout = 5000) { + const url = `${baseURL}${apiKey}`; + return new Promise(resolve => { + const timer = setTimeout(() => resolve(null), timeout); + fetch(url) + .then(response => { + if (!response.ok) throw new Error('API limit reached or other error'); + return response.json(); + }) + .then(data => { + clearTimeout(timer); + if (!data || data.Error) throw new Error('Data fetch error'); + resolve(data); + }) + .catch(() => { + clearTimeout(timer); + resolve(null); + }); + }); + } + + const requests = apiKeys.map(key => tryFetch(key)); + const responses = await Promise.all(requests); + const data = responses.find(response => response !== null); + + hideSpinner(); + return data && data.imdbRating ? data.imdbRating : 'View on IMDb'; +} + +function getLanguageName(code) { + const language = twoLetterLangCodes.find(lang => lang.code === code); + return language ? language.name : 'Unknown Language'; +} + +function getCountryName(code) { + const regionNames = new Intl.DisplayNames(['en'], { type: 'region' }); + return regionNames.of(code); +} + +async function populateTvSeriesDetails(tvSeries, imdbRating) { + const title = tvSeries.name || 'Title not available'; + document.getElementById('movie-title').textContent = title; + document.title = tvSeries.name + ' - TV Series Details'; + + const posterPath = `https://image.tmdb.org/t/p/w780${tvSeries.poster_path}`; + if (tvSeries.poster_path) { + document.getElementById('movie-image').src = posterPath; + document.getElementById('movie-image').alt = `Poster of ${title}`; + } else { + const noImageTitle = document.createElement('h2'); + noImageTitle.textContent = 'TV Show Image Not Available'; + noImageTitle.style.textAlign = 'center'; + document.getElementById('movie-image').replaceWith(noImageTitle); + } + + let detailsHTML = `

Overview: ${tvSeries.overview || 'Overview not available.'}

`; + + detailsHTML += `

Original Title: ${tvSeries.original_name || 'Not available'}

`; + + detailsHTML += `

Tagline: ${tvSeries.tagline || 'Not available'}

`; + + const genres = tvSeries.genres && tvSeries.genres.length ? tvSeries.genres.map(genre => genre.name).join(', ') : 'Genres not available'; + detailsHTML += `

Genres: ${genres}

`; + + detailsHTML += `

First Air Date: ${tvSeries.first_air_date || 'Not available'}

`; + + detailsHTML += `

Last Air Date: ${tvSeries.last_air_date || 'Not available'}

`; + + detailsHTML += `

Status: ${tvSeries.status || 'Not available'}

`; + + const type = tvSeries.type || 'Not available'; + detailsHTML += `

Type: ${type}

`; + + const networks = + tvSeries.networks && tvSeries.networks.length ? tvSeries.networks.map(network => network.name).join(', ') : 'Information not available'; + detailsHTML += `

Networks: ${networks}

`; + + const voteAverage = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + const voteCount = tvSeries.vote_count ? tvSeries.vote_count.toLocaleString() : 'N/A'; + detailsHTML += `

MovieVerse User Rating: ${( + voteAverage / 2 + ).toFixed(1)}/5.0 (based on ${voteCount} votes)

`; + + if (tvSeries.external_ids && tvSeries.external_ids.imdb_id) { + const imdbId = tvSeries.external_ids.imdb_id; + const imdbUrl = `https://www.imdb.com/title/${imdbId}/`; + detailsHTML += `

IMDb Rating: ${imdbRating}

`; + } else { + detailsHTML += `

IMDb Rating: IMDb rating not available

`; + } + + let tmdbRating = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + if (tmdbRating === 'N/A') { + detailsHTML += `

TMDB Rating: ${tmdbRating}

`; + } else { + detailsHTML += `

TMDB Rating: ${tmdbRating}/10.0

`; + } + + const homepage = tvSeries.homepage ? `Visit homepage` : 'Not available'; + detailsHTML += `

Homepage: ${homepage}

`; + + if (tvSeries.origin_country && tvSeries.origin_country.length > 0) { + const countryNames = tvSeries.origin_country.map(code => getCountryName(code)).join(', '); + detailsHTML += `

Country of Origin: ${countryNames}

`; + } else { + detailsHTML += `

Country of Origin: Information not available

`; + } + + const languageName = getLanguageName(tvSeries.original_language); + detailsHTML += `

Original Language: ${languageName}

`; + + const productionCountries = + tvSeries.production_countries && tvSeries.production_countries.length > 0 + ? tvSeries.production_countries.map(country => getCountryName(country.iso_3166_1)).join(', ') + : 'Information not available'; + detailsHTML += `

Production Countries: ${productionCountries}

`; + + detailsHTML += `

Seasons: ${tvSeries.number_of_seasons || 0}, Episodes: ${tvSeries.number_of_episodes || 0}

`; + + if (tvSeries.last_episode_to_air) { + const lastEpisode = tvSeries.last_episode_to_air; + + detailsHTML += `
+ Last Episode: ${lastEpisode.name || 'Title not available'} - ${ + lastEpisode.overview || 'Overview not available.' + } +
`; + + if (lastEpisode.still_path) { + detailsHTML += `
+ ${
+                                  lastEpisode.name
+                                } Still Image +
`; + } + } + + if (tvSeries.created_by && tvSeries.created_by.length > 0) { + const creatorsSection = document.createElement('div'); + creatorsSection.classList.add('creators-section'); + + const creatorsTitle = document.createElement('p'); + creatorsTitle.innerHTML = 'Creators:'; + creatorsSection.appendChild(creatorsTitle); + + const creatorsList = document.createElement('div'); + creatorsList.classList.add('creators-list'); + creatorsList.style.display = 'flex'; + creatorsList.style.flexWrap = 'wrap'; + creatorsList.style.justifyContent = 'center'; + creatorsList.style.gap = '2px'; + + tvSeries.created_by.forEach(creator => { + const creatorLink = document.createElement('a'); + creatorLink.classList.add('creator-link'); + creatorLink.href = 'javascript:void(0);'; + creatorLink.setAttribute('onclick', `handleCreatorClick(${creator.id}, '${creator.name.replace(/'/g, "\\'")}');`); + + const creatorItem = document.createElement('div'); + creatorItem.classList.add('creator-item'); + + const creatorImage = document.createElement('img'); + creatorImage.classList.add('creator-image'); + + if (creator.profile_path) { + creatorImage.src = IMGPATH + creator.profile_path; + creatorImage.alt = `${creator.name} Profile Picture`; + } else { + creatorImage.alt = 'Image Not Available'; + creatorImage.style.objectFit = 'cover'; + creatorImage.src = 'https://movie-verse.com/images/user-default.png'; + creatorImage.style.filter = 'grayscale(100%)'; + } + + creatorItem.appendChild(creatorImage); + + const creatorDetails = document.createElement('div'); + creatorDetails.classList.add('creator-details'); + + const creatorName = document.createElement('p'); + creatorName.classList.add('creator-name'); + creatorName.textContent = creator.name; + creatorDetails.appendChild(creatorName); + + creatorItem.appendChild(creatorDetails); + creatorLink.appendChild(creatorItem); + creatorsList.appendChild(creatorLink); + }); + + creatorsSection.appendChild(creatorsList); + detailsHTML += creatorsSection.outerHTML; + } else { + const noCreatorsElement = document.createElement('p'); + noCreatorsElement.innerHTML = `Creators: Information not available`; + detailsHTML += noCreatorsElement.outerHTML; + } + + if (tvSeries.credits && tvSeries.credits.cast && tvSeries.credits.cast.length > 0) { + const castSection = document.createElement('div'); + castSection.classList.add('cast-section'); + + const castTitle = document.createElement('p'); + castTitle.innerHTML = 'Notable Cast:'; + castSection.appendChild(castTitle); + + const castList = document.createElement('div'); + castList.classList.add('cast-list'); + castList.style.display = 'flex'; + castList.style.flexWrap = 'wrap'; + castList.style.justifyContent = 'center'; + castList.style.gap = '2px'; + + tvSeries.credits.cast.slice(0, 12).forEach(castMember => { + const castMemberLink = document.createElement('a'); + castMemberLink.classList.add('cast-member-link'); + castMemberLink.href = 'javascript:void(0);'; + castMemberLink.setAttribute('onclick', `selectActorId(${castMember.id}, '${castMember.name.replace(/'/g, "\\'")}');`); + + const castMemberItem = document.createElement('div'); + castMemberItem.classList.add('cast-member-item'); + + const castMemberImage = document.createElement('img'); + castMemberImage.classList.add('cast-member-image'); + + if (castMember.profile_path) { + castMemberImage.src = IMGPATH + castMember.profile_path; + castMemberImage.alt = `${castMember.name} Profile Picture`; + } else { + castMemberImage.alt = 'Image Not Available'; + castMemberImage.style.objectFit = 'cover'; + castMemberImage.src = 'https://movie-verse.com/images/user-default.png'; + castMemberImage.style.filter = 'grayscale(100%)'; + } + + castMemberItem.appendChild(castMemberImage); + + const castMemberDetails = document.createElement('div'); + castMemberDetails.classList.add('cast-member-details'); + + const castMemberName = document.createElement('p'); + castMemberName.classList.add('cast-member-name'); + castMemberName.textContent = castMember.name; + castMemberDetails.appendChild(castMemberName); + + const castMemberRole = document.createElement('p'); + castMemberRole.classList.add('cast-member-role'); + castMemberRole.textContent = castMember.character ? `(as ${castMember.character})` : ''; + castMemberRole.style.fontStyle = 'italic'; + castMemberDetails.appendChild(castMemberRole); + + castMemberItem.appendChild(castMemberDetails); + castMemberLink.appendChild(castMemberItem); + castList.appendChild(castMemberLink); + }); + + castSection.appendChild(castList); + detailsHTML += castSection.outerHTML; + } else { + const noCastElement = document.createElement('p'); + noCastElement.innerHTML = `Cast: Information not available`; + detailsHTML += noCastElement.outerHTML; + } + + if (tvSeries.similar && tvSeries.similar.results && tvSeries.similar.results.length > 0) { + const similarTvSeriesSection = document.createElement('div'); + similarTvSeriesSection.classList.add('similar-tv-series-section'); + + const similarTvSeriesTitle = document.createElement('p'); + similarTvSeriesTitle.innerHTML = 'Similar TV Series:'; + similarTvSeriesSection.appendChild(similarTvSeriesTitle); + + const similarTvSeriesList = document.createElement('div'); + similarTvSeriesList.classList.add('similar-tv-series-list'); + similarTvSeriesList.style.display = 'flex'; + similarTvSeriesList.style.flexWrap = 'wrap'; + similarTvSeriesList.style.justifyContent = 'center'; + similarTvSeriesList.style.gap = '10px'; + + let similarTvSeries = tvSeries.similar.results.sort((a, b) => b.popularity - a.popularity); + similarTvSeries = similarTvSeries.slice(0, 18); + + similarTvSeries.forEach(similarTv => { + const similarTvLink = document.createElement('a'); + similarTvLink.classList.add('similar-tv-link'); + similarTvLink.href = 'javascript:void(0);'; + similarTvLink.setAttribute('onclick', `selectTvSeriesId(${similarTv.id});`); + + const similarTvItem = document.createElement('div'); + similarTvItem.classList.add('similar-tv-item'); + + const similarTvImage = document.createElement('img'); + similarTvImage.classList.add('similar-tv-image'); + + if (similarTv.poster_path) { + similarTvImage.src = IMGPATH + similarTv.poster_path; + similarTvImage.alt = `${similarTv.name} Poster`; + } else { + similarTvImage.alt = 'Image Not Available'; + similarTvImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + similarTvImage.style.filter = 'grayscale(100%)'; + similarTvImage.style.objectFit = 'cover'; + } + + similarTvItem.appendChild(similarTvImage); + + const similarTvDetails = document.createElement('div'); + similarTvDetails.classList.add('similar-tv-details'); + + const similarTvName = document.createElement('p'); + similarTvName.classList.add('similar-tv-name'); + similarTvName.textContent = similarTv.name; + similarTvDetails.appendChild(similarTvName); + + similarTvItem.appendChild(similarTvDetails); + similarTvLink.appendChild(similarTvItem); + similarTvSeriesList.appendChild(similarTvLink); + }); + + similarTvSeriesSection.appendChild(similarTvSeriesList); + detailsHTML += similarTvSeriesSection.outerHTML; + } else { + const noSimilarTvSeriesElement = document.createElement('p'); + noSimilarTvSeriesElement.innerHTML = `Similar TV Series: Information not available`; + detailsHTML += noSimilarTvSeriesElement.outerHTML; + } + + if (tvSeries.production_companies && tvSeries.production_companies.length) { + const companiesSection = document.createElement('div'); + companiesSection.classList.add('companies-section'); + + const companiesTitle = document.createElement('p'); + companiesTitle.innerHTML = 'Production Companies:'; + companiesSection.appendChild(companiesTitle); + + const companiesList = document.createElement('div'); + companiesList.classList.add('companies-list'); + companiesList.style.display = 'flex'; + companiesList.style.flexWrap = 'wrap'; + companiesList.style.justifyContent = 'center'; + companiesList.style.gap = '5px'; + + let productionCompanies = tvSeries.production_companies.slice(0, 6); + + productionCompanies.forEach(company => { + const companyLink = document.createElement('a'); + companyLink.classList.add('company-link'); + companyLink.href = 'javascript:void(0);'; + companyLink.setAttribute('onclick', `selectCompanyId(${company.id});`); + + const companyItem = document.createElement('div'); + companyItem.classList.add('company-item'); + + const companyLogo = document.createElement('img'); + companyLogo.classList.add('company-logo'); + + if (company.logo_path) { + companyLogo.src = IMGPATH + company.logo_path; + companyLogo.alt = `${company.name} Logo`; + companyLogo.style.backgroundColor = 'white'; + } else { + companyLogo.alt = 'Logo Not Available'; + companyLogo.src = 'https://movie-verse.com/images/company-default.png'; + companyLogo.style.filter = 'grayscale(100%)'; + } + + companyItem.appendChild(companyLogo); + + const companyDetails = document.createElement('div'); + companyDetails.classList.add('company-details'); + + const companyName = document.createElement('p'); + companyName.classList.add('company-name'); + companyName.textContent = company.name; + companyDetails.appendChild(companyName); + + companyItem.appendChild(companyDetails); + companyLink.appendChild(companyItem); + companiesList.appendChild(companyLink); + }); + + companiesSection.appendChild(companiesList); + detailsHTML += companiesSection.outerHTML; + } else { + const noCompaniesElement = document.createElement('p'); + noCompaniesElement.innerHTML = `Production Companies: Information not available`; + detailsHTML += noCompaniesElement.outerHTML; + } + + const tvSeriesTitleEncoded = encodeURIComponent(title); + const streamingProviders = await fetchTvSeriesStreamingLinks(tvSeries.id); + const streamingHTML = + streamingProviders.length > 0 + ? streamingProviders + .map(provider => { + let providerLink = `https://www.google.com/search?q=watch+${tvSeriesTitleEncoded}+on+${encodeURIComponent(provider.provider_name)}`; + switch (provider.provider_name.toLowerCase()) { + case 'netflix': + providerLink = `https://www.netflix.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'disney plus': + providerLink = `https://www.disneyplus.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hbo max': + providerLink = `https://www.hbomax.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hulu': + providerLink = `https://www.hulu.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'amazon prime video': + providerLink = `https://www.amazon.com/s?k=${tvSeriesTitleEncoded}`; + break; + case 'apple tv plus': + providerLink = `https://tv.apple.com/search?term=${tvSeriesTitleEncoded}`; + break; + case 'stan': + providerLink = `https://www.stan.com.au/search?q=${tvSeriesTitleEncoded}`; + break; + case 'player': + providerLink = `https://player.pl/szukaj?search=${tvSeriesTitleEncoded}`; + break; + } + + return ``; + }) + .join('') + + `` + : 'No streaming options available.'; + + detailsHTML += `

Streaming Options: ${streamingHTML}

`; + + let keywordsHTML = tvSeries.keywords + ? tvSeries.keywords.results + .map( + kw => `${kw.name}` + ) + .join(', ') + : 'None Available'; + + if (tvSeries.keywords && tvSeries.keywords.results && tvSeries.keywords.results.length) { + detailsHTML += `

Keywords: ${keywordsHTML}

`; + } else { + detailsHTML += `

Keywords: None Available

`; + } + + const mediaUrl = `https://${getMovieVerseData()}/3/tv/${tvSeries.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; + } + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + document.getElementById('movie-description').innerHTML = detailsHTML; + document.getElementById('movie-description').appendChild(mediaTitle); + document.getElementById('movie-description').appendChild(mediaContainer); + + document.getElementById('last-episode-image').addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + + const modalHtml = ` +
+ Media Image + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + const modal = document.getElementById('image-modal'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + } + }); + }); + + if (tvSeries.videos.results.find(video => video.type === 'Trailer')?.key) { + const trailerKey = tvSeries.videos.results.find(video => video.type === 'Trailer')?.key; + const trailerUrl = trailerKey ? `https://www.youtube.com/embed/${trailerKey}` : null; + + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.id = 'trailer-button'; + trailerButton.style = ` + background-color: #7378c5; + color: white; + padding: 10px 20px; + border: none; + border-radius: 8px; + cursor: pointer; + margin-top: 10px; + font: inherit; + `; + + const iframeContainer = document.createElement('div'); + iframeContainer.id = 'trailer-iframe-container'; + iframeContainer.style = ` + display: none; + overflow: hidden; + margin-top: 10px; + max-height: 0; + transition: max-height 0.5s ease-in-out; + border: none; + border-radius: 8px; + `; + + trailerButton.addEventListener('click', () => { + if (iframeContainer.style.display === 'none') { + if (trailerUrl) { + const iframe = document.createElement('iframe'); + iframe.src = trailerUrl; + iframe.title = 'YouTube video player'; + iframe.frameborder = '0'; + iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'; + iframe.allowFullscreen = true; + iframeContainer.appendChild(iframe); + iframe.style.borderRadius = '16px'; + iframe.style.border = 'none'; + iframe.style.width = '400px'; + iframe.style.height = '315px'; + trailerButton.textContent = 'Close Trailer'; + } else { + iframeContainer.innerHTML = '

Trailer not available.

'; + } + iframeContainer.style.display = 'block'; + setTimeout(() => { + iframeContainer.style.maxHeight = '350px'; + }, 10); + } else { + iframeContainer.style.maxHeight = '0'; + setTimeout(() => { + iframeContainer.style.display = 'none'; + iframeContainer.innerHTML = ''; + trailerButton.textContent = 'Watch Trailer'; + }, 500); + } + }); + + document.getElementById('movie-description').appendChild(trailerButton); + document.getElementById('movie-description').appendChild(iframeContainer); + } +} + +async function fetchTvSeriesStreamingLinks(tvSeriesId) { + const url = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const results = data.results || {}; + let providersMap = {}; + + Object.values(results).forEach(region => { + if (region.flatrate) { + region.flatrate.forEach(provider => { + providersMap[provider.provider_id] = provider; + }); + } + }); + + return Object.values(providersMap).slice(0, 7); + } catch (error) { + console.error('Error fetching TV series streaming links:', error); + return []; + } +} + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + + localStorage.setItem('selectedActorId', actorId); + window.location.href = 'actor-details.html'; +} + +function selectTvSeriesId(tvSeriesId) { + localStorage.setItem('selectedTvSeriesId', tvSeriesId); + window.location.href = 'tv-details.html'; +} + +function selectCompanyId(companyId) { + localStorage.setItem('selectedCompanyId', companyId); + window.location.href = 'company-details.html'; +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +function handleKeywordClick(keyword) { + localStorage.setItem('searchQuery', keyword); + window.location.href = 'search.html'; +} + +function handleCreatorClick(creatorId, creatorName) { + localStorage.setItem('selectedDirectorId', creatorId); + document.title = `${creatorName} - Director's Details`; + updateUniqueDirectorsViewed(creatorId); + updateDirectorVisitCount(creatorId, creatorName); + window.location.href = 'director-details.html'; +} + +document.addEventListener('DOMContentLoaded', () => { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + if (tvSeriesId) { + fetchTvDetails(tvSeriesId); + } else { + fetchTvDetails(100088); + } + + document.getElementById('clear-search-btn').style.display = 'none'; + + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + const movieRating = savedRatings[tvSeriesId] || 0; + setStarRating(movieRating); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function getMovieCode2() { + const encodedKey = 'MmJhOGU1MzY='; + return atob(encodedKey); +} + +function getMovieName() { + const moviename = 'YXBpa2V5PQ=='; + return atob(moviename); +} + +function getMovieActor() { + const actor = 'd3d3Lm9tZGJhcGkuY29t'; + return atob(actor); +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/user-profile.js b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/user-profile.js new file mode 100644 index 00000000..be5a35ad --- /dev/null +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/js/user-profile.js @@ -0,0 +1,720 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + doc, + getDoc, + setDoc, + query, + collection, + where, + getDocs, + serverTimestamp, + deleteDoc, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { getAverageMovieRating } from './ratings-module.js'; +import { getTriviaStats } from './triviaModule.js'; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.addEventListener('DOMContentLoaded', function () { + showSpinner(); + handleProfileDisplay(); + setupEventListeners(); + setupSearchListeners(); + hideSpinner(); +}); + +function updateProgressCircles(movieRating, triviaScore) { + const movieRatingPercent = movieRating; + const triviaScorePercent = triviaScore; + + setProgress(document.getElementById('avgMovieRatingCircle'), document.getElementById('avgMovieRatingText'), movieRatingPercent); + setProgress(document.getElementById('avgTriviaScoreCircle'), document.getElementById('avgTriviaScoreText'), triviaScorePercent); +} + +function setProgress(circle, text, percent) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (percent / 100) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', percent > 50 ? '#4CAF50' : '#2196F3'); + text.textContent = `${Math.round(percent)}%`; + text.style.opacity = 1; + }, 10); +} + +function handleProfileDisplay() { + showSpinner(); + + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const welcomeMessage = document.getElementById('welcomeMessage'); + const signInPrompt = document.getElementById('signInPrompt'); + const viewMyProfileBtn = document.getElementById('viewMyProfileBtn'); + const profileContainer = document.getElementById('profileContainer'); + profileContainer.style.display = 'none'; + + if (isSignedIn && userEmail) { + loadProfile(userEmail); + viewMyProfileBtn.disabled = false; + viewMyProfileBtn.style.display = 'block'; + } else { + welcomeMessage.textContent = 'Please sign in to view your profile'; + signInPrompt.style.display = 'block'; + viewMyProfileBtn.disabled = true; + viewMyProfileBtn.style.display = 'none'; + } + + document.getElementById('viewMyProfileBtn').addEventListener('click', () => { + loadCurrentUserProfile(); + }); + + function loadCurrentUserProfile() { + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (currentUserEmail) { + loadProfile(currentUserEmail); + } else { + console.error('No user is currently signed in'); + } + } + + hideSpinner(); +} + +function setupSearchListeners() { + try { + const searchUserInput = document.getElementById('searchUserInput'); + const searchUserResults = document.getElementById('searchUserResults'); + + searchUserInput.addEventListener('input', () => { + const searchText = searchUserInput.value.trim(); + + if (searchText) { + performSearch(searchText); + } else { + searchUserResults.innerHTML = ''; + searchUserResults.style.display = 'none'; + } + }); + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + } +} + +async function performSearch(searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + const db = getFirestore(); + showSpinner(); + + try { + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); + const querySnapshot = await getDocs(userQuery); + + searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { + searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; + searchUserResults.style.display = 'block'; + } else { + searchUserResults.style.display = 'block'; + querySnapshot.forEach(doc => { + const user = doc.data(); + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadProfile(doc.id)); + + const img = document.createElement('img'); + img.src = user.profileImage || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.username}

Bio: ${ + user.bio || 'Not Set' + }

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + } + hideSpinner(); + } catch (error) { + console.error('Error during search: ', error); + searchUserResults.innerHTML = `
Error in searching: ${error.message}
`; + searchUserResults.style.display = 'block'; + hideSpinner(); + } +} + +document.getElementById('container1').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlyViewingProfile'); + + if (!userEmail) { + console.error('No user email found'); + return; + } + + try { + const rating = parseInt(localStorage.getItem('currentAverageRating'), 10); + const averageRating = rating.toFixed(1); + + const triviaStats = parseInt(localStorage.getItem('currentAverageTriviaScore'), 10); + const averageTriviaScore = triviaStats.toFixed(1); + + updateProgressCircles(averageRating, averageTriviaScore, 'container1'); + } catch (error) { + console.error('Error updating progress circles:', error); + } +}); + +document.getElementById('container2').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlyViewingProfile'); + + if (!userEmail) { + console.error('No user email found'); + return; + } + + try { + const rating = parseInt(localStorage.getItem('currentAverageRating'), 10); + const averageRating = rating.toFixed(1); + + const triviaStats = parseInt(localStorage.getItem('currentAverageTriviaScore'), 10); + const averageTriviaScore = triviaStats.toFixed(1); + + updateProgressCircles(averageRating, averageTriviaScore, 'container2'); + } catch (error) { + console.error('Error updating progress circles:', error); + } +}); + +async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMovieVerseUser')) { + showSpinner(); + try { + document.getElementById('viewMyProfileBtn').disabled = false; + + if (!userEmail) return; + + const welcomeMessage = document.getElementById('welcomeMessage'); + const profileContainer = document.getElementById('profileContainer'); + const changeProfileImageBtn = document.getElementById('changeProfileImageBtn'); + const editProfileBtn = document.getElementById('editProfileBtn'); + const removeProfileImageBtn = document.getElementById('removeProfileImage'); + const profileImage = document.getElementById('profileImage'); + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) + ) { + changeProfileImageBtn.style.display = 'none'; + editProfileBtn.style.display = 'none'; + profileImage.removeAttribute('onclick'); + profileImage.style.cursor = 'default'; + profileImage.title = 'Sign in to change profile image'; + } else { + changeProfileImageBtn.style.display = ''; + editProfileBtn.style.display = ''; + profileImage.setAttribute('onclick', 'document.getElementById("imageUpload").click()'); + profileImage.style.cursor = 'pointer'; + profileImage.title = 'Click to change profile image'; + } + + const rating = await getAverageMovieRating(userEmail); + const convertRatingToPercent = (rating / 5) * 100; + const averageRating = convertRatingToPercent.toFixed(1); + + const triviaStats = await getTriviaStats(userEmail); + + let averageTriviaScore = 0; + if (triviaStats.totalAttempted > 0) { + averageTriviaScore = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + } + + localStorage.setItem('currentlyViewingProfile', userEmail); + + updateProgressCircles(averageRating, averageTriviaScore); + + localStorage.setItem('currentAverageRating', averageRating); + localStorage.setItem('currentAverageTriviaScore', averageTriviaScore); + + profileContainer.style.display = 'block'; + + const docRef = doc(db, 'profiles', userEmail); + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let followUnfollowBtn = document.getElementById('followUnfollowBtn'); + if (!followUnfollowBtn) { + followUnfollowBtn = document.createElement('button'); + followUnfollowBtn.id = 'followUnfollowBtn'; + followUnfollowBtn.style.width = '100%'; + profileContainer.appendChild(followUnfollowBtn); + } + + if (currentUserEmail && userEmail !== currentUserEmail && isSignedIn) { + const followingRef = doc(db, 'profiles', currentUserEmail, 'following', userEmail); + const followersRef = doc(db, 'profiles', userEmail, 'followers', currentUserEmail); + + const followSnap = await getDoc(followingRef); + let isFollowing = followSnap.exists(); + + followUnfollowBtn.textContent = isFollowing ? 'Unfollow' : 'Follow'; + followUnfollowBtn.style.display = 'block'; + + followUnfollowBtn.onclick = async () => { + if (isFollowing) { + await deleteDoc(followingRef); + await deleteDoc(followersRef); + followUnfollowBtn.textContent = 'Follow'; + isFollowing = false; + await displayUserList('followers', userEmail); + } else { + const timestamp = serverTimestamp(); + await setDoc(followingRef, { timestamp: timestamp }); + await setDoc(followersRef, { timestamp: timestamp }); + followUnfollowBtn.textContent = 'Unfollow'; + isFollowing = true; + await displayUserList('followers', userEmail); + } + }; + } else { + followUnfollowBtn.style.display = 'none'; + } + + try { + const docSnap = await getDoc(docRef); + let profile = { + username: 'N/A', + dob: 'N/A', + bio: 'N/A', + favoriteGenres: 'N/A', + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: 'N/A', + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }; + + if (docSnap.exists()) { + profile = { ...profile, ...docSnap.data() }; + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } + + document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; + document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; + document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } + + hideSpinner(); + + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); + } else { + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } + + document.getElementById('usernameDisplay').innerHTML = `Username: N/A`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: N/A`; + document.getElementById('bioDisplay').innerHTML = `Bio: N/A`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: N/A`; + document.getElementById('locationDisplay').innerHTML = `Location: N/A`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: N/A`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: N/A`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: N/A`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: N/A`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: N/A`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } + + hideSpinner(); + + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); + } + } catch (error) { + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + + document.getElementById('viewMyProfileBtn').disabled = true; + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + + document.getElementById('viewMyProfileBtn').disabled = true; + } +} + +async function displayUserList(listType, userEmail) { + const db = getFirestore(); + const listRef = collection(db, 'profiles', userEmail, listType); + const userListSpan = document.getElementById(`${listType}List`); + + let loadingInterval; + function startLoadingAnimation() { + let dots = ''; + loadingInterval = setInterval(() => { + dots = dots.length < 3 ? dots + '.' : ''; + userListSpan.textContent = `Loading${dots}`; + }, 500); + } + + function stopLoadingAnimation() { + clearInterval(loadingInterval); + userListSpan.innerHTML = ''; + } + + startLoadingAnimation(); + + try { + const snapshot = await getDocs(listRef); + stopLoadingAnimation(); + + if (snapshot.empty) { + userListSpan.textContent = 'N/A'; + } else { + for (let docSnapshot of snapshot.docs) { + const userRef = doc(db, 'profiles', docSnapshot.id); + const userSnap = await getDoc(userRef); + if (userSnap.exists()) { + const userData = userSnap.data(); + + const userLink = document.createElement('a'); + userLink.textContent = userData.username; + userLink.href = '#'; + userLink.id = 'userLink'; + userLink.style.cursor = 'pointer'; + userLink.onclick = () => loadProfile(docSnapshot.id); + + userListSpan.appendChild(userLink); + userListSpan.appendChild(document.createTextNode(', ')); + } + } + + if (userListSpan.lastChild) { + userListSpan.removeChild(userListSpan.lastChild); + } + } + } catch (error) { + console.error('Error fetching user list:', error); + stopLoadingAnimation(); + userListSpan.innerHTML = 'Error loading data'; + } +} + +async function saveProfileChanges() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) return; + + const profileRef = doc(db, 'profiles', userEmail); + const currentDoc = await getDoc(profileRef); + const currentProfile = currentDoc.exists() ? currentDoc.data() : null; + + const newUsername = document.getElementById('editUsername').value.trim(); + + if (currentProfile && currentProfile.username && currentProfile.username !== 'N/A' && !newUsername) { + alert('You cannot delete your username. Please enter a valid username.'); + document.getElementById('editUsername').value = currentProfile.username; + return; + } + + const profile = { + username: newUsername || currentProfile.username, + dob: document.getElementById('editDob').value, + bio: document.getElementById('editBio').value, + favoriteGenres: document + .getElementById('editFavoriteGenres') + .value.split(',') + .map(genre => genre.trim()), + location: document.getElementById('editLocation').value, + favoriteMovie: document.getElementById('editFavoriteMovie').value, + hobbies: document + .getElementById('editHobbies') + .value.split(',') + .map(hobby => hobby.trim()), + favoriteActor: document.getElementById('editFavoriteActor').value, + favoriteDirector: document.getElementById('editFavoriteDirector').value, + personalQuote: document.getElementById('editPersonalQuote').value, + }; + + try { + await setDoc(profileRef, profile, { merge: true }); + console.log('Profile updated successfully.'); + closeModal(); + loadProfile(); + } catch (error) { + console.log('Error updating profile: ', error); + } +} + +async function removeProfileImage() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) return; + + const defaultImageUrl = '../../images/user-default.png'; + + try { + await setDoc(doc(db, 'profiles', userEmail), { profileImage: defaultImageUrl }, { merge: true }); + document.getElementById('profileImage').src = defaultImageUrl; + document.getElementById('removeProfileImage').style.display = 'none'; + } catch (error) { + console.log('Error removing image: ', error); + } +} + +async function uploadImage() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) { + alert("You're not signed in."); + return; + } + + const fileInput = document.getElementById('imageUpload'); + const file = fileInput.files[0]; + if (!file) { + alert('No file selected. Please choose an image.'); + return; + } + + try { + const base64Image = await resizeImageAndConvertToBase64(file, 1024, 1024); + + await setDoc(doc(db, 'profiles', userEmail), { profileImage: base64Image }, { merge: true }); + + document.getElementById('profileImage').src = base64Image; + console.log('Image processed and Firestore updated'); + window.location.reload(); + } catch (error) { + console.log('Error during image processing:', error); + alert('Error during image processing: ' + error.message); + } +} + +function resizeImageAndConvertToBase64(file, maxWidth, maxHeight) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = e => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement('canvas'); + let width = img.width; + let height = img.height; + + if (width > height) { + if (width > maxWidth) { + height *= maxWidth / width; + width = maxWidth; + } + } else { + if (height > maxHeight) { + width *= maxHeight / height; + height = maxHeight; + } + } + + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0, width, height); + const dataUrl = canvas.toDataURL('image/jpeg', 0.7); + resolve(dataUrl); + }; + img.src = e.target.result; + }; + reader.onerror = error => reject(error); + reader.readAsDataURL(file); + }); +} + +function setupEventListeners() { + document.getElementById('saveChanges').addEventListener('click', async () => { + await saveProfileChanges(); + }); + + document.getElementById('cancelEdit').addEventListener('click', () => { + closeModal(); + }); + + const imageUploadInput = document.getElementById('imageUpload'); + imageUploadInput.addEventListener('change', uploadImage); + + document.getElementById('editProfileBtn').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) { + alert("You're not signed in."); + return; + } + + try { + const docRef = doc(db, 'profiles', userEmail); + const docSnap = await getDoc(docRef); + + let profile = { + username: 'N/A', + dob: '', + bio: 'N/A', + favoriteGenres: [], + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: ['N/A'], + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }; + + if (docSnap.exists()) { + profile = docSnap.data(); + profile.hobbies = profile.hobbies.length > 0 ? profile.hobbies : ['N/A']; + } + + document.getElementById('editUsername').value = profile.username; + document.getElementById('editDob').value = profile.dob; + const defaultDOB = new Date(); + defaultDOB.setFullYear(defaultDOB.getFullYear() - 18); + const defaultDOBString = defaultDOB.toISOString().split('T')[0]; + + document.getElementById('editDob').value = profile.dob || defaultDOBString; + document.getElementById('editBio').value = profile.bio; + document.getElementById('editFavoriteGenres').value = profile.favoriteGenres.join(', '); + document.getElementById('editLocation').value = profile.location; + document.getElementById('editFavoriteMovie').value = profile.favoriteMovie; + document.getElementById('editHobbies').value = profile.hobbies.join(', '); + document.getElementById('editFavoriteActor').value = profile.favoriteActor; + document.getElementById('editFavoriteDirector').value = profile.favoriteDirector; + document.getElementById('editPersonalQuote').value = profile.personalQuote; + document.getElementById('profileImage').src = profile.profileImage || '../../images/user-default.png'; + document.getElementById('editProfileModal').style.display = 'block'; + } catch (error) { + console.log('Error accessing Firestore: ', error); + } + }); + + document.getElementById('imageUpload').addEventListener('change', async () => { + await uploadImage(); + }); + + document.getElementById('removeProfileImage').addEventListener('click', async () => { + await removeProfileImage(); + }); +} diff --git a/MovieVerse-Mobile/platforms/ios/www/index.js b/MovieVerse-Mobile/platforms/ios/www/index.js index 2e90def6..68445014 100644 --- a/MovieVerse-Mobile/platforms/ios/www/index.js +++ b/MovieVerse-Mobile/platforms/ios/www/index.js @@ -1,22 +1,22 @@ -const director_main = document.getElementById('director-spotlight'); -const form = document.getElementById('form'); -const search = document.getElementById('search'); -const searchButton = document.getElementById('button-search'); -const searchTitle = document.getElementById('search-title'); -const otherTitle = document.getElementById('other1'); +const director_main = document.getElementById("director-spotlight"); +const form = document.getElementById("form"); +const search = document.getElementById("search"); +const searchButton = document.getElementById("button-search"); +const searchTitle = document.getElementById("search-title"); +const otherTitle = document.getElementById("other1"); function showSpinner() { - document.getElementById('myModal').classList.add('modal-visible'); + document.getElementById("myModal").classList.add("modal-visible"); } function hideSpinner() { - document.getElementById('myModal').classList.remove('modal-visible'); + document.getElementById("myModal").classList.remove("modal-visible"); } -document.addEventListener('DOMContentLoaded', function () { - const pagination = document.getElementById('most-popular-pagination'); - const genresContainer = document.querySelector('.genres'); - const mainContainer = document.getElementById('most-popular'); +document.addEventListener("DOMContentLoaded", function () { + const pagination = document.getElementById("most-popular-pagination"); + const genresContainer = document.querySelector(".genres"); + const mainContainer = document.getElementById("most-popular"); function movePagination() { if (window.innerWidth <= 767) { @@ -27,14 +27,16 @@ document.addEventListener('DOMContentLoaded', function () { } movePagination(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { let currentPageMostPopular = 1; const totalPages = 320; - const mostPopularMain = document.getElementById('most-popular'); - const paginationContainer = document.getElementById('most-popular-pagination'); + const mostPopularMain = document.getElementById("most-popular"); + const paginationContainer = document.getElementById( + "most-popular-pagination", + ); const fetchAndUpdateMostPopular = () => { const mostPopularUrl = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}`; @@ -43,12 +45,16 @@ document.addEventListener('DOMContentLoaded', function () { }; const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageMostPopular > 1, () => { - currentPageMostPopular--; - fetchAndUpdateMostPopular(); - }); + const prevButton = createNavigationButton( + "<", + currentPageMostPopular > 1, + () => { + currentPageMostPopular--; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(prevButton); let startPage = Math.max(currentPageMostPopular - 2, 1); @@ -58,7 +64,8 @@ document.addEventListener('DOMContentLoaded', function () { if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -66,22 +73,27 @@ document.addEventListener('DOMContentLoaded', function () { } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPageMostPopular < totalPages, () => { - currentPageMostPopular++; - fetchAndUpdateMostPopular(); - }); + const nextButton = createNavigationButton( + ">", + currentPageMostPopular < totalPages, + () => { + currentPageMostPopular++; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(nextButton); }; const createNavigationButton = (text, enabled, clickHandler) => { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { button.onclick = clickHandler; @@ -90,12 +102,12 @@ document.addEventListener('DOMContentLoaded', function () { return button; }; - const createPageButton = pageNum => { - const button = document.createElement('button'); + const createPageButton = (pageNum) => { + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { button.onclick = function () { @@ -104,7 +116,7 @@ document.addEventListener('DOMContentLoaded', function () { }; if (pageNum === currentPageMostPopular) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -113,7 +125,12 @@ document.addEventListener('DOMContentLoaded', function () { fetchAndUpdateMostPopular(); }); -function setupPagination(mainElementId, paginationContainerId, genresContainerId, baseUrl) { +function setupPagination( + mainElementId, + paginationContainerId, + genresContainerId, + baseUrl, +) { let currentPage = 1; let totalPages = 10; @@ -168,7 +185,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId mainElement.innerHTML = `

No movies found on this page.

`; } } catch (error) { - console.log('Error fetching data: ', error); + console.log("Error fetching data: ", error); mainElement.innerHTML = `

No movies found on this page.

`; } finally { hideSpinner(); @@ -177,9 +194,9 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPage > 1, () => { + const prevButton = createNavigationButton("<", currentPage > 1, () => { currentPage--; fetchAndUpdate(); }); @@ -194,7 +211,8 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -202,45 +220,50 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPage < totalPages, () => { - currentPage++; - fetchAndUpdate(); - }); + const nextButton = createNavigationButton( + ">", + currentPage < totalPages, + () => { + currentPage++; + fetchAndUpdate(); + }, + ); paginationContainer.appendChild(nextButton); }; function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { - button.addEventListener('click', () => { - currentPage = typeof pageNum === 'number' ? pageNum : currentPage; + button.addEventListener("click", () => { + currentPage = typeof pageNum === "number" ? pageNum : currentPage; fetchAndUpdate(); }); if (pageNum === currentPage) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -250,7 +273,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId fetchAndUpdate(); let resizeTimer; - window.addEventListener('resize', () => { + window.addEventListener("resize", () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(movePagination, 250); }); @@ -265,16 +288,21 @@ async function fetchAndDisplayMovies(url, count, mainElement) { showMovies(movies, mainElement); } -document.addEventListener('DOMContentLoaded', async () => { +document.addEventListener("DOMContentLoaded", async () => { let currentPageRecommended = 1; const totalPagesRecommended = 60; - const recommendedMain = document.getElementById('recommended'); - const paginationContainerRecommended = document.getElementById('recommended-pagination'); - const genresContainer = document.getElementById('recommendedDIV'); + const recommendedMain = document.getElementById("recommended"); + const paginationContainerRecommended = document.getElementById( + "recommended-pagination", + ); + const genresContainer = document.getElementById("recommendedDIV"); function movePagination() { if (window.innerWidth <= 767) { - recommendedMain.parentNode.insertBefore(paginationContainerRecommended, recommendedMain); + recommendedMain.parentNode.insertBefore( + paginationContainerRecommended, + recommendedMain, + ); } else { genresContainer.appendChild(paginationContainerRecommended); } @@ -287,7 +315,7 @@ document.addEventListener('DOMContentLoaded', async () => { const mostCommonGenre = getMostCommonGenre(); const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); - recommendedMain.innerHTML = ''; + recommendedMain.innerHTML = ""; if (!mostVisitedMovieGenre || !mostCommonGenre) { recommendedMain.innerHTML = `
@@ -302,17 +330,29 @@ document.addEventListener('DOMContentLoaded', async () => { const commonGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostCommonGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; const visitedGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostVisitedMovieGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; - await fetchAndDisplayMovies(commonGenreUrl, totalMoviesToDisplay, recommendedMain); - await fetchAndDisplayMovies(visitedGenreUrl, totalMoviesToDisplay, recommendedMain); + await fetchAndDisplayMovies( + commonGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); + await fetchAndDisplayMovies( + visitedGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); updatePaginationDisplayRecommended(); hideSpinner(); } function updatePaginationDisplayRecommended() { - paginationContainerRecommended.innerHTML = ''; + paginationContainerRecommended.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageRecommended > 1, () => generateRecommendations(currentPageRecommended - 1)); + const prevButton = createNavigationButton( + "<", + currentPageRecommended > 1, + () => generateRecommendations(currentPageRecommended - 1), + ); paginationContainerRecommended.appendChild(prevButton); let startPage = Math.max(currentPageRecommended - 2, 1); @@ -321,43 +361,57 @@ document.addEventListener('DOMContentLoaded', async () => { if (endPage === totalPagesRecommended) startPage = Math.max(endPage - 4, 1); if (startPage > 1) { - paginationContainerRecommended.appendChild(createPageButton(1, generateRecommendations)); - if (startPage > 2) paginationContainerRecommended.appendChild(createPageButton('...')); + paginationContainerRecommended.appendChild( + createPageButton(1, generateRecommendations), + ); + if (startPage > 2) + paginationContainerRecommended.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { - paginationContainerRecommended.appendChild(createPageButton(i, generateRecommendations, i === currentPageRecommended)); + paginationContainerRecommended.appendChild( + createPageButton( + i, + generateRecommendations, + i === currentPageRecommended, + ), + ); } if (endPage < totalPagesRecommended) { - if (endPage < totalPagesRecommended - 1) paginationContainerRecommended.appendChild(createPageButton('...')); - paginationContainerRecommended.appendChild(createPageButton(totalPagesRecommended, generateRecommendations)); + if (endPage < totalPagesRecommended - 1) + paginationContainerRecommended.appendChild(createPageButton("...")); + paginationContainerRecommended.appendChild( + createPageButton(totalPagesRecommended, generateRecommendations), + ); } - const nextButton = createNavigationButton('>', currentPageRecommended < totalPagesRecommended, () => - generateRecommendations(currentPageRecommended + 1) + const nextButton = createNavigationButton( + ">", + currentPageRecommended < totalPagesRecommended, + () => generateRecommendations(currentPageRecommended + 1), ); paginationContainerRecommended.appendChild(nextButton); } function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum, fetchFunction, isActive) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button' + (isActive ? ' active' : ''); + button.className = "page-button" + (isActive ? " active" : ""); - if (pageNum !== '...') { - button.addEventListener('click', () => fetchFunction(pageNum)); + if (pageNum !== "...") { + button.addEventListener("click", () => fetchFunction(pageNum)); } else { button.disabled = true; } @@ -367,7 +421,7 @@ document.addEventListener('DOMContentLoaded', async () => { movePagination(); await generateRecommendations(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); async function getMovies(url, mainElement, page = 1) { @@ -398,102 +452,149 @@ async function getMovies(url, mainElement, page = 1) { } async function getAdditionalPosters(movieId) { - const response = await fetch(`https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`); + const response = await fetch( + `https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`, + ); const data = await response.json(); - return data.posters.map(poster => poster.file_path); + return data.posters.map((poster) => poster.file_path); } function rotateImages(imageElements, interval = 3000) { - const uniqueImageElements = Array.from(imageElements).filter((el, index, self) => index === self.findIndex(e => e.src === el.src)); + const uniqueImageElements = Array.from(imageElements).filter( + (el, index, self) => index === self.findIndex((e) => e.src === el.src), + ); if (uniqueImageElements.length <= 1) return; let currentIndex = 0; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; setTimeout(() => { setInterval(() => { - uniqueImageElements[currentIndex].style.opacity = '0'; + uniqueImageElements[currentIndex].style.opacity = "0"; currentIndex = (currentIndex + 1) % uniqueImageElements.length; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; }, interval); }, 0); } async function showMovies(movies, mainElement) { - mainElement.innerHTML = ''; + mainElement.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - const observer = new IntersectionObserver( + // Observer for background image loading and rotation setup + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch additional posters and set up rotation in the background const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); + const movieImageContainer = movieEl.querySelector(".movie-images"); allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); - const imagePromises = allPosters.map((poster, index) => { + // Load images in the background + allPosters.forEach((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; - img.loading = index === 0 ? 'eager' : 'lazy'; + img.loading = index === 0 ? "eager" : "lazy"; img.alt = `${movieEl.dataset.title} poster ${index + 1}`; img.width = 300; img.height = 435; - img.style.position = 'absolute'; + img.style.position = "absolute"; img.style.top = 0; img.style.left = 0; - img.style.transition = 'opacity 1s ease-in-out'; - img.style.opacity = '0'; - img.classList.add('poster-img'); + img.style.transition = "opacity 1s ease-in-out"; + img.style.opacity = "0"; + img.classList.add("poster-img"); movieImageContainer.appendChild(img); - return new Promise(resolve => { - img.onload = () => resolve(img); - }); + img.onload = () => { + if (index === 0) img.style.opacity = "1"; // Show the first image + }; }); - const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); - await Promise.race([Promise.all(imagePromises), maxWait]); - - movieImageContainer.querySelector('.poster-img').style.opacity = '1'; - + // Start rotating images in the background rotateImages(Array.from(movieImageContainer.children)); observer.unobserve(movieEl); } } }, { - rootMargin: '50px 0px', + rootMargin: "50px 0px", threshold: 0.1, - } + }, ); - movies.forEach(movie => { - let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; - - const movieEl = document.createElement('div'); - movieEl.style.zIndex = '1000'; - movieEl.classList.add('movie'); + movies.forEach((movie, index) => { + let { + id, + poster_path, + title, + vote_average, + vote_count, + overview, + genre_ids, + } = movie; + + const movieEl = document.createElement("div"); + movieEl.style.zIndex = "1000"; + movieEl.classList.add("movie"); movieEl.dataset.id = id; movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; - const words = title.split(' '); + const words = title.split(" "); if (words.length >= 8) { - words[7] = '...'; - title = words.slice(0, 8).join(' '); + words[7] = "..."; + title = words.slice(0, 8).join(" "); } - const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); - const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); + const voteAvg = vote_count === 0 ? "Unrated" : vote_average.toFixed(1); + const ratingClass = + vote_count === 0 ? "unrated" : getClassByRate(vote_average); - if (overview === '') { - overview = 'No overview available.'; + if (overview === "") { + overview = "No overview available."; } movieEl.innerHTML = ` @@ -511,37 +612,44 @@ async function showMovies(movies, mainElement) { ${overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); + + // Observe for background image loading and rotation + imageObserver.observe(movieEl); }); } function updateFavoriteGenre(genre_ids) { if (genre_ids && genre_ids.length > 0) { - const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenres = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; favoriteGenres.push(genre_ids[0]); - localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + localStorage.setItem("favoriteGenres", JSON.stringify(favoriteGenres)); } } function updateUniqueMoviesViewed(movieId) { - let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + let viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; if (!viewedMovies.includes(movieId)) { viewedMovies.push(movieId); - localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); + localStorage.setItem("uniqueMoviesViewed", JSON.stringify(viewedMovies)); } } async function ensureGenreMapIsAvailable() { - if (!localStorage.getItem('genreMap')) { + if (!localStorage.getItem("genreMap")) { await fetchGenreMap(); } } @@ -556,9 +664,9 @@ async function fetchGenreMap() { map[genre.id] = genre.name; return map; }, {}); - localStorage.setItem('genreMap', JSON.stringify(genreMap)); + localStorage.setItem("genreMap", JSON.stringify(genreMap)); } catch (error) { - console.log('Error fetching genre map:', error); + console.log("Error fetching genre map:", error); } } @@ -567,49 +675,51 @@ async function rotateUserStats() { const stats = [ { - label: 'Your Current Time', + label: "Your Current Time", getValue: () => { const now = new Date(); let hours = now.getHours(); let minutes = now.getMinutes(); - hours = hours < 10 ? '0' + hours : hours; - minutes = minutes < 10 ? '0' + minutes : minutes; + hours = hours < 10 ? "0" + hours : hours; + minutes = minutes < 10 ? "0" + minutes : minutes; return `${hours}:${minutes}`; }, }, - { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, - { label: 'Most Visited Director', getValue: getMostVisitedDirector }, - { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { label: "Most Visited Movie", getValue: getMostVisitedMovie }, + { label: "Most Visited Director", getValue: getMostVisitedDirector }, + { label: "Most Visited Actor", getValue: getMostVisitedActor }, { - label: 'Movies Discovered', + label: "Movies Discovered", getValue: () => { - const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + const viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; return viewedMovies.length; }, }, { - label: 'Favorite Movies', + label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritedMovies = + JSON.parse(localStorage.getItem("moviesFavorited")) || []; return favoritedMovies.length; }, }, { - label: 'Favorite Genre', + label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMapString = localStorage.getItem('genreMap'); + const genreMapString = localStorage.getItem("genreMap"); if (!genreMapString) { - console.log('No genre map found in localStorage.'); - return 'Not Available'; + console.log("No genre map found in localStorage."); + return "Not Available"; } let genreMap; try { genreMap = JSON.parse(genreMapString); } catch (e) { - console.log('Error parsing genre map:', e); - return 'Not Available'; + console.log("Error parsing genre map:", e); + return "Not Available"; } let genreObject; @@ -618,74 +728,81 @@ async function rotateUserStats() { acc[genre.id] = genre.name; return acc; }, {}); - } else if (typeof genreMap === 'object' && genreMap !== null) { + } else if (typeof genreMap === "object" && genreMap !== null) { genreObject = genreMap; } else { - console.log('genreMap is neither an array nor a proper object:', genreMap); - return 'Not Available'; + console.log( + "genreMap is neither an array nor a proper object:", + genreMap, + ); + return "Not Available"; } - return genreObject[mostCommonGenreCode] || 'Not Available'; + return genreObject[mostCommonGenreCode] || "Not Available"; }, }, { - label: 'Watchlists Created', - getValue: () => localStorage.getItem('watchlistsCreated') || 0, + label: "Watchlists Created", + getValue: () => localStorage.getItem("watchlistsCreated") || 0, }, { - label: 'Average Movie Rating', - getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + label: "Average Movie Rating", + getValue: () => localStorage.getItem("averageMovieRating") || "Not Rated", }, { - label: 'Directors Discovered', + label: "Directors Discovered", getValue: () => { - const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + const viewedDirectors = + JSON.parse(localStorage.getItem("uniqueDirectorsViewed")) || []; return viewedDirectors.length; }, }, { - label: 'Actors Discovered', + label: "Actors Discovered", getValue: () => { - const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + const viewedActors = + JSON.parse(localStorage.getItem("uniqueActorsViewed")) || []; return viewedActors.length; }, }, - { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + { label: "Your Trivia Accuracy", getValue: getTriviaAccuracy }, ]; let currentStatIndex = 0; function updateStatDisplay() { const currentStat = stats[currentStatIndex]; - document.getElementById('stats-label').textContent = currentStat.label + ':'; - document.getElementById('stats-display').textContent = currentStat.getValue(); + document.getElementById("stats-label").textContent = + currentStat.label + ":"; + document.getElementById("stats-display").textContent = + currentStat.getValue(); currentStatIndex = (currentStatIndex + 1) % stats.length; } updateStatDisplay(); - const localTimeDiv = document.getElementById('local-time'); + const localTimeDiv = document.getElementById("local-time"); let statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.addEventListener('click', () => { + localTimeDiv.addEventListener("click", () => { clearInterval(statRotationInterval); updateStatDisplay(); statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + localTimeDiv.scrollIntoView({ behavior: "smooth" }); }); } function updateMovieVisitCount(movieId, movieTitle) { - let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; if (!movieVisits[movieId]) { movieVisits[movieId] = { count: 0, title: movieTitle }; } movieVisits[movieId].count += 1; - localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem("movieVisits", JSON.stringify(movieVisits)); } function getMostVisitedMovie() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; - let mostVisitedMovie = ''; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; + let mostVisitedMovie = ""; let maxVisits = 0; for (const movieId in movieVisits) { @@ -695,11 +812,11 @@ function getMostVisitedMovie() { } } - return mostVisitedMovie || 'Not Available'; + return mostVisitedMovie || "Not Available"; } async function getMostVisitedMovieGenre() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; let mostVisitedGenre = null; let maxVisits = 0; @@ -722,8 +839,8 @@ async function fetchGenreForMovie(movieId) { } function getMostVisitedActor() { - const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; - let mostVisitedActor = ''; + const actorVisits = JSON.parse(localStorage.getItem("actorVisits")) || {}; + let mostVisitedActor = ""; let maxVisits = 0; for (const actorId in actorVisits) { @@ -733,12 +850,13 @@ function getMostVisitedActor() { } } - return mostVisitedActor || 'Not Available'; + return mostVisitedActor || "Not Available"; } function getMostVisitedDirector() { - const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; - let mostVisitedDirector = ''; + const directorVisits = + JSON.parse(localStorage.getItem("directorVisits")) || {}; + let mostVisitedDirector = ""; let maxVisits = 0; for (const directorId in directorVisits) { @@ -747,16 +865,16 @@ function getMostVisitedDirector() { maxVisits = directorVisits[directorId].count; } } - return mostVisitedDirector || 'Not Available'; + return mostVisitedDirector || "Not Available"; } function getTriviaAccuracy() { - let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + let triviaStats = JSON.parse(localStorage.getItem("triviaStats")) || { totalCorrect: 0, totalAttempted: 0, }; if (triviaStats.totalAttempted === 0) { - return 'No trivia attempted'; + return "No trivia attempted"; } let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; @@ -764,13 +882,14 @@ function getTriviaAccuracy() { } function getMostCommonGenre() { - const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenresArray = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; const genreCounts = favoriteGenresArray.reduce((acc, genre) => { acc[genre] = (acc[genre] || 0) + 1; return acc; }, {}); - let mostCommonGenre = ''; + let mostCommonGenre = ""; let maxCount = 0; for (const genre in genreCounts) { @@ -780,16 +899,16 @@ function getMostCommonGenre() { } } - return mostCommonGenre || 'Not Available'; + return mostCommonGenre || "Not Available"; } const movieCode = { - part1: 'YzVhMjBjODY=', - part2: 'MWFjZjdiYjg=', - part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', + part1: "YzVhMjBjODY=", + part2: "MWFjZjdiYjg=", + part3: "ZDllOTg3ZGNjN2YxYjU1OA==", }; -document.addEventListener('DOMContentLoaded', rotateUserStats); +document.addEventListener("DOMContentLoaded", rotateUserStats); async function showMovieOfTheDay() { const year = new Date().getFullYear(); @@ -802,26 +921,28 @@ async function showMovieOfTheDay() { if (movies.length > 0) { const randomMovie = movies[Math.floor(Math.random() * movies.length)]; - localStorage.setItem('selectedMovieId', randomMovie.id); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomMovie.id); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } else { fallbackMovieSelection(); } } catch (error) { - console.log('Error fetching movie:', error); + console.log("Error fetching movie:", error); fallbackMovieSelection(); } } function fallbackMovieSelection() { const fallbackMovies = [ - 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, - 424, 98, + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, + 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, 424, + 98, ]; - const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + const randomFallbackMovie = + fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; - localStorage.setItem('selectedMovieId', randomFallbackMovie); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomFallbackMovie); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } function calculateMoviesToDisplay() { @@ -855,71 +976,75 @@ function calculateMoviesToDisplay() { function getClassByRate(vote) { if (vote >= 8) { - return 'green'; + return "green"; } else if (vote >= 5) { - return 'orange'; + return "orange"; } else { - return 'red'; + return "red"; } } -form.addEventListener('submit', e => { +form.addEventListener("submit", (e) => { e.preventDefault(); - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; }); function toggleNav() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - sideNav.classList.toggle('manual-toggle'); + sideNav.classList.toggle("manual-toggle"); adjustNavBar(); } function removeNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if (sideNav.classList.contains("manual-toggle")) { + sideNav.classList.remove("manual-toggle"); } adjustNavBar(); } function adjustNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0px'; + if (sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0px"; } else { - sideNav.style.left = '-250px'; + sideNav.style.left = "-250px"; } } -document.addEventListener('mousemove', function (event) { - const sideNav = document.getElementById('side-nav'); +document.addEventListener("mousemove", function (event) { + const sideNav = document.getElementById("side-nav"); - if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0'; + if (event.clientX < 10 && !sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0"; } }); -document.addEventListener('click', function (event) { - const sideNav = document.getElementById('side-nav'); - const navToggle = document.getElementById('nav-toggle'); +document.addEventListener("click", function (event) { + const sideNav = document.getElementById("side-nav"); + const navToggle = document.getElementById("nav-toggle"); - if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if ( + !sideNav.contains(event.target) && + !navToggle.contains(event.target) && + sideNav.classList.contains("manual-toggle") + ) { + sideNav.classList.remove("manual-toggle"); adjustNavBar(); } }); -document.getElementById('side-nav').addEventListener('mouseleave', function () { - const sideNav = document.getElementById('side-nav'); +document.getElementById("side-nav").addEventListener("mouseleave", function () { + const sideNav = document.getElementById("side-nav"); - if (!sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '-250px'; + if (!sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "-250px"; } }); @@ -928,32 +1053,32 @@ const IMGPATH = `https://image.tmdb.org/t/p/w500`; const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; const directors = [ - { name: 'Alfred Hitchcock', id: '2636' }, - { name: 'Steven Spielberg', id: '488' }, - { name: 'Martin Scorsese', id: '1032' }, - { name: 'Quentin Tarantino', id: '138' }, - { name: 'Christopher Nolan', id: '525' }, - { name: 'Stanley Kubrick', id: '240' }, - { name: 'Bong Joon-ho', id: '21684' }, - { name: 'David Fincher', id: '7467' }, - { name: 'James Cameron', id: '2710' }, - { name: 'Francis Ford Coppola', id: '1776' }, - { name: 'Tim Burton', id: '510' }, - { name: 'Ridley Scott', id: '578' }, - { name: 'Joel Coen', id: '1223' }, - { name: 'Spike Lee', id: '5281' }, - { name: 'Woody Allen', id: '1243' }, - { name: 'Peter Jackson', id: '108' }, - { name: 'Oliver Stone', id: '1152' }, - { name: 'David Lynch', id: '5602' }, - { name: 'Roman Polanski', id: '3556' }, - { name: 'Wes Anderson', id: '5655' }, - { name: 'Sergio Leone', id: '4385' }, - { name: 'Akira Kurosawa', id: '5026' }, - { name: 'Federico Fellini', id: '4415' }, - { name: 'John Ford', id: '8500' }, - { name: 'Fritz Lang', id: '68' }, - { name: 'Frank Capra', id: '2662' }, + { name: "Alfred Hitchcock", id: "2636" }, + { name: "Steven Spielberg", id: "488" }, + { name: "Martin Scorsese", id: "1032" }, + { name: "Quentin Tarantino", id: "138" }, + { name: "Christopher Nolan", id: "525" }, + { name: "Stanley Kubrick", id: "240" }, + { name: "Bong Joon-ho", id: "21684" }, + { name: "David Fincher", id: "7467" }, + { name: "James Cameron", id: "2710" }, + { name: "Francis Ford Coppola", id: "1776" }, + { name: "Tim Burton", id: "510" }, + { name: "Ridley Scott", id: "578" }, + { name: "Joel Coen", id: "1223" }, + { name: "Spike Lee", id: "5281" }, + { name: "Woody Allen", id: "1243" }, + { name: "Peter Jackson", id: "108" }, + { name: "Oliver Stone", id: "1152" }, + { name: "David Lynch", id: "5602" }, + { name: "Roman Polanski", id: "3556" }, + { name: "Wes Anderson", id: "5655" }, + { name: "Sergio Leone", id: "4385" }, + { name: "Akira Kurosawa", id: "5026" }, + { name: "Federico Fellini", id: "4415" }, + { name: "John Ford", id: "8500" }, + { name: "Fritz Lang", id: "68" }, + { name: "Frank Capra", id: "2662" }, ]; let currentDirectorIndex = 0; @@ -972,7 +1097,8 @@ setInterval(changeDirector, 3600000); function updateDirectorSpotlight() { const director = directors[currentDirectorIndex]; - document.getElementById('spotlight-director-name').textContent = director.name; + document.getElementById("spotlight-director-name").textContent = + director.name; const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_people=${ director.id @@ -981,7 +1107,26 @@ function updateDirectorSpotlight() { } function getMovieVerseData(input) { - return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); + return String.fromCharCode( + 97, + 112, + 105, + 46, + 116, + 104, + 101, + 109, + 111, + 118, + 105, + 101, + 100, + 98, + 46, + 111, + 114, + 103, + ); } function generateMovieNames(input) { @@ -1005,21 +1150,59 @@ async function getDirectorSpotlight(url) { } function showMoviesDirectorSpotlight(movies) { - director_main.innerHTML = ''; + director_main.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - movies.forEach(movie => { + movies.forEach((movie, index) => { const { id, poster_path, title, vote_average, genre_ids } = movie; - const movieEl = document.createElement('div'); + const movieEl = document.createElement("div"); - movieEl.classList.add('movie'); - movieEl.style.zIndex = '1000'; + movieEl.classList.add("movie"); + movieEl.style.zIndex = "1000"; + // Movie image and fallback in case the image is unavailable const movieImage = poster_path ? `${title}` : `
Image Not Available
`; - const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : 'Unrated'; - const ratingClass = vote_average > 0 ? getClassByRate(vote_average) : 'unrated'; + const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : "Unrated"; + const ratingClass = + vote_average > 0 ? getClassByRate(vote_average) : "unrated"; movieEl.innerHTML = ` ${movieImage} @@ -1032,26 +1215,29 @@ function showMoviesDirectorSpotlight(movies) { ${movie.overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); director_main.appendChild(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); }); } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); + localStorage.setItem("isSignedIn", JSON.stringify(false)); + alert("You have been signed out."); } else { - window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; + window.location.href = "MovieVerse-Frontend/html/sign-in.html"; return; } @@ -1059,213 +1245,215 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const signInText = document.getElementById("signInOutText"); + const signInIcon = document.getElementById("signInIcon"); + const signOutIcon = document.getElementById("signOutIcon"); if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; + signInText.textContent = "Sign Out"; + signInIcon.style.display = "none"; + signOutIcon.style.display = "inline-block"; } else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; + signInText.textContent = "Sign In"; + signInIcon.style.display = "inline-block"; + signOutIcon.style.display = "none"; } - const mobileSignInText = document.getElementById('mobileSignInOutText'); - const mobileSignInIcon = document.getElementById('mobileSignInIcon'); - const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); + const mobileSignInText = document.getElementById("mobileSignInOutText"); + const mobileSignInIcon = document.getElementById("mobileSignInIcon"); + const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); if (isSignedIn) { - mobileSignInText.textContent = 'Sign Out'; - mobileSignInIcon.style.display = 'none'; - mobileSignOutIcon.style.display = 'inline-block'; + mobileSignInText.textContent = "Sign Out"; + mobileSignInIcon.style.display = "none"; + mobileSignOutIcon.style.display = "inline-block"; } else { - mobileSignInText.textContent = 'Sign In'; - mobileSignInIcon.style.display = 'inline-block'; - mobileSignOutIcon.style.display = 'none'; + mobileSignInText.textContent = "Sign In"; + mobileSignInIcon.style.display = "inline-block"; + mobileSignOutIcon.style.display = "none"; } } setupPagination( - 'award-winning', - 'award-winning-pagination', - 'award-winning-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` + "award-winning", + "award-winning-pagination", + "award-winning-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, ); setupPagination( - 'hidden-gems', - 'hidden-gems-pagination', - 'hidden-gems-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` + "hidden-gems", + "hidden-gems-pagination", + "hidden-gems-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, ); setupPagination( - 'western', - 'western-pagination', - 'western-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` + "western", + "western-pagination", + "western-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'war', - 'war-pagination', - 'war-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` + "war", + "war-pagination", + "war-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'vietnamese', - 'vietnamese-pagination', - 'vietnamese-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` + "vietnamese", + "vietnamese-pagination", + "vietnamese-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, ); setupPagination( - 'korean', - 'korean-pagination', - 'korean-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` + "korean", + "korean-pagination", + "korean-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, ); setupPagination( - 'musical', - 'musical-pagination', - 'musical-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` + "musical", + "musical-pagination", + "musical-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'drama', - 'drama-pagination', - 'drama-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` + "drama", + "drama-pagination", + "drama-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'indian', - 'indian-pagination', - 'indian-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` + "indian", + "indian-pagination", + "indian-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, ); setupPagination( - 'action', - 'action-pagination', - 'action-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` + "action", + "action-pagination", + "action-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'horror', - 'horror-pagination', - 'horror-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` + "horror", + "horror-pagination", + "horror-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'documentary', - 'documentary-pagination', - 'documentary-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` + "documentary", + "documentary-pagination", + "documentary-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'animation', - 'animation-pagination', - 'animation-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` + "animation", + "animation-pagination", + "animation-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'sci-fi', - 'sci-fi-pagination', - 'sci-fi-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` + "sci-fi", + "sci-fi-pagination", + "sci-fi-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'romantic', - 'romantic-pagination', - 'romantic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` + "romantic", + "romantic-pagination", + "romantic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'thriller', - 'thriller-pagination', - 'thriller-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` + "thriller", + "thriller-pagination", + "thriller-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'mystery', - 'mystery-pagination', - 'mystery-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` + "mystery", + "mystery-pagination", + "mystery-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'comedy', - 'comedy-pagination', - 'comedy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` + "comedy", + "comedy-pagination", + "comedy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'fantasy', - 'fantasy-pagination', - 'fantasy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` + "fantasy", + "fantasy-pagination", + "fantasy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'family', - 'family-pagination', - 'family-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` + "family", + "family-pagination", + "family-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'tv-series', - 'tv-series-pagination', - 'tv-series-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` + "tv-series", + "tv-series-pagination", + "tv-series-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'crime', - 'crime-pagination', - 'crime-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` + "crime", + "crime-pagination", + "crime-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'classic', - 'classic-pagination', - 'classic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` + "classic", + "classic-pagination", + "classic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, ); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + document + .getElementById("googleSignInBtn") + .addEventListener("click", handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; } -document.addEventListener('DOMContentLoaded', () => { - const notificationBtn = document.getElementById('notificationBtn'); +document.addEventListener("DOMContentLoaded", () => { + const notificationBtn = document.getElementById("notificationBtn"); - notificationBtn.addEventListener('click', () => { - window.location.href = 'MovieVerse-Frontend/html/notifications.html'; + notificationBtn.addEventListener("click", () => { + window.location.href = "MovieVerse-Frontend/html/notifications.html"; }); }); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/README.md b/MovieVerse-Mobile/www/MovieVerse-Frontend/README.md index 1a216e41..0fcbf3e5 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/README.md +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/README.md @@ -158,7 +158,7 @@ Contributions to MovieVerse are always welcome. Whether it's bug reports, featur ## License -This project is licensed under MIT license. Refer to the `LICENSE` file in each subdirectory for more information. +This project is licensed under CC BY-NC 4.0 license. Refer to the [LICENSE](LICENSE.md) file for more information. --- diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js index 44af428a..d3841f0a 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js index 1052ad5c..6aff1353 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js @@ -362,6 +362,7 @@ function rotateImages(imageElements, interval = 3000) { function showMovies(movies, mainElement, startYear, endYear, append) { showSpinner(); + // Add header for the selected year range if not appending if (!append) { mainElement.innerHTML = ''; const header = document.createElement('h2'); @@ -370,31 +371,28 @@ function showMovies(movies, mainElement, startYear, endYear, append) { header.style.marginBottom = '20px'; header.style.color = '#ff8623'; header.style.fontSize = '23px'; - if (startYear === endYear) { - header.textContent = `Movies released in ${startYear}`; - } else { - header.textContent = `Movies released between ${startYear} and ${endYear}`; - } + header.textContent = startYear === endYear ? `Movies released in ${startYear}` : `Movies released between ${startYear} and ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.innerHTML = ''; centerContainer1.appendChild(header); centerContainer1.appendChild(mainElement); } - const observer = new IntersectionObserver( + // Observer for loading additional images when movie enters viewport + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch and set up additional posters const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); - allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + const movieImageContainer = movieEl.querySelector('.movie-images'); const imagePromises = allPosters.map((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; @@ -415,9 +413,11 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); }); + // Wait for images to load or timeout after 3 seconds const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); await Promise.race([Promise.all(imagePromises), maxWait]); + // Show the first poster image movieImageContainer.querySelector('.poster-img').style.opacity = '1'; rotateImages(Array.from(movieImageContainer.children)); @@ -441,6 +441,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; + // Limit the title to 8 words, adding "..." if necessary const words = title.split(' '); if (words.length >= 8) { words[7] = '...'; @@ -454,6 +455,7 @@ function showMovies(movies, mainElement, startYear, endYear, append) { overview = 'No overview available.'; } + // Define HTML structure for the movie card movieEl.innerHTML = `
@@ -478,8 +480,26 @@ function showMovies(movies, mainElement, startYear, endYear, append) { }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + imageObserver.observe(movieEl); + + // Observer for the slide-up animation + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); centerContainer1.appendChild(mainElement); @@ -487,6 +507,24 @@ function showMovies(movies, mainElement, startYear, endYear, append) { hideSpinner(); } +// Inject CSS for sliding-up animation if it doesn't already exist +if (!document.getElementById('slide-animation-style')) { + const style = document.createElement('style'); + style.id = 'slide-animation-style'; + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); +} + function createLoadMoreButton(startYear, endYear, mainElement) { const existingButtonDiv = mainElement.querySelector('.load-more-container'); if (existingButtonDiv) { diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/search.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/search.js index 82bdc1cf..985710f0 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/search.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/search.js @@ -807,6 +807,21 @@ function rotateImages(imageElements, interval = 3000) { async function showMovies(items, container, category) { container.innerHTML = ''; + // Inject CSS for sliding-up animation if it doesn't already exist + const style = document.createElement('style'); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 1s ease, transform 1s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + items.forEach(async item => { const hasVoteAverage = typeof item.vote_average === 'number'; const isPerson = !hasVoteAverage; @@ -815,7 +830,6 @@ async function showMovies(items, container, category) { let title = item.title || item.name || 'N/A'; const words = title.split(' '); - if (words.length >= 8) { words[7] = '...'; title = words.slice(0, 8).join(' '); @@ -823,7 +837,6 @@ async function showMovies(items, container, category) { let overview = item.overview || 'Click to view the details of this movie/TV series.'; const biography = item.biography || 'Click to view the details of this person.'; - if (overview === '') { overview = 'Click to view the details of this movie/TV series.'; } @@ -971,6 +984,23 @@ async function showMovies(items, container, category) { const img = movieEl.querySelector('img'); observer.observe(img); } + + // Slide-up animation observer + const slideObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + slideObserver.unobserve(entry.target); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + slideObserver.observe(movieEl); }); } diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/about.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/about.js new file mode 100644 index 00000000..916bbac0 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/about.js @@ -0,0 +1,336 @@ +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/actor-details.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/actor-details.js new file mode 100644 index 00000000..b3d7fe24 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/actor-details.js @@ -0,0 +1,824 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +let initialMainContent = ''; + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + currentIndex = 0; + + const actorId = localStorage.getItem('selectedActorId'); + if (actorId) { + fetchActorDetails(actorId); + } else { + fetchActorDetails(2037); + } +}); + +async function fetchActorDetails(actorId) { + showSpinner(); + const actorUrl = `https://${getMovieVerseData()}/3/person/${actorId}?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/${actorId}/movie_credits?${generateMovieNames()}${getMovieCode()}`; + + try { + const [actorResponse, creditsResponse] = await Promise.all([fetch(actorUrl), fetch(creditsUrl)]); + + const actor = await actorResponse.json(); + const credits = await creditsResponse.json(); + if (actor.success === false) { + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details currently unavailable - please try again

+
`; + } else { + updateBrowserURL(actor.name); + populateActorDetails(actor, credits); + } + hideSpinner(); + } catch (error) { + console.log('Error fetching actor details:', error); + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details currently unavailable - please try again

+
`; + hideSpinner(); + } +} + +async function populateActorDetails(actor, credits) { + const actorImage = document.getElementById('actor-image'); + const actorName = document.getElementById('actor-name'); + const actorDescription = document.getElementById('actor-description'); + + if (actor.profile_path) { + actorImage.src = `https://image.tmdb.org/t/p/w1280${actor.profile_path}`; + actorName.textContent = actor.name; + document.title = `${actor.name} - Actor's Details`; + } else { + actorImage.style.display = 'none'; + actorName.textContent = actor.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.actor-left').appendChild(noImageText); + } + + let ageOrStatus; + if (actor.birthday) { + if (actor.deathday) { + ageOrStatus = calculateAge(actor.birthday, actor.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(actor.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + actorDescription.innerHTML = ` +

Biography: ${actor.biography || 'Information Unavailable'}

+

Also Known As: ${actor.also_known_as.join(', ') || 'Information Unavailable'}

+

Date of Birth: ${actor.birthday || 'Information Unavailable'}

+

Date of Death: ${actor.deathday || 'Information Unavailable'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${actor.place_of_birth || 'Information Unavailable'}

+

Known For: ${actor.known_for_department || 'Information Unavailable'}

+

Height: ${actor.height || 'Information Unavailable'}

+ `; + + const gender = document.createElement('div'); + gender.innerHTML = `

Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'Information Unavailable'}

`; + actorDescription.appendChild(gender); + + const popularity = document.createElement('div'); + popularity.innerHTML = `

Popularity Score: ${actor.popularity.toFixed(2)}

`; + actorDescription.appendChild(popularity); + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + actorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + movieList.style.display = 'flex'; + movieList.style.flexWrap = 'wrap'; + movieList.style.justifyContent = 'center'; + movieList.style.gap = '5px'; + + let filmsToDisplay = credits.cast; + filmsToDisplay = filmsToDisplay.sort((a, b) => b.popularity - a.popularity); + + filmsToDisplay.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + movieList.appendChild(movieLink); + + if (index < credits.cast.length - 1) { + movieList.appendChild(document.createTextNode('')); + } + }); + + filmographyHeading.appendChild(movieList); + + const mediaUrl = `https://${getMovieVerseData()}/3/person/${actor.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + const detailsContainer = document.getElementById('actor-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + const imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + applySettings(); +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +function calculateAge(birthday, deathday = null) { + const birthDate = new Date(birthday); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const diff = referenceDate - birthDate.getTime(); + const ageDate = new Date(diff); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + applySettings(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/add-to-favorites.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/add-to-favorites.js new file mode 100644 index 00000000..eae22b78 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/add-to-favorites.js @@ -0,0 +1,252 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + query, + where, + getDocs, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function checkAndUpdateFavoriteButton() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const movieId = localStorage.getItem('selectedMovieId'); + + if (!movieId) { + console.log('Movie ID is missing'); + return; + } + + try { + if (!userEmail) { + console.log('User is not signed in. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + if (querySnapshot.empty) { + console.log('No user found with that email'); + return; + } + + const userData = querySnapshot.docs[0].data(); + const favorites = userData.favoritesMovies || []; + + updateFavoriteButton(movieId, favorites); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + } else { + console.error('An error occurred:', error); + } + } +} + +function updateFavoriteButton(movieId, favorites) { + const favoriteButton = document.getElementById('favorite-btn'); + + if (favorites.includes(movieId)) { + favoriteButton.classList.add('favorited'); + favoriteButton.style.backgroundColor = 'grey'; + favoriteButton.title = 'Remove from favorites'; + } else { + favoriteButton.classList.remove('favorited'); + favoriteButton.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + favoriteButton.title = 'Add to favorites'; + } +} + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +async function getMovieGenre(movieId) { + const tmdbUrl = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(tmdbUrl); + const movieData = await response.json(); + return movieData.genres.length > 0 ? movieData.genres[0].name : 'Unknown'; +} + +export async function toggleFavorite() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const movieId = localStorage.getItem('selectedMovieId'); + + if (!movieId) { + console.log('Movie ID is missing'); + return; + } + + const movieGenre = await getMovieGenre(movieId); + + try { + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + let userDocRef; + + if (querySnapshot.empty && userEmail === '') { + const newUserRef = doc(collection(db, 'MovieVerseUsers')); + userDocRef = newUserRef; + await setDoc(newUserRef, { + email: userEmail, + favoritesMovies: [movieId], + }); + console.log('New user created with favorite movie.'); + } else if (!querySnapshot.empty) { + userDocRef = doc(db, 'MovieVerseUsers', querySnapshot.docs[0].id); + } else { + console.log('No user found with that email and user is supposed to be signed in.'); + return; + } + + if (userDocRef) { + const userData = querySnapshot.empty ? { favoritesMovies: [] } : querySnapshot.docs[0].data(); + let favoritesMovies = userData.favoritesMovies || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + await updateDoc(userDocRef, { favoritesMovies }); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in Firestore'); + } + + updateMoviesFavorited(movieId); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => + favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + }) + ); + } else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; + } else { + console.error('An error occurred:', error); + } + + updateMoviesFavorited(movieId); + } + window.location.reload(); +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js new file mode 100644 index 00000000..704efa91 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/add-to-tv-favorites.js @@ -0,0 +1,169 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + query, + where, + getDocs, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function toggleFavoriteTVSeries() { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } + + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + await checkAndUpdateFavoriteButtonTVSeries(); + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + let userDocRef; + if (querySnapshot.empty) { + console.log('Signed-in user does not have a Firestore document.'); + return; + } else { + userDocRef = doc(db, 'MovieVerseUsers', querySnapshot.docs[0].id); + } + + const userData = querySnapshot.docs[0].data(); + let favoritesTVSeries = userData.favoritesTVSeries || []; + + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + + await updateDoc(userDocRef, { favoritesTVSeries }); + console.log('Favorites TV Series updated successfully in Firestore'); + await checkAndUpdateFavoriteButtonTVSeries(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + } else { + console.error('An error occurred:', error); + } + window.location.reload(); + } +} + +export async function checkAndUpdateFavoriteButtonTVSeries() { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } + + let favoritesTVSeries = []; + + if (userEmail) { + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', userEmail)); + const querySnapshot = await getDocs(usersRef); + + if (!querySnapshot.empty) { + const userData = querySnapshot.docs[0].data(); + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); + } else { + console.error('An error occurred:', error); + } + } +} + +function updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries) { + const favoriteBtn = document.getElementById('favorite-btn'); + + if (favoritesTVSeries.includes(tvSeriesId)) { + favoriteBtn.classList.add('favorited'); + favoriteBtn.title = 'Remove from Favorites'; + favoriteBtn.style.backgroundColor = 'grey'; + } else { + favoriteBtn.classList.remove('favorited'); + favoriteBtn.title = 'Add to Favorites'; + favoriteBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + } +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/analytics.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/analytics.js new file mode 100644 index 00000000..f8e4b2dd --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/analytics.js @@ -0,0 +1,867 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const string = `${getMovieCode()}`; + +async function fetchData(url) { + try { + const response = await fetch(url); + return await response.json(); + } catch (error) { + console.log('Error fetching data:', error); + return null; + } +} + +function createChart(canvasId, chartType, data, options = {}) { + const ctx = document.getElementById(canvasId).getContext('2d'); + new Chart(ctx, { + type: chartType, + data: data, + options: options, + }); +} + +async function loadMoviesByYearChart() { + showSpinner(); + const years = []; + const movieCounts = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + movieCounts.push(response.total_results); + } + + createChart('chart1', 'line', { + labels: years, + datasets: [ + { + label: 'Number of Movies Released', + data: movieCounts, + backgroundColor: 'rgba(0,148,255,1)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadGenrePopularityChart() { + showSpinner(); + const genresResponse = await fetchData(`${BASE_URL}/genre/movie/list?${generateMovieNames()}=${string}`); + const genres = genresResponse.genres; + + const genreNames = []; + const genrePopularity = []; + + for (const genre of genres) { + genreNames.push(genre.name); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_genres=${genre.id}`); + genrePopularity.push(response.results.reduce((acc, movie) => acc + movie.popularity, 0) / response.results.length); + } + + createChart('chart2', 'bar', { + labels: genreNames, + datasets: [ + { + label: 'Average Popularity', + data: genrePopularity, + backgroundColor: 'rgba(255, 99, 132, 1)', + borderColor: 'rgba(255, 99, 132, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMoviesByCertificationChart() { + showSpinner(); + const certifications = ['G', 'PG', 'PG-13', 'R']; + const movieCounts = []; + + for (const certification of certifications) { + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&certification_country=US&certification=${certification}` + ); + movieCounts.push(response.total_results); + } + + createChart('chart3', 'bar', { + labels: certifications, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(75, 192, 192, 1)', + borderColor: 'rgba(75, 192, 192, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadAveragePopularityChart() { + showSpinner(); + const years = []; + const averagePopularity = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 4; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + const totalPopularity = response.results.reduce((sum, movie) => sum + movie.popularity, 0); + averagePopularity.push(totalPopularity / response.results.length); + } + + createChart('chart4', 'line', { + labels: years, + datasets: [ + { + label: 'Average Popularity', + data: averagePopularity, + backgroundColor: 'rgba(255, 159, 64, 1)', + borderColor: 'rgba(255, 159, 64, 1)', + borderWidth: 1, + }, + ], + }); + showSpinner(); +} + +Chart.defaults.color = 'black'; +Chart.defaults.scale.grid.borderColor = 'black'; + +async function loadMoviesByLanguageChart() { + showSpinner(); + const languages = ['en', 'es', 'fr', 'de', 'it']; + const movieCounts = []; + + for (const language of languages) { + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_original_language=${language}`); + movieCounts.push(response.total_results); + } + + createChart('chart5', 'bar', { + labels: languages.map(lang => lang.toUpperCase()), + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(153, 102, 255, 1)', + borderColor: 'rgba(153, 102, 255, 1)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + }, + }); + + hideSpinner(); +} + +async function loadVoteCountByGenreChart() { + showSpinner(); + const genreResponse = await fetchData(`${BASE_URL}/genre/movie/list?${generateMovieNames()}=${string}`); + const genres = genreResponse.genres.slice(0, 5); + const genreNames = []; + const averageVoteCounts = []; + + for (const genre of genres) { + genreNames.push(genre.name); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_genres=${genre.id}`); + const totalVotes = response.results.reduce((sum, movie) => sum + movie.vote_count, 0); + averageVoteCounts.push(totalVotes / response.results.length); + } + + createChart('chart6', 'bar', { + labels: genreNames, + datasets: [ + { + label: 'Average Vote Count', + data: averageVoteCounts, + backgroundColor: 'rgba(255, 206, 86, 1)', + borderColor: 'rgba(255, 206, 86, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMovieReleaseDatesByMonthChart() { + showSpinner(); + const months = Array.from({ length: 12 }, (_, i) => new Date(0, i).toLocaleString('en', { month: 'long' })); + const movieCounts = Array(12).fill(0); + const currentYear = new Date().getFullYear(); + + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${currentYear}`); + response.results.forEach(movie => { + const releaseDate = new Date(movie.release_date); + movieCounts[releaseDate.getMonth()]++; + }); + + createChart('chart7', 'bar', { + labels: months, + datasets: [ + { + label: 'Movies Released', + data: movieCounts, + backgroundColor: 'rgba(123, 239, 178, 1)', + borderColor: 'rgba(123, 239, 178, 1)', + borderWidth: 1, + }, + ], + }); + + hideSpinner(); +} + +async function loadMoviesByDecadeChart() { + showSpinner(); + const decades = ['1980s', '1990s', '2000s', '2010s', '2020s']; + const decadeStartYears = [1980, 1990, 2000, 2010, 2020]; + const movieCounts = []; + + for (const startYear of decadeStartYears) { + const endYear = startYear + 9; + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31` + ); + movieCounts.push(response.total_results); + } + + createChart('chart8', 'bar', { + labels: decades, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgb(255,0,0)', + borderColor: 'rgb(255,0,0)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + ticks: { + color: 'black', + }, + }, + y: { + ticks: { + color: 'black', + }, + }, + }, + plugins: { + legend: { + position: 'right', + labels: { + color: 'black', + }, + }, + }, + }, + }); + + hideSpinner(); +} + +async function loadMoviesByProductionCountriesChart() { + showSpinner(); + const countries = ['US', 'GB', 'CA', 'FR', 'DE']; + const countryNames = ['USA', 'UK', 'Canada', 'France', 'Germany']; + const movieCounts = []; + + for (const country of countries) { + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&with_original_language=en®ion=${country}`); + movieCounts.push(response.total_results); + } + + createChart('chart9', 'bar', { + labels: countryNames, + datasets: [ + { + label: 'Number of Movies', + data: movieCounts, + backgroundColor: 'rgba(0,32,255,0.75)', + borderColor: 'rgb(0,21,255)', + borderWidth: 1, + }, + ], + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + ticks: { + color: 'black', + }, + }, + y: { + ticks: { + color: 'black', + }, + }, + }, + plugins: { + legend: { + position: 'right', + labels: { + color: 'black', + }, + }, + }, + }, + }); + + hideSpinner(); +} + +async function loadTopRatedMoviesPerYearChart() { + const years = []; + const topMovies = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData( + `${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&sort_by=vote_average.desc&vote_count.gte=100` + ); + if (response.results.length > 0) { + topMovies.push(response.results[0].vote_average); + } else { + topMovies.push(0); + } + } + + createChart('chart11', 'bar', { + labels: years, + datasets: [ + { + label: 'Top Rated Movie Score', + data: topMovies, + backgroundColor: 'rgba(255, 159, 64, 1)', + borderColor: 'rgba(255, 159, 64, 1)', + borderWidth: 1, + }, + ], + }); +} + +async function loadTotalMovieVotesOverYearsChart() { + const years = []; + const totalVoteCounts = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + const yearlyTotalVotes = response.results.reduce((sum, movie) => sum + movie.vote_count, 0); + totalVoteCounts.push(yearlyTotalVotes); + } + + createChart('chartVotesOverYears', 'line', { + labels: years, + datasets: [ + { + label: 'Total Movie Votes', + data: totalVoteCounts, + backgroundColor: 'rgba(255, 193, 7, 1)', + borderColor: 'rgba(255, 193, 7, 1)', + borderWidth: 1, + }, + ], + }); +} + +async function loadHighlyRatedMoviesOverYearsChart() { + const years = []; + const highRatedMovieCounts = []; + const currentYear = new Date().getFullYear(); + const startYear = currentYear - 10; + + for (let year = startYear; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&vote_average.gte=8`); + highRatedMovieCounts.push(response.total_results); + } + + createChart('chartHighlyRatedMovies', 'line', { + labels: years, + datasets: [ + { + label: 'Highly Rated Movies (Rating >= 8)', + data: highRatedMovieCounts, + backgroundColor: 'rgba(0, 206, 209, 1)', + borderColor: 'rgba(0, 206, 209, 1)', + borderWidth: 1, + }, + ], + }); +} + +function loadAllCharts() { + showSpinner(); + loadMoviesByYearChart(); + loadGenrePopularityChart(); + loadMoviesByCertificationChart(); + loadAveragePopularityChart(); + loadMoviesByLanguageChart(); + loadVoteCountByGenreChart(); + loadMovieReleaseDatesByMonthChart(); + loadMoviesByDecadeChart(); + loadMoviesByProductionCountriesChart(); + loadTopRatedMoviesPerYearChart(); + loadTotalMovieVotesOverYearsChart(); + loadHighlyRatedMoviesOverYearsChart(); + hideSpinner(); +} + +document.addEventListener('DOMContentLoaded', loadAllCharts); + +const BASE_URL = `https://${getMovieVerseData()}/3`; + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}=${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.png'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +document.getElementById('chart-title1').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title1').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title2').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title3').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title4').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title4').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title5').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title5').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title6').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title6').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title7').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title7').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title8').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title8').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title9').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title9').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title11').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title11').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title10').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title10').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('chart-title12').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('chart-title12').scrollIntoView({ behavior: 'smooth' }); +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chat-auxiliary.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chat-auxiliary.js new file mode 100644 index 00000000..165d6e5b --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chat-auxiliary.js @@ -0,0 +1,268 @@ +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chat.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chat.js new file mode 100644 index 00000000..b3a0da63 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chat.js @@ -0,0 +1,496 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + collection, + addDoc, + doc, + startAfter, + getDocs, + query, + where, + orderBy, + onSnapshot, + documentId, + serverTimestamp, + limit, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +document.addEventListener('DOMContentLoaded', () => { + const mainElement = document.getElementById('main'); + const isLoggedIn = localStorage.getItem('isSignedIn'); + + if (!isLoggedIn || isLoggedIn !== 'true') { + mainElement.style.display = 'none'; + + const signInMessage = document.createElement('div'); + signInMessage.innerHTML = '

You must be signed in to access MovieVerse chat services.

'; + signInMessage.style.display = 'flex'; + signInMessage.style.justifyContent = 'center'; + signInMessage.style.alignItems = 'center'; + signInMessage.style.height = '100vh'; + signInMessage.style.borderRadius = '12px'; + signInMessage.style.margin = '10px auto'; + signInMessage.style.marginRight = '20px'; + signInMessage.style.marginLeft = '20px'; + signInMessage.style.marginBottom = '20px'; + signInMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'; + document.getElementById('footer').style.display = 'none'; + + const adContainer2 = document.getElementById('ad-container2'); + if (adContainer2) { + document.body.insertBefore(signInMessage, adContainer2); + } else { + document.body.appendChild(signInMessage); + } + } else { + mainElement.style.display = ''; + loadUserList(); + setupSearchListeners(); + } +}); + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading chats${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +initializeApp(firebaseConfig); +const db = getFirestore(); + +const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); +let selectedUserEmail = null; + +const messagesDiv = document.getElementById('messages'); +const userListDiv = document.getElementById('userList'); +const messageInput = document.getElementById('messageInput'); +const sendButton = document.getElementById('sendButton'); + +sendButton.addEventListener('click', async () => { + const text = messageInput.value.trim(); + if (text && selectedUserEmail) { + try { + await addDoc(collection(db, 'messages'), { + sender: currentUserEmail, + recipient: selectedUserEmail, + message: text, + timestamp: serverTimestamp(), + readBy: [currentUserEmail], + }); + messageInput.value = ''; + + const userElement = document.querySelector(`.user[data-email="${selectedUserEmail}"]`); + + if (!userElement) { + const newUserElement = await createUserElement(selectedUserEmail); + userListDiv.prepend(newUserElement); + selectUser(newUserElement); + } else { + userListDiv.prepend(userElement); + selectUser(userElement); + } + } catch (error) { + console.error('Error adding message: ', error); + } + } +}); + +async function createUserElement(email) { + const userElement = document.createElement('div'); + userElement.classList.add('user'); + userElement.setAttribute('data-email', email); + userElement.addEventListener('click', () => loadMessages(email)); + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '50px'; + img.style.borderRadius = '25px'; + img.style.marginRight = '10px'; + userElement.appendChild(img); + + const emailDiv = document.createElement('div'); + emailDiv.textContent = email; + userElement.appendChild(emailDiv); + + return userElement; +} + +function selectUser(userElement) { + if (previouslySelectedUserElement) { + previouslySelectedUserElement.classList.remove('selected'); + previouslySelectedUserElement.style.backgroundColor = ''; + } + userElement.classList.add('selected'); + userElement.style.backgroundColor = '#ff8623'; + previouslySelectedUserElement = userElement; +} + +document.getElementById('messageInput').addEventListener('keydown', function (event) { + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault(); + sendButton.click(); + } +}); + +function formatMessage(message, isCurrentUser, timestamp) { + const messageElement = document.createElement('div'); + messageElement.classList.add('message'); + messageElement.textContent = isCurrentUser ? `You: ${message}` : `${selectedUserEmail}: ${message}`; + + if (timestamp && timestamp.toDate) { + messageElement.dataset.timestamp = timestamp.toDate().toISOString(); + } else { + console.log('Timestamp is not in the expected format:', timestamp); + messageElement.dataset.timestamp = 'Unknown time'; + } + + messageElement.classList.add(isCurrentUser ? 'my-message' : 'other-message'); + messageElement.addEventListener('mouseover', showTooltip); + messageElement.addEventListener('click', showTooltip); + + return messageElement; +} + +function showTooltip(event) { + const messageElement = event.target.closest('.message'); + const timestampString = messageElement.dataset.timestamp; + + const date = new Date(timestampString); + const tooltipText = isNaN(date.getTime()) + ? 'Unknown time' + : date.toLocaleString('default', { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + }); + + const tooltip = document.createElement('div'); + tooltip.className = 'tooltip'; + tooltip.textContent = tooltipText; + document.body.appendChild(tooltip); + + const rect = messageElement.getBoundingClientRect(); + const tooltipRect = tooltip.getBoundingClientRect(); + + const leftPosition = rect.left + rect.width / 2 - tooltipRect.width / 2; + tooltip.style.position = 'fixed'; + tooltip.style.top = `${rect.top - tooltipRect.height - 5}px`; + tooltip.style.left = `${Math.max(leftPosition, 0) - 12}px`; + + function removeTooltip() { + tooltip.remove(); + } + messageElement.addEventListener('mouseout', removeTooltip); + setTimeout(removeTooltip, 5000); +} + +const chatSection = document.getElementById('chatSection'); +const noUserSelected = document.getElementById('noUserSelected'); + +chatSection.style.display = 'none'; +noUserSelected.style.display = 'flex'; + +async function loadMessages(userEmail) { + selectedUserEmail = userEmail; + messagesDiv.innerHTML = ''; + + chatSection.style.display = 'flex'; + noUserSelected.style.display = 'none'; + + const userEmailDisplay = document.getElementById('userEmailDisplay'); + if (userEmailDisplay) { + userEmailDisplay.textContent = `Chatting with: ${selectedUserEmail}`; + } + + document.querySelectorAll('.user').forEach(user => user.classList.remove('selected')); + const selectedUser = document.querySelector(`.user[data-email="${selectedUserEmail}"]`); + if (selectedUser) { + selectedUser.classList.add('selected'); + } + + const messagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp'), + where('sender', 'in', [currentUserEmail, selectedUserEmail]), + where('recipient', 'in', [currentUserEmail, selectedUserEmail]) + ); + + onSnapshot(messagesQuery, snapshot => { + messagesDiv.innerHTML = ''; + snapshot.docs.forEach(doc => { + const messageData = doc.data(); + const isCurrentUser = messageData.sender === currentUserEmail; + const timestamp = messageData.timestamp; + const messageElement = formatMessage(messageData.message, isCurrentUser, timestamp); + messagesDiv.appendChild(messageElement); + + if (!isCurrentUser && (!messageData.readBy || !messageData.readBy.includes(currentUserEmail))) { + updateReadStatus(doc.id); + } + }); + + messagesDiv.scrollTop = messagesDiv.scrollHeight; + }); +} + +async function updateReadStatus(messageId) { + const messageRef = doc(db, 'messages', messageId); + await updateDoc(messageRef, { + readBy: arrayUnion(currentUserEmail), + }); +} + +let searchDebounceTimeout; +let lastVisible = null; +const initialFetchLimit = 5; +const maxTotalFetch = 20; + +function setupSearchListeners() { + const searchUserInput = document.getElementById('searchUserInput'); + const searchUserResults = document.getElementById('searchUserResults'); + + searchUserInput.addEventListener('input', () => { + clearTimeout(searchDebounceTimeout); + const searchText = searchUserInput.value.trim(); + + if (searchText) { + searchDebounceTimeout = setTimeout(() => { + lastVisible = null; + performSearch(searchText, true); + }, 300); + } else { + searchUserResults.innerHTML = ''; + searchUserResults.style.display = 'none'; + } + }); +} + +async function performSearch(searchText, isNewSearch = false) { + const searchUserResults = document.getElementById('searchUserResults'); + + try { + showSpinner(); + animateLoadingDots(); + + let userQuery = query( + collection(db, 'MovieVerseUsers'), + where('email', '>=', searchText), + where('email', '<=', searchText + '\uf8ff'), + orderBy('email'), + limit(initialFetchLimit) + ); + + if (!isNewSearch && lastVisible) { + userQuery = query(userQuery, startAfter(lastVisible)); + } + + const querySnapshot = await getDocs(userQuery); + + if (isNewSearch) { + searchUserResults.innerHTML = ''; + } + + if (!querySnapshot.empty) { + lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; + } + + for (const doc of querySnapshot.docs) { + const user = doc.data(); + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadMessages(user.email)); + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.email}

${user.bio || ''}

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + } + + searchUserResults.style.display = 'block'; + hideSpinner(); + + if (isNewSearch || (!querySnapshot.empty && querySnapshot.size === initialFetchLimit)) { + const loadMoreButton = document.createElement('button'); + loadMoreButton.textContent = 'Load More'; + loadMoreButton.id = 'loadMoreButton'; + loadMoreButton.style.marginBottom = '20px'; + loadMoreButton.addEventListener('click', () => performSearch(searchText)); + searchUserResults.appendChild(loadMoreButton); + + if (searchUserResults.children.length >= maxTotalFetch) { + loadMoreButton.style.display = 'none'; + } + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.margin = '25px auto'; + } + hideSpinner(); + } + } +} + +let previouslySelectedUserElement = null; + +async function loadUserList() { + try { + showSpinner(); + animateLoadingDots(); + + const userLimit = 5; + const messageLimit = 30; + + const sentMessagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp', 'desc'), + where('sender', '==', currentUserEmail), + limit(messageLimit) + ); + const receivedMessagesQuery = query( + collection(db, 'messages'), + orderBy('timestamp', 'desc'), + where('recipient', '==', currentUserEmail), + limit(messageLimit) + ); + + const [sentMessagesSnapshot, receivedMessagesSnapshot] = await Promise.all([getDocs(sentMessagesQuery), getDocs(receivedMessagesQuery)]); + + let userEmails = new Set(); + sentMessagesSnapshot.forEach(doc => userEmails.add(doc.data().recipient)); + receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); + + let users = []; + for (let email of userEmails) { + if (email) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + let userData = doc.data(); + if (userData.email) { + users.push(userData); + } + }); + } + } + + users.sort((a, b) => { + const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( + doc => doc.data().sender === a.email || doc.data().recipient === a.email + ); + const bLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( + doc => doc.data().sender === b.email || doc.data().recipient === b.email + ); + return (bLastMessage?.data().timestamp.toDate() || 0) - (aLastMessage?.data().timestamp.toDate() || 0); + }); + + users = users.slice(0, userLimit); + + userListDiv.innerHTML = ''; + for (const user of users) { + const userElement = document.createElement('div'); + userElement.classList.add('user'); + userElement.setAttribute('data-email', user.email); + userElement.onclick = () => { + if (previouslySelectedUserElement) { + previouslySelectedUserElement.classList.remove('selected'); + previouslySelectedUserElement.style.backgroundColor = ''; + } + selectedUserEmail = user.email; + loadMessages(user.email); + document.querySelectorAll('.user').forEach(u => u.classList.remove('selected')); + userElement.classList.add('selected'); + userElement.style.backgroundColor = '#ff8623'; + previouslySelectedUserElement = userElement; + }; + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '50px'; + img.style.borderRadius = '25px'; + img.style.marginRight = '10px'; + userElement.appendChild(img); + + const emailDiv = document.createElement('div'); + emailDiv.textContent = user.email; + userElement.appendChild(emailDiv); + + userListDiv.appendChild(userElement); + } + + hideSpinner(); + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + } + hideSpinner(); + } + } +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chatbot.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chatbot.js new file mode 100644 index 00000000..db8687e8 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/chatbot.js @@ -0,0 +1,501 @@ +import { GoogleGenerativeAI, HarmBlockThreshold, HarmCategory } from '@google/generative-ai'; + +const chatbotBody = document.getElementById('chatbotBody'); +const movieee = `https://${getMovieVerseData()}/3`; + +let initialMainContent; +let conversationHistory = []; + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +document.addEventListener('DOMContentLoaded', function () { + initialMainContent = document.getElementById('main').innerHTML; + initializeChatbot(); + document.getElementById('clear-search-btn').style.display = 'none'; +}); + +const searchTitle = document.getElementById('search-title'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function initializeChatbot() { + const chatbotInput = document.getElementById('chatbotInput'); + sendInitialInstructions(); + chatbotInput.addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + sendMessage(chatbotInput.value); + chatbotInput.value = ''; + } + }); + + const sendButton = document.getElementById('sendButton'); + sendButton.addEventListener('click', function () { + sendMessage(chatbotInput.value); + chatbotInput.value = ''; + }); +} + +async function sendMessage(message) { + chatbotBody.innerHTML += `
You: ${message}
`; + const botReply = await movieVerseResponse(message); + setTimeout(() => { + chatbotBody.innerHTML += `
MovieVerse Assistant: ${botReply}
`; + scrollToBottom(); + }, 1000); + scrollToBottom(); +} + +function sendInitialInstructions() { + const initialMessage = ` +
+ MovieVerse Assistant: + + Welcome to MovieVerse Assistant 🍿! Here's how to get started: + +
+
    +
  • To quickly find the trailer of a movie, type "Show trailer for [movie name]".
  • +
  • You can also ask about genres, top-rated movies, latest movies, get a recommended movie, and any general questions!
  • +
  • 💡Tip: To get the best results, try to avoid phrasing requests like "Show trailer for ...", as they might trigger specific functions instead of a broader search.
  • +
+
How may I assist you today? 🎬🍿
+ `; + chatbotBody.innerHTML += `
${initialMessage}
`; + scrollToBottom(); +} + +function scrollToBottom() { + chatbotBody.scrollTop = chatbotBody.scrollHeight; +} + +document.getElementById('clear-search-btn').addEventListener('click', function () { + document.getElementById('main').innerHTML = initialMainContent; + initializeChatbot(); + searchTitle.innerHTML = ''; + this.style.display = 'none'; +}); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +async function fetchMovieTrailer(movieName) { + const searchUrl = SEARCHPATH + encodeURIComponent(movieName); + try { + const response = await fetch(searchUrl); + const data = await response.json(); + const movie = data.results[0]; + if (movie) { + const trailerUrl = await getTrailerUrl(movie.id); + if (trailerUrl) { + createTrailerButton(trailerUrl, movie.title); + } else { + chatbotBody.innerHTML += '
No trailer available for this movie.
'; + } + } else { + chatbotBody.innerHTML += '
Movie not found. Please try another search.
'; + } + } catch (error) { + console.log('Error fetching movie trailer:', error); + } +} + +async function getTrailerUrl(movieId) { + const trailerApiUrl = `https://${getMovieVerseData()}/3/movie/${movieId}/videos?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(trailerApiUrl); + const data = await response.json(); + const trailer = data.results.find(video => video.type === 'Trailer' && video.site === 'YouTube'); + return trailer ? `https://www.youtube.com/watch?v=${trailer.key}` : null; + } catch (error) { + console.log('Error fetching trailer:', error); + return null; + } +} + +function createTrailerButton(trailerUrl, movieTitle) { + const buttonId = 'trailerButton'; + chatbotBody.innerHTML += ` + + `; + chatbotBody.addEventListener('click', function (event) { + if (event.target && event.target.id === buttonId) { + window.open(trailerUrl, '_blank'); + } + }); +} + +async function movieVerseResponse(message) { + const lowerMessage = message.toLowerCase(); + + if (lowerMessage.startsWith('show trailer for ')) { + const movieName = lowerMessage.replace('show trailer for ', ''); + fetchMovieTrailer(movieName); + return `Searching for the trailer of "${movieName}". Please wait...`; + } + + if (lowerMessage.startsWith('hello') || lowerMessage.startsWith('hi') || lowerMessage.startsWith('hey')) { + return 'Hello! How can I assist you with MovieVerse today?'; + } else if (lowerMessage.startsWith('bye') || lowerMessage.startsWith('goodbye')) { + return 'Goodbye! Thank you for using MovieVerse Assistant and have a nice day!'; + } else { + showSpinner(); + animateLoadingDots(); + + let fullResponse = ''; + try { + const genAI = new GoogleGenerativeAI(getAIResponse()); + const model = genAI.getGenerativeModel({ + model: 'gemini-1.5-flash', + systemInstruction: + 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + }); + + conversationHistory.push({ role: 'user', parts: [{ text: message }] }); + + const chatSession = model.startChat({ + generationConfig: { + temperature: 1, + topP: 0.95, + topK: 64, + maxOutputTokens: 8192, + responseMimeType: 'text/plain', + }, + safetySettings: [ + { + category: HarmCategory.HARM_CATEGORY_HARASSMENT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + { + category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, + threshold: HarmBlockThreshold.BLOCK_NONE, + }, + ], + history: conversationHistory, + }); + + const result = await chatSession.sendMessage(message); + fullResponse = result.response.text(); + conversationHistory.push({ + role: 'model', + parts: [{ text: fullResponse }], + }); + } catch (error) { + console.error('Error fetching response:', error.message); + fullResponse = + 'An error occurred while generating the response, possibly due to high traffic or safety concerns. Please understand that I am trained by MovieVerse to provide safe and helpful responses within my limitations. I apologize for any inconvenience caused. Please try again with a different query or contact MovieVerse support for further assistance.'; + } + + hideSpinner(); + return removeMarkdown(fullResponse); + } +} + +async function animateLoadingDots() { + const loadingTextElement = document.querySelector('#myModal p'); + let dots = ''; + + while (document.getElementById('myModal').classList.contains('modal-visible')) { + loadingTextElement.textContent = `Loading response${dots}`; + dots = dots.length < 3 ? dots + '.' : '.'; + await new Promise(resolve => setTimeout(resolve, 500)); + } +} + +function removeMarkdown(text) { + const converter = new showdown.Converter(); + const html = converter.makeHtml(text); + + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = html; + return tempDiv.textContent || tempDiv.innerText || ''; +} + +function getAIResponse() { + const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + return atob(response); +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/christopher-nolan.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/christopher-nolan.js new file mode 100644 index 00000000..ddddd17a --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/christopher-nolan.js @@ -0,0 +1,488 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const searchTitle = document.getElementById('search-title'); + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function showMovies(movies) { + main.innerHTML = ''; + movies.forEach(movie => { + const { id, poster_path, title, vote_average, overview } = movie; + const movieE1 = document.createElement('div'); + const voteAverage = vote_average.toFixed(1); + movieE1.classList.add('movie'); + const movieImage = poster_path + ? `${title}` + : `
Image Not Available
`; + movieE1.innerHTML = ` + ${movieImage} +
+

${title}

+ ${voteAverage} +
+
+

Movie Overview:

+ ${overview} +
`; + movieE1.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); + window.location.href = 'movie-details.html'; + updateMovieVisitCount(id, title); + }); + main.appendChild(movieE1); + }); + applySettings(); +} + +function clearMovieDetails() { + const movieDetailsContainer = document.getElementById('director-details-container'); + if (movieDetailsContainer) { + movieDetailsContainer.innerHTML = ''; + } +} + +document.addEventListener('DOMContentLoaded', () => { + const directorId = '525'; + if (directorId) { + fetchDirectorDetails(directorId); + } else { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details not found.

+
`; + } +}); + +async function fetchDirectorDetails(directorId) { + const directorUrl = `https://${getMovieVerseData()}/3/person/525?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/525/movie_credits?${generateMovieNames()}${getMovieCode()}`; + try { + const [directorResponse, creditsResponse] = await Promise.all([fetch(directorUrl), fetch(creditsUrl)]); + + const director = await directorResponse.json(); + const credits = await creditsResponse.json(); + + if (director.success === false) { + document.getElementById('director-details-container').innerHTML = '

No Information is Available for this Director

'; + } else { + updateBrowserURL(director.name); + populateDirectorDetails(director, credits); + } + } catch (error) { + console.log('Error fetching director details:', error); + document.getElementById('director-details-container').innerHTML = '

Error fetching director details

'; + } +} + +function populateDirectorDetails(director, credits) { + const directorImage = document.getElementById('director-image'); + const directorName = document.getElementById('director-name'); + const directorDescription = document.getElementById('director-description'); + + if (director.profile_path) { + directorImage.src = `https://image.tmdb.org/t/p/w1280${director.profile_path}`; + directorName.textContent = director.name; + document.title = `${director.name} - Director's Details`; + } else { + directorImage.style.display = 'none'; + directorName.textContent = director.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.director-left').appendChild(noImageText); + } + + let ageOrStatus; + if (director.birthday) { + if (director.deathday) { + ageOrStatus = calculateAge(director.birthday, director.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(director.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + directorDescription.innerHTML = ` +

Biography: ${director.biography || 'N/A'}

+

Date of Birth: ${director.birthday || 'N/A'}

+

Date of Death: ${director.deathday || 'N/A'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${director.place_of_birth || 'N/A'}

+

Known For: Directing

+ `; + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + directorDescription.appendChild(filmographyHeading); + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + credits.crew.forEach(movie => { + if (movie.job === 'Director') { + const movieLink = document.createElement('span'); + movieLink.textContent = movie.title; + movieLink.classList.add('movie-link'); + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + window.location.href = 'movie-details.html'; + }); + movieList.appendChild(movieLink); + movieList.appendChild(document.createTextNode(', ')); + } + }); + filmographyHeading.appendChild(movieList); + + applySettings(); +} + +function calculateAge(dob, deathday = null) { + const birthDate = new Date(dob); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const ageDifMs = referenceDate - birthDate.getTime(); + const ageDate = new Date(ageDifMs); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + applyTextColor(savedTextColor); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/comments-tv.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/comments-tv.js new file mode 100644 index 00000000..9217424f --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/comments-tv.js @@ -0,0 +1,156 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, addDoc, getDocs, query, orderBy, where } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { app, db } from './firebase.js'; + +const commentForm = document.getElementById('comment-form'); +commentForm.addEventListener('submit', async e => { + e.preventDefault(); + const userName = document.getElementById('user-name').value; + const userComment = document.getElementById('user-comment').value; + const commentDate = new Date(); + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + + try { + await addDoc(collection(db, 'comments'), { + userName, + userComment, + commentDate, + tvSeriesId, + }); + commentForm.reset(); + fetchComments(); + } catch (error) { + console.log('Error adding comment: ', error); + } +}); + +let modal = document.getElementById('comment-modal'); +let btn = document.getElementById('toggle-comment-modal'); +let span = document.getElementsByClassName('close')[0]; + +btn.onclick = function () { + modal.style.display = 'block'; +}; + +span.onclick = function () { + modal.style.display = 'none'; +}; + +document.getElementById('post-comment-btn').onclick = function () { + modal.style.display = 'none'; +}; + +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } +}; + +let currentPage = 1; +const commentsPerPage = 3; +let totalComments = 0; +let totalPages = 1; + +async function fetchComments() { + try { + const commentsContainer = document.getElementById('comments-container'); + commentsContainer.innerHTML = ''; + commentsContainer.style.maxWidth = '100%'; + const movieId = localStorage.getItem('selectedTvSeriesId'); + + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', movieId), orderBy('commentDate', 'desc')); + const querySnapshot = await getDocs(q); + + totalComments = querySnapshot.size; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let index = 0; + let displayedComments = 0; + + if (querySnapshot.empty) { + const noCommentsMsg = document.createElement('p'); + noCommentsMsg.textContent = 'No comments for this TV series yet.'; + commentsContainer.appendChild(noCommentsMsg); + } else { + querySnapshot.forEach(doc => { + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { + const comment = doc.data(); + const commentDate = comment.commentDate.toDate(); + + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; + } + hideSpinner(); + } + } +} + +function formatCommentDate(commentDate) { + const formattedDate = commentDate.toLocaleString('default', { month: 'short' }) + ' ' + commentDate.getDate() + 'th, ' + commentDate.getFullYear(); + return formattedDate; +} + +function formatAMPM(date) { + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours || 12; + minutes = minutes < 10 ? '0' + minutes : minutes; + const strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +document.getElementById('prev-page').addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + fetchComments(); + } +}); + +document.getElementById('next-page').addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage++; + fetchComments(); + } +}); + +fetchComments(); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/comments.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/comments.js new file mode 100644 index 00000000..1d2e97a9 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/comments.js @@ -0,0 +1,156 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, addDoc, getDocs, query, orderBy, where } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { app, db } from './firebase.js'; + +const commentForm = document.getElementById('comment-form'); +commentForm.addEventListener('submit', async e => { + e.preventDefault(); + const userName = document.getElementById('user-name').value; + const userComment = document.getElementById('user-comment').value; + const commentDate = new Date(); + const movieId = localStorage.getItem('selectedMovieId'); + + try { + await addDoc(collection(db, 'comments'), { + userName, + userComment, + commentDate, + movieId, + }); + commentForm.reset(); + fetchComments(); + } catch (error) { + console.log('Error adding comment: ', error); + } +}); + +let modal = document.getElementById('comment-modal'); +let btn = document.getElementById('toggle-comment-modal'); +let span = document.getElementsByClassName('close')[0]; + +btn.onclick = function () { + modal.style.display = 'block'; +}; + +span.onclick = function () { + modal.style.display = 'none'; +}; + +document.getElementById('post-comment-btn').onclick = function () { + modal.style.display = 'none'; +}; + +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } +}; + +let currentPage = 1; +const commentsPerPage = 3; +let totalComments = 0; +let totalPages = 1; + +async function fetchComments() { + try { + const commentsContainer = document.getElementById('comments-container'); + commentsContainer.innerHTML = ''; + commentsContainer.style.maxWidth = '100%'; + const movieId = localStorage.getItem('selectedMovieId'); + + const q = query(collection(db, 'comments'), where('movieId', '==', movieId), orderBy('commentDate', 'desc')); + const querySnapshot = await getDocs(q); + + totalComments = querySnapshot.size; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let index = 0; + let displayedComments = 0; + + if (querySnapshot.empty) { + const noCommentsMsg = document.createElement('p'); + noCommentsMsg.textContent = 'No comments for this movie yet.'; + commentsContainer.appendChild(noCommentsMsg); + } else { + querySnapshot.forEach(doc => { + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { + const comment = doc.data(); + const commentDate = comment.commentDate.toDate(); + + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement('div'); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` +

+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +

+ `; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; + } + hideSpinner(); + } + } +} + +function formatCommentDate(commentDate) { + const formattedDate = commentDate.toLocaleString('default', { month: 'short' }) + ' ' + commentDate.getDate() + 'th, ' + commentDate.getFullYear(); + return formattedDate; +} + +function formatAMPM(date) { + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours || 12; + minutes = minutes < 10 ? '0' + minutes : minutes; + const strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +document.getElementById('prev-page').addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + fetchComments(); + } +}); + +document.getElementById('next-page').addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage++; + fetchComments(); + } +}); + +fetchComments(); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/company-details.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/company-details.js new file mode 100644 index 00000000..b87c3bcf --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/company-details.js @@ -0,0 +1,742 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +document.addEventListener('DOMContentLoaded', () => { + const companyId = localStorage.getItem('selectedCompanyId'); + if (companyId) { + fetchCompanyDetails(companyId); + fetchCompanyMovies(companyId); + } else { + fetchCompanyDetails(521); + fetchCompanyMovies(521); + } +}); + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function fetchCompanyDetails(companyId) { + showSpinner(); + const url = `https://${getMovieVerseData()}/3/company/${companyId}?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const company = await response.json(); + const logoImg = document.getElementById('company-logo'); + + if (company.logo_path) { + logoImg.src = `https://image.tmdb.org/t/p/w500${company.logo_path}`; + } else { + logoImg.style.display = 'none'; + const logoFallbackText = document.createElement('p'); + logoFallbackText.textContent = 'Logo Not Available'; + logoImg.parentNode.insertBefore(logoFallbackText, logoImg); + } + + const fullCountryName = twoLetterCountryCodes.find(country => country.code === company.origin_country)?.name; + + document.getElementById('company-name').textContent = company.name || 'Information Unavailable'; + document.getElementById('company-headquarters').textContent = company.headquarters || 'Information Unavailable'; + document.getElementById('company-country').textContent = fullCountryName || 'Information Unavailable'; + document.title = `${company.name} - Company Details`; + + const homepage = company.homepage || '#'; + const companyWebsite = document.getElementById('company-website'); + + if (homepage !== '#') { + companyWebsite.href = homepage; + companyWebsite.textContent = homepage; + } else { + companyWebsite.textContent = 'Information Unavailable'; + } + + updateBrowserURL(company.name); + hideSpinner(); + } catch (error) { + console.log('Error fetching company details:', error); + const companyDetailsContainer = document.getElementById('company-details-container'); + companyDetailsContainer.innerHTML = ` +
+

Company details currently unavailable - please try again

+
`; + hideSpinner(); + } +} + +async function fetchCompanyMovies(companyId) { + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_companies=${companyId}`; + try { + const response = await fetch(url); + const data = await response.json(); + + if (data.results.length === 0) { + const companyMoviesContainer = document.getElementById('company-movies-container'); + companyMoviesContainer.innerHTML = `

No movies found for this company.

`; + return; + } + displayCompanyMovies(data.results); + } catch (error) { + console.log('Error fetching movies:', error); + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +const twoLetterCountryCodes = [ + { name: 'Afghanistan', code: 'AF' }, + { name: 'Albania', code: 'AL' }, + { name: 'Algeria', code: 'DZ' }, + { name: 'American Samoa', code: 'AS' }, + { name: 'Andorra', code: 'AD' }, + { name: 'Angola', code: 'AO' }, + { name: 'Anguilla', code: 'AI' }, + { name: 'Antarctica', code: 'AQ' }, + { name: 'Antigua and Barbuda', code: 'AG' }, + { name: 'Argentina', code: 'AR' }, + { name: 'Armenia', code: 'AM' }, + { name: 'Aruba', code: 'AW' }, + { name: 'Australia', code: 'AU' }, + { name: 'Austria', code: 'AT' }, + { name: 'Azerbaijan', code: 'AZ' }, + { name: 'Bahamas', code: 'BS' }, + { name: 'Bahrain', code: 'BH' }, + { name: 'Bangladesh', code: 'BD' }, + { name: 'Barbados', code: 'BB' }, + { name: 'Belarus', code: 'BY' }, + { name: 'Belgium', code: 'BE' }, + { name: 'Belize', code: 'BZ' }, + { name: 'Benin', code: 'BJ' }, + { name: 'Bermuda', code: 'BM' }, + { name: 'Bhutan', code: 'BT' }, + { name: 'Bolivia', code: 'BO' }, + { name: 'Bonaire', code: 'BQ' }, + { name: 'Bosnia and Herzegovina', code: 'BA' }, + { name: 'Botswana', code: 'BW' }, + { name: 'Bouvet Island', code: 'BV' }, + { name: 'Brazil', code: 'BR' }, + { name: 'British Indian Ocean Territory', code: 'IO' }, + { name: 'Brunei Darussalam', code: 'BN' }, + { name: 'Bulgaria', code: 'BG' }, + { name: 'Burkina Faso', code: 'BF' }, + { name: 'Burundi', code: 'BI' }, + { name: 'Cambodia', code: 'KH' }, + { name: 'Cameroon', code: 'CM' }, + { name: 'Canada', code: 'CA' }, + { name: 'Cape Verde', code: 'CV' }, + { name: 'Cayman Islands', code: 'KY' }, + { name: 'Central African Republic', code: 'CF' }, + { name: 'Chad', code: 'TD' }, + { name: 'Chile', code: 'CL' }, + { name: 'China', code: 'CN' }, + { name: 'Christmas Island', code: 'CX' }, + { name: 'Cocos (Keeling) Islands', code: 'CC' }, + { name: 'Colombia', code: 'CO' }, + { name: 'Comoros', code: 'KM' }, + { name: 'Congo', code: 'CG' }, + { name: 'Congo, The Democratic Republic of the', code: 'CD' }, + { name: 'Cook Islands', code: 'CK' }, + { name: 'Costa Rica', code: 'CR' }, + { name: 'Cote D Ivoire', code: 'CI' }, + { name: 'Croatia', code: 'HR' }, + { name: 'Cuba', code: 'CU' }, + { name: 'Curacao', code: 'CW' }, + { name: 'Cyprus', code: 'CY' }, + { name: 'Czech Republic', code: 'CZ' }, + { name: 'Denmark', code: 'DK' }, + { name: 'Djibouti', code: 'DJ' }, + { name: 'Dominica', code: 'DM' }, + { name: 'Dominican Republic', code: 'DO' }, + { name: 'Ecuador', code: 'EC' }, + { name: 'Egypt', code: 'EG' }, + { name: 'El Salvador', code: 'SV' }, + { name: 'Equatorial Guinea', code: 'GQ' }, + { name: 'Eritrea', code: 'ER' }, + { name: 'Estonia', code: 'EE' }, + { name: 'Eswatini', code: 'SZ' }, + { name: 'Ethiopia', code: 'ET' }, + { name: 'Falkland Islands (Malvinas)', code: 'FK' }, + { name: 'Faroe Islands', code: 'FO' }, + { name: 'Fiji', code: 'FJ' }, + { name: 'Finland', code: 'FI' }, + { name: 'France', code: 'FR' }, + { name: 'French Guiana', code: 'GF' }, + { name: 'French Polynesia', code: 'PF' }, + { name: 'French Southern Territories', code: 'TF' }, + { name: 'Gabon', code: 'GA' }, + { name: 'Gambia', code: 'GM' }, + { name: 'Georgia', code: 'GE' }, + { name: 'Germany', code: 'DE' }, + { name: 'Ghana', code: 'GH' }, + { name: 'Gibraltar', code: 'GI' }, + { name: 'Greece', code: 'GR' }, + { name: 'Greenland', code: 'GL' }, + { name: 'Grenada', code: 'GD' }, + { name: 'Guadeloupe', code: 'GP' }, + { name: 'Guam', code: 'GU' }, + { name: 'Guatemala', code: 'GT' }, + { name: 'Guernsey', code: 'GG' }, + { name: 'Guinea', code: 'GN' }, + { name: 'Guinea-Bissau', code: 'GW' }, + { name: 'Guyana', code: 'GY' }, + { name: 'Haiti', code: 'HT' }, + { name: 'Heard Island and Mcdonald Islands', code: 'HM' }, + { name: 'Holy See (Vatican City State)', code: 'VA' }, + { name: 'Honduras', code: 'HN' }, + { name: 'Hong Kong', code: 'HK' }, + { name: 'Hungary', code: 'HU' }, + { name: 'Iceland', code: 'IS' }, + { name: 'India', code: 'IN' }, + { name: 'Indonesia', code: 'ID' }, + { name: 'Iran, Islamic Republic Of', code: 'IR' }, + { name: 'Iraq', code: 'IQ' }, + { name: 'Ireland', code: 'IE' }, + { name: 'Isle of Man', code: 'IM' }, + { name: 'Israel', code: 'IL' }, + { name: 'Italy', code: 'IT' }, + { name: 'Ivory Coast', code: 'CI' }, + { name: 'Jamaica', code: 'JM' }, + { name: 'Japan', code: 'JP' }, + { name: 'Jersey', code: 'JE' }, + { name: 'Jordan', code: 'JO' }, + { name: 'Kazakhstan', code: 'KZ' }, + { name: 'Kenya', code: 'KE' }, + { name: 'Kiribati', code: 'KI' }, + { name: 'DPR Korea', code: 'KP' }, + { name: 'South Korea', code: 'KR' }, + { name: 'Kuwait', code: 'KW' }, + { name: 'Kyrgyzstan', code: 'KG' }, + { name: 'Laos', code: 'LA' }, + { name: 'Latvia', code: 'LV' }, + { name: 'Lebanon', code: 'LB' }, + { name: 'Lesotho', code: 'LS' }, + { name: 'Liberia', code: 'LR' }, + { name: 'Libyan Arab Jamahiriya', code: 'LY' }, + { name: 'Liechtenstein', code: 'LI' }, + { name: 'Lithuania', code: 'LT' }, + { name: 'Luxembourg', code: 'LU' }, + { name: 'Macao', code: 'MO' }, + { name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK' }, + { name: 'Madagascar', code: 'MG' }, + { name: 'Malawi', code: 'MW' }, + { name: 'Malaysia', code: 'MY' }, + { name: 'Maldives', code: 'MV' }, + { name: 'Mali', code: 'ML' }, + { name: 'Malta', code: 'MT' }, + { name: 'Marshall Islands', code: 'MH' }, + { name: 'Martinique', code: 'MQ' }, + { name: 'Mauritania', code: 'MR' }, + { name: 'Mauritius', code: 'MU' }, + { name: 'Mayotte', code: 'YT' }, + { name: 'Mexico', code: 'MX' }, + { name: 'Micronesia, Federated States of', code: 'FM' }, + { name: 'Moldova, Republic of', code: 'MD' }, + { name: 'Monaco', code: 'MC' }, + { name: 'Mongolia', code: 'MN' }, + { name: 'Montenegro', code: 'ME' }, + { name: 'Montserrat', code: 'MS' }, + { name: 'Morocco', code: 'MA' }, + { name: 'Mozambique', code: 'MZ' }, + { name: 'Myanmar', code: 'MM' }, + { name: 'Namibia', code: 'NA' }, + { name: 'Nauru', code: 'NR' }, + { name: 'Nepal', code: 'NP' }, + { name: 'Netherlands', code: 'NL' }, + { name: 'Netherlands Antilles', code: 'AN' }, + { name: 'New Caledonia', code: 'NC' }, + { name: 'New Zealand', code: 'NZ' }, + { name: 'Nicaragua', code: 'NI' }, + { name: 'Niger', code: 'NE' }, + { name: 'Nigeria', code: 'NG' }, + { name: 'Niue', code: 'NU' }, + { name: 'Norfolk Island', code: 'NF' }, + { name: 'Northern Mariana Islands', code: 'MP' }, + { name: 'Norway', code: 'NO' }, + { name: 'Oman', code: 'OM' }, + { name: 'Pakistan', code: 'PK' }, + { name: 'Palau', code: 'PW' }, + { name: 'Palestinian Territory, Occupied', code: 'PS' }, + { name: 'Panama', code: 'PA' }, + { name: 'Papua New Guinea', code: 'PG' }, + { name: 'Paraguay', code: 'PY' }, + { name: 'Peru', code: 'PE' }, + { name: 'Philippines', code: 'PH' }, + { name: 'Pitcairn', code: 'PN' }, + { name: 'Poland', code: 'PL' }, + { name: 'Portugal', code: 'PT' }, + { name: 'Puerto Rico', code: 'PR' }, + { name: 'Qatar', code: 'QA' }, + { name: 'RWANDA', code: 'RW' }, + { name: 'Reunion', code: 'RE' }, + { name: 'Romania', code: 'RO' }, + { name: 'Russian Federation', code: 'RU' }, + { name: 'Saint Barthelemy', code: 'BL' }, + { name: 'Saint Helena', code: 'SH' }, + { name: 'Saint Kitts and Nevis', code: 'KN' }, + { name: 'Saint Lucia', code: 'LC' }, + { name: 'Saint Martin', code: 'MF' }, + { name: 'Saint Pierre and Miquelon', code: 'PM' }, + { name: 'Saint Vincent and the Grenadines', code: 'VC' }, + { name: 'Samoa', code: 'WS' }, + { name: 'San Marino', code: 'SM' }, + { name: 'Sao Tome and Principe', code: 'ST' }, + { name: 'Saudi Arabia', code: 'SA' }, + { name: 'Senegal', code: 'SN' }, + { name: 'Serbia', code: 'RS' }, + { name: 'Seychelles', code: 'SC' }, + { name: 'Sierra Leone', code: 'SL' }, + { name: 'Singapore', code: 'SG' }, + { name: 'Sint Maarten', code: 'SX' }, + { name: 'Slovakia', code: 'SK' }, + { name: 'Slovenia', code: 'SI' }, + { name: 'Solomon Islands', code: 'SB' }, + { name: 'Somalia', code: 'SO' }, + { name: 'South Africa', code: 'ZA' }, + { name: 'South Georgia and the South Sandwich Islands', code: 'GS' }, + { name: 'South Sudan', code: 'SS' }, + { name: 'Spain', code: 'ES' }, + { name: 'Sri Lanka', code: 'LK' }, + { name: 'Sudan', code: 'SD' }, + { name: 'Suriname', code: 'SR' }, + { name: 'Svalbard and Jan Mayen', code: 'SJ' }, + { name: 'Swaziland', code: 'SZ' }, + { name: 'Sweden', code: 'SE' }, + { name: 'Switzerland', code: 'CH' }, + { name: 'Syrian Arab Republic', code: 'SY' }, + { name: 'Taiwan', code: 'TW' }, + { name: 'Tajikistan', code: 'TJ' }, + { name: 'Tanzania, United Republic of', code: 'TZ' }, + { name: 'Thailand', code: 'TH' }, + { name: 'Timor-Leste', code: 'TL' }, + { name: 'Togo', code: 'TG' }, + { name: 'Tokelau', code: 'TK' }, + { name: 'Tonga', code: 'TO' }, + { name: 'Trinidad and Tobago', code: 'TT' }, + { name: 'Tunisia', code: 'TN' }, + { name: 'Turkey', code: 'TR' }, + { name: 'Turkmenistan', code: 'TM' }, + { name: 'Turks and Caicos Islands', code: 'TC' }, + { name: 'Tuvalu', code: 'TV' }, + { name: 'Uganda', code: 'UG' }, + { name: 'Ukraine', code: 'UA' }, + { name: 'United Arab Emirates', code: 'AE' }, + { name: 'United Kingdom', code: 'GB' }, + { name: 'United States', code: 'US' }, + { name: 'United States Minor Outlying Islands', code: 'UM' }, + { name: 'Uruguay', code: 'UY' }, + { name: 'Uzbekistan', code: 'UZ' }, + { name: 'Vanuatu', code: 'VU' }, + { name: 'Venezuela', code: 'VE' }, + { name: 'Viet Nam', code: 'VN' }, + { name: 'Vietnam', code: 'VN' }, + { name: 'Virgin Islands, British', code: 'VG' }, + { name: 'Virgin Islands, U.S.', code: 'VI' }, + { name: 'Wallis and Futuna', code: 'WF' }, + { name: 'Western Sahara', code: 'EH' }, + { name: 'Yemen', code: 'YE' }, + { name: 'Zambia', code: 'ZM' }, + { name: 'Zimbabwe', code: 'ZW' }, + { name: 'Åland Islands', code: 'AX' }, +]; + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function displayCompanyMovies(movies) { + const moviesList = document.getElementById('company-movies-list'); + moviesList.style.display = 'flex'; + moviesList.style.flexWrap = 'wrap'; + moviesList.style.justifyContent = 'center'; + moviesList.style.gap = '5px'; + + let moviesToDisplay = movies.sort((a, b) => b.popularity - a.popularity); + + moviesToDisplay.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + moviesList.appendChild(movieLink); + + if (index < movies.length - 1) { + const separator = document.createTextNode(' '); + moviesList.appendChild(separator); + } + }); +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/create-account.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/create-account.js new file mode 100644 index 00000000..33047f26 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/create-account.js @@ -0,0 +1,140 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + collection, + addDoc, + getDocs, + query, + where, + doc, + setDoc, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function isValidPassword(password) { + const minLength = 8; + const hasUppercase = /[A-Z]/.test(password); + const hasLowercase = /[a-z]/.test(password); + const hasNumbers = /\d/.test(password); + const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password); + + return password.length >= minLength && hasUppercase && hasLowercase && hasNumbers && hasSpecialChar; +} + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('createAccountForm').addEventListener('submit', async e => { + try { + e.preventDefault(); + const email = document.getElementById('newEmail').value; + const password = document.getElementById('newPassword').value; + const confirmPassword = document.getElementById('confirmPassword').value; + + if (!isValidPassword(password)) { + alert( + 'Password does not meet the security requirements.\n\n' + + 'Your password must include:\n' + + '- At least 8 characters\n' + + '- At least one uppercase letter\n' + + '- At least one lowercase letter\n' + + '- At least one number\n' + + '- At least one special character (e.g., !@#$%^&*)' + ); + return; + } + + if (password !== confirmPassword) { + alert('Passwords do not match.'); + return; + } + + const exists = await accountExists(email); + if (exists) { + alert('An account with this email already exists.'); + return; + } + + try { + await addDoc(collection(db, 'MovieVerseUsers'), { + email: email, + password: password, + }); + + const profileRef = doc(db, 'profiles', email); // Using email as document ID for simplicity + await setDoc(profileRef, { + username: 'N/A', + dob: 'N/A', + bio: 'N/A', + favoriteGenres: ['N/A'], + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: ['N/A'], + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }); + + alert('Account created successfully! Now please sign in on the sign in page to proceed.'); + window.location.href = 'sign-in.html'; + } catch (error) { + console.log('Error creating account: ', error); + alert('Failed to create account. Please try again later.'); + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('account-creation-form-container'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +async function accountExists(email) { + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', email)); + const querySnapshot = await getDocs(q); + return !querySnapshot.empty; +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/director-details.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/director-details.js new file mode 100644 index 00000000..4a0dfc46 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/director-details.js @@ -0,0 +1,781 @@ +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const searchTitle = document.getElementById('search-title'); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + currentIndex = 0; + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', () => { + const directorId = localStorage.getItem('selectedDirectorId'); + + if (directorId) { + fetchDirectorDetails(directorId); + } else { + fetchDirectorDetails(488); + } +}); + +async function fetchDirectorDetails(directorId) { + showSpinner(); + + const directorUrl = `https://${getMovieVerseData()}/3/person/${directorId}?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/${directorId}/movie_credits?${generateMovieNames()}${getMovieCode()}`; + + try { + const [directorResponse, creditsResponse] = await Promise.all([fetch(directorUrl), fetch(creditsUrl)]); + + const director = await directorResponse.json(); + const credits = await creditsResponse.json(); + + if (director.success === false) { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details currently unavailable - please try again

+
`; + } else { + updateBrowserURL(director.name); + populateDirectorDetails(director, credits); + } + hideSpinner(); + } catch (error) { + document.getElementById('director-details-container').innerHTML = ` +
+

Director details currently unavailable - please try again

+
`; + console.log('Error fetching director details:', error); + hideSpinner(); + } +} + +async function populateDirectorDetails(director, credits) { + const directorImage = document.getElementById('director-image'); + const directorName = document.getElementById('director-name'); + const directorDescription = document.getElementById('director-description'); + + if (director.profile_path) { + directorImage.src = `https://image.tmdb.org/t/p/w1280${director.profile_path}`; + directorName.textContent = director.name; + document.title = `${director.name} - Director's Details`; + } else { + directorImage.style.display = 'none'; + directorName.textContent = director.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.director-left').appendChild(noImageText); + } + + let ageOrStatus; + if (director.birthday) { + if (director.deathday) { + ageOrStatus = calculateAge(director.birthday, director.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(director.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + directorDescription.innerHTML = ` +

Biography: ${director.biography || 'Information Unavailable'}

+

Also Known As: ${director.also_known_as.join(', ') || 'Information Unavailable'}

+

Date of Birth: ${director.birthday || 'Information Unavailable'}

+

Date of Death: ${director.deathday || 'Information Unavailable'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${director.place_of_birth || 'Information Unavailable'}

+

Known For: Directing

+ `; + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + directorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + movieList.style.display = 'flex'; + movieList.style.flexWrap = 'wrap'; + movieList.style.justifyContent = 'center'; + movieList.style.gap = '5px'; + + let directedMovies = credits.crew.filter(movie => movie.job === 'Director'); + directedMovies = directedMovies.sort((a, b) => b.popularity - a.popularity); + + directedMovies.forEach((movie, index) => { + const movieLink = document.createElement('a'); + movieLink.classList.add('movie-link'); + movieLink.href = 'javascript:void(0);'; + movieLink.setAttribute('onclick', `selectMovieId(${movie.id});`); + + const movieItem = document.createElement('div'); + movieItem.classList.add('movie-item'); + + const movieImage = document.createElement('img'); + movieImage.classList.add('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH2 + movie.poster_path; + movieImage.alt = `${movie.title} Poster`; + } else { + movieImage.alt = 'Image Not Available'; + movieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + movieImage.style.filter = 'grayscale(100%)'; + movieImage.style.objectFit = 'cover'; + } + + movieItem.appendChild(movieImage); + + const movieDetails = document.createElement('div'); + movieDetails.classList.add('movie-details'); + + const movieTitle = document.createElement('p'); + movieTitle.classList.add('movie-title'); + movieTitle.textContent = movie.title; + movieDetails.appendChild(movieTitle); + + movieItem.appendChild(movieDetails); + movieLink.appendChild(movieItem); + movieList.appendChild(movieLink); + + if (index < directedMovies.length - 1) { + movieList.appendChild(document.createTextNode('')); + } + }); + + filmographyHeading.appendChild(movieList); + + const mediaUrl = `https://${getMovieVerseData()}/3/person/${director.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + + const detailsContainer = document.getElementById('director-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + let modalOpen = false; + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + imageElement.addEventListener('click', function () { + const imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 380); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + applySettings(); +} + +function calculateAge(dob, deathday = null) { + const birthDate = new Date(dob); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const ageDifMs = referenceDate - birthDate.getTime(); + const ageDate = new Date(ageDifMs); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +function selectMovieId(movieId) { + localStorage.setItem('selectedMovieId', movieId); + window.location.href = 'movie-details.html'; +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + applyTextColor(savedTextColor); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/favorites.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/favorites.js new file mode 100644 index 00000000..fcb4771a --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/favorites.js @@ -0,0 +1,2062 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js'; +import { + getFirestore, + doc, + setDoc, + collection, + updateDoc, + getDocs, + getDoc, + query, + where, + orderBy, + writeBatch, + deleteDoc, +} from 'https://www.gstatic.com/firebasejs/9.6.10/firebase-firestore.js'; + +let initialMoviesSelection = []; +let initialTVSeriesSelection = []; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.addEventListener('DOMContentLoaded', function () { + loadWatchLists(); +}); + +const tvCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(tvCode.part1) + atob(tvCode.part2) + atob(tvCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +document.addEventListener('DOMContentLoaded', function () { + adjustButtonMargin(); + document.getElementById('how-to-use-btn').addEventListener('click', function () { + let howToUseSection = document.getElementById('how-to-use-section'); + if (howToUseSection.style.display === 'none') { + howToUseSection.style.display = 'block'; + window.location.href = '#how-to-use-section'; + document.getElementById('how-to-use-btn').textContent = 'Hide Tutorial'; + document.getElementById('how-to-use-btn').style.marginBottom = '0'; + } else { + howToUseSection.style.display = 'none'; + document.getElementById('how-to-use-btn').textContent = 'How to Use'; + document.getElementById('how-to-use-btn').style.marginBottom = '180px'; + } + }); +}); + +function adjustButtonMargin() { + let howToUseSection = document.getElementById('how-to-use-section'); + if (howToUseSection.style.display === 'none' || !howToUseSection.style.display) { + document.getElementById('how-to-use-btn').style.marginBottom = '200px'; + } else { + document.getElementById('how-to-use-btn').style.marginBottom = '0'; + } +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function openModal(modalId) { + document.getElementById(modalId).style.display = 'block'; +} + +document.addEventListener('DOMContentLoaded', () => { + const closeButtons = document.querySelectorAll('.close-button'); + + closeButtons.forEach(button => { + button.addEventListener('click', function () { + const modalId = this.closest('.modal').id; + closeModal(modalId); + }); + }); +}); + +function closeModal(modalId) { + document.getElementById(modalId).style.display = 'none'; +} + +document.getElementById('delete-watchlist-btn').addEventListener('click', () => openModal('delete-watchlist-modal')); + +async function getMovieTitle(movieId) { + const apiKey = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${apiKey}`; + + try { + const response = await fetch(url); + const movie = await response.json(); + return movie.title; + } catch (error) { + return 'Unknown Movie'; + } +} + +async function populateCreateModalWithFavorites() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || ''; + + if (!currentUserEmail) { + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + return; + } + + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + + const createForm = document.getElementById('create-watchlist-form'); + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + createForm.insertBefore(container, createForm.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + const moviesFavorited = userData.favoritesMovies || []; + const favoritesTVSeries = userData.favoritesTVSeries || []; + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + } else { + container.innerHTML = '

No favorites found. Please add some favorites first.

'; + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + } else { + container.innerHTML = ''; + } + + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); + + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('create-watchlist-modal'); + } + }); +} + +document.getElementById('create-watchlist-form').addEventListener('submit', async function (e) { + e.preventDefault(); + showSpinner(); + + const name = document.getElementById('new-watchlist-name').value.trim(); + const description = document.getElementById('new-watchlist-description').value; + const selectedMovies = Array.from(document.querySelectorAll('#movies-container input:checked')).map(checkbox => checkbox.value); + const selectedTVSeries = Array.from(document.querySelectorAll('#tvseries-container input:checked')).map(checkbox => checkbox.value); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let isDuplicate = false; + let maxOrder = 0; + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + try { + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + maxOrder = querySnapshot.docs.reduce((max, docSnapshot) => Math.max(max, docSnapshot.data().order || 0), 0); + isDuplicate = querySnapshot.docs.some(doc => doc.data().name.toLowerCase() === name.toLowerCase()); + } else { + isDuplicate = localWatchlists.some(watchlist => watchlist.name.toLowerCase() === name.toLowerCase()); + } + + if (isDuplicate) { + alert('A watchlist with this name already exists. Please choose a different name.'); + hideSpinner(); + return; + } + + if (currentUserEmail) { + const newWatchlistRef = doc(collection(db, 'watchlists')); + await setDoc(newWatchlistRef, { + userEmail: currentUserEmail, + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + order: maxOrder + 1, + }); + } else { + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: '', + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: '', + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } else { + console.error('An error occurred while creating a watchlist:', error); + alert('Failed to create the watchlist due to an error.'); + } + } + + closeModal('create-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); +}); + +async function getTVSeriesTitle(seriesId) { + const apiKey = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/tv/${seriesId}?${generateMovieNames()}${apiKey}`; + + try { + const response = await fetch(url); + const series = await response.json(); + return series.name; + } catch (error) { + return 'Unknown Series'; + } +} + +function appendCheckbox(container, id, title, name, isChecked = false) { + const item = document.createElement('div'); + item.classList.add('favorite-item'); + item.style.display = 'flex'; + item.style.alignItems = 'center'; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `${name}-${id}`; + checkbox.value = id; + checkbox.name = name; + checkbox.checked = isChecked; + + const label = document.createElement('label'); + label.htmlFor = `${name}-${id}`; + label.textContent = title; + label.style.marginTop = '12px'; + label.style.marginLeft = '10px'; + + item.appendChild(checkbox); + item.appendChild(label); + container.appendChild(item); +} + +document.getElementById('create-watchlist-btn').addEventListener('click', function () { + document.getElementById('create-watchlist-form').reset(); + populateCreateModalWithFavorites(); + openModal('create-watchlist-modal'); + updateWatchlistsCreated(); +}); + +function generateUniqueId() { + return Date.now().toString(36) + Math.random().toString(36).substr(2); +} + +document.getElementById('edit-watchlist-btn').addEventListener('click', async function () { + await populateEditModal(); + openModal('edit-watchlist-modal'); +}); + +async function populateEditModal() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let watchlists = []; + let moviesFavorited = []; + let favoritesTVSeries = []; + + if (currentUserEmail) { + const qWatchlists = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const qUsers = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + + const [watchlistsSnapshot, usersSnapshot] = await Promise.all([getDocs(qWatchlists), getDocs(qUsers)]); + + watchlists = watchlistsSnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + if (!usersSnapshot.empty) { + const userData = usersSnapshot.docs[0].data(); + moviesFavorited = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; + + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } + + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute('for', 'watchlist-select'); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach(watchlist => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); + + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; + + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); + + const updateForm = async watchlist => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; + + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } + } + + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; + + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); + + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } + + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; + + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } + + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute('for', 'watchlist-select'); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach(watchlist => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); + + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; + + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); + + const updateForm = async watchlist => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; + + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; + } else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } + } + + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; + } else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; + + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); + + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } + + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('edit-watchlist-modal'); + } + }); +} + +document.getElementById('edit-watchlist-form').addEventListener('submit', async function (e) { + try { + showSpinner(); + e.preventDefault(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; + + let selectedMovies; + let selectedTVSeries; + + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + + const moviesSelectionChanged = !( + initialMoviesSelection.length === currentMoviesSelection.length && initialMoviesSelection.every(value => currentMoviesSelection.includes(value)) + ); + const tvSeriesSelectionChanged = !( + initialTVSeriesSelection.length === currentTVSeriesSelection.length && + initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value)) + ); + + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } else { + selectedMovies = initialMoviesSelection; + } + + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } else { + selectedTVSeries = initialTVSeriesSelection; + } + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + + const watchlistRef = doc(db, 'watchlists', watchlistId); + await updateDoc(watchlistRef, { + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }); + } else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); + + e.preventDefault(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; + + let selectedMovies; + let selectedTVSeries; + + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map( + checkbox => checkbox.value + ); + + const moviesSelectionChanged = !( + initialMoviesSelection.length === currentMoviesSelection.length && + initialMoviesSelection.every(value => currentMoviesSelection.includes(value)) + ); + const tvSeriesSelectionChanged = !( + initialTVSeriesSelection.length === currentTVSeriesSelection.length && + initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value)) + ); + + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } else { + selectedMovies = initialMoviesSelection; + } + + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } else { + selectedTVSeries = initialTVSeriesSelection; + } + + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries, + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } +}); + +async function populateDeleteModal() { + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; + + let watchlists = []; + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + } else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + } + + if (watchlists.length === 0) { + deleteForm.innerHTML = '

No Watchlists Available to Delete.

'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); + + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; + + if (watchlists.length === 0) { + deleteForm.innerHTML = '

No Watchlists Available to Delete.

'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); + + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); + } + } + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeModal('delete-watchlist-modal'); + } + }); +} + +async function deleteSelectedWatchlists() { + try { + showSpinner(); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + + for (const id of selectedIds) { + await deleteDoc(doc(db, 'watchlists', id)); + } + } else { + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + } + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); + + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } +} + +document.getElementById('delete-watchlist-btn').addEventListener('click', populateDeleteModal); + +async function fetchMovieDetails(movieId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + + try { + const response = await fetch(url); + const movie = await response.json(); + const movieCard = await createMovieCard(movie); + movieCard.setAttribute('data-movie-title', movie.title); + return movieCard; + } catch (error) { + const errorDiv = document.createElement('div'); + errorDiv.textContent = 'Error loading movie card. Please try refreshing the page.'; + return errorDiv; + } +} + +async function getAdditionalMovieImages(movieId) { + const response = await fetch(`https://api.themoviedb.org/3/movie/${movieId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +async function createMovieCard(movie) { + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = movie.title; + const words = movieTitle.split(' '); + if (words.length >= 9) { + words[8] = '...'; + movieTitle = words.slice(0, 9).join(' '); + } + + const ratingClass = movie.vote_count === 0 ? 'unrated' : getClassByRate(movie.vote_average); + const voteAvg = movie.vote_count === 0 ? 'Unrated' : movie.vote_average.toFixed(1); + + let overview = movie.overview; + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+ ${movie.title} +
+
+

${movieTitle}

+ ${voteAvg} +
+
+

Movie Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + updateUniqueMoviesViewed(movie.id); + updateFavoriteGenre(movie.genre_ids); + updateMovieVisitCount(movie.id, movie.title); + window.location.href = 'movie-details.html'; + }); + + const additionalImages = await getAdditionalMovieImages(movie.id); + let allImages = [movie.poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + + return movieEl; +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +const searchForm = document.getElementById('form'); + +searchForm.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function loadWatchLists() { + const displaySection = document.getElementById('watchlists-display-section'); + + try { + showSpinner(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (currentUserEmail) { + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + const watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + if (watchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Click on "Create Watch Lists" to start adding movies.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += + '

Your Watch Lists

'; + document.getElementById('watchlist-header').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); + }); + watchlists.sort((a, b) => a.order - b.order); + watchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of watchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + } else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + if (localWatchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += '

Your Watch Lists

'; + localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + } + + let favorites = []; + let favoritesTVSeries = []; + + if (currentUserEmail) { + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + } + + if (favorites.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite Movies'; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite movies.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const movieId of favorites) { + const movieCard = await fetchMovieDetails(movieId); + moviesContainer.appendChild(movieCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + favoritesDiv.innerHTML = + '

Favorite Movies

No favorite movies added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + if (favoritesTVSeries.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite TV Series'; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + favoritesDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite TV series.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const tvSeriesId of favoritesTVSeries) { + const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); + moviesContainer.appendChild(tvSeriesCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + favoritesDiv.innerHTML = + '

Favorite TV Series

No favorite TV series added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + hideSpinner(); + } catch (error) { + if (error.code === 'resource-exhausted') { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + if (localWatchlists.length === 0) { + displaySection.innerHTML = '

No watch lists found. Start by adding movies to your watchlist.

'; + } else { + displaySection.innerHTML = ''; + displaySection.innerHTML += '

Your Watch Lists

'; + localWatchlists.sort((a, b) => (b.pinned === a.pinned ? 0 : b.pinned ? 1 : -1)); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + + let favorites = []; + let favoritesTVSeries = []; + + favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + if (favorites.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite Movies'; + title.className = 'watchlist-title'; + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite movies.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const movieId of favorites) { + const movieCard = await fetchMovieDetails(movieId); + moviesContainer.appendChild(movieCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-movies'; + favoritesDiv.innerHTML = + '

Favorite Movies

No favorite movies added yet.

'; + displaySection.appendChild(favoritesDiv); + } + + if (favoritesTVSeries.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + + const title = document.createElement('h3'); + title.textContent = 'Favorite TV Series'; + title.className = 'watchlist-title'; + + const description = document.createElement('p'); + description.textContent = 'A collection of your favorite TV series.'; + description.className = 'watchlist-description'; + + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const tvSeriesId of favoritesTVSeries) { + const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); + moviesContainer.appendChild(tvSeriesCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); + hideSpinner(); + } else { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorite-tv-series'; + favoritesDiv.innerHTML = + '

Favorite TV Series

No favorite TV series added yet.

'; + displaySection.appendChild(favoritesDiv); + hideSpinner(); + } + } else { + console.error('An error occurred:', error); + } + } +} + +async function fetchTVSeriesDetails(tvSeriesId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + + try { + const response = await fetch(url); + const series = await response.json(); + const seriesCard = await createTVSeriesCard(series); + seriesCard.setAttribute('data-series-title', series.name); + return seriesCard; + } catch (error) { + const errorDiv = document.createElement('div'); + errorDiv.textContent = 'Error loading series details. Please try refreshing the page.'; + return errorDiv; + } +} + +async function getAdditionalTVSeriesImages(tvSeriesId) { + const response = await fetch(`https://api.themoviedb.org/3/tv/${tvSeriesId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +async function createTVSeriesCard(tvSeries) { + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = tvSeries.name; + const words = movieTitle.split(' '); + if (words.length >= 9) { + words[8] = '...'; + movieTitle = words.slice(0, 9).join(' '); + } + + const ratingClass = tvSeries.vote_count === 0 ? 'unrated' : getClassByRate(tvSeries.vote_average); + const voteAvg = tvSeries.vote_count === 0 ? 'Unrated' : tvSeries.vote_average.toFixed(1); + + let overview = tvSeries.overview; + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+ ${tvSeries.name} +
+
+

${movieTitle}

+ ${voteAvg} +
+
+

TV Series Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedTvSeriesId', tvSeries.id); + updateMovieVisitCount(tvSeries.id, tvSeries.name); + updateUniqueMoviesViewed(tvSeries.id); + updateFavoriteGenre(tvSeries.genres_ids); + window.location.href = 'tv-details.html'; + }); + + const additionalImages = await getAdditionalTVSeriesImages(tvSeries.id); + let allImages = [tvSeries.poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + + return movieEl; +} + +function updateFavoriteGenre(genre_ids) { + if (genre_ids && genre_ids.length > 0) { + const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + favoriteGenres.push(genre_ids[0]); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + } +} + +function updateUniqueMoviesViewed(movieId) { + let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + if (!viewedMovies.includes(movieId)) { + viewedMovies.push(movieId); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); + } +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +async function isListPinned(watchlistId) { + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (currentUserEmail) { + try { + const watchlistRef = doc(db, 'watchlists', watchlistId); + const watchlistDoc = await getDoc(watchlistRef); + + if (watchlistDoc.exists()) { + const watchlistData = watchlistDoc.data(); + return watchlistData.pinned || false; + } else { + return false; + } + } catch (error) { + return false; + } + } else { + const watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + const watchlist = watchlists.find(watchlist => watchlist.id === watchlistId); + return watchlist ? watchlist.pinned : false; + } +} + +function addWatchListControls(watchlistDiv, watchlistId) { + if (!watchlistId) { + return; + } + + const controlContainer = document.createElement('div'); + controlContainer.className = 'watchlist-controls'; + + const pinBtn = document.createElement('button'); + pinBtn.innerHTML = ''; + pinBtn.classList.add('pin-btn'); + + isListPinned(watchlistId).then(isPinned => { + pinBtn.title = isPinned ? 'Unpin this watch list' : 'Pin this watch list'; + if (isPinned) { + pinBtn.classList.add('pinned'); + } else { + pinBtn.classList.remove('pinned'); + } + pinBtn.onclick = function () { + pinWatchList(watchlistDiv, watchlistId); + }; + }); + + const moveUpBtn = document.createElement('button'); + moveUpBtn.innerHTML = ''; + moveUpBtn.onclick = function () { + moveWatchList(watchlistDiv, true); + }; + moveUpBtn.title = 'Move this watch list up'; + + const moveDownBtn = document.createElement('button'); + moveDownBtn.innerHTML = ''; + moveDownBtn.onclick = function () { + moveWatchList(watchlistDiv, false); + }; + moveDownBtn.title = 'Move this watch list down'; + + const shareBtn = document.createElement('button'); + shareBtn.innerHTML = ''; + shareBtn.title = 'Share this watch list'; + shareBtn.onclick = function () { + shareWatchList(watchlistDiv); + }; + + controlContainer.appendChild(pinBtn); + controlContainer.appendChild(moveUpBtn); + controlContainer.appendChild(moveDownBtn); + controlContainer.appendChild(shareBtn); + watchlistDiv.appendChild(controlContainer); +} + +function shareWatchList(watchlistDiv) { + const watchlistTitle = watchlistDiv.querySelector('.watchlist-title').textContent; + let itemsToShare = `Explore my curated watchlist, "${watchlistTitle}", which contains:\n`; + let finalLine = 'Happy Watching! 🍿🎬🎥\n\n'; + const movieCards = watchlistDiv.querySelectorAll('[data-movie-title]'); + const tvSeriesCards = watchlistDiv.querySelectorAll('[data-series-title]'); + + movieCards.forEach(movieCard => { + itemsToShare += `- ${movieCard.getAttribute('data-movie-title')}\n`; + }); + + tvSeriesCards.forEach(seriesCard => { + itemsToShare += `- ${seriesCard.getAttribute('data-series-title')}\n`; + }); + + itemsToShare += finalLine; + + if (navigator.share) { + navigator + .share({ + title: `Share Watchlist: ${watchlistTitle}`, + text: itemsToShare, + }) + .catch(err => { + console.error('Error sharing the watchlist:', err); + }); + } else { + downloadWatchlist(watchlistTitle, itemsToShare); + } +} + +function downloadWatchlist(title, content) { + const encodedContent = encodeURIComponent(content); + const dataUri = `data:text/plain;charset=utf-8,${encodedContent}`; + + const element = document.createElement('a'); + element.setAttribute('href', dataUri); + element.setAttribute('download', `${title.replace(/[\s]+/g, '_')}.txt`); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + document.body.removeChild(element); +} + +function createWatchListDiv(watchlist) { + const watchlistDiv = document.createElement('div'); + watchlistDiv.className = 'watchlist'; + watchlistDiv.setAttribute('data-watchlist-id', watchlist.id); + + const title = document.createElement('h3'); + title.textContent = watchlist.name; + title.className = 'watchlist-title'; + title.style.cursor = 'pointer'; + title.addEventListener('click', () => { + watchlistDiv.scrollIntoView({ behavior: 'smooth' }); + }); + + const description = document.createElement('p'); + description.textContent = watchlist.description; + description.className = 'watchlist-description'; + + watchlistDiv.appendChild(title); + watchlistDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + moviesContainer.style.flexWrap = 'wrap'; + + if (watchlist.movies === undefined) { + moviesContainer.innerHTML = ''; + } else { + watchlist.movies.forEach(movieId => { + fetchMovieDetails(movieId).then(movieCard => moviesContainer.appendChild(movieCard)); + }); + } + + if (watchlist.tvSeries === undefined) { + moviesContainer.innerHTML = ''; + } else { + watchlist.tvSeries.forEach(tvSeriesId => { + fetchTVSeriesDetails(tvSeriesId).then(tvSeriesCard => moviesContainer.appendChild(tvSeriesCard)); + }); + } + + watchlistDiv.appendChild(moviesContainer); + addWatchListControls(watchlistDiv, watchlist.id); + return watchlistDiv; +} + +function updateWatchlistsOrderInLS() { + const watchlistsDivs = document.querySelectorAll('#watchlists-display-section > .watchlist'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + const newOrder = Array.from(watchlistsDivs).map(div => div.getAttribute('data-watchlist-id')); + + watchlists.sort((a, b) => newOrder.indexOf(a.id) - newOrder.indexOf(b.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); +} + +async function moveWatchList(watchlistDiv, moveUp) { + showSpinner(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const watchlistId = watchlistDiv.getAttribute('data-watchlist-id'); + + if (currentUserEmail) { + try { + const watchlistsQuery = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail), orderBy('order', 'asc')); + const snapshot = await getDocs(watchlistsQuery); + let watchlists = snapshot.docs.map(doc => { + return { docId: doc.id, ...doc.data() }; + }); + + const index = watchlists.findIndex(watchlist => watchlist.docId === watchlistId); + if (index === -1 || watchlists.length < 2) { + hideSpinner(); + return; + } + + const swapIndex = moveUp ? index - 1 : index + 1; + if (swapIndex < 0 || swapIndex >= watchlists.length) { + hideSpinner(); + return; + } + + let currentOrder = watchlists[index].order; + let swapOrder = watchlists[swapIndex].order; + + const batch = writeBatch(db); + batch.update(doc(db, 'watchlists', watchlists[index].docId), { + order: swapOrder, + }); + batch.update(doc(db, 'watchlists', watchlists[swapIndex].docId), { + order: currentOrder, + }); + + await batch.commit(); + } catch (error) { + hideSpinner(); + } + hideSpinner(); + } else { + const sibling = moveUp ? watchlistDiv.previousElementSibling : watchlistDiv.nextElementSibling; + if (sibling) { + const parent = watchlistDiv.parentNode; + if (moveUp) { + parent.insertBefore(watchlistDiv, sibling); + } else { + parent.insertBefore(sibling, watchlistDiv); + } + updateWatchlistsOrderInLS(); + } + hideSpinner(); + } + + loadWatchLists(); + window.location.reload(); +} + +async function pinWatchList(watchlistDiv, watchlistId) { + showSpinner(); + + const isPinned = watchlistDiv.classList.contains('pinned'); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (currentUserEmail) { + const watchlistRef = doc(db, 'watchlists', watchlistId); + await updateDoc(watchlistRef, { + pinned: !isPinned, + }); + hideSpinner(); + } else { + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists.forEach(watchlist => { + if (watchlist.id === watchlistId) { + watchlist.pinned = !isPinned; + } + }); + + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + hideSpinner(); + } + + loadWatchLists(); + window.location.reload(); +} + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +function updateWatchlistsCreated() { + let watchlistsCount = parseInt(localStorage.getItem('watchlistsCreated')) || 0; + watchlistsCount++; + localStorage.setItem('watchlistsCreated', watchlistsCount.toString()); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/firebase.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/firebase.js new file mode 100644 index 00000000..bddd3301 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/firebase.js @@ -0,0 +1,43 @@ +import { initializeApp, getApps, getApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +export const app = !getApps().length ? initializeApp(firebaseConfig) : getApp(); +export const db = getFirestore(app); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/inception.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/inception.js new file mode 100644 index 00000000..cf9779e6 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/inception.js @@ -0,0 +1,1265 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const favoriteButton = document.getElementById('favorite-btn'); +const searchTitle = document.getElementById('search-title'); + +let trailerUrlGlobal; +let initialMainContent; +let trailerButton; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function setStarRating(rating) { + const stars = document.querySelectorAll('.rating .star'); + stars.forEach(star => { + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; + }); + + document.getElementById('rating-value').textContent = `${rating}.0/5.0`; +} + +document.querySelectorAll('.rating .star').forEach(star => { + star.addEventListener('mouseover', e => { + setStarRating(e.target.dataset.value); + }); + + star.addEventListener('mouseout', () => { + const movieId = localStorage.getItem('selectedMovieId'); + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); + }); + + star.addEventListener('click', e => { + const movieId = localStorage.getItem('selectedMovieId'); + const rating = e.target.dataset.value; + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + savedRatings[movieId] = rating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + setStarRating(rating); + updateAverageMovieRating(movieId, rating); + window.location.reload(); + }); +}); + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + + const movieId = localStorage.getItem('selectedMovieId'); + if (movieId) { + fetchMovieDetails(movieId); + } else { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details not found.

+
`; + } + + document.getElementById('clear-search-btn').style.display = 'none'; + + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButton(); + initClient(); + applySettings(); +}); + +async function fetchMovieDetails(movieId) { + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + const url2 = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=videos`; + const imdbUrl = `https://${getMovieVerseData()}/3/movie/27205?${generateMovieNames()}${code}&append_to_response=external_ids`; + + try { + const response = await fetch(url); + const movie = await response.json(); + const imdbId = movie.imdb_id; + + fetchMovieRatings(imdbId, movie); + + const response2 = await fetch(url2); + const movie2 = await response2.json(); + const trailers = movie2.videos.results.filter(video => video.type === 'Trailer'); + + if (trailers.length > 0) { + const trailerUrl = `https://www.youtube.com/watch?v=${trailers[0].key}`; + trailerButton = createTrailerButton(trailerUrl); + positionTrailerButton(); + } + updateBrowserURL(movie.title); + } catch (error) { + console.log('Error fetching movie details:', error); + } +} + +function getRatingDetails(rating) { + let details = { color: 'black', text: rating, description: '' }; + + switch (rating) { + case 'R': + details = { + color: 'red', + text: 'R (Restricted)', + description: ' - No one 17 and under admitted', + }; + break; + case 'PG-13': + details = { + color: 'yellow', + text: 'PG-13 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 13', + }; + break; + case 'PG': + details = { + color: 'orange', + text: 'PG (Parental Guidance Suggested)', + description: ' - May not be suitable for children', + }; + break; + case 'G': + details = { + color: 'green', + text: 'G (General Audiences)', + description: ' - All ages admitted', + }; + break; + case 'NC-17': + details = { + color: 'darkred', + text: 'NC-17 (Adults Only)', + description: ' - No one 17 and under admitted', + }; + break; + case 'TV-Y': + details = { + color: 'lightgreen', + text: 'TV-Y (All Children)', + description: ' - Appropriate for all children', + }; + break; + case 'TV-Y7': + details = { + color: 'lightblue', + text: 'TV-Y7 (Directed to Older Children)', + description: ' - Suitable for children ages 7 and up', + }; + break; + case 'TV-G': + details = { + color: 'green', + text: 'TV-G (General Audience)', + description: ' - Suitable for all ages', + }; + break; + case 'TV-PG': + details = { + color: 'orange', + text: 'TV-PG (Parental Guidance Suggested)', + description: ' - May not be suitable for younger children', + }; + break; + case 'TV-14': + details = { + color: 'yellow', + text: 'TV-14 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 14', + }; + break; + case 'TV-MA': + details = { + color: 'red', + text: 'TV-MA (Mature Audience Only)', + description: ' - Specifically designed to be viewed by adults', + }; + break; + case 'NR': + details = { + color: 'grey', + text: 'NR (Not Rated)', + description: ' - Movie has not been officially rated', + }; + break; + case 'UR': + case 'Unrated': + details = { + color: 'grey', + text: 'UR (Unrated)', + description: ' - Contains content not used in the rated version', + }; + break; + default: + details = { + color: 'white', + text: rating, + description: ' - Rating information not available', + }; + break; + } + + return details; +} + +async function fetchMovieRatings(imdbId, tmdbMovieData) { + const omdbApiKey = '2ba8e536'; + const omdbUrl = `https://www.omdbapi.com/?i=${imdbId}&apikey=${omdbApiKey}`; + + try { + const response = await fetch(omdbUrl); + const data = await response.json(); + + let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + + if (imdbRating === 'N/A' && tmdbMovieData.vote_average) { + imdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; + } + + const rtRatingObj = data.Ratings.find(rating => rating.Source === 'Rotten Tomatoes'); + let rtRating = rtRatingObj ? rtRatingObj.Value : 'N/A'; + + let metascore = data.Metascore ? `${data.Metascore}/100` : 'N/A'; + let awards = data.Awards; + let rated = data.Rated ? data.Rated : 'Rating information unavailable'; + + if (awards === 'N/A') { + awards = 'No awards information available'; + } + + if (metascore === 'N/A/100') { + const metacriticsRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + metascore = calculateFallbackMetacriticsRating(metacriticsRatingValue, tmdbMovieData.vote_average) + '/100'; + } + + if (rtRating === 'N/A') { + const imdbRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + rtRating = calculateFallbackRTRating(imdbRatingValue, tmdbMovieData.vote_average); + } + populateMovieDetails(tmdbMovieData, imdbRating, rtRating, metascore, awards, rated); + } catch (error) { + console.log('Error fetching movie ratings:', error); + const fallbackImdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; + populateMovieDetails(tmdbMovieData, fallbackImdbRating, 'N/A', 'No metascore information available', 'No awards information available'); + } +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +function calculateFallbackRTRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0) + '%'; // Calculate fallback RT rating out of 100% scale (in case data is not available from OMDB) +} + +function calculateFallbackMetacriticsRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0); // Calculate fallback Metacritics rating out of 100 scale (in case data is not available from OMDB) +} + +let trailerIframeDisplayed = false; + +function createTrailerButton(trailerUrl) { + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + + trailerButton.addEventListener('click', function () { + if (!trailerIframeDisplayed) { + showTrailerIframe(trailerUrl); + trailerButton.textContent = 'Close Trailer'; + trailerButton.title = 'Click to close the trailer'; + } else { + closeTrailerIframe(); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + } + }); + + trailerButton.classList.add('trailer-button'); + trailerButton.style.font = 'inherit'; + + return trailerButton; +} + +function closeTrailerIframe() { + const iframeContainer = document.querySelector('.trailer-button + div'); + + if (iframeContainer) { + iframeContainer.style.height = '0'; + setTimeout(() => iframeContainer.remove(), 500); + } + trailerIframeDisplayed = false; +} + +function getYouTubeVideoId(url) { + const urlObj = new URL(url); + return urlObj.searchParams.get('v'); +} + +function positionTrailerButton() { + if (!trailerButton) return; + + if (window.innerWidth <= 900) { + const movieDescription = document.getElementById('movie-description'); + movieDescription.parentNode.insertBefore(trailerButton, movieDescription); + } else { + const movieRating = document.getElementById('movie-rating'); + movieRating.parentNode.insertBefore(trailerButton, movieRating.nextSibling); + } +} + +document.addEventListener('DOMContentLoaded', positionTrailerButton); + +function showTrailerIframe(trailerUrl) { + trailerUrlGlobal = trailerUrl; + + const iframeContainer = document.createElement('div'); + iframeContainer.style.position = 'relative'; + iframeContainer.style.width = '400px'; + iframeContainer.style.margin = '0 auto'; + iframeContainer.style.overflow = 'hidden'; + iframeContainer.style.height = '0'; + iframeContainer.style.transition = 'height 0.5s ease-in-out'; + + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', `https://www.youtube.com/embed/${getYouTubeVideoId(trailerUrl)}?autoplay=1`); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('height', '315'); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'); + iframe.setAttribute('allowfullscreen', true); + + iframeContainer.appendChild(iframe); + + const trailerButton = document.querySelector('.trailer-button'); + trailerButton.parentNode.insertBefore(iframeContainer, trailerButton.nextSibling); + + setTimeout(() => (iframeContainer.style.height = '315px'), 50); + + trailerIframeDisplayed = true; +} + +function toggleFavorite(movie) { + let favorites = JSON.parse(localStorage.getItem('favorites')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || {}; + + if (favorites.includes(movie.id)) { + favorites = favorites.filter(favId => favId !== movie.id); + movie.genres.forEach(genre => { + favoriteGenres[genre.name] = favoriteGenres[genre.name] ? favoriteGenres[genre.name] - 1 : 0; + }); + } else { + favorites.push(movie.id); + movie.genres.forEach(genre => { + favoriteGenres[genre.name] = favoriteGenres[genre.name] ? favoriteGenres[genre.name] + 1 : 1; + }); + } + + localStorage.setItem('favorites', JSON.stringify(favorites)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + + updateFavoriteButton(movie.id); +} + +function updateFavoriteButton(movieId) { + const favorites = JSON.parse(localStorage.getItem('favorites')) || []; + const favoriteButton = document.getElementById('favorite-btn'); + + if (favorites.includes(movieId)) { + favoriteButton.classList.add('favorited'); + favoriteButton.style.backgroundColor = 'grey'; + favoriteButton.title = 'Remove from favorites'; + } else { + favoriteButton.classList.remove('favorited'); + favoriteButton.style.background = 'transparent'; + favoriteButton.title = 'Add to favorites'; + } +} + +function getRtSlug(title) { + return title + .toLowerCase() + .replace(/:/g, '') + .replace(/part one/g, 'part_1') + .replace(/-/g, '') + .replace(/&/g, 'and') + .replace(/ /g, '_') + .replace(/[^\w-]/g, ''); +} + +function createMetacriticSlug(title) { + return title + .toLowerCase() + .replace(/part\sone/g, 'part-1') + .replace(/:|_|-|\s/g, '-') + .replace(/&/g, 'and') + .replace(/--+/g, '-') + .replace(/[^\w-]/g, ''); +} + +function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, rated) { + document.getElementById('movie-image').src = `https://image.tmdb.org/t/p/w1280${movie.poster_path}`; + document.getElementById('movie-title').textContent = movie.title; + + const movieRating = movie.vote_average.toFixed(1); + const imdbLink = `https://www.imdb.com/title/${movie.imdb_id}`; + + const rtLink = rtRating !== 'N/A' ? `https://www.rottentomatoes.com/m/${getRtSlug(movie.title)}` : '#'; + const metaCriticsLink = metascore !== 'N/A' ? `https://www.metacritic.com/movie/${createMetacriticSlug(movie.title)}` : '#'; + + const ratingDetails = getRatingDetails(rated); + const ratedElement = rated + ? `

Rated: ${ratingDetails.text}${ratingDetails.description}

` + : ''; + + document.getElementById('movie-rating').innerHTML = ` + IMDB Rating: ${imdbRating} + `; + document.getElementById('movie-rating').style.marginTop = '120px'; + document.title = movie.title + ' - Movie Details'; + + const movieImage = document.getElementById('movie-image'); + const movieDescription = document.getElementById('movie-description'); + + const metascoreElement = metascore ? `

Metascore: ${metascore}

` : ''; + const awardsElement = awards ? `

Awards: ${awards}

` : ''; + + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + } else { + movieImage.style.display = 'none'; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.movie-left').appendChild(noImageText); + } + + const fullLanguage = twoLetterLangCodes.find(lang => lang.code === movie.original_language).name; + const overview = movie.overview; + const genres = movie.genres.map(genre => genre.name).join(', '); + const releaseDate = movie.release_date; + + const budget = movie.budget === 0 ? 'Information Not Available' : `$${movie.budget.toLocaleString()}`; + const revenue = movie.revenue <= 1000 ? 'Information Not Available' : `$${movie.revenue.toLocaleString()}`; + const tagline = movie.tagline ? movie.tagline : 'No tagline found'; + const languages = movie.spoken_languages.map(lang => lang.name).join(', '); + + const countries = movie.production_countries.map(country => country.name).join(', '); + const originalLanguage = fullLanguage; + const popularityScore = movie.popularity.toFixed(0); + const status = movie.status; + + const voteCount = movie.vote_count.toLocaleString(); + let keywords = movie.keywords ? movie.keywords.keywords.map(kw => kw.name).join(', ') : 'None Available'; + const similarTitles = movie.similar ? movie.similar.results.map(m => m.title).join(', ') : 'None Available'; + const scaledRating = (movie.vote_average / 2).toFixed(1); + + if (keywords.length === 0) { + keywords = 'None Available'; + } + + const popularityThreshold = 80; + const isPopular = movie.popularity >= popularityThreshold; + const popularityText = isPopular ? `${popularityScore} (This movie is popular)` : `${popularityScore} (This movie is unpopular)`; + + const adultContentIndicator = movie.adult + ? `Adult Content` + : `General Audience`; + + const movieStatus = `

Status: ${movie.status}

`; + + const runtime = movie.runtime > 0 ? movie.runtime + ' minutes' : 'Runtime Info Not Available'; + + document.getElementById('movie-description').innerHTML += ` +

Description: ${overview}

+

Genres: ${genres}

+ ${ratedElement} + ${movieStatus} +

Release Date: ${releaseDate}

+

Runtime: ${runtime}

+

Budget: ${budget}

+

Revenue: ${revenue}

+

Languages: ${languages}

+

Countries of Production: ${countries}

+

Original Language: ${originalLanguage}

+

Popularity Score: ${popularityText}

+

Averaged User Ratings: ${scaledRating}/5.0 (based on ${ + movie.vote_count + } votes)

+ ${awardsElement} + ${metascoreElement} +

Rotten Tomatoes: ${rtRating}

+

Tagline: ${tagline}

+ `; + + if (movie.credits && movie.credits.crew) { + const director = movie.credits.crew.find(member => member.job === 'Director'); + if (director) { + const directorAge = director.birthday ? calculateAge(director.birthday) : 'N/A'; + const directorElement = document.createElement('p'); + directorElement.innerHTML = `Director: ${director.name}`; + directorElement.querySelector('.director-link').addEventListener('click', e => { + e.preventDefault(); + localStorage.setItem('selectedDirectorId', director.id); + document.title = `${director.name} - Director's Details`; + window.location.href = 'director-details.html'; + updateUniqueDirectorsViewed(director.id); + updateDirectorVisitCount(director.id, director.name); + }); + document.getElementById('movie-description').appendChild(directorElement); + } + } + + const castHeading = document.createElement('p'); + castHeading.innerHTML = 'Cast: '; + document.getElementById('movie-description').appendChild(castHeading); + + if (movie.credits && movie.credits.cast.length > 0) { + const topTenCast = movie.credits.cast.slice(0, 10); + topTenCast.forEach((actor, index) => { + const actorLink = document.createElement('span'); + actorLink.textContent = actor.name; + actorLink.classList.add('actor-link'); + actorLink.addEventListener('click', () => { + localStorage.setItem('selectedActorId', actor.id); + window.location.href = 'actor-details.html'; + updateUniqueActorsViewed(actor.id); + updateActorVisitCount(actor.id, actor.name); + }); + + castHeading.appendChild(actorLink); + + if (index < topTenCast.length - 1) { + castHeading.appendChild(document.createTextNode(', ')); + } + }); + } else { + castHeading.appendChild(document.createTextNode('None available.')); + } + + const productionCompanies = movie.production_companies; + const productionCompaniesElement = document.createElement('p'); + productionCompaniesElement.innerHTML = 'Production Companies: '; + + if (productionCompanies.length === 0) { + productionCompaniesElement.innerHTML += 'None available.'; + } + productionCompanies.forEach((company, index) => { + const companyLink = document.createElement('a'); + companyLink.textContent = company.name; + companyLink.style.cursor = 'pointer'; + companyLink.style.textDecoration = 'underline'; + companyLink.href = '#'; + companyLink.classList.add('company-link'); + companyLink.addEventListener('click', e => { + e.preventDefault(); + localStorage.setItem('selectedCompanyId', company.id); + window.location.href = 'company-details.html'; + updateUniqueCompaniesViewed(company.id); + }); + + productionCompaniesElement.appendChild(companyLink); + + if (index < productionCompanies.length - 1) { + productionCompaniesElement.appendChild(document.createTextNode(', ')); + } + }); + + document.getElementById('movie-description').appendChild(productionCompaniesElement); + const similarMoviesHeading = document.createElement('p'); + + similarMoviesHeading.innerHTML = 'Similar Movies: '; + document.getElementById('movie-description').appendChild(similarMoviesHeading); + + if (movie.similar && movie.similar.results.length > 0) { + movie.similar.results.forEach((similarMovie, index) => { + const movieLink = document.createElement('span'); + movieLink.textContent = similarMovie.title; + movieLink.style.cursor = 'pointer'; + movieLink.style.textDecoration = 'underline'; + movieLink.addEventListener('mouseenter', () => { + movieLink.style.color = '#f509d9'; + }); + + movieLink.addEventListener('mouseleave', () => { + movieLink.style.color = getSavedTextColor(); + }); + + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', similarMovie.id); + window.location.href = 'movie-details.html'; + }); + + similarMoviesHeading.appendChild(movieLink); + + if (index < movie.similar.results.length - 1) { + similarMoviesHeading.appendChild(document.createTextNode(', ')); + } + }); + } else { + similarMoviesHeading.appendChild(document.createTextNode('None available.')); + } + + const keywordsElement = document.createElement('p'); + keywordsElement.innerHTML = `Keywords: ${keywords}`; + + movieDescription.appendChild(keywordsElement); + updateFavoriteButton(movie.id); + + favoriteButton.addEventListener('click', () => { + toggleFavorite(movie); + updateMoviesFavorited(movie.id); + window.location.reload(); + }); + + updateMoviesFavorited(movie.id); + applySettings(); +} + +function getSavedTextColor() { + return localStorage.getItem('textColor') || 'white'; +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} + +function updateAverageMovieRating(movieId, newRating) { + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + + let totalRating = 0; + let totalMoviesRated = 0; + + for (let id in savedRatings) { + totalRating += parseFloat(savedRatings[id]); + totalMoviesRated++; + } + let averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1).toString()); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function updateUniqueActorsViewed(actorId) { + let viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + if (!viewedActors.includes(actorId)) { + viewedActors.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(viewedActors)); + } +} + +function updateUniqueCompaniesViewed(companyId) { + let viewedCompanies = JSON.parse(localStorage.getItem('uniqueCompaniesViewed')) || []; + if (!viewedCompanies.includes(companyId)) { + viewedCompanies.push(companyId); + localStorage.setItem('uniqueCompaniesViewed', JSON.stringify(viewedCompanies)); + } +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js new file mode 100644 index 00000000..0628d210 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/leonardo-dicarprio.js @@ -0,0 +1,486 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const searchTitle = document.getElementById('search-title'); + +function updateBrowserURL(name) { + const nameSlug = createNameSlug(name); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(name) { + return name + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +let initialMainContent = ''; + +document.addEventListener('DOMContentLoaded', () => { + initialMainContent = document.getElementById('main').innerHTML; + + const actorId = 6193; + if (actorId) { + fetchActorDetails(actorId); + } else { + document.getElementById('actor-details-container').innerHTML = ` +
+

Actor details not found.

+
`; + } + + document.getElementById('clear-search-btn').style.display = 'none'; +}); + +async function fetchActorDetails(actorId) { + const actorUrl = `https://${getMovieVerseData()}/3/person/6193?${generateMovieNames()}${getMovieCode()}`; + const creditsUrl = `https://${getMovieVerseData()}/3/person/6193/movie_credits?${generateMovieNames()}${getMovieCode()}`; + try { + const [actorResponse, creditsResponse] = await Promise.all([fetch(actorUrl), fetch(creditsUrl)]); + + const actor = await actorResponse.json(); + const credits = await creditsResponse.json(); + if (actor.success === false) { + document.getElementById('actor-details-container').innerHTML = '

No Information is Available for this Actor

'; + } else { + updateBrowserURL(actor.name); + populateActorDetails(actor, credits); + } + } catch (error) { + console.log('Error fetching actor details:', error); + document.getElementById('actor-details-container').innerHTML = '

Error fetching actor details

'; + } +} + +function populateActorDetails(actor, credits) { + const actorImage = document.getElementById('actor-image'); + const actorName = document.getElementById('actor-name'); + const actorDescription = document.getElementById('actor-description'); + + if (actor.profile_path) { + actorImage.src = `https://image.tmdb.org/t/p/w1280${actor.profile_path}`; + actorName.textContent = actor.name; + document.title = `${actor.name} - Actor's Details`; + } else { + actorImage.style.display = 'none'; + actorName.textContent = actor.name; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Image Not Available'; + noImageText.style.textAlign = 'center'; + document.querySelector('.actor-left').appendChild(noImageText); + } + + let ageOrStatus; + if (actor.birthday) { + if (actor.deathday) { + ageOrStatus = calculateAge(actor.birthday, actor.deathday) + ' (Deceased)'; + } else { + ageOrStatus = calculateAge(actor.birthday) + ' (Alive)'; + } + } else { + ageOrStatus = 'Unknown'; + } + + actorDescription.innerHTML = ` +

Biography: ${actor.biography || 'N/A'}

+

Date of Birth: ${actor.birthday || 'N/A'}

+

Date of Death: ${actor.deathday || 'N/A'}

+

Age: ${ageOrStatus}

+

Place of Birth: ${actor.place_of_birth || 'N/A'}

+

Known For: ${actor.known_for_department || 'N/A'}

+

Height: ${actor.height || 'N/A'}

+ `; + + const gender = document.createElement('div'); + gender.innerHTML = `

Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'N/A'}

`; + actorDescription.appendChild(gender); + + const popularity = document.createElement('div'); + popularity.innerHTML = `

Popularity Score: ${actor.popularity.toFixed(2)}

`; + actorDescription.appendChild(popularity); + + const filmographyHeading = document.createElement('p'); + filmographyHeading.innerHTML = 'Filmography: '; + actorDescription.appendChild(filmographyHeading); + + const movieList = document.createElement('div'); + movieList.classList.add('movie-list'); + credits.cast.forEach(movie => { + const movieLink = document.createElement('span'); + movieLink.textContent = movie.title; + movieLink.classList.add('movie-link'); + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + window.location.href = 'movie-details.html'; + }); + movieList.appendChild(movieLink); + movieList.appendChild(document.createTextNode(', ')); + }); + + filmographyHeading.appendChild(movieList); + applySettings(); +} + +function calculateAge(birthday, deathday = null) { + const birthDate = new Date(birthday); + const referenceDate = deathday ? new Date(deathday) : new Date(); + const diff = referenceDate - birthDate.getTime(); + const ageDate = new Date(diff); + return Math.abs(ageDate.getUTCFullYear() - 1970); +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + applySettings(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-details.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-details.js new file mode 100644 index 00000000..dcaa4028 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-details.js @@ -0,0 +1,1902 @@ +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w780'; +const IMGPATH2 = 'https://image.tmdb.org/t/p/w185'; +const favoriteButton = document.getElementById('favorite-btn'); +const searchTitle = document.getElementById('search-title'); + +let trailerUrlGlobal; +let initialMainContent; +let trailerButton; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + console.log(genreMap); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let uniqueMoviesViewed = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + + if (!uniqueMoviesViewed.includes(movieId)) { + uniqueMoviesViewed.push(movieId); + } + + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(uniqueMoviesViewed)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +document.addEventListener('DOMContentLoaded', () => { + showSpinner(); + initialMainContent = document.getElementById('main').innerHTML; + currentIndex = 0; + + const movieId = localStorage.getItem('selectedMovieId'); + if (movieId) { + fetchMovieDetails(movieId); + } else { + fetchMovieDetails(1011985); + } + + hideSpinner(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + showSpinner(); + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + hideSpinner(); +}); + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +document.addEventListener('DOMContentLoaded', function () { + applySettings(); +}); + +async function fetchMovieDetails(movieId) { + showSpinner(); + const code = `${getMovieCode()}`; + const url = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=credits,keywords,similar`; + const url2 = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=videos`; + + try { + showSpinner(); + const response = await fetch(url); + const movie = await response.json(); + const imdbId = movie.imdb_id; + + fetchMovieRatings(imdbId, movie); + updateBrowserURL(movie.title); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details currently unavailable - please try again

+
`; + console.log('Error fetching movie details:', error); + } finally { + hideSpinner(); + } +} + +function getRatingDetails(rating) { + let details = { color: 'black', text: rating, description: '' }; + + switch (rating) { + case 'R': + details = { + color: 'red', + text: 'R (Restricted)', + description: ' - No one 17 and under admitted', + }; + break; + case 'PG-13': + details = { + color: 'yellow', + text: 'PG-13 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 13', + }; + break; + case 'PG': + details = { + color: 'orange', + text: 'PG (Parental Guidance Suggested)', + description: ' - May not be suitable for children', + }; + break; + case 'G': + details = { + color: 'green', + text: 'G (General Audiences)', + description: ' - All ages admitted', + }; + break; + case 'NC-17': + details = { + color: 'darkred', + text: 'NC-17 (Adults Only)', + description: ' - No one 17 and under admitted', + }; + break; + case 'TV-Y': + details = { + color: 'lightgreen', + text: 'TV-Y (All Children)', + description: ' - Appropriate for all children', + }; + break; + case 'TV-Y7': + details = { + color: 'lightblue', + text: 'TV-Y7 (Directed to Older Children)', + description: ' - Suitable for children ages 7 and up', + }; + break; + case 'TV-G': + details = { + color: 'green', + text: 'TV-G (General Audience)', + description: ' - Suitable for all ages', + }; + break; + case 'TV-PG': + details = { + color: 'orange', + text: 'TV-PG (Parental Guidance Suggested)', + description: ' - May not be suitable for younger children', + }; + break; + case 'TV-14': + details = { + color: 'yellow', + text: 'TV-14 (Parents Strongly Cautioned)', + description: ' - May be inappropriate for children under 14', + }; + break; + case 'TV-MA': + details = { + color: 'red', + text: 'TV-MA (Mature Audience Only)', + description: ' - Specifically designed to be viewed by adults', + }; + break; + case 'NR': + details = { + color: 'white', + text: 'NR (Not Rated)', + description: ' - Movie has not been officially rated', + }; + break; + case 'UR': + case 'Unrated': + details = { + color: 'white', + text: 'UR (Unrated)', + description: ' - Contains content not used in the rated version', + }; + break; + default: + details = { + color: 'white', + text: rating, + description: ' - Rating information not available', + }; + break; + } + + return details; +} + +async function fetchMovieRatings(imdbId, tmdbMovieData) { + showSpinner(); + document.body.offsetHeight; + + const req = [await getMovieCode2(), '58efe859', '60a09d79', '956e468a', 'bd55ada4', 'cbfc076', 'dc091ff2', '6e367eef', '2a2a3080', 'd20a931f']; + const baseURL = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}`; + + async function tryFetch(apiKey) { + const url = `${baseURL}${apiKey}`; + + try { + const response = await fetch(url); + if (!response.ok) throw new Error('API limit reached or other error'); + return await response.json(); + } catch (error) { + return null; + } + } + + async function fetchWithTimeout(apiKey, timeout = 5000) { + return new Promise(resolve => { + const timer = setTimeout(() => resolve(null), timeout); + tryFetch(apiKey) + .then(data => { + clearTimeout(timer); + resolve(data); + }) + .catch(() => { + clearTimeout(timer); + resolve(null); + }); + }); + } + + const requests = req.map(key => fetchWithTimeout(key)); + const responses = await Promise.all(requests); + const data = responses.find(response => response !== null); + + if (!data) { + populateMovieDetails(tmdbMovieData, tmdbMovieData.vote_average, 'N/A', 'View on Metacritics', 'Awards information unavailable'); + return; + } + + let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + if (imdbRating === 'N/A' || imdbRating === '0.0' || imdbRating === null) { + imdbRating = 'N/A'; + } + + let rtRating = 'N/A'; + let metascore = data.Metascore ? `${data.Metascore}/100` : 'N/A'; + let awards = data.Awards; + let rated = data.Rated ? data.Rated : 'Rating information unavailable'; + + if (awards === 'N/A') { + awards = 'Awards information unavailable'; + } + if (metascore === 'N/A/100') { + const metacriticsRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + metascore = calculateFallbackMetacriticsRating(metacriticsRatingValue, tmdbMovieData.vote_average) + '/100'; + } + if (rtRating === 'N/A') { + const imdbRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : tmdbMovieData.vote_average / 2; + rtRating = calculateFallbackRTRating(imdbRatingValue, tmdbMovieData.vote_average); + } + + populateMovieDetails(tmdbMovieData, imdbRating, rtRating, metascore, awards, rated); + hideSpinner(); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} + +function calculateFallbackRTRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0) + '%'; +} + +function calculateFallbackMetacriticsRating(imdbRating, tmdbRating) { + const normalizedImdbRating = imdbRating * 10; + const normalizedTmdbRating = tmdbRating * 10; + + const weightImdb = 0.8; + const weightTmdb = 0.1; + + return (normalizedImdbRating * weightImdb + normalizedTmdbRating * weightTmdb).toFixed(0); +} + +let trailerIframeDisplayed = false; + +function createTrailerButton(trailerUrl) { + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + trailerButton.id = 'trailerButton'; + + trailerButton.addEventListener('click', function () { + if (!trailerIframeDisplayed) { + showTrailerIframe(trailerUrl); + trailerButton.textContent = 'Close Trailer'; + trailerButton.title = 'Click to close the trailer'; + } else { + closeTrailerIframe(); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.title = 'Click to watch the trailer of this movie'; + } + }); + + trailerButton.classList.add('trailer-button'); + trailerButton.style.font = 'inherit'; + + return trailerButton; +} + +function closeTrailerIframe() { + const iframeContainer = document.querySelector('.trailer-button + div'); + + if (iframeContainer) { + iframeContainer.style.height = '0'; + setTimeout(() => iframeContainer.remove(), 500); + } + trailerIframeDisplayed = false; +} + +function getYouTubeVideoId(url) { + const urlObj = new URL(url); + return urlObj.searchParams.get('v'); +} + +function showTrailerIframe(trailerUrl) { + trailerUrlGlobal = trailerUrl; + + const iframeContainer = document.createElement('div'); + iframeContainer.style.position = 'relative'; + iframeContainer.style.width = '400px'; + iframeContainer.style.margin = '0 auto'; + iframeContainer.style.overflow = 'hidden'; + iframeContainer.style.height = '0'; + iframeContainer.style.transition = 'height 0.5s ease-in-out'; + iframeContainer.style.borderRadius = '8px'; + + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', `https://www.youtube.com/embed/${getYouTubeVideoId(trailerUrl)}?autoplay=1`); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('height', '315'); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'); + iframe.setAttribute('allowfullscreen', true); + + iframeContainer.appendChild(iframe); + + const trailerButton = document.querySelector('.trailer-button'); + trailerButton.parentNode.insertBefore(iframeContainer, trailerButton.nextSibling); + trailerButton.id = 'trailerButton'; + + setTimeout(() => (iframeContainer.style.height = '315px'), 50); + + trailerIframeDisplayed = true; +} + +function getRtSlug(title) { + return title + .toLowerCase() + .replace(/:/g, '') + .replace(/part one/g, 'part_1') + .replace(/-/g, '') + .replace(/&/g, 'and') + .replace(/ /g, '_') + .replace(/[^\w-]/g, ''); +} + +function createMetacriticSlug(title) { + return title + .toLowerCase() + .replace(/part\sone/g, 'part-1') + .replace(/:|_|-|\s/g, '-') + .replace(/&/g, 'and') + .replace(/--+/g, '-') + .replace(/[^\w-]/g, ''); +} + +async function fetchStreamingLinks(movieId) { + const url = `https://${getMovieVerseData()}/3/movie/${movieId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const results = data.results || {}; + let providersMap = {}; + + Object.values(results).forEach(region => { + if (region.flatrate) { + region.flatrate.forEach(provider => { + providersMap[provider.provider_id] = provider; + }); + } + }); + + return Object.values(providersMap).slice(0, 7); + } catch (error) { + console.error('Error fetching streaming links:', error); + } +} + +async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, rated) { + showSpinner(); + document.getElementById('movie-title').textContent = movie.title; + + const imdbLink = `https://www.imdb.com/title/${movie.imdb_id}`; + const streamingProviders = await fetchStreamingLinks(movie.id); + const movieTitleEncoded = encodeURIComponent(movie.title); + + const streamingHTML = + streamingProviders.length > 0 + ? streamingProviders + .map(provider => { + let providerLink; + switch (provider.provider_name.toLowerCase()) { + case 'netflix': + providerLink = `https://www.netflix.com/search?q=${movieTitleEncoded}`; + break; + case 'disney plus': + providerLink = `https://www.disneyplus.com/search?q=${movieTitleEncoded}`; + break; + case 'hbo max': + providerLink = `https://www.hbomax.com/search?q=${movieTitleEncoded}`; + break; + case 'hulu': + providerLink = `https://www.hulu.com/search?q=${movieTitleEncoded}`; + break; + case 'amazon prime video': + providerLink = `https://www.amazon.com/s?k=${movieTitleEncoded}`; + break; + case 'apple tv plus': + providerLink = `https://tv.apple.com/search?term=${movieTitleEncoded}`; + break; + case 'stan': + providerLink = `https://www.stan.com.au/search?q=${movieTitleEncoded}`; + break; + case 'player': + providerLink = `https://player.pl/szukaj?search=${movieTitleEncoded}`; + break; + default: + providerLink = `https://www.google.com/search?q=watch+${movieTitleEncoded}+on+${encodeURIComponent(provider.provider_name)}`; + break; + } + + return ``; + }) + .join('') + + `` + : 'No streaming options available.'; + + const metaCriticsLink = metascore !== 'N/A' ? `https://www.metacritic.com/search/${createMetacriticSlug(movie.title)}` : '#'; + const ratingDetails = getRatingDetails(rated); + const ratedElement = rated + ? `

Rated: ${ratingDetails.text}${ratingDetails.description}

` + : ''; + + document.getElementById('movie-rating').innerHTML = ``; + document.title = movie.title + ' - Movie Details'; + + const movieDescription = document.getElementById('movie-description'); + const metascoreElement = metascore + ? `

Metascore: ${metascore}

` + : ''; + const awardsElement = awards ? `

Awards: ${awards}

` : ''; + + const overview = movie.overview ? movie.overview : 'No overview available'; + const genres = movie.genres.map(genre => genre.name).join(', '); + + const releaseDate = movie.release_date || 'Release date not available'; + const releaseDateObj = new Date(releaseDate); + const currentDate = new Date(); + + let timeAgoString = ''; + if (releaseDateObj > currentDate) { + timeAgoString = '0 months'; + } else { + const timeDiff = currentDate - releaseDateObj; + let years = Math.floor(timeDiff / (1000 * 60 * 60 * 24 * 365.25)); + let remainingMonths = Math.round((timeDiff % (1000 * 60 * 60 * 24 * 365.25)) / (1000 * 60 * 60 * 24 * 30.44)); + + if (remainingMonths >= 12) { + years += 1; + remainingMonths -= 12; + } + if (years > 0) { + timeAgoString += `${years} year${years > 1 ? 's' : ''}`; + if (remainingMonths > 0) { + timeAgoString += ` and `; + } + } + if (remainingMonths > 0 || years === 0) { + timeAgoString += `${remainingMonths} month${remainingMonths > 1 ? 's' : ''}`; + } + } + + const releaseDateWithTimeAgo = `${releaseDate} (${timeAgoString} ago)`; + const budget = movie.budget === 0 ? 'Information Not Available' : `$${movie.budget.toLocaleString()}`; + const revenue = movie.revenue <= 1000 ? 'Information Not Available' : `$${movie.revenue.toLocaleString()}`; + const tagline = movie.tagline ? movie.tagline : 'No tagline found'; + const languages = movie.spoken_languages.map(lang => lang.name).join(', '); + + const countries = movie.production_countries.map(country => country.name).join(', '); + const popularityScore = movie.popularity.toFixed(0); + + let keywords = movie.keywords + ? movie.keywords.keywords + .map( + kw => `${kw.name}` + ) + .join(', ') + : 'None Available'; + + if (keywords.length === 0) { + keywords = 'No keywords have been added'; + } + + const scaledRating = (movie.vote_average / 2).toFixed(1); + const popularityThreshold = 80; + const isPopular = movie.popularity >= popularityThreshold; + const popularityText = isPopular + ? `${popularityScore} (This movie is popular)` + : `${popularityScore} (This movie is unpopular)`; + + const movieStatus = `

Status: ${movie.status}

`; + const runtime = movie.runtime > 0 ? movie.runtime + ' minutes' : 'Runtime Info Not Available'; + + const originalTitle = + movie.original_title !== movie.title + ? `

Original Title: ${movie.original_title}

` + : `

Original Title: ${movie.title}

`; + const tmdbRating = movie.vote_average.toFixed(1); + + document.getElementById('movie-description').innerHTML += ` +

Description: ${overview}

+ ${originalTitle} +

Tagline: ${tagline}

+

Genres: ${genres}

+ ${ratedElement} + ${movieStatus} +

Release Date: ${releaseDateWithTimeAgo}

+

Runtime: ${runtime}

+

Budget: ${budget}

+

Revenue: ${revenue}

+

Languages: ${languages}

+

Countries of Production: ${countries}

+

Popularity Score: ${popularityText}

+

MovieVerse User Rating: ${scaledRating}/5.0 (based on ${ + movie.vote_count + } votes)

+ ${awardsElement} +

TMDb Rating: ${tmdbRating}/10.0

+ ${metascoreElement} + `; + + if (movie.credits && movie.credits.crew) { + const directors = movie.credits.crew.filter(member => member.job === 'Director'); + + if (directors.length > 0) { + const directorSection = document.createElement('div'); + directorSection.classList.add('director-section'); + directorSection.style.textAlign = 'center'; + + const directorTitle = document.createElement('p'); + directorTitle.innerHTML = 'Director:'; + directorTitle.style.padding = '0'; + directorSection.appendChild(directorTitle); + + const directorList = document.createElement('div'); + directorList.classList.add('director-list'); + + directors.forEach(director => { + const directorLink = document.createElement('a'); + directorLink.classList.add('director-link'); + directorLink.href = 'javascript:void(0);'; + directorLink.style.textDecoration = 'none'; + directorLink.setAttribute('onclick', `handleDirectorClick(${director.id}, '${director.name.replace(/'/g, "\\'")}');`); + + const directorItem = document.createElement('div'); + directorItem.classList.add('cast-item'); + + const directorImage = document.createElement('img'); + directorImage.classList.add('cast-image'); + + if (director.profile_path) { + directorImage.src = IMGPATH2 + director.profile_path; + directorImage.alt = `${director.name} Profile Picture`; + } else { + directorImage.alt = 'Image Not Available'; + directorImage.src = 'https://movie-verse.com/images/user-default.png'; + directorImage.style.filter = 'grayscale(100%)'; + directorImage.style.objectFit = 'cover'; + } + + directorItem.appendChild(directorImage); + + const directorDetails = document.createElement('div'); + directorDetails.classList.add('cast-details'); + + const directorName = document.createElement('p'); + directorName.classList.add('actor-name'); + directorName.textContent = director.name; + directorDetails.appendChild(directorName); + + directorItem.appendChild(directorDetails); + directorLink.appendChild(directorItem); + directorList.appendChild(directorLink); + }); + + directorSection.appendChild(directorList); + document.getElementById('movie-description').appendChild(directorSection); + } else { + const noDirectorsElement = document.createElement('p'); + noDirectorsElement.innerHTML = `Director: Information not available`; + document.getElementById('movie-description').appendChild(noDirectorsElement); + } + } + + const castSection = document.createElement('div'); + castSection.classList.add('cast-section'); + + const castTitle = document.createElement('p'); + castTitle.innerHTML = 'Notable Cast:'; + castSection.appendChild(castTitle); + + if (movie.credits && movie.credits.cast.length > 0) { + const castList = document.createElement('div'); + castList.classList.add('cast-list'); + castList.style.display = 'flex'; + castList.style.flexWrap = 'wrap'; + castList.style.justifyContent = 'center'; + castList.style.gap = '3px'; + const topTwelveCast = movie.credits.cast.slice(0, 12); + + topTwelveCast.forEach(actor => { + const castItemLink = document.createElement('a'); + castItemLink.classList.add('actor-link'); + castItemLink.href = 'javascript:void(0);'; + castItemLink.setAttribute('onclick', `selectActorId(${actor.id}, '${actor.name.replace(/'/g, "\\'")}');`); + + const castItem = document.createElement('div'); + castItem.classList.add('cast-item'); + + const actorImage = document.createElement('img'); + actorImage.classList.add('cast-image'); + + if (actor.profile_path) { + actorImage.src = IMGPATH2 + actor.profile_path; + actorImage.alt = `${actor.name} Profile Picture`; + } else { + actorImage.alt = 'Image Not Available'; + actorImage.src = 'https://movie-verse.com/images/user-default.png'; + actorImage.style.filter = 'grayscale(100%)'; + actorImage.style.objectFit = 'cover'; + } + + castItem.appendChild(actorImage); + + const actorDetails = document.createElement('div'); + actorDetails.classList.add('cast-details'); + + const actorName = document.createElement('p'); + actorName.classList.add('actor-name'); + actorName.textContent = actor.name; + actorDetails.appendChild(actorName); + + const character = actor.character ? ` (as ${actor.character})` : ''; + const actorRole = document.createElement('p'); + actorRole.classList.add('actor-role'); + actorRole.textContent = character; + actorDetails.appendChild(actorRole); + + castItem.appendChild(actorDetails); + castItemLink.appendChild(castItem); + castList.appendChild(castItemLink); + }); + + castSection.appendChild(castList); + } else { + castSection.appendChild(document.createTextNode('None available.')); + } + + document.getElementById('movie-description').appendChild(castSection); + + if (movie.similar && movie.similar.results && movie.similar.results.length > 0) { + const similarMoviesSection = document.createElement('div'); + similarMoviesSection.classList.add('similar-movies-section'); + + const similarMoviesTitle = document.createElement('p'); + similarMoviesTitle.innerHTML = 'Similar Movies:'; + similarMoviesSection.appendChild(similarMoviesTitle); + + const similarMoviesList = document.createElement('div'); + similarMoviesList.classList.add('similar-movies-list'); + similarMoviesList.style.display = 'flex'; + similarMoviesList.style.flexWrap = 'wrap'; + similarMoviesList.style.justifyContent = 'center'; + similarMoviesList.style.gap = '3px'; + + let topTenSimilarMovies = movie.similar.results; + topTenSimilarMovies = topTenSimilarMovies.sort((a, b) => b.popularity - a.popularity); + topTenSimilarMovies = topTenSimilarMovies.slice(0, 18); + topTenSimilarMovies.forEach(similarMovie => { + const similarMovieLink = document.createElement('a'); + similarMovieLink.classList.add('similar-movie-link'); + similarMovieLink.href = 'javascript:void(0);'; + similarMovieLink.setAttribute('onclick', `handleSimilarMovieClick(${similarMovie.id}, '${similarMovie.title.replace(/'/g, "\\'")}');`); + + const similarMovieItem = document.createElement('div'); + similarMovieItem.classList.add('cast-item'); + + const similarMovieImage = document.createElement('img'); + similarMovieImage.classList.add('cast-image'); + + if (similarMovie.poster_path) { + similarMovieImage.src = IMGPATH2 + similarMovie.poster_path; + similarMovieImage.alt = `${similarMovie.title} Poster`; + similarMovieImage.style.objectFit = 'fill'; + } else { + similarMovieImage.alt = 'Image Not Available'; + similarMovieImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + similarMovieImage.style.filter = 'grayscale(100%)'; + similarMovieImage.style.objectFit = 'cover'; + } + + similarMovieItem.appendChild(similarMovieImage); + + const similarMovieDetails = document.createElement('div'); + similarMovieDetails.classList.add('cast-details'); + + const similarMovieTitle = document.createElement('p'); + similarMovieTitle.classList.add('actor-name'); + similarMovieTitle.textContent = similarMovie.title; + similarMovieDetails.appendChild(similarMovieTitle); + + similarMovieItem.appendChild(similarMovieDetails); + similarMovieLink.appendChild(similarMovieItem); + similarMoviesList.appendChild(similarMovieLink); + }); + + similarMoviesSection.appendChild(similarMoviesList); + document.getElementById('movie-description').appendChild(similarMoviesSection); + } else { + const noSimilarMoviesElement = document.createElement('p'); + noSimilarMoviesElement.innerHTML = `Similar Movies: None available`; + document.getElementById('movie-description').appendChild(noSimilarMoviesElement); + } + + if (movie.production_companies && movie.production_companies.length > 0) { + const companiesSection = document.createElement('div'); + companiesSection.classList.add('companies-section'); + + const companiesTitle = document.createElement('p'); + companiesTitle.innerHTML = 'Production Companies:'; + companiesSection.appendChild(companiesTitle); + + const companiesList = document.createElement('div'); + companiesList.classList.add('companies-list'); + companiesList.style.display = 'flex'; + companiesList.style.flexWrap = 'wrap'; + companiesList.style.justifyContent = 'center'; + companiesList.style.gap = '5px'; + + let productionCompanies = movie.production_companies.slice(0, 6); + + productionCompanies.forEach(company => { + const companyLink = document.createElement('a'); + companyLink.classList.add('company-link'); + companyLink.href = 'javascript:void(0);'; + companyLink.setAttribute('onclick', `handleCompanyClick(${company.id}, '${company.name.replace(/'/g, "\\'")}');`); + + const companyItem = document.createElement('div'); + companyItem.classList.add('company-item'); + + const companyLogo = document.createElement('img'); + companyLogo.classList.add('company-logo'); + + const IMGPATH3 = 'https://image.tmdb.org/t/p/w300'; + + if (company.logo_path) { + companyLogo.src = IMGPATH3 + company.logo_path; + companyLogo.alt = `${company.name} Logo`; + companyLogo.style.backgroundColor = 'white'; + } else { + companyLogo.alt = 'Logo Not Available'; + companyLogo.src = 'https://movie-verse.com/images/company-default.png'; + companyLogo.style.filter = 'grayscale(100%)'; + companyLogo.style.objectFit = 'cover'; + } + + companyItem.appendChild(companyLogo); + + const companyDetails = document.createElement('div'); + companyDetails.classList.add('company-details'); + + const companyName = document.createElement('p'); + companyName.classList.add('company-name'); + companyName.textContent = company.name; + companyDetails.appendChild(companyName); + + companyItem.appendChild(companyDetails); + companyLink.appendChild(companyItem); + companiesList.appendChild(companyLink); + }); + + companiesSection.appendChild(companiesList); + document.getElementById('movie-description').appendChild(companiesSection); + } else { + const noCompaniesElement = document.createElement('p'); + noCompaniesElement.innerHTML = `Production Companies: Information not available`; + document.getElementById('movie-description').appendChild(noCompaniesElement); + } + + document.getElementById('movie-description').innerHTML += ` +

Streaming Options: ${streamingHTML}

`; + + const homepage = document.createElement('p'); + homepage.innerHTML = movie.homepage + ? `Homepage: Visit homepage` + : `Homepage: Information unavailable`; + movieDescription.appendChild(homepage); + + const keywordsElement = document.createElement('p'); + keywordsElement.innerHTML = `Keywords: ${keywords}`; + movieDescription.appendChild(keywordsElement); + + createImdbRatingCircle(imdbRating, imdbLink); + + const mediaUrl = `https://${getMovieVerseData()}/3/movie/${movie.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + const mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 90vw; + max-width: 450px; + margin: 20px auto; + overflow: hidden; + box-sizing: border-box; + border-radius: 16px; + `; + + const mediaTitle = document.createElement('p'); + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + const imageWrapper = document.createElement('div'); + imageWrapper.style = ` + width: 100%; + max-height: 210px; + border-radius: 16px; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + position: relative; + `; + + const imageElement = document.createElement('img'); + imageElement.style = ` + width: 100%; + height: auto; + transition: opacity 0.5s ease-in-out; + opacity: 1; + cursor: pointer; + object-fit: contain; + border-radius: 16px; + `; + + imageWrapper.appendChild(imageElement); + mediaContainer.appendChild(imageWrapper); + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Movie Image + + × +
+ `; + + document.body.insertAdjacentHTML('beforeend', modalHtml); + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const prevButton = document.createElement('button'); + prevButton.innerHTML = ''; + prevButton.style = ` + position: absolute; + left: 5px; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + z-index: 10; + `; + prevButton.onmouseover = () => (prevButton.style.backgroundColor = '#ff8623'); + prevButton.onmouseout = () => (prevButton.style.backgroundColor = '#7378c5'); + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + imageWrapper.appendChild(prevButton); + + const nextButton = document.createElement('button'); + nextButton.innerHTML = ''; + nextButton.style = ` + position: absolute; + right: 5px; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + z-index: 10; + `; + nextButton.onmouseover = () => (nextButton.style.backgroundColor = '#ff8623'); + nextButton.onmouseout = () => (nextButton.style.backgroundColor = '#7378c5'); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + imageWrapper.appendChild(nextButton); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + dot.addEventListener('mouseover', () => (dot.style.backgroundColor = '#6a6a6a')); + dot.addEventListener('mouseout', () => (dot.style.backgroundColor = index === currentIndex ? '#ff8623' : '#bbb')); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + const movieImage = document.getElementById('movie-image'); + + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + movieImage.loading = 'lazy'; + } else { + const noImageContainer = document.createElement('div'); + noImageContainer.id = 'no-image-container'; + noImageContainer.style.textAlign = 'center'; + + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageContainer.appendChild(noImageText); + + if (movieImage.parentNode) { + movieImage.parentNode.replaceChild(noImageContainer, movieImage); + } else { + document.body.appendChild(noImageContainer); + } + } + + const movieId = movie.id; + const code = `${getMovieCode()}`; + const url2 = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=videos`; + + try { + const response2 = await fetch(url2); + const movie2 = await response2.json(); + const trailers = movie2.videos.results.filter(video => video.type === 'Trailer'); + + if (trailers.length > 0) { + const trailerUrl = `https://www.youtube.com/watch?v=${trailers[0].key}`; + trailerButton = createTrailerButton(trailerUrl); + detailsContainer.appendChild(trailerButton); + } + + updateBrowserURL(movie.title); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

Movie details not found - Try again with a different movie

+
`; + console.log('Error fetching movie details:', error); + } + + hideSpinner(); +} + +function createImdbRatingCircle(imdbRating, imdbId) { + if (imdbRating === 'N/A' || imdbRating === null || imdbRating === undefined) { + imdbRating = 'N/A'; + } else { + imdbRating = parseFloat(imdbRating); + if (!isNaN(imdbRating)) { + imdbRating = imdbRating.toFixed(1); + } else { + imdbRating = 'N/A'; + } + } + + let circleContainer = document.getElementById('imdbRatingCircleContainer'); + if (!circleContainer) { + circleContainer = document.createElement('div'); + circleContainer.id = 'imdbRatingCircleContainer'; + circleContainer.className = 'progress-container'; + const imdbLink = `${imdbId}`; + circleContainer.innerHTML = ` + +
IMDb Rating
+
+ + + + ${imdbRating} + + `; + + if (imdbRating === 'N/A') { + circleContainer.innerHTML += `

Rating information currently unavailable

`; + } + + document.getElementById('movie-description').appendChild(circleContainer); + } else { + const text = document.getElementById('imdbRatingText'); + text.textContent = `${imdbRating}`; + } + + const circle = circleContainer.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); +} + +function setProgress(circle, text, rating) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (rating / 10) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', rating <= 5 ? '#FF0000' : rating >= 7.5 ? '#4CAF50' : '#2196F3'); + text.textContent = `${rating}`; + }, 10); +} + +function retriggerAnimation(imdbRating) { + const circle = document.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); +} + +function getSavedTextColor() { + return localStorage.getItem('textColor') || 'white'; +} + +function handleKeywordClick(keyword) { + localStorage.setItem('searchQuery', keyword); + window.location.href = 'search.html'; +} + +function handleActorClick(actorId, actorName) { + selectActorId(actorId, actorName); +} + +function handleDirectorClick(directorId, directorName) { + localStorage.setItem('selectedDirectorId', directorId); + document.title = `${directorName} - Director's Details`; + updateUniqueDirectorsViewed(directorId); + updateDirectorVisitCount(directorId, directorName); + window.location.href = 'director-details.html'; +} + +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + localStorage.setItem('selectedActorId', actorId); + window.location.href = 'actor-details.html'; +} + +function handleCompanyClick(companyId, companyName) { + localStorage.setItem('selectedCompanyId', companyId); + document.title = `${companyName} - Company Details`; + window.location.href = 'company-details.html'; + updateUniqueCompaniesViewed(companyId); +} + +function handleSimilarMovieClick(movieId, movieTitle) { + localStorage.setItem('selectedMovieId', movieId); + document.title = `${movieTitle} - Movie Details`; + window.location.href = 'movie-details.html'; + updateMovieVisitCount(movieId, movieTitle); +} + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} + +function getMovieCode2() { + const codeOfMovie = 'MmJhOGU1MzY='; + return atob(codeOfMovie); +} + +function getMovieName() { + const moviename = 'YXBpa2V5PQ=='; + return atob(moviename); +} + +function getMovieActor() { + const actor = 'd3d3Lm9tZGJhcGkuY29t'; + return atob(actor); +} + +function updateAverageMovieRating(movieId, newRating) { + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + + let totalRating = 0; + let totalMoviesRated = 0; + + for (let id in savedRatings) { + totalRating += parseFloat(savedRatings[id]); + totalMoviesRated++; + } + let averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1).toString()); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + fallbackMovieSelection(); + } +} + +function updateUniqueActorsViewed(actorId) { + let viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + if (!viewedActors.includes(actorId)) { + viewedActors.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(viewedActors)); + } +} + +function updateUniqueCompaniesViewed(companyId) { + let viewedCompanies = JSON.parse(localStorage.getItem('uniqueCompaniesViewed')) || []; + if (!viewedCompanies.includes(companyId)) { + viewedCompanies.push(companyId); + localStorage.setItem('uniqueCompaniesViewed', JSON.stringify(viewedCompanies)); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-match.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-match.js new file mode 100644 index 00000000..069f5c82 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-match.js @@ -0,0 +1,1378 @@ +const main = document.getElementById('movie-match-form'); +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const searchTitle = document.getElementById('search-title'); +const otherTitle = document.getElementById('other1'); + +document.getElementById('movie-match-form').addEventListener('submit', function (event) { + event.preventDefault(); + const mood = document.getElementById('mood').value; + const genre = document.getElementById('genre').value; + const period = document.getElementById('period').value; + findMovieMatch(mood, genre, period); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://api.themoviedb.org/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function findMovieMatch(mood, genre, period) { + const movieDatabase = [ + // Movies starting with the mood "happy" + { + id: '432413', + title: 'The Avengers', + mood: 'happy', + genre: 'action', + period: '2010s', + }, + { + id: '299534', + title: 'Avengers: Endgame', + mood: 'happy', + genre: 'action', + period: '2020s', + }, + { + id: '1726', + title: 'Iron Man', + mood: 'happy', + genre: 'action', + period: '2000s', + }, + { + id: '562', + title: 'Die Hard', + mood: 'happy', + genre: 'action', + period: '90s', + }, + { + id: '89', + title: 'Indiana Jones and the Last Crusade', + mood: 'happy', + genre: 'action', + period: '80s', + }, + + { + id: '620', + title: 'Ghostbusters', + mood: 'happy', + genre: 'comedy', + period: '80s', + }, + { + id: '105', + title: 'Back to the Future', + mood: 'happy', + genre: 'comedy', + period: '90s', + }, + { + id: '18785', + title: 'The Hangover', + mood: 'happy', + genre: 'comedy', + period: '2000s', + }, + { + id: '284053', + title: 'Thor: Ragnarok', + mood: 'happy', + genre: 'comedy', + period: '2010s', + }, + { + id: '515001', + title: 'Jojo Rabbit', + mood: 'happy', + genre: 'comedy', + period: '2020s', + }, + + { + id: '773', + title: 'Little Miss Sunshine', + mood: 'happy', + genre: 'drama', + period: '2000s', + }, + { + id: '1402', + title: 'The Pursuit of Happyness', + mood: 'happy', + genre: 'drama', + period: '2010s', + }, + { + id: '508442', + title: 'Soul', + mood: 'happy', + genre: 'drama', + period: '2020s', + }, + { + id: '489', + title: 'Good Will Hunting', + mood: 'happy', + genre: 'drama', + period: '90s', + }, + { + id: '207', + title: 'Dead Poets Society', + mood: 'happy', + genre: 'drama', + period: '80s', + }, + + { + id: '118340', + title: 'Guardians of the Galaxy', + mood: 'happy', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '607', + title: 'Men in Black', + mood: 'happy', + genre: 'sci-fi', + period: '90s', + }, + { + id: '601', + title: 'E.T. the Extra-Terrestrial', + mood: 'happy', + genre: 'sci-fi', + period: '80s', + }, + { + id: '333339', + title: 'Ready Player One', + mood: 'happy', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '438631', + title: 'Dune', + mood: 'happy', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '50646', + title: 'Crazy Stupid Love', + mood: 'happy', + genre: 'romance', + period: '2010s', + }, + { + id: '1581', + title: 'The Holiday', + mood: 'happy', + genre: 'romance', + period: '2000s', + }, + { + id: '114', + title: 'Pretty Woman', + mood: 'happy', + genre: 'romance', + period: '90s', + }, + { + id: '2028', + title: 'Say Anything...', + mood: 'happy', + genre: 'romance', + period: '80s', + }, + { + id: '614409', + title: 'To All the Boys: Always and Forever', + mood: 'happy', + genre: 'romance', + period: '2020s', + }, + + // Movies starting with the mood "sad" + { + id: '424', + title: "Schindler's List", + mood: 'sad', + genre: 'drama', + period: '90s', + }, + { + id: '334541', + title: 'Manchester by the Sea', + mood: 'sad', + genre: 'drama', + period: '2010s', + }, + { + id: '4148', + title: 'Revolutionary Road', + mood: 'sad', + genre: 'drama', + period: '2000s', + }, + { + id: '16619', + title: 'Ordinary People', + mood: 'sad', + genre: 'drama', + period: '80s', + }, + { + id: '1135095', + title: 'Pieces of a Woman', + mood: 'sad', + genre: 'drama', + period: '2020s', + }, + + { + id: '38', + title: 'Eternal Sunshine of the Spotless Mind', + mood: 'sad', + genre: 'romance', + period: '2000s', + }, + { + id: '46705', + title: 'Blue Valentine', + mood: 'sad', + genre: 'romance', + period: '2010s', + }, + { + id: '222935', + title: 'The Fault in Our Stars', + mood: 'sad', + genre: 'romance', + period: '2010s', + }, + { + id: '142', + title: 'Brokeback Mountain', + mood: 'sad', + genre: 'romance', + period: '2000s', + }, + { + id: '589049', + title: 'The Photograph', + mood: 'sad', + genre: 'romance', + period: '2020s', + }, + + { + id: '335984', + title: 'Blade Runner 2049', + mood: 'sad', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '644', + title: 'A.I. Artificial Intelligence', + mood: 'sad', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '152601', + title: 'Her', + mood: 'sad', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '9426', + title: 'The Fly', + mood: 'sad', + genre: 'sci-fi', + period: '80s', + }, + { + id: '419704', + title: 'Ad Astra', + mood: 'sad', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '637', + title: 'Life Is Beautiful', + mood: 'sad', + genre: 'comedy', + period: '90s', + }, + { + id: '9428', + title: 'The Royal Tenenbaums', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '153', + title: 'Lost in Translation', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '9675', + title: 'Sideways', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + { + id: '7326', + title: 'Juno', + mood: 'sad', + genre: 'comedy', + period: '2000s', + }, + + { + id: '263115', + title: 'Logan', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '70', + title: 'Million Dollar Baby', + mood: 'sad', + genre: 'action', + period: '2000s', + }, + { + id: '49026', + title: 'The Dark Knight Rises', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '475557', + title: 'Joker', + mood: 'sad', + genre: 'action', + period: '2010s', + }, + { + id: '98', + title: 'Gladiator', + mood: 'sad', + genre: 'action', + period: '2000s', + }, + + // Movies starting with the mood "adventurous" + { + id: '85', + title: 'Indiana Jones and the Raiders of the Lost Ark', + mood: 'adventurous', + genre: 'action', + period: '80s', + }, + { + id: '76341', + title: 'Mad Max: Fury Road', + mood: 'adventurous', + genre: 'action', + period: '2010s', + }, + { + id: '98', + title: 'Gladiator', + mood: 'adventurous', + genre: 'action', + period: '2000s', + }, + { + id: '562', + title: 'Die Hard', + mood: 'adventurous', + genre: 'action', + period: '90s', + }, + { + id: '438631', + title: 'Dune', + mood: 'adventurous', + genre: 'action', + period: '2020s', + }, + + { + id: '620', + title: 'Ghostbusters', + mood: 'adventurous', + genre: 'comedy', + period: '80s', + }, + { + id: '353486', + title: 'Jumanji: Welcome to the Jungle', + mood: 'adventurous', + genre: 'comedy', + period: '2010s', + }, + { + id: '22', + title: 'Pirates of the Caribbean', + mood: 'adventurous', + genre: 'comedy', + period: '2000s', + }, + { + id: '607', + title: 'Men in Black', + mood: 'adventurous', + genre: 'comedy', + period: '90s', + }, + { + id: '550988', + title: 'Free Guy', + mood: 'adventurous', + genre: 'comedy', + period: '2020s', + }, + + { + id: '281957', + title: 'The Revenant', + mood: 'adventurous', + genre: 'drama', + period: '2010s', + }, + { + id: '8358', + title: 'Cast Away', + mood: 'adventurous', + genre: 'drama', + period: '2000s', + }, + { + id: '947', + title: 'Lawrence of Arabia', + mood: 'adventurous', + genre: 'drama', + period: '80s', + }, + { + id: '13', + title: 'Forrest Gump', + mood: 'adventurous', + genre: 'drama', + period: '90s', + }, + { + id: '581734', + title: 'Nomadland', + mood: 'adventurous', + genre: 'drama', + period: '2020s', + }, + + { + id: '11', + title: 'Star Wars', + mood: 'adventurous', + genre: 'sci-fi', + period: '80s', + }, + { + id: '19995', + title: 'Avatar', + mood: 'adventurous', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '27205', + title: 'Inception', + mood: 'adventurous', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '335984', + title: 'Blade Runner', + mood: 'adventurous', + genre: 'sci-fi', + period: '90s', + }, + { + id: '438631', + title: 'Dune', + mood: 'adventurous', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '2493', + title: 'The Princess Bride', + mood: 'adventurous', + genre: 'romance', + period: '80s', + }, + { + id: '313369', + title: 'La La Land', + mood: 'adventurous', + genre: 'romance', + period: '2010s', + }, + { + id: '24420', + title: "The Time Traveler's Wife", + mood: 'adventurous', + genre: 'romance', + period: '2000s', + }, + { + id: '597', + title: 'Titanic', + mood: 'adventurous', + genre: 'romance', + period: '90s', + }, + { + id: '672647', + title: 'The Map of Tiny Perfect Things', + mood: 'adventurous', + genre: 'romance', + period: '2020s', + }, + + // Movies starting with the mood "romantic" + { + id: '11036', + title: 'The Notebook', + mood: 'romantic', + genre: 'drama', + period: '2000s', + }, + { + id: '332562', + title: 'A Star is Born', + mood: 'romantic', + genre: 'drama', + period: '2010s', + }, + { + id: '4348', + title: 'Pride and Prejudice', + mood: 'romantic', + genre: 'drama', + period: '2000s', + }, + { + id: '289', + title: 'Casablanca', + mood: 'romantic', + genre: 'drama', + period: 'classic', + }, + { + id: '398818', + title: 'Call Me by Your Name', + mood: 'romantic', + genre: 'drama', + period: '2010s', + }, + + { + id: '194', + title: 'Amélie', + mood: 'romantic', + genre: 'romance', + period: '2000s', + }, + { + id: '313369', + title: 'La La Land', + mood: 'romantic', + genre: 'romance', + period: '2010s', + }, + { + id: '76', + title: 'Before Sunrise', + mood: 'romantic', + genre: 'romance', + period: '90s', + }, + { + id: '416477', + title: 'The Big Sick', + mood: 'romantic', + genre: 'romance', + period: '2010s', + }, + { + id: '531428', + title: 'Portrait of a Lady on Fire', + mood: 'romantic', + genre: 'romance', + period: '2020s', + }, + + { + id: '152601', + title: 'Her', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '38050', + title: 'The Adjustment Bureau', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '38', + title: 'Eternal Sunshine of the Spotless Mind', + mood: 'romantic', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '274870', + title: 'Passengers', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '122906', + title: 'About Time', + mood: 'romantic', + genre: 'sci-fi', + period: '2010s', + }, + + { + id: '639', + title: 'When Harry Met Sally', + mood: 'romantic', + genre: 'comedy', + period: '80s', + }, + { + id: '455207', + title: 'Crazy Rich Asians', + mood: 'romantic', + genre: 'comedy', + period: '2010s', + }, + { + id: '509', + title: 'Notting Hill', + mood: 'romantic', + genre: 'comedy', + period: '90s', + }, + { + id: '4951', + title: '10 Things I Hate About You', + mood: 'romantic', + genre: 'comedy', + period: '90s', + }, + { + id: '18240', + title: 'The Proposal', + mood: 'romantic', + genre: 'comedy', + period: '2000s', + }, + + { + id: '787', + title: 'Mr. & Mrs. Smith', + mood: 'romantic', + genre: 'action', + period: '2000s', + }, + { + id: '36955', + title: 'True Lies', + mood: 'romantic', + genre: 'action', + period: '90s', + }, + { + id: '10529', + title: 'Outlander', + mood: 'romantic', + genre: 'action', + period: '2000s', + }, + { + id: '2493', + title: 'The Princess Bride', + mood: 'romantic', + genre: 'action', + period: '80s', + }, + { + id: '547016', + title: 'The Old Guard', + mood: 'romantic', + genre: 'action', + period: '2020s', + }, + + // Movies starting with the mood "scary" + { + id: '493922', + title: 'Hereditary', + mood: 'scary', + genre: 'drama', + period: '2010s', + }, + { + id: '274', + title: 'The Silence of the Lambs', + mood: 'scary', + genre: 'drama', + period: '90s', + }, + { + id: '539', + title: 'Psycho', + mood: 'scary', + genre: 'drama', + period: 'classic', + }, + { + id: '44214', + title: 'Black Swan', + mood: 'scary', + genre: 'drama', + period: '2000s', + }, + { + id: '503919', + title: 'The Lighthouse', + mood: 'scary', + genre: 'drama', + period: '2020s', + }, + + { + id: '310131', + title: 'The Witch', + mood: 'scary', + genre: 'horror', + period: '2010s', + }, + { + id: '694', + title: 'The Shining', + mood: 'scary', + genre: 'horror', + period: '80s', + }, + { + id: '377', + title: 'A Nightmare on Elm Street', + mood: 'scary', + genre: 'horror', + period: '80s', + }, + { + id: '419430', + title: 'Get Out', + mood: 'scary', + genre: 'horror', + period: '2010s', + }, + { + id: '565', + title: 'The Ring', + mood: 'scary', + genre: 'horror', + period: '2000s', + }, + + { + id: '8413', + title: 'Event Horizon', + mood: 'scary', + genre: 'sci-fi', + period: '90s', + }, + { + id: '348', + title: 'Alien', + mood: 'scary', + genre: 'sci-fi', + period: '80s', + }, + { + id: '300668', + title: 'Annihilation', + mood: 'scary', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '447332', + title: 'A Quiet Place', + mood: 'scary', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '443791', + title: 'Underwater', + mood: 'scary', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '747', + title: 'Shaun of the Dead', + mood: 'scary', + genre: 'comedy', + period: '2000s', + }, + { + id: '19908', + title: 'Zombieland', + mood: 'scary', + genre: 'comedy', + period: '2000s', + }, + { + id: '4011', + title: 'Beetlejuice', + mood: 'scary', + genre: 'comedy', + period: '80s', + }, + { + id: '22970', + title: 'The Cabin in the Woods', + mood: 'scary', + genre: 'comedy', + period: '2010s', + }, + { + id: '425909', + title: 'Ghostbusters: Afterlife', + mood: 'scary', + genre: 'comedy', + period: '2020s', + }, + + { + id: '72190', + title: 'World War Z', + mood: 'scary', + genre: 'action', + period: '2010s', + }, + { + id: '6479', + title: 'I Am Legend', + mood: 'scary', + genre: 'action', + period: '2000s', + }, + { + id: '106', + title: 'Predator', + mood: 'scary', + genre: 'action', + period: '80s', + }, + { + id: '396535', + title: 'Train to Busan', + mood: 'scary', + genre: 'action', + period: '2010s', + }, + { + id: '503736', + title: 'Army of the Dead', + mood: 'scary', + genre: 'action', + period: '2020s', + }, + + // Movies starting with the mood "thoughtful" + { + id: '8967', + title: 'The Tree of Life', + mood: 'thoughtful', + genre: 'drama', + period: '2010s', + }, + { + id: '14', + title: 'American Beauty', + mood: 'thoughtful', + genre: 'drama', + period: '90s', + }, + { + id: '453', + title: 'A Beautiful Mind', + mood: 'thoughtful', + genre: 'drama', + period: '2000s', + }, + { + id: '595', + title: 'To Kill a Mockingbird', + mood: 'thoughtful', + genre: 'drama', + period: 'classic', + }, + { + id: '581734', + title: 'Nomadland', + mood: 'thoughtful', + genre: 'drama', + period: '2020s', + }, + + { + id: '419430', + title: 'Get Out', + mood: 'thoughtful', + genre: 'horror', + period: '2010s', + }, + { + id: '1933', + title: 'The Others', + mood: 'thoughtful', + genre: 'horror', + period: '2000s', + }, + { + id: '745', + title: 'The Sixth Sense', + mood: 'thoughtful', + genre: 'horror', + period: '90s', + }, + { + id: '805', + title: "Rosemary's Baby", + mood: 'thoughtful', + genre: 'horror', + period: 'classic', + }, + { + id: '530385', + title: 'Midsommar', + mood: 'thoughtful', + genre: 'horror', + period: '2020s', + }, + + { + id: '335984', + title: 'Blade Runner 2049', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '27205', + title: 'Inception', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2010s', + }, + { + id: '141', + title: 'Donnie Darko', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2000s', + }, + { + id: '62', + title: '2001: A Space Odyssey', + mood: 'thoughtful', + genre: 'sci-fi', + period: 'classic', + }, + { + id: '264660', + title: 'Ex Machina', + mood: 'thoughtful', + genre: 'sci-fi', + period: '2020s', + }, + + { + id: '120467', + title: 'The Grand Budapest Hotel', + mood: 'thoughtful', + genre: 'comedy', + period: '2010s', + }, + { + id: '153', + title: 'Lost in Translation', + mood: 'thoughtful', + genre: 'comedy', + period: '2000s', + }, + { + id: '137', + title: 'Groundhog Day', + mood: 'thoughtful', + genre: 'comedy', + period: '90s', + }, + { + id: '935', + title: 'Dr. Strangelove', + mood: 'thoughtful', + genre: 'comedy', + period: 'classic', + }, + { + id: '515001', + title: 'Jojo Rabbit', + mood: 'thoughtful', + genre: 'comedy', + period: '2020s', + }, + + { + id: '603', + title: 'The Matrix', + mood: 'thoughtful', + genre: 'action', + period: '90s', + }, + { + id: '76341', + title: 'Mad Max: Fury Road', + mood: 'thoughtful', + genre: 'action', + period: '2010s', + }, + { + id: '9693', + title: 'Children of Men', + mood: 'thoughtful', + genre: 'action', + period: '2000s', + }, + { + id: '577922', + title: 'Tenet', + mood: 'thoughtful', + genre: 'action', + period: '2020s', + }, + { + id: '335984', + title: 'Blade Runner', + mood: 'thoughtful', + genre: 'action', + period: '80s', + }, + ]; + + const filteredMovies = movieDatabase.filter(movie => movie.mood === mood && movie.genre === genre && movie.period === period); + + if (filteredMovies.length > 0) { + const randomIndex = Math.floor(Math.random() * filteredMovies.length); + const matchedMovie = filteredMovies[randomIndex]; + + localStorage.setItem('selectedMovieId', matchedMovie.id); + window.location.href = 'movie-details.html'; + } else { + alert('No match found. Try different criteria.'); + } +} + +const form = document.getElementById('form1'); +const IMGPATH = 'https://image.tmdb.org/t/p/w1280'; +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-timeline.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-timeline.js new file mode 100644 index 00000000..5d947c26 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/movie-timeline.js @@ -0,0 +1,647 @@ +let alertShown = false; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.getElementById('start-year').addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + event.preventDefault(); + updateMovies(); + } +}); + +document.getElementById('end-year').addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + event.preventDefault(); + updateMovies(); + } +}); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const IMGPATH = 'https://image.tmdb.org/t/p/w500'; +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; +const searchTitle = document.getElementById('select-text'); +const searchButton = document.getElementById('button-search'); +const search = document.getElementById('search'); +const main = document.getElementById('results'); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +async function getMovies(url) { + clearMovieDetails(); + const numberOfMovies = calculateMoviesToDisplay(); + const pagesToFetch = numberOfMovies <= 20 ? 1 : 2; + let allMovies = []; + + for (let page = 1; page <= pagesToFetch; page++) { + const response = await fetch(`${url}&page=${page}`); + const data = await response.json(); + allMovies = allMovies.concat(data.results); + } + + const popularityThreshold = 0.5; + + allMovies.sort((a, b) => { + const popularityDifference = Math.abs(a.popularity - b.popularity); + if (popularityDifference < popularityThreshold) { + return b.vote_average - a.vote_average; + } + return b.popularity - a.popularity; + }); + + if (allMovies.length > 0) { + showMovies(allMovies.slice(0, numberOfMovies), main); + } else { + main.innerHTML = `

No movie with the specified search term found. Please try again.

`; + } +} + +function clearMovieDetails() { + const movieDetailsContainer = document.getElementById('movie-details-container'); + if (movieDetailsContainer) { + movieDetailsContainer.innerHTML = ''; + } +} + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function updateMovies() { + showSpinner(); + let startYear = document.getElementById('start-year').value; + let endYear = document.getElementById('end-year').value; + let currentYear = new Date().getFullYear(); + if (startYear && endYear && startYear <= endYear && endYear <= currentYear && startYear >= 1900 && startYear <= currentYear) { + fetchMoviesByTimePeriod(startYear, endYear); + hideSpinner(); + alertShown = false; + } else { + if (!alertShown) { + alert( + 'Please ensure the start year is before the end year, the start year is later than the year 1900, and both are not later than the current year.' + ); + alertShown = true; + } + hideSpinner(); + } +} + +async function getAdditionalPosters(movieId) { + const response = await fetch(`https://api.themoviedb.org/3/movie/${movieId}/images?api_key=${getMovieCode()}`); + const data = await response.json(); + return data.posters.map(poster => poster.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +function showMovies(movies, mainElement, startYear, endYear, append) { + showSpinner(); + + if (!append) { + mainElement.innerHTML = ''; + const header = document.createElement('h2'); + header.style.textAlign = 'center'; + header.style.marginTop = '20px'; + header.style.marginBottom = '20px'; + header.style.color = '#ff8623'; + header.style.fontSize = '23px'; + if (startYear === endYear) { + header.textContent = `Movies released in ${startYear}`; + } else { + header.textContent = `Movies released between ${startYear} and ${endYear}`; + } + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.innerHTML = ''; + centerContainer1.appendChild(header); + centerContainer1.appendChild(mainElement); + } + + const observer = new IntersectionObserver( + async (entries, observer) => { + for (const entry of entries) { + if (entry.isIntersecting) { + const movieEl = entry.target; + const movieId = movieEl.dataset.id; + + const additionalPosters = await getAdditionalPosters(movieId); + let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; + + const movieImageContainer = movieEl.querySelector('.movie-images'); + + allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); + + const imagePromises = allPosters.map((poster, index) => { + const img = new Image(); + img.src = `${IMGPATH + poster}`; + img.loading = index === 0 ? 'eager' : 'lazy'; + img.alt = `${movieEl.dataset.title} poster ${index + 1}`; + img.width = 300; + img.height = 435; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = '0'; + img.classList.add('poster-img'); + movieImageContainer.appendChild(img); + + return new Promise(resolve => { + img.onload = () => resolve(img); + }); + }); + + const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); + await Promise.race([Promise.all(imagePromises), maxWait]); + + movieImageContainer.querySelector('.poster-img').style.opacity = '1'; + + rotateImages(Array.from(movieImageContainer.children)); + observer.unobserve(movieEl); + } + } + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + movies.forEach(movie => { + let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; + + const movieEl = document.createElement('div'); + movieEl.style.zIndex = '1000'; + movieEl.classList.add('movie'); + movieEl.dataset.id = id; + movieEl.dataset.posterPath = poster_path; + movieEl.dataset.title = title; + + const words = title.split(' '); + if (words.length >= 8) { + words[7] = '...'; + title = words.slice(0, 8).join(' '); + } + + const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); + const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); + + if (overview === '') { + overview = 'No overview available.'; + } + + movieEl.innerHTML = ` +
+
+ ${title} poster +
+
+
+

${title}

+ ${voteAvg} +
+
+

Overview:

+ ${overview} +
`; + + movieEl.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', id); + updateUniqueMoviesViewed(id); + updateFavoriteGenre(genre_ids); + updateMovieVisitCount(id, title); + window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + }); + + mainElement.appendChild(movieEl); + observer.observe(movieEl); + }); + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.appendChild(mainElement); + + createLoadMoreButton(startYear, endYear, mainElement); + hideSpinner(); +} + +function createLoadMoreButton(startYear, endYear, mainElement) { + const existingButtonDiv = mainElement.querySelector('.load-more-container'); + if (existingButtonDiv) { + mainElement.removeChild(existingButtonDiv); + } + + const buttonContainer = document.createElement('div'); + buttonContainer.className = 'load-more-container'; + buttonContainer.style.width = '100%'; + buttonContainer.style.textAlign = 'center'; + buttonContainer.style.marginTop = '20px'; + + const moreButton = document.createElement('button'); + moreButton.textContent = 'Get More Movies in this Period'; + moreButton.style.margin = '10px auto'; + + moreButton.addEventListener('click', function () { + currentPage++; + fetchMoviesByTimePeriod(startYear, endYear, true); + }); + + buttonContainer.appendChild(moreButton); + mainElement.appendChild(buttonContainer); +} + +let currentPage = 1; + +async function fetchMoviesByTimePeriod(startYear, endYear, append = false) { + showSpinner(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31&page=${currentPage}`; + const response = await fetch(url); + const data = await response.json(); + const moviesToShow = data.results; + + if (append) { + showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, true); + } else { + showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, false); + } + hideSpinner(); +} + +document.getElementById('load-movies').addEventListener('click', () => { + showSpinner(); + updateMovies(); + alertShown = false; + hideSpinner(); +}); + +function calculateMoviesToDisplay() { + const screenWidth = window.innerWidth; + if (screenWidth <= 689.9) return 10; // 1 movie per row + if (screenWidth <= 1021.24) return 20; // 2 movies per row + if (screenWidth <= 1353.74) return 21; // 3 movies per row + if (screenWidth <= 1684.9) return 20; // 4 movies per row + if (screenWidth <= 2017.49) return 20; // 5 movies per row + if (screenWidth <= 2349.99) return 18; // 6 movies per row + if (screenWidth <= 2681.99) return 21; // 7 movies per row + if (screenWidth <= 3014.49) return 24; // 8 movies per row + if (screenWidth <= 3345.99) return 27; // 9 movies per row + if (screenWidth <= 3677.99) return 20; // 10 movies per row + if (screenWidth <= 4009.99) return 22; // 11 movies per row + if (screenWidth <= 4340.99) return 24; // 12 movies per row + if (screenWidth <= 4673.49) return 26; // 13 movies per row + if (screenWidth <= 5005.99) return 28; // 14 movies per row + if (screenWidth <= 5337.99) return 30; // 15 movies per row + if (screenWidth <= 5669.99) return 32; // 16 movies per row + if (screenWidth <= 6001.99) return 34; // 17 movies per row + if (screenWidth <= 6333.99) return 36; // 18 movies per row + if (screenWidth <= 6665.99) return 38; // 19 movies per row + if (screenWidth <= 6997.99) return 40; // 20 movies per row + if (screenWidth <= 7329.99) return 42; // 21 movies per row + if (screenWidth <= 7661.99) return 44; // 22 movies per row + if (screenWidth <= 7993.99) return 46; // 23 movies per row + if (screenWidth <= 8325.99) return 48; // 24 movies per row + return 20; +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/notifications.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/notifications.js new file mode 100644 index 00000000..4ea7acef --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/notifications.js @@ -0,0 +1,176 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +document.addEventListener('DOMContentLoaded', () => { + const today = new Date(); + fetchReleasesByCategory('releasesSinceLastVisit', new Date(localStorage.getItem('lastVisit')), today, true); + fetchReleasesByCategory('releasesThisMonth', new Date(today.getFullYear(), today.getMonth(), 1), today, false); + fetchReleasesByCategory('releasesThisYear', new Date(today.getFullYear(), 0, 1), today, false); + fetchRecommendedReleases(); +}); + +async function fetchReleasesByCategory(elementId, startDate, endDate, isLastVisit) { + const list = document.getElementById(elementId); + list.innerHTML = ''; + + let movies = await fetchMovies(startDate, endDate); + + movies = movies.sort((a, b) => new Date(b.release_date) - new Date(a.release_date)); + + populateList(elementId, movies.slice(0, 5)); +} + +async function fetchMovies(startDate, endDate) { + const formattedStartDate = `${startDate.getFullYear()}-${(startDate.getMonth() + 1) + .toString() + .padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`; + const formattedEndDate = `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`; + + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&release_date.gte=${formattedStartDate}&release_date.lte=${formattedEndDate}`; + + try { + const response = await fetch(url); + const data = await response.json(); + return data.results; + } catch (error) { + console.log('Failed to fetch movies for', elementId + ':', error); + return []; + } +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +async function getMostVisitedMovieGenre() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedGenre = null; + let maxVisits = 0; + for (const movieId in movieVisits) { + const visits = movieVisits[movieId]; + if (visits.count > maxVisits) { + maxVisits = visits.count; + mostVisitedGenre = await fetchGenreForMovie(movieId); + } + } + return mostVisitedGenre; +} + +async function fetchGenreForMovie(movieId) { + const movieDetailsUrl = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(movieDetailsUrl); + const movieDetails = await response.json(); + return movieDetails.genres[0] ? movieDetails.genres[0].id : null; +} + +async function fetchRecommendedReleases() { + let url; + + const mostCommonGenre = getMostCommonGenre(); + const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); + + try { + const genreId = mostVisitedMovieGenre || mostCommonGenre; + if (!genreId) { + throw new Error('Genre ID is not valid.'); + } + url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${genreId}`; + } catch (error) { + console.log('Fetching recommended movies failed or data issues:', error); + url = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}&language=en-US&page=1`; + } + + try { + const response = await fetch(url); + const data = await response.json(); + populateList('recommendedReleases', data.results.slice(0, 5)); + } catch (error) { + console.log('Failed to fetch movies:', error); + } +} + +function populateList(elementId, movies) { + const list = document.getElementById(elementId); + list.innerHTML = ''; + movies.forEach(movie => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id.toString()); + window.location.href = 'movie-details.html'; + }); + + const title = document.createElement('span'); + title.textContent = movie.title; + title.style.color = 'black'; + li.appendChild(title); + list.appendChild(li); + }); +} + +document.addEventListener('DOMContentLoaded', () => { + populateActors(); + populateDirectors(); +}); + +function populateActors() { + const actors = [ + { name: 'Robert Downey Jr.', id: 3223 }, + { name: 'Scarlett Johansson', id: 1245 }, + { name: 'Denzel Washington', id: 5292 }, + { name: 'Meryl Streep', id: 5064 }, + { name: 'Leonardo DiCaprio', id: 6193 }, + { name: 'Sandra Bullock', id: 18277 }, + { name: 'Tom Hanks', id: 31 }, + ]; + + const list = document.getElementById('popularActors').querySelector('ul'); + actors.forEach(actor => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedActorId', actor.id.toString()); + window.location.href = 'actor-details.html'; + }); + + const name = document.createElement('span'); + name.textContent = actor.name; + li.appendChild(name); + list.appendChild(li); + }); +} + +function populateDirectors() { + const directors = [ + { name: 'Steven Spielberg', id: 488 }, + { name: 'Martin Scorsese', id: 1032 }, + { name: 'Christopher Nolan', id: 525 }, + { name: 'Quentin Tarantino', id: 138 }, + { name: 'Kathryn Bigelow', id: 14392 }, + { name: 'James Cameron', id: 2710 }, + { name: 'Sofia Coppola', id: 1776 }, + ]; + + const list = document.getElementById('popularDirectors').querySelector('ul'); + directors.forEach(director => { + const li = document.createElement('li'); + li.style.cursor = 'pointer'; + li.addEventListener('click', () => { + localStorage.setItem('selectedDirectorId', director.id.toString()); + window.location.href = 'director-details.html'; + }); + + const name = document.createElement('span'); + name.textContent = director.name; + li.appendChild(name); + + list.appendChild(li); + }); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/privacy-policy.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/privacy-policy.js new file mode 100644 index 00000000..7f4afb2d --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/privacy-policy.js @@ -0,0 +1,789 @@ +function toggleNav() { + const sideNav = document.getElementById('side-nav'); + sideNav.classList.toggle('manual-toggle'); + adjustNavBar(); +} + +function removeNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + } + + adjustNavBar(); +} + +function adjustNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0px'; + } else { + sideNav.style.left = '-250px'; + } +} + +document.addEventListener('mousemove', function (event) { + const sideNav = document.getElementById('side-nav'); + if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0'; + } +}); + +document.getElementById('side-nav').addEventListener('mouseleave', function () { + const sideNav = document.getElementById('side-nav'); + if (!sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '-250px'; + } +}); + +document.addEventListener('click', function (event) { + const sideNav = document.getElementById('side-nav'); + const navToggle = document.getElementById('nav-toggle'); + if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + adjustNavBar(); + } +}); + +document.getElementById('introduction').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('introduction').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('consent').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('consent').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading2').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading3').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading4').addEventListener('click', function (e) { + e.preventDefault(); + + document.getElementById('subheading4').scrollIntoView({ behavior: 'smooth' }); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.webp'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +window.addEventListener('load', function () { + adjustAnchorHeights(); +}); + +window.addEventListener('resize', adjustAnchorHeights); + +function adjustAnchorHeights() { + const bottomBarAnchors = document.querySelectorAll('.mobile-bottom-bar a'); + let maxHeight = 0; + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = 'auto'; + const anchorHeight = anchor.getBoundingClientRect().height; + maxHeight = Math.max(maxHeight, anchorHeight); + }); + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = `${maxHeight}px`; + }); +} + +let lastScrollY = window.scrollY; + +window.addEventListener('scroll', () => { + const currentScrollY = window.scrollY; + + if (currentScrollY > lastScrollY && currentScrollY > 0) { + document.querySelector('.mobile-bottom-bar').classList.add('hide-bar'); + } else { + document.querySelector('.mobile-bottom-bar').classList.remove('hide-bar'); + } + + lastScrollY = currentScrollY; +}); + +let isAnimating = false; + +document.getElementById('menu-btn').addEventListener('click', () => { + if (isAnimating) return; + + isAnimating = true; + + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach((id, index) => { + const button = document.getElementById(id); + if (button.style.display === 'none' || !button.style.display) { + button.style.display = 'block'; + setTimeout(() => { + button.style.opacity = '1'; + button.style.transform = 'translateY(0)'; + }, 50 * index); + } else { + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + } + + setTimeout( + () => { + button.style.display = button.style.opacity === '1' ? 'block' : 'none'; + if (index === buttonIds.length - 1) { + isAnimating = false; + } + }, + 500 + 50 * index + ); + }); +}); + +window.addEventListener('resize', () => { + if (window.innerWidth < 767) { + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach(id => { + const button = document.getElementById(id); + button.style.display = 'none'; + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + }); + } +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/quiz.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/quiz.js new file mode 100644 index 00000000..c5adcd57 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/quiz.js @@ -0,0 +1,859 @@ +import { updateTriviaStats } from './triviaModule.js'; + +const questionBank = [ + { + question: 'What movie won the Academy Award for Best Picture in 2020?', + options: ['Joker', '1917', 'Parasite'], + answer: 'Parasite', + }, + { + question: "Who directed the movie 'The Godfather'?", + options: ['Steven Spielberg', 'Francis Ford Coppola', 'Martin Scorsese'], + answer: 'Francis Ford Coppola', + }, + { + question: 'What was the first feature-length animated movie ever released?', + options: ['Snow White and the Seven Dwarfs', 'Bambi', 'Pinocchio'], + answer: 'Snow White and the Seven Dwarfs', + }, + { + question: "What was the highest-grossing movie of all time before the release of 'Avatar'?", + options: ['Titanic', 'Star Wars: The Force Awakens', 'Avengers: Endgame'], + answer: 'Titanic', + }, + { + question: "Who played the lead role in the movie 'Forrest Gump'?", + options: ['Tom Hanks', 'Brad Pitt', 'Leonardo DiCaprio'], + answer: 'Tom Hanks', + }, + { + question: 'What movie won the Academy Award for Best Picture in 2019?', + options: ['Bohemian Rhapsody', 'Green Book', 'Roma'], + answer: 'Green Book', + }, + { + question: 'Who played the character of John McClane in the Die Hard movie series?', + options: ['Arnold Schwarzenegger', 'Sylvester Stallone', 'Bruce Willis'], + answer: 'Bruce Willis', + }, + { + question: 'What movie is based on a novel by Stephen King and features a character named Jack Torrance?', + options: ['Carrie', 'The Shining', 'Misery'], + answer: 'The Shining', + }, + { + question: "Who directed the movie 'Forrest Gump'?", + options: ['Steven Spielberg', 'Robert Zemeckis', 'Martin Scorsese'], + answer: 'Robert Zemeckis', + }, + { + question: 'What is the highest-grossing movie of all time (as of 2021)?', + options: ['Avatar', 'Avengers: Endgame', 'Titanic'], + answer: 'Avatar', + }, + { + question: "What movie features the line 'You can't handle the truth!'?", + options: ['The Shawshank Redemption', 'A Few Good Men', 'Goodfellas'], + answer: 'A Few Good Men', + }, + { + question: 'Who played the character of Tony Stark/Iron Man in the Marvel Cinematic Universe?', + options: ['Chris Hemsworth', 'Mark Ruffalo', 'Robert Downey Jr.'], + answer: 'Robert Downey Jr.', + }, + { + question: "In which movie did Tom Hanks say, 'Houston, we have a problem'?", + options: ['Apollo 13', 'Cast Away', 'The Terminal'], + answer: 'Apollo 13', + }, + { + question: 'What is the name of the hobbit played by Elijah Wood in the Lord of the Rings movies?', + options: ['Frodo', 'Sam', 'Merry'], + answer: 'Frodo', + }, + { + question: "What is the name of the kingdom where the 2013 animated movie 'Frozen' is set?", + options: ['Arendelle', 'Genovia', 'DunBroch'], + answer: 'Arendelle', + }, + { + question: 'Which 1997 science fiction movie stars Will Smith and Tommy Lee Jones?', + options: ['Independence Day', 'Men in Black', 'Wild Wild West'], + answer: 'Men in Black', + }, + { + question: 'Which movie features Bruce Willis as a child psychologist?', + options: ['Die Hard', 'The Sixth Sense', 'Unbreakable'], + answer: 'The Sixth Sense', + }, + { + question: "In 'The Matrix', does Neo take the blue pill or the red pill?", + options: ['Blue', 'Red', 'Green'], + answer: 'Red', + }, + { + question: "Which actress played Katniss Everdeen in 'The Hunger Games' movies?", + options: ['Jennifer Lawrence', 'Emma Watson', 'Shailene Woodley'], + answer: 'Jennifer Lawrence', + }, + { + question: "Who directed 'Jurassic Park'?", + options: ['James Cameron', 'Steven Spielberg', 'George Lucas'], + answer: 'Steven Spielberg', + }, + { + question: 'What 1980s movie was the highest grossing film of the decade?', + options: ['E.T. the Extra-Terrestrial', 'Star Wars: Episode V', 'Back to the Future'], + answer: 'E.T. the Extra-Terrestrial', + }, + { + question: "Which movie features the song 'My Heart Will Go On'?", + options: ['The Bodyguard', 'Titanic', 'Romeo + Juliet'], + answer: 'Titanic', + }, + { + question: 'What was the first Pixar movie?', + options: ['Toy Story', "A Bug's Life", 'Monsters, Inc.'], + answer: 'Toy Story', + }, + { + question: 'Who played Wolverine in the X-Men movies?', + options: ['Hugh Jackman', 'Liam Hemsworth', 'Chris Evans'], + answer: 'Hugh Jackman', + }, + { + question: 'Which film did NOT win the Academy Award for Best Picture?', + options: ['The Shawshank Redemption', 'The Godfather', 'Forrest Gump'], + answer: 'The Shawshank Redemption', + }, + { + question: "What is Indiana Jones' real first name?", + options: ['Henry', 'John', 'Walter'], + answer: 'Henry', + }, + { + question: "In 'The Wizard of Oz', what did the Scarecrow want from the wizard?", + options: ['Heart', 'Brain', 'Courage'], + answer: 'Brain', + }, + { + question: 'Who is the only actor to receive an Oscar nomination for acting in a Lord of the Rings movie?', + options: ['Viggo Mortensen', 'Ian McKellen', 'Elijah Wood'], + answer: 'Ian McKellen', + }, + { + question: 'Which movie features an iconic dance scene between Uma Thurman and John Travolta?', + options: ['Pulp Fiction', 'Kill Bill', 'Saturday Night Fever'], + answer: 'Pulp Fiction', + }, + { + question: 'What is the highest-grossing R-rated movie of all time?', + options: ['Deadpool', 'Joker', 'The Matrix'], + answer: 'Joker', + }, + { + question: 'Which Alfred Hitchcock movie is notorious for its shower scene?', + options: ['Vertigo', 'Psycho', 'Rear Window'], + answer: 'Psycho', + }, + { + question: "What is Darth Vader's real name?", + options: ['Anakin Skywalker', 'Luke Skywalker', 'Obi-Wan Kenobi'], + answer: 'Anakin Skywalker', + }, + { + question: "Who directed 'Schindler's List'?", + options: ['Martin Scorsese', 'Steven Spielberg', 'Ridley Scott'], + answer: 'Steven Spielberg', + }, + { + question: 'In which movie does Tom Cruise perform his own stunts climbing the Burj Khalifa?', + options: ['Mission: Impossible - Rogue Nation', 'Mission: Impossible - Ghost Protocol', 'Edge of Tomorrow'], + answer: 'Mission: Impossible - Ghost Protocol', + }, + { + question: "What is the name of the fictional African country where 'Black Panther' is set?", + options: ['Wakanda', 'Genovia', 'Zamunda'], + answer: 'Wakanda', + }, + { + question: "Who directed 'Inception' and 'Interstellar'?", + options: ['Christopher Nolan', 'James Cameron', 'Steven Spielberg'], + answer: 'Christopher Nolan', + }, + { + question: "In 'The Hunger Games', what district do Katniss and Peeta represent?", + options: ['District 12', 'District 9', 'District 7'], + answer: 'District 12', + }, + { + question: 'Which movie features a character named Tyler Durden?', + options: ['Fight Club', 'Gone Girl', 'Seven'], + answer: 'Fight Club', + }, + { + question: "What is the name of the island in 'Jurassic Park'?", + options: ['Isla Nublar', 'Isla Sorna', 'Skull Island'], + answer: 'Isla Nublar', + }, + { + question: "Who played the Joker in 'The Dark Knight'?", + options: ['Heath Ledger', 'Joaquin Phoenix', 'Jared Leto'], + answer: 'Heath Ledger', + }, + { + question: 'In which movie is the fictional company Initech featured?', + options: ['Office Space', 'The Social Network', 'Wall Street'], + answer: 'Office Space', + }, + { + question: "What year was the first 'Harry Potter' movie released?", + options: ['2001', '2003', '1999'], + answer: '2001', + }, + { + question: "What fictional country is 'Wonder Woman' from?", + options: ['Themyscira', 'Asgard', 'Genovia'], + answer: 'Themyscira', + }, + { + question: "Which movie is known for the quote 'Here's looking at you, kid'?", + options: ['Casablanca', 'Gone with the Wind', 'The Maltese Falcon'], + answer: 'Casablanca', + }, + { + question: "In 'The Lion King', what is Simba's mother's name?", + options: ['Nala', 'Sarabi', 'Shenzi'], + answer: 'Sarabi', + }, + { + question: "Who directed 'Avengers: Endgame'?", + options: ['The Russo Brothers', 'Joss Whedon', 'Jon Favreau'], + answer: 'The Russo Brothers', + }, + { + question: "What is the name of the kingdom in 'Tangled'?", + options: ['Corona', 'Far Far Away', 'Arendelle'], + answer: 'Corona', + }, + { + question: 'Which film features a famous dance scene with Uma Thurman and John Travolta?', + options: ['Pulp Fiction', 'Saturday Night Fever', 'Kill Bill'], + answer: 'Pulp Fiction', + }, + { + question: "Who played Jack Dawson in 'Titanic'?", + options: ['Leonardo DiCaprio', 'Brad Pitt', 'Johnny Depp'], + answer: 'Leonardo DiCaprio', + }, + { + question: 'What is the highest-grossing film of all time?', + options: ['Avengers: Endgame', 'Avatar', 'Titanic'], + answer: 'Avatar', + }, + { + question: 'In which movie does the character Neo appear?', + options: ['The Matrix', 'John Wick', 'Speed'], + answer: 'The Matrix', + }, + { + question: 'What is the real name of the Black Panther in the Marvel Cinematic Universe?', + options: ["T'Challa", "M'Baku", "N'Jadaka"], + answer: "T'Challa", + }, + { + question: "Who directed 'Mad Max: Fury Road'?", + options: ['George Miller', 'Ridley Scott', 'Peter Jackson'], + answer: 'George Miller', + }, + { + question: "What animated film features a character named 'Hiccup'?", + options: ['Brave', 'How to Train Your Dragon', 'Shrek'], + answer: 'How to Train Your Dragon', + }, + { + question: "In which film is the fictional mineral 'Unobtainium' sought after?", + options: ['Avatar', 'The Core', 'Transformers'], + answer: 'Avatar', + }, + { + question: 'What is the name of the fictional city where the Batman movies take place?', + options: ['Gotham City', 'Metropolis', 'Star City'], + answer: 'Gotham City', + }, + { + question: "Who directed 'The Dark Knight'?", + options: ['Christopher Nolan', 'Martin Scorsese', 'Steven Spielberg'], + answer: 'Christopher Nolan', + }, + { + question: 'Who won the Best Actress award at the Oscars in 2021?', + options: ['Viola Davis', 'Frances McDormand', 'Carey Mulligan'], + answer: 'Frances McDormand', + }, + { + question: 'Which movie features a dystopian future divided into faction-based societies?', + options: ['The Hunger Games', 'Divergent', 'The Maze Runner'], + answer: 'Divergent', + }, + { + question: "What is the name of the spaceship in 'Alien' (1979)?", + options: ['Nostromo', 'Serenity', 'Millennium Falcon'], + answer: 'Nostromo', + }, + { + question: "Which director is known for the 'Dark Knight' trilogy?", + options: ['Christopher Nolan', 'Tim Burton', 'Joel Schumacher'], + answer: 'Christopher Nolan', + }, + { + question: "In 'The Terminator', what is the name of the company that created Skynet?", + options: ['Cyberdyne Systems', 'Wayland Industries', 'Oscorp'], + answer: 'Cyberdyne Systems', + }, + { + question: "What 1994 film revitalized John Travolta's career?", + options: ['Get Shorty', 'Pulp Fiction', 'Face/Off'], + answer: 'Pulp Fiction', + }, + { + question: 'Which movie was incorrectly announced as the Best Picture winner at the 2017 Academy Awards?', + options: ['La La Land', 'Moonlight', 'Manchester by the Sea'], + answer: 'La La Land', + }, + { + question: "What animated film was Disney's first ever full-length feature?", + options: ['Snow White and the Seven Dwarfs', 'Cinderella', 'The Little Mermaid'], + answer: 'Snow White and the Seven Dwarfs', + }, + { + question: "Who directed 'E.T. the Extra-Terrestrial'?", + options: ['Steven Spielberg', 'George Lucas', 'Ridley Scott'], + answer: 'Steven Spielberg', + }, + { + question: "Which film contains the quote, 'There's no place like home'?", + options: ['The Wizard of Oz', 'Gone with the Wind', 'Casablanca'], + answer: 'The Wizard of Oz', + }, + { + question: 'What is the highest grossing film of all time (not adjusted for inflation) as of 2023?', + options: ['Avengers: Endgame', 'Avatar', 'Titanic'], + answer: 'Avatar', + }, + { + question: "Who composed the score for 'The Lion King' (1994)?", + options: ['John Williams', 'Hans Zimmer', 'Alan Menken'], + answer: 'Hans Zimmer', + }, + { + question: 'Which movie did Leonardo DiCaprio win his first Oscar for Best Actor?', + options: ['The Revenant', 'The Wolf of Wall Street', 'Inception'], + answer: 'The Revenant', + }, + { + question: 'In which film does the character Maximus Decimus Meridius appear?', + options: ['300', 'Gladiator', 'Troy'], + answer: 'Gladiator', + }, + { + question: 'What is the name of the fictional British spy in the film series created by Ian Fleming?', + options: ['James Bond', 'Jason Bourne', 'Jack Ryan'], + answer: 'James Bond', + }, + { + question: 'Which movie won the Academy Award for Best Animated Feature in 2021?', + options: ['Onward', 'Soul', 'Wolfwalkers'], + answer: 'Soul', + }, + { + question: "Who played the role of Michael Corleone in 'The Godfather'?", + options: ['Al Pacino', 'Robert De Niro', 'Marlon Brando'], + answer: 'Al Pacino', + }, + { + question: 'What 2009 film is known for pioneering modern 3D cinema technology?', + options: ['Inception', 'Avatar', 'The Hurt Locker'], + answer: 'Avatar', + }, + { + question: 'Which 2012 film features a protagonist who survives a shipwreck with a tiger?', + options: ['Life of Pi', 'Cast Away', 'The Revenant'], + answer: 'Life of Pi', + }, + { + question: "What is the main theme of the movie 'Inception'?", + options: ['Time travel', 'Dream manipulation', 'Space exploration'], + answer: 'Dream manipulation', + }, + { + question: 'Which film features the character Sarah Connor, who is central to the plot?', + options: ['The Terminator', 'Aliens', 'Jurassic Park'], + answer: 'The Terminator', + }, + { + question: "What 1999 movie is famous for the quote, 'I see dead people'?", + options: ['The Sixth Sense', 'Ghost', 'The Others'], + answer: 'The Sixth Sense', + }, + { + question: "Who directed 'Titanic', which won the Academy Award for Best Picture in 1997?", + options: ['James Cameron', 'Steven Spielberg', 'Martin Scorsese'], + answer: 'James Cameron', + }, + { + question: 'Which film did NOT feature Leonardo DiCaprio?', + options: ['Titanic', 'The Great Gatsby', 'The Prestige'], + answer: 'The Prestige', + }, + { + question: "In which movie do characters compete in the 'Hunger Games'?", + options: ['Catching Fire', 'The Hunger Games', 'Battle Royale'], + answer: 'The Hunger Games', + }, + { + question: 'What film, released in 1982, features a character named E.T.?', + options: ['Star Wars', 'Close Encounters of the Third Kind', 'E.T. the Extra-Terrestrial'], + answer: 'E.T. the Extra-Terrestrial', + }, + { + question: "Who starred as the lead in the 2018 film 'Black Panther'?", + options: ['Chadwick Boseman', 'Michael B. Jordan', 'Denzel Washington'], + answer: 'Chadwick Boseman', + }, + { + question: "What iconic 1980s movie features the quote, 'Say hello to my little friend!'?", + options: ['Scarface', 'The Godfather', 'Goodfellas'], + answer: 'Scarface', + }, + { + question: 'Which film features a unique spinning top in its final scene?', + options: ['Inception', 'Minority Report', 'The Matrix'], + answer: 'Inception', + }, + { + question: 'What movie, featuring a journey to Mordor, won the Academy Award for Best Picture in 2003?', + options: [ + 'The Lord of the Rings: The Two Towers', + 'The Lord of the Rings: The Return of the King', + 'The Lord of the Rings: The Fellowship of the Ring', + ], + answer: 'The Lord of the Rings: The Return of the King', + }, + { + question: 'Which movie features a giant monster known as Godzilla?', + options: ['Pacific Rim', 'Godzilla', 'Cloverfield'], + answer: 'Godzilla', + }, + { + question: 'What classic film was remade in 2005 starring Naomi Watts and Jack Black?', + options: ['King Kong', 'Godzilla', 'Planet of the Apes'], + answer: 'King Kong', + }, + { + question: "Who directed the 1994 crime film 'Pulp Fiction'?", + options: ['Quentin Tarantino', 'Steven Spielberg', 'Martin Scorsese'], + answer: 'Quentin Tarantino', + }, + { + question: 'Which movie includes a character named Norman Bates?', + options: ['Psycho', 'Rebecca', 'The Birds'], + answer: 'Psycho', + }, + { + question: "What is the name of the fictional theme park in 'Jurassic Park'?", + options: ['Dinosaur Land', 'Jurassic World', 'Isla Nublar'], + answer: 'Isla Nublar', + }, + { + question: "Who played the role of Clarice Starling in the film 'The Silence of the Lambs'?", + options: ['Jodie Foster', 'Julianne Moore', 'Sigourney Weaver'], + answer: 'Jodie Foster', + }, + { + question: "Which film is famous for the line, 'May the Force be with you'?", + options: ['Star Trek', 'Star Wars', 'Guardians of the Galaxy'], + answer: 'Star Wars', + }, + { + question: 'What 1975 thriller is known for its menacing shark and famous soundtrack?', + options: ['Deep Blue Sea', 'Jaws', 'Sharknado'], + answer: 'Jaws', + }, + { + question: 'Which film did Tom Hanks win his first Academy Award for Best Actor?', + options: ['Big', 'Philadelphia', 'Forrest Gump'], + answer: 'Philadelphia', + }, + { + question: "What is the name of the ring in 'The Lord of the Rings'?", + options: ['The Ring of Power', 'The One Ring', 'The Master Ring'], + answer: 'The One Ring', + }, + { + question: "Who directed 'Avatar', the groundbreaking sci-fi movie released in 2009?", + options: ['James Cameron', 'George Lucas', 'Steven Spielberg'], + answer: 'James Cameron', + }, + { + question: 'Which 1988 animated film features a dystopian future and psychic powers?', + options: ['Ghost in the Shell', 'Akira', 'Blade Runner'], + answer: 'Akira', + }, + { + question: 'Who played the role of Hermione Granger in the Harry Potter films?', + options: ['Emma Watson', 'Emma Stone', 'Emily Blunt'], + answer: 'Emma Watson', + }, + { + question: "Which film features a group of friends who use a map to find a pirate's treasure?", + options: ['The Goonies', 'Treasure Island', 'Pirates of the Caribbean'], + answer: 'The Goonies', + }, + { + question: 'What was the first animated film to receive a Best Picture nomination at the Oscars?', + options: ['Beauty and the Beast', 'The Lion King', 'Up'], + answer: 'Beauty and the Beast', + }, + { + question: "What is the fictional sport played in the 'Harry Potter' series?", + options: ['Quidditch', 'Bludgers', 'Snitchball'], + answer: 'Quidditch', + }, + { + question: "Who composed the iconic score for 'Star Wars'?", + options: ['Hans Zimmer', 'John Williams', 'Danny Elfman'], + answer: 'John Williams', + }, + { + question: 'What 2000 film, directed by Ridley Scott, features a Roman general turned gladiator?', + options: ['Spartacus', 'Gladiator', 'Ben-Hur'], + answer: 'Gladiator', + }, + { + question: "Which movie's plot centers around a unique wooden board game?", + options: ['Clue', 'Jumanji', 'Zathura'], + answer: 'Jumanji', + }, + { + question: "Who directed the 1980 horror film 'The Shining'?", + options: ['Stanley Kubrick', 'Alfred Hitchcock', 'Stephen King'], + answer: 'Stanley Kubrick', + }, + { + question: 'What 1993 science fiction film directed by Steven Spielberg features dinosaurs brought back to life through cloning?', + options: ['Jurassic Park', 'The Lost World', 'Dinosaur'], + answer: 'Jurassic Park', + }, + { + question: "Who voiced the character of Woody in the 'Toy Story' movies?", + options: ['Tom Hanks', 'Tim Allen', 'Billy Crystal'], + answer: 'Tom Hanks', + }, + { + question: 'Which 2010 film directed by Christopher Nolan explores dream-sharing technology?', + options: ['Inception', 'Interstellar', 'Memento'], + answer: 'Inception', + }, + { + question: 'What film series features a secret British spy agency known as Kingsman?', + options: ['James Bond', 'Kingsman', 'Johnny English'], + answer: 'Kingsman', + }, + { + question: "Who played the role of Jack Sparrow in the 'Pirates of the Caribbean' film series?", + options: ['Johnny Depp', 'Orlando Bloom', 'Keira Knightley'], + answer: 'Johnny Depp', + }, + { + question: "Which 2001 film, based on a J.R.R. Tolkien novel, follows a hobbit's quest to destroy a powerful ring?", + options: ['The Hobbit', 'The Lord of the Rings: The Fellowship of the Ring', 'The Lord of the Rings: The Two Towers'], + answer: 'The Lord of the Rings: The Fellowship of the Ring', + }, + { + question: 'What 2003 animated film features a fish named Nemo?', + options: ['Shark Tale', 'Finding Nemo', 'The Little Mermaid'], + answer: 'Finding Nemo', + }, + { + question: 'Which 2017 film is based on a DC Comics character and set during World War I?', + options: ['Wonder Woman', 'Captain America: The First Avenger', 'Justice League'], + answer: 'Wonder Woman', + }, + { + question: "Who directed the 1994 film 'Pulp Fiction'?", + options: ['Quentin Tarantino', 'Martin Scorsese', 'Ridley Scott'], + answer: 'Quentin Tarantino', + }, + { + question: 'What movie introduced the character of Hannibal Lecter?', + options: ['Silence of the Lambs', 'Hannibal', 'Manhunter'], + answer: 'Manhunter', + }, + { + question: 'Which 2016 film tells the story of a group of rebels who plan to steal plans for the Death Star?', + options: ['Star Wars: The Force Awakens', 'Rogue One: A Star Wars Story', 'Star Wars: The Last Jedi'], + answer: 'Rogue One: A Star Wars Story', + }, + { + question: "What is the name of the fictional African kingdom in 'Coming to America'?", + options: ['Wakanda', 'Zamunda', 'Genovia'], + answer: 'Zamunda', + }, + { + question: "Who directed the 2017 movie 'Get Out'?", + options: ['Jordan Peele', 'Spike Lee', 'John Singleton'], + answer: 'Jordan Peele', + }, + { + question: 'Which movie features an AI character named HAL 9000?', + options: ['Blade Runner', 'Ex Machina', '2001: A Space Odyssey'], + answer: '2001: A Space Odyssey', + }, + { + question: "What 1980s movie is known for the quote 'Nobody puts Baby in a corner'?", + options: ['Dirty Dancing', 'Footloose', 'Flashdance'], + answer: 'Dirty Dancing', + }, + { + question: 'What 1995 film directed by Michael Mann stars Robert De Niro and Al Pacino?', + options: ['Heat', 'The Godfather', 'Scarface'], + answer: 'Heat', + }, + { + question: "Who starred as the titular character in the 2014 film 'Maleficent'?", + options: ['Angelina Jolie', 'Charlize Theron', 'Nicole Kidman'], + answer: 'Angelina Jolie', + }, + { + question: 'Which film is about a board game that becomes real for the players?', + options: ['Zathura', 'Jumanji', 'The Game'], + answer: 'Jumanji', + }, + { + question: 'In which movie does a group of archaeologists find a frozen prehistoric man?', + options: ['Encino Man', 'Ice Age', 'The Thing'], + answer: 'Encino Man', + }, + { + question: 'What movie features a theme park filled with cloned dinosaurs?', + options: ['Jurassic Park', 'Westworld', 'Prehistoric Park'], + answer: 'Jurassic Park', + }, +]; + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const form = document.getElementById('form'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +function generateRandomQuestions() { + const questionsToDisplay = 10; + const shuffledQuestions = questionBank.sort(() => 0.5 - Math.random()); + let selectedQuestions = shuffledQuestions.slice(0, questionsToDisplay); + + const quizContainer = document.getElementById('quiz-container'); + quizContainer.innerHTML = ''; + + selectedQuestions.forEach((question, index) => { + const questionElement = document.createElement('div'); + questionElement.innerHTML = ` +

Question ${index + 1}:

+

${question.question}

+ ${question.options.map((option, i) => `
`).join('')} +
`; + quizContainer.appendChild(questionElement); + + const headerElement = questionElement.querySelector(`h2`); + + headerElement.addEventListener('click', function (e) { + e.preventDefault(); + + headerElement.scrollIntoView({ behavior: 'smooth' }); + }); + + headerElement.addEventListener('mouseover', function () { + headerElement.style.color = 'orange'; + }); + + headerElement.addEventListener('mouseout', function () { + headerElement.style.color = '#ff8623'; + }); + + headerElement.style.cursor = 'pointer'; + }); +} + +document.getElementById('regenerate-questions').addEventListener('click', generateRandomQuestions); +generateRandomQuestions(); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('quiz-form').addEventListener('submit', function (event) { + event.preventDefault(); + + let answeredQuestions = 0; + + for (let i = 0; i < 10; i++) { + if (document.querySelector(`input[name="q${i}"]:checked`)) { + answeredQuestions++; + } + } + + if (answeredQuestions < 10) { + const confirmSubmit = confirm(`You have only answered ${answeredQuestions} questions. Are you sure you want to submit?`); + if (!confirmSubmit) { + return; + } + } + + calculateAndDisplayResults(); +}); + +function calculateAndDisplayResults() { + let score = 0; + const totalQuestions = 10; + + questionBank.forEach((question, index) => { + const selectedAnswer = document.querySelector(`input[name="q${index}"]:checked`); + if (selectedAnswer && selectedAnswer.value === question.answer) { + score++; + } + }); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || null; + + updateTriviaStats(currentUserEmail, score, totalQuestions); + + displayResults(score); +} + +function displayResults(score) { + let accuracy = (score / 10) * 100; + let progress = 0; + + document.getElementById('progress-circle').style.setProperty('--progress', `${progress}%`); + document.getElementById('correct-answers').textContent = score; + document.getElementById('result-text').textContent = `Your score is ${score} out of 10 (${accuracy.toFixed(1)}% accuracy)`; + + const interval = setInterval(() => { + if (progress < accuracy) { + progress++; + document.getElementById('progress-circle').style.setProperty('--progress', `${progress}%`); + } else { + clearInterval(interval); + } + }, 20); + + showModal(); +} + +function showModal() { + const modal = document.getElementById('result-modal'); + modal.style.display = 'block'; + + modal.querySelector('.close-button').addEventListener('click', function () { + modal.style.display = 'none'; + }); + + window.addEventListener('click', function (event) { + if (event.target == modal) { + modal.style.display = 'none'; + } + }); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/ratings-module.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/ratings-module.js new file mode 100644 index 00000000..80d4ec59 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/ratings-module.js @@ -0,0 +1,77 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +export async function loadUserRatings(currentUserEmail) { + if (currentUserEmail) { + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + return docSnap.exists() ? docSnap.data().ratings : {}; + } else { + return JSON.parse(localStorage.getItem('movieRatings')) || {}; + } +} + +export async function updateAverageMovieRating(currentUserEmail, movieId, newRating) { + if (!currentUserEmail) { + console.error('No user signed in, using localStorage to save ratings.'); + const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + savedRatings[movieId] = newRating; + localStorage.setItem('movieRatings', JSON.stringify(savedRatings)); + updateLocalAverage(savedRatings); + } else { + console.log('User signed in, saving ratings to Firebase.'); + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + let ratings = docSnap.exists() ? docSnap.data().ratings || {} : {}; + ratings[movieId] = newRating; + + await setDoc(ratingsRef, { ratings: ratings }, { merge: true }); + updateFirebaseAverage(ratings, ratingsRef); + updateLocalAverage(ratings); + } +} + +function updateLocalAverage(savedRatings) { + let totalRating = 0; + let totalMoviesRated = 0; + Object.values(savedRatings).forEach(rating => { + totalRating += parseFloat(rating); + totalMoviesRated++; + }); + const averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + localStorage.setItem('averageMovieRating', averageRating.toFixed(1)); +} + +async function updateFirebaseAverage(ratings, ratingsRef) { + let totalRating = 0; + let totalMoviesRated = 0; + Object.values(ratings).forEach(rating => { + totalRating += parseFloat(rating); + totalMoviesRated++; + }); + const averageRating = totalMoviesRated > 0 ? totalRating / totalMoviesRated : 0; + await setDoc(ratingsRef, { averageRating: averageRating }, { merge: true }); +} + +export async function getAverageMovieRating(currentUserEmail) { + if (!currentUserEmail) { + console.error('No user signed in, retrieving average rating from localStorage.'); + return localStorage.getItem('averageMovieRating') || 0; + } else { + const ratingsRef = doc(db, 'userRatings', currentUserEmail); + const docSnap = await getDoc(ratingsRef); + return docSnap.exists() && docSnap.data().averageRating ? docSnap.data().averageRating : 0; + } +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/reset-password.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/reset-password.js new file mode 100644 index 00000000..78e46da9 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/reset-password.js @@ -0,0 +1,128 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, query, where, getDocs, doc, updateDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('resetPasswordForm').addEventListener('submit', async function (event) { + try { + event.preventDefault(); + const resetEmail = document.getElementById('resetEmail').value; + + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', resetEmail)); + const querySnapshot = await getDocs(q); + + if (querySnapshot.empty) { + alert('No account with such credentials exists in our database, or you might have mistyped something. Please try again.'); + return; + } + + document.getElementById('newPasswordFields').style.display = 'block'; + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('password-reset-form-container'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +async function updatePassword() { + const resetEmail = document.getElementById('resetEmail').value; + const newPassword = document.getElementById('newPassword').value; + const confirmNewPassword = document.getElementById('confirmNewPassword').value; + + if (!isValidPassword(newPassword)) { + alert( + 'New password does not meet the security requirements.\n\n' + + 'Your password must include:\n' + + '- At least 8 characters\n' + + '- At least one uppercase letter\n' + + '- At least one lowercase letter\n' + + '- At least one number\n' + + '- At least one special character (e.g., !@#$%^&*)' + ); + return; + } + + if (newPassword !== confirmNewPassword) { + alert('Passwords do not match.'); + return; + } + + const q = query(collection(db, 'MovieVerseUsers'), where('email', '==', resetEmail)); + const querySnapshot = await getDocs(q); + + if (!querySnapshot.empty) { + querySnapshot.forEach(async docSnapshot => { + await updateDoc(doc(db, 'MovieVerseUsers', docSnapshot.id), { + password: newPassword, + }) + .then(() => { + alert('Password updated successfully!'); + window.location.href = 'sign-in.html'; + }) + .catch(error => { + console.log('Error updating password: ', error); + alert('Failed to update password. Please try again.'); + }); + }); + } else { + alert('Failed to find account. Please try again.'); + } +} + +document.getElementById('updatePasswordButton').addEventListener('click', updatePassword); + +function isValidPassword(password) { + const minLength = 8; + const hasUppercase = /[A-Z]/.test(password); + const hasLowercase = /[a-z]/.test(password); + const hasNumbers = /\d/.test(password); + const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password); + + return password.length >= minLength && hasUppercase && hasLowercase && hasNumbers && hasSpecialChar; +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/root-config.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/root-config.js new file mode 100644 index 00000000..b8083782 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/root-config.js @@ -0,0 +1,34 @@ +import { registerApplication, start } from 'single-spa'; + +// Defines a function that takes a location and returns true if the location should be active +function pathPrefix(prefix) { + return function (location) { + return location.pathname.startsWith(prefix); + }; +} + +// Load React Microfrontend for the homepage +registerApplication('home', () => System.import('http://localhost:8080/home.js'), pathPrefix('/home')); + +// Load React Microfrontend for the about page +registerApplication('about', () => System.import('http://localhost:8083/about.js'), pathPrefix('/about')); + +// Load React Microfrontend for the trivia page +registerApplication('quiz', () => System.import('http://localhost:8084/quiz.js'), pathPrefix('/contact')); + +// Load React Microfrontend for the favorites / watchlist page +registerApplication('favorites', () => System.import('http://localhost:8085/favorites.js'), pathPrefix('/favorites')); + +// Load React Microfrontend for the movie match page +registerApplication('movie-match', () => System.import('http://localhost:8086/movie-match.js'), pathPrefix('/movie-match')); + +// Load React Microfrontend for the movie timeline page +registerApplication('movie-timeline', () => System.import('http://localhost:8087/movie-timeline.js'), pathPrefix('/movie-details')); + +// Load Vue Microfrontend for the movie listing +registerApplication('movies', () => System.import('http://localhost:8081/movies.js'), pathPrefix('/movies')); + +// Load Vue Microfrontend for the navbar +registerApplication('navbar', () => System.import('http://localhost:8082/navbar.js'), pathPrefix('/navbar')); + +start(); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/router.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/router.js new file mode 100644 index 00000000..f78ed621 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/router.js @@ -0,0 +1,51 @@ +import Vue from 'vue'; +import Router from 'vue-router'; + +import HomePage from './components/HomePage.vue'; +import MovieDetails from './components/MovieDetails.vue'; +import AboutPage from './components/AboutPage.vue'; +import MovieMatch from './components/MovieMatch.vue'; +import MovieTimeline from './components/MovieTimeline.vue'; +import MovieOfTheDay from './components/MovieOfTheDay.vue'; + +Vue.use(Router); + +export default new Router({ + mode: 'history', + routes: [ + { + path: '/', + name: 'Home', + component: HomePage, + }, + { + path: '/movie/:id', + name: 'MovieDetails', + component: MovieDetails, + }, + { + path: '/about', + name: 'About', + component: AboutPage, + }, + { + path: '/movie-match', + name: 'MovieMatch', + component: MovieMatch, + }, + { + path: '/movie-timeline', + name: 'MovieTimeline', + component: MovieTimeline, + }, + { + path: '/movie-of-the-day', + name: 'MovieOfTheDay', + component: MovieOfTheDay, + }, + { + path: '*', // This wildcard route is for 404 Not Found pages + redirect: '/', + }, + ], +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/search.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/search.js new file mode 100644 index 00000000..ee46fb1b --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/search.js @@ -0,0 +1,1039 @@ +const form = document.getElementById('form1'); +const IMGPATH = 'https://image.tmdb.org/t/p/w500'; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + attachEventListeners(); + attachArrowKeyNavigation(); + + document.getElementById('form1').addEventListener('submit', function (event) { + event.preventDefault(); + handleSearch(); + }); +}); + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +document.addEventListener('DOMContentLoaded', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + attachEventListeners(); + attachArrowKeyNavigation(); + fetchGenreMap(); + fetchTvGenreMap(); + fetchLanguages(); + fetchTvLanguages(); + + document.getElementById('form1').addEventListener('submit', function (event) { + event.preventDefault(); + handleSearch(); + }); +}); + +async function fetchTvLanguages() { + const url = `https://${getMovieVerseData()}/3/configuration/languages?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + let languages = await response.json(); + languages = languages.sort((a, b) => a.english_name.localeCompare(b.english_name)); + populateTvLanguageFilter(languages); + } catch (error) { + console.log('Error fetching languages:', error); + } +} + +function populateTvLanguageFilter(languages) { + const languageFilter = document.getElementById('language-tv-filter'); + languageFilter.innerHTML = ''; + + languages.forEach(language => { + const option = document.createElement('option'); + option.value = language.iso_639_1; + option.textContent = language.english_name; + languageFilter.appendChild(option); + }); +} + +async function fetchLanguages() { + const url = `https://${getMovieVerseData()}/3/configuration/languages?${generateMovieNames()}${getMovieCode()}`; + + try { + const response = await fetch(url); + let languages = await response.json(); + languages = languages.sort((a, b) => a.english_name.localeCompare(b.english_name)); + populateLanguageFilter(languages); + } catch (error) { + console.log('Error fetching languages:', error); + } +} + +function populateLanguageFilter(languages) { + const languageFilter = document.getElementById('language-filter'); + languageFilter.innerHTML = ''; + + languages.forEach(language => { + const option = document.createElement('option'); + option.value = language.iso_639_1; + option.textContent = language.english_name; + languageFilter.appendChild(option); + }); +} + +async function fetchGenreMap() { + const code = getMovieCode(); + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${code}`; + + try { + const response = await fetch(url); + const data = await response.json(); + localStorage.setItem('genreMap', JSON.stringify(data.genres)); + populateGenreFilter(data.genres); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function fetchTvGenreMap() { + const code = getMovieCode(); + const url = `https://${getMovieVerseData()}/3/genre/tv/list?${generateMovieNames()}${code}`; + + try { + const response = await fetch(url); + const data = await response.json(); + localStorage.setItem('tvGenreMap', JSON.stringify(data.genres)); + populateTvGenreFilter(data.genres); + } catch (error) { + console.log('Error fetching TV genre map:', error); + } +} + +function populateGenreFilter(genres) { + const genreFilter = document.getElementById('genre-filter'); + genreFilter.innerHTML = ''; + + genres.forEach(genre => { + const option = document.createElement('option'); + option.value = genre.id; + option.textContent = genre.name; + genreFilter.appendChild(option); + }); +} + +function populateTvGenreFilter(genres) { + const genreFilter = document.getElementById('genre-tv-filter'); + genreFilter.innerHTML = ''; + + genres.forEach(genre => { + const option = document.createElement('option'); + option.value = genre.id; + option.textContent = genre.name; + genreFilter.appendChild(option); + }); +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let uniqueMoviesViewed = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + + if (!uniqueMoviesViewed.includes(movieId)) { + uniqueMoviesViewed.push(movieId); + } + + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem('uniqueMoviesViewed', JSON.stringify(uniqueMoviesViewed)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function attachEventListeners() { + const movieBtn = document.querySelector('[data-category="movie"]'); + const tvBtn = document.querySelector('[data-category="tv"]'); + const peopleBtn = document.querySelector('[data-category="person"]'); + const toggleFiltersBtn = document.getElementById('toggle-filters-btn'); + + const movieFilters = document.getElementById('movie-tv-filters'); + const tvFilters = document.getElementById('tv-filters'); + const peopleFilters = document.getElementById('people-filters'); + + const genreMovieFilter = document.getElementById('genre-filter'); + const yearMovieFilter = document.getElementById('year-filter'); + const ratingMovieFilter = document.getElementById('rating-filter'); + const languageFilter = document.getElementById('language-filter'); + + const genreTvFilter = document.getElementById('genre-tv-filter'); + const yearTvFilter = document.getElementById('year-tv-filter'); + const ratingTvFilter = document.getElementById('rating-tv-filter'); + const languageTvFilter = document.getElementById('language-tv-filter'); + + const professionFilter = document.getElementById('profession-filter'); + const genderFilter = document.getElementById('gender-filter'); + const popularityFilter = document.getElementById('popularity-filter'); + + const ratingValueSpan = document.getElementById('rating-value'); + const ratingTvValueSpan = document.getElementById('rating-tv-value'); + const popularityValueSpan = document.getElementById('popularity-value'); + + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + + function setFilterDisplayValues() { + ratingValueSpan.textContent = `Rating: ${ratingMovieFilter.value} and above`; + ratingTvValueSpan.textContent = `Rating: ${ratingTvFilter.value} and above`; + popularityValueSpan.textContent = `Popularity: ${popularityFilter.value} and above`; + } + + function showCorrectFilters(category) { + movieFilters.style.display = category === 'movie' ? 'block' : 'none'; + tvFilters.style.display = category === 'tv' ? 'block' : 'none'; + peopleFilters.style.display = category === 'person' ? 'block' : 'none'; + } + + movieBtn.addEventListener('click', () => { + showResults('movie'); + updateCategoryButtonStyles('movie'); + showCorrectFilters('movie'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + tvBtn.addEventListener('click', () => { + showResults('tv'); + updateCategoryButtonStyles('tv'); + showCorrectFilters('tv'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + peopleBtn.addEventListener('click', () => { + showResults('person'); + updateCategoryButtonStyles('person'); + showCorrectFilters('person'); + movieFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + }); + + toggleFiltersBtn.addEventListener('click', () => { + if (currentCategory === 'movie') { + movieFilters.style.display = movieFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'tv') { + tvFilters.style.display = tvFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'person') { + peopleFilters.style.display = peopleFilters.style.display === 'none' ? 'block' : 'none'; + } + }); + + genreMovieFilter.addEventListener('change', () => showResults('movie')); + yearMovieFilter.addEventListener('change', () => showResults('movie')); + ratingMovieFilter.addEventListener('input', () => { + ratingValueSpan.textContent = `Rating: ${ratingMovieFilter.value} and above`; + showResults('movie'); + }); + languageFilter.addEventListener('change', () => showResults('movie')); + + genreTvFilter.addEventListener('change', () => showResults('tv')); + yearTvFilter.addEventListener('change', () => showResults('tv')); + ratingTvFilter.addEventListener('input', () => { + ratingTvValueSpan.textContent = `Rating: ${ratingTvFilter.value} and above`; + showResults('tv'); + }); + languageTvFilter.addEventListener('change', () => showResults('tv')); + + genderFilter.addEventListener('change', () => showResults('person')); + professionFilter.addEventListener('change', () => showResults('person')); + popularityFilter.addEventListener('input', () => { + popularityValueSpan.textContent = `Popularity: ${popularityFilter.value} and above`; + showResults('person'); + }); + + const resetMovieFiltersBtn = movieFilters.querySelector('button[id="reset-filters"]'); + const resetTvFiltersBtn = tvFilters.querySelector('button[id="reset-filters"]'); + const resetPeopleFiltersBtn = peopleFilters.querySelector('button[id="reset-filters"]'); + + resetMovieFiltersBtn.addEventListener('click', () => { + genreMovieFilter.selectedIndex = 0; + yearMovieFilter.value = ''; + ratingMovieFilter.value = 5; + languageFilter.selectedIndex = 0; + setFilterDisplayValues(); + showResults('movie'); + }); + + resetTvFiltersBtn.addEventListener('click', () => { + genreTvFilter.selectedIndex = 0; + yearTvFilter.value = ''; + ratingTvFilter.value = 5; + languageTvFilter.selectedIndex = 0; + setFilterDisplayValues(); + showResults('tv'); + }); + + resetPeopleFiltersBtn.addEventListener('click', () => { + professionFilter.selectedIndex = 0; + genderFilter.selectedIndex = 0; + popularityFilter.value = 20; + setFilterDisplayValues(); + showResults('person'); + }); + + setFilterDisplayValues(); + showCorrectFilters(localStorage.getItem('selectedCategory')); +} + +let currentCategory = 'movie'; + +document.addEventListener('DOMContentLoaded', function () { + const toggleFiltersBtn = document.getElementById('toggle-filters-btn'); + const movieTvFilters = document.getElementById('movie-tv-filters'); + const peopleFilters = document.getElementById('people-filters'); + const tvFilters = document.getElementById('tv-filters'); + + movieTvFilters.style.display = 'none'; + peopleFilters.style.display = 'none'; + tvFilters.style.display = 'none'; + + toggleFiltersBtn.addEventListener('click', function () { + if (currentCategory === 'movie') { + movieTvFilters.style.display = movieTvFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'person') { + peopleFilters.style.display = peopleFilters.style.display === 'none' ? 'block' : 'none'; + } else if (currentCategory === 'tv') { + tvFilters.style.display = tvFilters.style.display === 'none' ? 'block' : 'none'; + } + + if (currentCategory === 'movie' && movieTvFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else if (currentCategory === 'person' && peopleFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else if (currentCategory === 'tv' && tvFilters.style.display !== 'none') { + toggleFiltersBtn.textContent = 'Close Filters'; + } else { + toggleFiltersBtn.textContent = 'Filter & Sort Results'; + } + }); + + document.getElementById('sort-movie').addEventListener('change', () => { + movieSortChanged = true; + showResults('movie'); + }); + + document.getElementById('sort-tv').addEventListener('change', () => { + tvSortChanged = true; + showResults('tv'); + }); + + document.getElementById('sort-people').addEventListener('change', () => { + peopleSortChanged = true; + showResults('person'); + }); + + document.querySelectorAll('.category-buttons button').forEach(button => { + button.addEventListener('click', function () { + currentCategory = this.getAttribute('data-category'); + }); + }); +}); + +let movieSortChanged = false; +let tvSortChanged = false; +let peopleSortChanged = false; + +function attachArrowKeyNavigation() { + const categories = ['movie', 'tv', 'person']; + let currentIndex = 0; + + document.addEventListener('keydown', e => { + switch (e.key) { + case 'ArrowRight': + currentIndex = (currentIndex + 1) % categories.length; + break; + case 'ArrowLeft': + currentIndex = (currentIndex - 1 + categories.length) % categories.length; + break; + default: + return; + } + const selectedCategory = categories[currentIndex]; + showResults(selectedCategory); + updateCategoryButtonStyles(selectedCategory); + e.preventDefault(); + }); +} + +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +function sortResults(results, sortBy) { + if (!sortBy) return results; + + const [property, order] = sortBy.split('.'); + results.sort((a, b) => { + let propA = property === 'release_date' || property === 'first_air_date' ? new Date(a[property]) : a[property]; + let propB = property === 'release_date' || property === 'first_air_date' ? new Date(b[property]) : b[property]; + + if (order === 'asc') { + return propA > propB ? 1 : propA < propB ? -1 : 0; + } else { + return propA < propB ? 1 : propA > propB ? -1 : 0; + } + }); + return results; +} + +async function showResults(category) { + showSpinner(); + localStorage.setItem('selectedCategory', category); + currentCategory = category; + + const searchQuery = localStorage.getItem('searchQuery') || ''; + document.getElementById('search-results-label').textContent = `Search Results for "${searchQuery}"`; + + const code = getMovieCode(); + const baseApiUrl = `https://${getMovieVerseData()}/3`; + let url = `${baseApiUrl}/search/${category}?${generateMovieNames()}${code}&query=${encodeURIComponent(searchQuery)}`; + let sortValue = ''; + + if (category === 'movie') { + sortValue = document.getElementById('sort-movie').value; + } else if (category === 'tv') { + sortValue = document.getElementById('sort-tv').value; + } else if (category === 'person') { + sortValue = document.getElementById('sort-people').value; + } + + try { + const response = await fetch(url); + let data = await response.json(); + + if (category === 'movie') { + const genre = document.getElementById('genre-filter').value; + const year = category === 'movie' ? document.getElementById('year-filter').value : document.getElementById('year-filter').value; + const rating = parseFloat(document.getElementById('rating-filter').value); + const language = document.getElementById('language-filter').value; + + data.results = data.results.filter(item => { + const itemYear = category === 'movie' ? item.release_date?.substring(0, 4) : item.first_air_date?.substring(0, 4); + const itemRating = item.vote_average; + const itemGenres = item.genre_ids; + const itemLanguage = item.original_language; + + return ( + (!genre || itemGenres.includes(parseInt(genre))) && + (!year || itemYear === year) && + (!rating || itemRating >= rating) && + (!language || itemLanguage === language) + ); + }); + } else if (category === 'person') { + const profession = document.getElementById('profession-filter').value; + const gender = document.getElementById('gender-filter').value; + + if (profession) { + data.results = data.results.filter( + person => person.known_for_department && person.known_for_department.toLowerCase() === profession.toLowerCase() + ); + } + + if (gender) { + data.results = data.results.filter(person => person.gender.toString() === gender); + } + + const popularity = parseFloat(document.getElementById('popularity-filter').value); + if (!isNaN(popularity) && popularity > 0) { + data.results = data.results.filter(person => person.popularity >= popularity); + } + + data.results.sort((a, b) => b.popularity - a.popularity); + + const personDetailsPromises = data.results.map(async person => { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${person.id}?${generateMovieNames()}${code}`; + const personResponse = await fetch(personDetailsUrl); + const personDetails = await personResponse.json(); + person.biography = personDetails.biography || 'Click to view the details of this person.'; + return person; + }); + + data.results = await Promise.all(personDetailsPromises); + } else if (category === 'tv') { + const genre = document.getElementById('genre-tv-filter').value; + const year = document.getElementById('year-tv-filter').value; + const rating = parseFloat(document.getElementById('rating-tv-filter').value); + const language = document.getElementById('language-tv-filter').value; + + data.results = data.results.filter(item => { + const itemYear = item.first_air_date?.substring(0, 4); + const itemRating = item.vote_average; + const itemGenres = item.genre_ids; + const itemLanguage = item.original_language; + + return ( + (!genre || itemGenres.includes(parseInt(genre))) && + (!year || itemYear === year) && + (!rating || itemRating >= rating) && + (!language || itemLanguage === language) + ); + }); + } + + if ((category === 'movie' && movieSortChanged) || (category === 'tv' && tvSortChanged) || (category === 'person' && peopleSortChanged)) { + data.results = sortResults(data.results, sortValue); + } + + displayResults(data.results, category, searchQuery); + } catch (error) { + console.log('Error fetching search results:', error); + } finally { + hideSpinner(); + } +} + +document.querySelector('button[onclick="showResults(\'movie\')"]').addEventListener('click', function () { + showResults('movie'); + localStorage.setItem('selectedCategory', 'movie'); + updateCategoryButtonStyles(); +}); + +document.querySelector('button[onclick="showResults(\'tv\')"]').addEventListener('click', function () { + showResults('tv'); + localStorage.setItem('selectedCategory', 'tv'); + updateCategoryButtonStyles(); +}); + +document.querySelector('button[onclick="showResults(\'person\')"]').addEventListener('click', function () { + showResults('person'); + localStorage.setItem('selectedCategory', 'person'); + updateCategoryButtonStyles(); +}); + +function updateCategoryButtonStyles(selectedCategory) { + const movieBtn = document.querySelector('[data-category="movie"]'); + const tvBtn = document.querySelector('[data-category="tv"]'); + const peopleBtn = document.querySelector('[data-category="person"]'); + + movieBtn.style.backgroundColor = ''; + tvBtn.style.backgroundColor = ''; + peopleBtn.style.backgroundColor = ''; + + if (selectedCategory === 'movie') { + movieBtn.style.backgroundColor = '#ff8623'; + } else if (selectedCategory === 'tv') { + tvBtn.style.backgroundColor = '#ff8623'; + } else if (selectedCategory === 'person') { + peopleBtn.style.backgroundColor = '#ff8623'; + } +} + +function displayResults(results, category, searchTerm) { + const container = document.getElementById('movie-match-container1'); + container.innerHTML = ''; + + const capitalizedCategory = category.charAt(0).toUpperCase() + category.slice(1); + + if (results.length === 0) { + container.innerHTML = `

No results found for "${searchTerm}" in the ${capitalizedCategory} category or no results with the specified filters found. Please try again with a different query or change your filters.

`; + container.style.height = '800px'; + return; + } + + showMovies(results, container, category); +} + +const main = document.getElementById('movie-match-container1'); + +async function getAdditionalImages(itemId, category) { + let endpoint; + if (category === 'movie') { + endpoint = `https://api.themoviedb.org/3/movie/${itemId}/images?api_key=${getMovieCode()}`; + } else if (category === 'person') { + endpoint = `https://api.themoviedb.org/3/person/${itemId}/images?api_key=${getMovieCode()}`; + } else if (category === 'tv') { + endpoint = `https://api.themoviedb.org/3/tv/${itemId}/images?api_key=${getMovieCode()}`; + } + + const response = await fetch(endpoint); + const data = await response.json(); + return data.profiles ? data.profiles.map(image => image.file_path) : data.posters.map(image => image.file_path); +} + +function rotateImages(imageElements, interval = 3000) { + if (imageElements.length <= 1) return; + + let currentIndex = 0; + imageElements[currentIndex].style.opacity = '1'; + + setTimeout(() => { + setInterval(() => { + imageElements[currentIndex].style.opacity = '0'; + currentIndex = (currentIndex + 1) % imageElements.length; + imageElements[currentIndex].style.opacity = '1'; + }, interval); + }, 0); +} + +async function showMovies(items, container, category) { + container.innerHTML = ''; + + items.forEach(async item => { + const hasVoteAverage = typeof item.vote_average === 'number'; + const isPerson = !hasVoteAverage; + const isMovie = item.title && hasVoteAverage; + const isTvSeries = item.name && hasVoteAverage && category === 'tv'; + + let title = item.title || item.name || 'N/A'; + const words = title.split(' '); + + if (words.length >= 8) { + words[7] = '...'; + title = words.slice(0, 8).join(' '); + } + + let overview = item.overview || 'Click to view the details of this movie/TV series.'; + const biography = item.biography || 'Click to view the details of this person.'; + + if (overview === '') { + overview = 'Click to view the details of this movie/TV series.'; + } + + const { id, profile_path, poster_path } = item; + const imagePath = profile_path || poster_path ? IMGPATH + (profile_path || poster_path) : null; + + const movieEl = document.createElement('div'); + movieEl.classList.add('movie'); + movieEl.style.zIndex = 10000; + + let movieContentHTML = `
`; + + if (imagePath) { + movieContentHTML += `
`; + movieContentHTML += `${title}`; + movieContentHTML += `
`; + } else { + movieContentHTML += `
Image Unavailable
`; + } + + movieContentHTML += `
`; + movieContentHTML += `

${title}

`; + + if ((isMovie || isTvSeries) && hasVoteAverage) { + const voteAverage = item.vote_average.toFixed(1); + movieContentHTML += `${voteAverage}`; + } + + movieContentHTML += `
`; + + if (isPerson) { + const roleOverview = item.known_for_department === 'Directing' ? 'Director Overview' : 'Actor Overview'; + movieContentHTML += `

${roleOverview}:

${biography}
`; + } else if (isTvSeries) { + movieContentHTML += `

TV Series Overview:

${overview}
`; + } else { + movieContentHTML += `

Movie Overview:

${overview}
`; + } + + movieEl.innerHTML = movieContentHTML; + + movieEl.addEventListener('click', async () => { + if (isPerson) { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + if (personDetails.known_for_department === 'Directing') { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + const uniqueDirectorsViewed = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + + if (!uniqueDirectorsViewed.includes(id)) { + uniqueDirectorsViewed.push(id); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(uniqueDirectorsViewed)); + } + + if (directorVisits[id]) { + directorVisits[id].count++; + } else { + directorVisits[id] = { + count: 1, + name: personDetails.name || 'Unknown', + }; + } + + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); + localStorage.setItem('selectedDirectorId', id); + window.location.href = 'director-details.html?' + id; + } else { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(id)) { + uniqueActorsViewed.push(id); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[id]) { + actorVisits[id].count++; + } else { + actorVisits[id] = { + count: 1, + name: personDetails.name || 'Unknown', + }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + localStorage.setItem('selectedActorId', id); + window.location.href = 'actor-details.html?' + id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else if (isMovie) { + localStorage.setItem('selectedMovieId', id); + window.location.href = 'movie-details.html?' + id; + updateMovieVisitCount(id, title); + } else if (isTvSeries) { + localStorage.setItem('selectedTvSeriesId', id); + window.location.href = 'tv-details.html?' + id; + updateMovieVisitCount(id, title); + } + }); + + container.appendChild(movieEl); + + const additionalImages = await getAdditionalImages(id, category); + let allImages = [profile_path || poster_path, ...additionalImages].filter(Boolean); + allImages = allImages.sort(() => 0.5 - Math.random()).slice(0, 10); + + if (allImages.length > 1) { + const imageContainer = movieEl.querySelector('.movie-images'); + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + observer.unobserve(img); + + // Load additional images once the first image is in view + allImages.forEach((image, index) => { + if (index === 0) return; + const img = new Image(); + img.src = `${IMGPATH + image}`; + img.style.position = 'absolute'; + img.style.top = 0; + img.style.left = 0; + img.style.width = '100%'; + img.style.height = '100%'; + img.style.transition = 'opacity 1s ease-in-out'; + img.style.opacity = 0; + imageContainer.appendChild(img); + }); + rotateImages(Array.from(imageContainer.children), 3000); + } + }); + }, + { + rootMargin: '50px 0px', + threshold: 0.1, + } + ); + + const img = movieEl.querySelector('img'); + observer.observe(img); + } + }); +} + +function handleDirectorClick(directorId, directorName) { + updateUniqueDirectorsViewed(directorId); + updateDirectorVisitCount(directorId, directorName); + localStorage.setItem('selectedDirectorId', directorId); + document.title = `${directorName} - Director's Details`; + window.location.href = 'director-details.html'; +} + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +function getClassByRate(vote) { + if (vote >= 8) { + return 'green'; + } else if (vote >= 5) { + return 'orange'; + } else { + return 'red'; + } +} + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.reload(); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?search_query=' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/service-worker.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/service-worker.js new file mode 100644 index 00000000..5fdc059d --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/service-worker.js @@ -0,0 +1,108 @@ +const CACHE_NAME = 'movieverse-cache-v1'; + +const urlsToCache = [ + '/index.html', + '/MovieVerse-Frontend/css/style.css', + '/MovieVerse-Frontend/css/trivia.css', + '/index.js', + '/manifest.json', + '/MovieVerse-Frontend/js/settings.js', + '/images/favicon.ico', + '/images/image.png', + '/MovieVerse-Frontend/js/chatbot.js', + '/MovieVerse-Frontend/js/movie-details.js', + '/MovieVerse-Frontend/js/movie-timeline.js', + '/MovieVerse-Frontend/js/quiz.js', + '/MovieVerse-Frontend/js/actor-details.js', + '/MovieVerse-Frontend/js/director-details.js', + '/MovieVerse-Frontend/html/about.html', + '/MovieVerse-Frontend/html/actor-details.html', + '/MovieVerse-Frontend/html/director-details.html', + '/MovieVerse-Frontend/html/movie-details.html', + '/MovieVerse-Frontend/html/movie-timeline.html', + '/MovieVerse-Frontend/html/notifications.html', + '/MovieVerse-Frontend/html/trivia.html', + '/MovieVerse-Frontend/html/settings.html', + '/MovieVerse-Frontend/html/favorites.html', + '/MovieVerse-Frontend/html/chat.html', + '/MovieVerse-Frontend/html/chatbot.html', + '/MovieVerse-Frontend/html/privacy-policy.html', + '/MovieVerse-Frontend/html/terms-of-service.html', + '/images/black.webp', + '/images/blue.webp', + '/images/brown.webp', + '/images/green.webp', + '/images/gold.webp', + '/images/grey.webp', + '/images/orange.webp', + '/images/pink.webp', + '/images/purple.webp', + '/images/red.webp', + '/images/rose.webp', + '/images/silver.webp', + '/images/universe.webp', + '/images/universe-1.webp', + '/images/universe-1-small.webp', + '/images/universe-1-medium.webp', + '/images/universe-22.webp', + '/images/universe-2.webp', + '/images/universe-23.webp', + '/images/universe-3.webp', + '/images/universe-4.webp', + '/images/universe-5.webp', + '/images/universe-6.webp', + '/images/universe-7.webp', + '/images/universe-8.webp', + '/images/universe-9.webp', + '/images/universe-10.webp', + '/images/universe-11.webp', + '/images/universe-12.webp', + '/images/universe-13.webp', + '/images/universe-14.webp', + '/images/universe-15.webp', + '/images/universe-16.webp', + '/images/universe-17.webp', + '/images/universe-18.webp', + '/images/universe-19.webp', + '/images/universe-20.webp', + '/images/universe-21.webp', + '/images/yellow.webp', + '/MovieVerse-Frontend/js/analytics.js', + '/MovieVerse-Frontend/html/analytics.html', + '/MovieVerse-Frontend/html/offline.html', +]; + +self.addEventListener('install', event => { + event.waitUntil( + caches.open(CACHE_NAME).then(cache => { + return cache.addAll(urlsToCache); + }) + ); +}); + +self.addEventListener('fetch', event => { + event.respondWith( + caches.match(event.request).then(response => { + if (response) { + return response; + } + return fetch(event.request) + .then(fetchResponse => { + return caches.open(CACHE_NAME).then(cache => { + cache.put(event.request, fetchResponse.clone()); + return fetchResponse; + }); + }) + .catch(() => caches.match('/MovieVerse-Frontend/html/offline.html')); + }) + ); +}); + +self.addEventListener('activate', event => { + const cacheWhitelist = [CACHE_NAME]; + event.waitUntil( + caches.keys().then(cacheNames => { + return Promise.all(cacheNames.filter(cacheName => !cacheWhitelist.includes(cacheName)).map(cacheName => caches.delete(cacheName))); + }) + ); +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/settings.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/settings.js new file mode 100644 index 00000000..d666801a --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/settings.js @@ -0,0 +1,397 @@ +const DEFAULT_BACKGROUND_IMAGE = '../../images/universe-1.webp'; + +document.addEventListener('DOMContentLoaded', () => { + const bgSelect = document.getElementById('background-select'); + const textColorInput = document.getElementById('text-color-input'); + const fontSizeSelect = document.getElementById('font-size-select'); + const resetButton = document.getElementById('reset-button'); + const deleteButton = document.getElementById('delete-uploaded-btn'); + const deleteImagesSection = document.getElementById('delete-images-section'); + const customImagesContainer = document.getElementById('custom-images-container'); + const deleteSelectedImagesBtn = document.getElementById('delete-selected-images-btn'); + + loadCustomBackgrounds(); + loadSettings(); + + if (bgSelect) { + bgSelect.addEventListener('change', function () { + document.body.style.backgroundImage = `url('${this.value}')`; + localStorage.setItem('backgroundImage', this.value); + window.location.reload(); + }); + } + + if (textColorInput) { + textColorInput.addEventListener('input', function () { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = this.value; + }); + localStorage.setItem('textColor', this.value); + }); + } + + if (fontSizeSelect) { + fontSizeSelect.addEventListener('change', function () { + const size = this.value === 'small' ? '12px' : this.value === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + localStorage.setItem('fontSize', this.value); + }); + } + + if (resetButton) { + resetButton.addEventListener('click', function () { + localStorage.removeItem('backgroundImage'); + localStorage.setItem('backgroundImage', '../../images/universe-1.webp'); + localStorage.removeItem('textColor'); + localStorage.removeItem('fontSize'); + window.location.reload(); + }); + } + + if (deleteButton) { + deleteButton.addEventListener('click', function () { + if (deleteImagesSection.style.display === 'block') { + deleteImagesSection.style.display = 'none'; + } else { + deleteImagesSection.style.display = 'block'; + updateCustomImagesDisplay(); + } + }); + } + + if (deleteSelectedImagesBtn) { + deleteSelectedImagesBtn.addEventListener('click', () => { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const selectedIndexes = Array.from(document.querySelectorAll('.delete-checkbox:checked')).map(checkbox => parseInt(checkbox.value)); + + const updatedImages = customImages.filter((_, index) => !selectedIndexes.includes(index)); + localStorage.setItem('customImages', JSON.stringify(updatedImages)); + + updateCustomImagesDisplay(); + updateBackgroundSelectOptions(); + alert('Selected images have been deleted.'); + window.location.reload(); + }); + } + + function updateCustomImagesDisplay() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + customImagesContainer.innerHTML = ''; + + if (customImages.length === 0) { + customImagesContainer.innerHTML = '

No custom images uploaded.

'; + deleteSelectedImagesBtn.style.display = 'none'; + return; + } + + customImages.forEach((image, index) => { + const imageContainer = document.createElement('div'); + imageContainer.classList.add('image-container'); + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.classList.add('delete-checkbox'); + checkbox.value = index; + + const img = document.createElement('img'); + img.src = image.dataURL; + img.alt = image.name; + img.style.width = '100px'; + + const imageName = document.createElement('span'); + imageName.classList.add('image-name'); + imageName.textContent = image.name; + + // Toggle checkbox when image container is clicked + imageContainer.addEventListener('click', e => { + if (e.target !== checkbox) { + // Prevent checkbox click event from toggling twice + checkbox.checked = !checkbox.checked; + } + }); + + imageContainer.appendChild(checkbox); + imageContainer.appendChild(img); + imageContainer.appendChild(imageName); + customImagesContainer.appendChild(imageContainer); + }); + + deleteSelectedImagesBtn.style.display = 'block'; + } + + function loadSettings() { + let savedBg = localStorage.getItem('backgroundImage'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (!savedBg) { + savedBg = DEFAULT_BACKGROUND_IMAGE; + } + + const availableBackgrounds = [ + '../../images/universe-1.webp', + '../../images/universe-2.webp', + '../../images/universe-22.webp', + '../../images/universe-3.webp', + '../../images/universe-4.webp', + '../../images/universe-5.webp', + '../../images/universe-6.webp', + '../../images/universe-7.webp', + '../../images/universe-8.webp', + '../../images/universe-9.webp', + '../../images/universe-10.webp', + '../../images/universe-11.webp', + '../../images/universe-12.webp', + '../../images/universe-13.webp', + '../../images/universe-14.webp', + '../../images/universe-15.webp', + '../../images/universe-16.webp', + '../../images/universe-17.webp', + '../../images/universe-18.webp', + '../../images/universe-19.webp', + '../../images/universe-20.webp', + '../../images/universe-21.webp', + '../../images/universe.webp', + '../../images/universe-23.webp', + '../../images/black.webp', + '../../images/grey.webp', + '../../images/blue.webp', + '../../images/silver.webp', + '../../images/gold.webp', + '../../images/rose.webp', + '../../images/pink.webp', + '../../images/red.webp', + '../../images/green.webp', + '../../images/brown.webp', + '../../images/purple.webp', + '../../images/orange.webp', + '../../images/yellow.webp', + ]; + + if (!availableBackgrounds.includes(savedBg) && !customImages.find(image => image.dataURL === savedBg)) { + savedBg = DEFAULT_BACKGROUND_IMAGE; + localStorage.setItem('backgroundImage', savedBg); + } + + if (savedBg) { + let imageUrl = savedBg; + if (savedBg === DEFAULT_BACKGROUND_IMAGE) { + if (window.innerWidth <= 680) { + imageUrl = '../../images/universe-1-small.webp'; + } else if (window.innerWidth <= 1124) { + imageUrl = '../../images/universe-1-medium.webp'; + } + } + document.body.style.backgroundImage = `url('${imageUrl}')`; + } + + const foundImage = customImages.find(image => image.dataURL === savedBg); + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + textColorInput.value = savedTextColor; + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + fontSizeSelect.value = savedFontSize; + } + + if (bgSelect) { + bgSelect.value = foundImage ? foundImage.dataURL : savedBg; + } + } + + function loadCustomBackgrounds() { + const bgSelect = document.getElementById('background-select'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + + if (bgSelect) { + customImages.forEach(image => { + const newOption = new Option(image.name, image.dataURL); + bgSelect.add(newOption); + }); + } + } +}); + +document.addEventListener('DOMContentLoaded', () => { + const uploadButton = document.getElementById('upload-bg-btn'); + + if (!uploadButton) { + console.log('Upload button not found'); + return; + } + + uploadButton.addEventListener('click', function () { + const fileInput = document.getElementById('custom-bg-upload'); + const imageNameInput = document.getElementById('custom-bg-name'); + const bgSelect = document.getElementById('background-select'); + + if (fileInput && fileInput.files.length > 0) { + const file = fileInput.files[0]; + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const totalSize = customImages.reduce((sum, img) => sum + img.dataURL.length, 0); + const quota = 4.5 * 1024 * 1024; // 4.5 MB + + if (totalSize >= quota) { + handleQuotaExceedance(); + window.location.reload(); + return; + } + + if (file.size > 204800) { + // 200 KB + resizeImage(file, 204800, (resizedDataUrl, err) => { + if (err) { + alert( + `Error resizing the image due to a limitation in your browser. Browser error: ${err.message} Your image might still appear as the background, but it will not be stable. We recommend deleting it and then using a different browser or uploading an image smaller than 1MB.` + ); + return; + } + processImageUpload(resizedDataUrl, imageNameInput, bgSelect); + alert('The uploaded image was resized to fit the size limit of 200KB.'); + window.location.reload(); + }); + } else { + const reader = new FileReader(); + reader.onload = function (e) { + processImageUpload(e.target.result, imageNameInput, bgSelect); + window.location.reload(); + }; + reader.onerror = function () { + alert('Error reading the file.'); + window.location.reload(); + }; + reader.readAsDataURL(file); + } + } else { + alert('Please select an image to upload.'); + } + }); +}); + +function handleQuotaExceedance() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + if (customImages.length > 0) { + alert('Your custom image storage has exceeded the quota. Please delete at least two images to continue.'); + + deleteImagesPrompt(); + } +} + +function deleteImagesPrompt() { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + if (customImages.length === 0) { + alert('No custom images to delete.'); + return; + } + + let message = 'Select images to delete:\n'; + customImages.forEach((image, index) => { + message += `${index + 1}. ${image.name}\n`; + }); + message += 'Enter the numbers of the images to delete (e.g., 1,3):'; + + const input = prompt(message); + if (input) { + const indexesToDelete = input.split(',').map(num => parseInt(num.trim()) - 1); + const updatedImages = customImages.filter((_, index) => !indexesToDelete.includes(index)); + localStorage.setItem('customImages', JSON.stringify(updatedImages)); + updateBackgroundSelectOptions(); + alert('Selected images have been deleted.'); + } +} + +function updateBackgroundSelectOptions() { + const bgSelect = document.getElementById('background-select'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + + Array.from(bgSelect.options).forEach(option => { + if (option.value.startsWith('data:image')) { + bgSelect.remove(option.index); + } + }); + + customImages.forEach(image => { + const newOption = new Option(image.name, image.dataURL); + bgSelect.add(newOption); + }); +} + +function processImageUpload(dataUrl, imageNameInput, bgSelect) { + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + let imageName = imageNameInput.value.trim(); + + if (!imageName) { + imageName = `User-Added Image ${customImages.length + 1}`; + } + + customImages.push({ name: imageName, dataURL: dataUrl }); + localStorage.setItem('customImages', JSON.stringify(customImages)); + + const newOption = new Option(imageName, dataUrl); + bgSelect.add(newOption); + bgSelect.value = dataUrl; + + document.body.style.backgroundImage = `url('${dataUrl}')`; + localStorage.setItem('backgroundImage', dataUrl); +} + +function resizeImage(file, maxSize, callback) { + if (!(window.FileReader && window.Blob && window.HTMLCanvasElement)) { + callback(null, new Error('Your browser does not support resizing images. Please use a different browser or upload an image smaller than 200KB.')); + return; + } + + const reader = new FileReader(); + reader.onload = function (e) { + const img = new Image(); + img.onload = function () { + try { + let canvas = document.createElement('canvas'); + let ctx = canvas.getContext('2d'); + + let width = img.width; + let height = img.height; + + if (width > height) { + if (width > maxSize) { + height *= maxSize / width; + width = maxSize; + } + } else { + if (height > maxSize) { + width *= maxSize / height; + height = maxSize; + } + } + + canvas.width = width; + canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + + callback(canvas.toDataURL('image/jpeg'), null); + + canvas.height = 0; + canvas.width = 0; + canvas = null; + } catch (error) { + callback(null, error); + } + }; + img.onerror = function () { + callback(null, new Error('Failed to load the image.')); + }; + img.src = e.target.result; + }; + reader.onerror = function () { + callback(null, new Error('Failed to read the image file.')); + }; + + reader.readAsDataURL(file); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/sign-in.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/sign-in.js new file mode 100644 index 00000000..024d4228 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/sign-in.js @@ -0,0 +1,80 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, collection, query, where, getDocs } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.getElementById('signInForm').addEventListener('submit', async function (event) { + event.preventDefault(); + + try { + const email = document.getElementById('signInEmail').value; + const password = document.getElementById('signInPassword').value; + + const usersRef = collection(db, 'MovieVerseUsers'); + const q = query(usersRef, where('email', '==', email), where('password', '==', password)); + const querySnapshot = await getDocs(q); + + if (!querySnapshot.empty) { + alert('Successfully signed in!'); + localStorage.setItem('isSignedIn', JSON.stringify(true)); + localStorage.setItem('currentlySignedInMovieVerseUser', email); + window.location.href = '../../index.html'; + } else { + alert('Invalid email or password. Ensure that you have entered a correct combination of email and password - one that we have on file.'); + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('signInForm'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } + } +}); + +document.getElementById('createAccountBtn').addEventListener('click', function () { + window.location.href = 'create-account.html'; +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/single-spa-config.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/single-spa-config.js new file mode 100644 index 00000000..96ed54cf --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/single-spa-config.js @@ -0,0 +1,16 @@ +import * as singleSpa from 'single-spa'; + +// Function to load microfrontends (apps) +function loadApp(name, path, activeWhen, customProps = {}) { + singleSpa.registerApplication(name, () => System.import(path), activeWhen, customProps); +} + +loadApp('navbar', '/navbar.js', () => true); + +loadApp('home', '/home.js', location => location.pathname === '' || location.pathname === '/'); + +loadApp('movie-details', '/movie-details.js', location => location.pathname.startsWith('/movie')); + +loadApp('about', '/about.js', location => location.pathname.startsWith('/about')); + +singleSpa.start(); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/systemjs-importmap.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/systemjs-importmap.js new file mode 100644 index 00000000..ea5553e9 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/systemjs-importmap.js @@ -0,0 +1,25 @@ +let System = (window.System = window.System || {}); +System.import('@system-env').then(env => { + env.production = true; + if (!env.production) { + let System = window.System; + System.importMap({ + imports: { + 'single-spa': 'https://unpkg.com/single-spa/lib/system/single-spa.dev.js', + 'movieverse-navbar': 'http://localhost:8500/movieverse-navbar.js', + 'movieverse-main-content': 'http://localhost:8501/movieverse-main-content.js', + 'movieverse-footer': 'http://localhost:8502/movieverse-footer.js', + }, + }); + } else { + let System = window.System; + System.importMap({ + imports: { + 'single-spa': 'https://unpkg.com/single-spa/lib/system/single-spa.min.js', + 'movieverse-navbar': 'https://your-production-url/movieverse-navbar.js', + 'movieverse-main-content': 'https://your-production-url/movieverse-main-content.js', + 'movieverse-footer': 'https://your-production-url/movieverse-footer.js', + }, + }); + } +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/terms-of-service.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/terms-of-service.js new file mode 100644 index 00000000..7f193db6 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/terms-of-service.js @@ -0,0 +1,814 @@ +document.getElementById('agreement').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('agreement').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('consent').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('consent').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading2').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading2').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading3').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading3').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading4').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading4').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading5').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading5').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading6').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading6').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading7').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading7').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading8').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading8').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading9').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading9').scrollIntoView({ behavior: 'smooth' }); +}); + +document.getElementById('subheading10').addEventListener('click', function (e) { + e.preventDefault(); + document.getElementById('subheading10').scrollIntoView({ behavior: 'smooth' }); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } + } + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function () { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function toggleNav() { + const sideNav = document.getElementById('side-nav'); + sideNav.classList.toggle('manual-toggle'); + adjustNavBar(); +} + +function removeNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + } + + adjustNavBar(); +} + +function adjustNavBar() { + const sideNav = document.getElementById('side-nav'); + if (sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0px'; + } else { + sideNav.style.left = '-250px'; + } +} + +document.addEventListener('mousemove', function (event) { + const sideNav = document.getElementById('side-nav'); + if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '0'; + } +}); + +document.getElementById('side-nav').addEventListener('mouseleave', function () { + const sideNav = document.getElementById('side-nav'); + if (!sideNav.classList.contains('manual-toggle')) { + sideNav.style.left = '-250px'; + } +}); + +document.addEventListener('click', function (event) { + const sideNav = document.getElementById('side-nav'); + const navToggle = document.getElementById('nav-toggle'); + if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { + sideNav.classList.remove('manual-toggle'); + adjustNavBar(); + } +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('search').addEventListener('input', function (e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log('Fetching error:', err)); + } else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function () { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function () { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } catch (error) { + console.log('Error fetching person details:', error); + } + } else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function () { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: 'nearest' }); + } else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: 'nearest' }); + } + } + + searchInput.addEventListener('keydown', function (e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.getElementById('settings-btn').addEventListener('click', () => { + window.location.href = 'settings.html'; +}); + +document.addEventListener('DOMContentLoaded', () => { + applySettings(); + + function applySettings() { + const defaultBg = '../../images/universe-1.webp'; + const savedBg = localStorage.getItem('backgroundImage') || defaultBg; + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedTextColor) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = savedTextColor; + }); + } + + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } + } +}); + +const movieCode1 = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +function getMovieCode() { + return atob(movieCode1.part1) + atob(movieCode1.part2) + atob(movieCode1.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +const form = document.getElementById('form1'); + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +window.addEventListener('load', function () { + adjustAnchorHeights(); +}); + +window.addEventListener('resize', adjustAnchorHeights); + +function adjustAnchorHeights() { + const bottomBarAnchors = document.querySelectorAll('.mobile-bottom-bar a'); + let maxHeight = 0; + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = 'auto'; + const anchorHeight = anchor.getBoundingClientRect().height; + maxHeight = Math.max(maxHeight, anchorHeight); + }); + + bottomBarAnchors.forEach(anchor => { + anchor.style.height = `${maxHeight}px`; + }); +} + +let lastScrollY = window.scrollY; + +window.addEventListener('scroll', () => { + const currentScrollY = window.scrollY; + + if (currentScrollY > lastScrollY && currentScrollY > 0) { + document.querySelector('.mobile-bottom-bar').classList.add('hide-bar'); + } else { + document.querySelector('.mobile-bottom-bar').classList.remove('hide-bar'); + } + + lastScrollY = currentScrollY; +}); + +let isAnimating = false; + +document.getElementById('menu-btn').addEventListener('click', () => { + if (isAnimating) return; + + isAnimating = true; + + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach((id, index) => { + const button = document.getElementById(id); + if (button.style.display === 'none' || !button.style.display) { + button.style.display = 'block'; + setTimeout(() => { + button.style.opacity = '1'; + button.style.transform = 'translateY(0)'; + }, 50 * index); + } else { + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + } + + setTimeout( + () => { + button.style.display = button.style.opacity === '1' ? 'block' : 'none'; + if (index === buttonIds.length - 1) { + isAnimating = false; + } + }, + 500 + 50 * index + ); + }); +}); + +window.addEventListener('resize', () => { + if (window.innerWidth < 767) { + const buttonIds = [ + 'chat-button', + 'settings-btn', + 'movie-of-the-day-btn', + 'movie-match-btn3', + 'movie-timeline-btn', + 'discussions-btn', + 'trivia-btn', + ]; + + buttonIds.forEach(id => { + const button = document.getElementById(id); + button.style.display = 'none'; + button.style.opacity = '0'; + button.style.transform = 'translateY(20px)'; + }); + } +}); diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/triviaModule.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/triviaModule.js new file mode 100644 index 00000000..e84a36b9 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/triviaModule.js @@ -0,0 +1,79 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { getFirestore, doc, setDoc, getDoc } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; + +const firebaseConfig = { + apiKey: atob('QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='), + authDomain: atob('bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'), + projectId: 'movieverse-app', + storageBucket: atob('bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='), + messagingSenderId: atob('ODAyOTQzNzE4ODcx'), + appId: atob('MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='), +}; + +const app = initializeApp(firebaseConfig); + +const db = getFirestore(app); + +export async function updateTriviaStats(currentUserEmail, correctAnswers, totalQuestions) { + if (!currentUserEmail) { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } else { + try { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + const docSnap = await getDoc(statsRef); + let triviaStats = docSnap.exists() ? docSnap.data() : { totalCorrect: 0, totalAttempted: 0 }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + await setDoc(statsRef, triviaStats, { merge: true }); + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } catch (error) { + if (error.code === 'resource-exhausted') { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } + } + } +} + +export async function getTriviaStats(currentUserEmail) { + if (!currentUserEmail) { + return ( + JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + } + ); + } else { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + try { + const docSnap = await getDoc(statsRef); + if (docSnap.exists()) { + return docSnap.data(); + } else { + console.log('No trivia stats found in Firebase for:', currentUserEmail); + return { totalCorrect: 0, totalAttempted: 0 }; + } + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded, fetching trivia stats from localStorage.'); + return ( + JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + } + ); + } + } + } +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/tv-details.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/tv-details.js new file mode 100644 index 00000000..fa47a025 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/tv-details.js @@ -0,0 +1,1609 @@ +const movieCode = { + part1: 'YzVhMjBjODY=', + part2: 'MWFjZjdiYjg=', + part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', +}; + +let currentIndex = sessionStorage.getItem('currentIndex') ? parseInt(sessionStorage.getItem('currentIndex')) : 0; + +function getMovieCode() { + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); +} + +function generateMovieNames(input) { + return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); +} + +const search = document.getElementById('search'); +const searchButton = document.getElementById('button-search'); +const form = document.getElementById('form1'); +const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; + +const main = document.getElementById('main'); +const IMGPATH = 'https://image.tmdb.org/t/p/w780'; +const searchTitle = document.getElementById('search-title'); +let initialMainContent; + +form.addEventListener('submit', e => { + e.preventDefault(); + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +}); + +function handleSearch() { + const searchQuery = document.getElementById('search').value; + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; +} + +async function ensureGenreMapIsAvailable() { + if (!localStorage.getItem('genreMap')) { + await fetchGenreMap(); + } +} + +async function fetchGenreMap() { + const url = `https://${getMovieVerseData()}/3/genre/movie/list?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const genreMap = data.genres.reduce((map, genre) => { + map[genre.id] = genre.name; + return map; + }, {}); + localStorage.setItem('genreMap', JSON.stringify(genreMap)); + } catch (error) { + console.log('Error fetching genre map:', error); + } +} + +async function rotateUserStats() { + await ensureGenreMapIsAvailable(); + + const stats = [ + { + label: 'Your Current Time', + getValue: () => { + const now = new Date(); + let hours = now.getHours(); + let minutes = now.getMinutes(); + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + return `${hours}:${minutes}`; + }, + }, + { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, + { label: 'Most Visited Director', getValue: getMostVisitedDirector }, + { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { + label: 'Movies Discovered', + getValue: () => { + const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + return viewedMovies.length; + }, + }, + { + label: 'Favorite Movies', + getValue: () => { + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + return favoritedMovies.length; + }, + }, + { + label: 'Favorite Genre', + getValue: () => { + const mostCommonGenreCode = getMostCommonGenre(); + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; + }, + }, + { + label: 'Watchlists Created', + getValue: () => localStorage.getItem('watchlistsCreated') || 0, + }, + { + label: 'Average Movie Rating', + getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + }, + { + label: 'Directors Discovered', + getValue: () => { + const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + return viewedDirectors.length; + }, + }, + { + label: 'Actors Discovered', + getValue: () => { + const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + return viewedActors.length; + }, + }, + { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + ]; + + let currentStatIndex = 0; + + function updateStatDisplay() { + const currentStat = stats[currentStatIndex]; + document.getElementById('stats-label').textContent = currentStat.label + ':'; + document.getElementById('stats-display').textContent = currentStat.getValue(); + currentStatIndex = (currentStatIndex + 1) % stats.length; + } + + updateStatDisplay(); + + const localTimeDiv = document.getElementById('local-time'); + let statRotationInterval = setInterval(updateStatDisplay, 3000); + + localTimeDiv.addEventListener('click', () => { + clearInterval(statRotationInterval); + updateStatDisplay(); + statRotationInterval = setInterval(updateStatDisplay, 3000); + localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + }); +} + +function updateMovieVisitCount(movieId, movieTitle) { + let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + + if (!movieVisits[movieId]) { + movieVisits[movieId] = { count: 0, title: movieTitle }; + } + movieVisits[movieId].count += 1; + localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); +} + +function getMostVisitedDirector() { + const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + let mostVisitedDirector = ''; + let maxVisits = 0; + + for (const directorId in directorVisits) { + if (directorVisits[directorId].count > maxVisits) { + mostVisitedDirector = directorVisits[directorId].name; + maxVisits = directorVisits[directorId].count; + } + } + + return mostVisitedDirector || 'Not Available'; +} + +function getMostVisitedMovie() { + const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let mostVisitedMovie = ''; + let maxVisits = 0; + + for (const movieId in movieVisits) { + if (movieVisits[movieId].count > maxVisits) { + mostVisitedMovie = movieVisits[movieId].title; + maxVisits = movieVisits[movieId].count; + } + } + + return mostVisitedMovie || 'Not Available'; +} + +function getMostVisitedActor() { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + let mostVisitedActor = ''; + let maxVisits = 0; + + for (const actorId in actorVisits) { + if (actorVisits[actorId].count > maxVisits) { + mostVisitedActor = actorVisits[actorId].name; + maxVisits = actorVisits[actorId].count; + } + } + + return mostVisitedActor || 'Not Available'; +} + +function getTriviaAccuracy() { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + totalCorrect: 0, + totalAttempted: 0, + }; + if (triviaStats.totalAttempted === 0) { + return 'No trivia attempted'; + } + + let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + return `${accuracy.toFixed(1)}% accuracy`; +} + +function getMostCommonGenre() { + const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const genreCounts = favoriteGenresArray.reduce((acc, genre) => { + acc[genre] = (acc[genre] || 0) + 1; + return acc; + }, {}); + + let mostCommonGenre = ''; + let maxCount = 0; + + for (const genre in genreCounts) { + if (genreCounts[genre] > maxCount) { + mostCommonGenre = genre; + maxCount = genreCounts[genre]; + } + } + + return mostCommonGenre || 'Not Available'; +} + +document.addEventListener('DOMContentLoaded', rotateUserStats); + +function setStarRating(rating) { + const stars = document.querySelectorAll('.rating .star'); + stars.forEach(star => { + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; + }); + + document.getElementById('rating-value').textContent = `${rating}.0/5.0`; +} + +function getMovieVerseData(input) { + return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); +} + +document.querySelectorAll('.rating .star').forEach(star => { + star.addEventListener('mouseover', e => { + setStarRating(e.target.dataset.value); + }); + + star.addEventListener('mouseout', () => { + const movieId = localStorage.getItem('selectedTvSeriesId'); + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + const movieRating = savedRatings[movieId] || 0; + setStarRating(movieRating); + }); + + star.addEventListener('click', e => { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + if (!tvSeriesId) return; + const rating = e.target.dataset.value; + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + savedRatings[tvSeriesId] = rating; + localStorage.setItem('tvSeriesRatings', JSON.stringify(savedRatings)); + setStarRating(rating); + window.location.reload(); + }); +}); + +document.getElementById('clear-search-btn').addEventListener('click', () => { + location.reload(); +}); + +function handleSignInOut() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + if (isSignedIn) { + localStorage.setItem('isSignedIn', JSON.stringify(false)); + alert('You have been signed out.'); + } else { + window.location.href = 'sign-in.html'; + return; + } + + updateSignInButtonState(); +} + +function updateSignInButtonState() { + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + + const signInText = document.getElementById('signInOutText'); + const signInIcon = document.getElementById('signInIcon'); + const signOutIcon = document.getElementById('signOutIcon'); + + if (isSignedIn) { + signInText.textContent = 'Sign Out'; + signInIcon.style.display = 'none'; + signOutIcon.style.display = 'inline-block'; + } else { + signInText.textContent = 'Sign In'; + signInIcon.style.display = 'inline-block'; + signOutIcon.style.display = 'none'; + } +} + +document.addEventListener('DOMContentLoaded', function () { + updateSignInButtonState(); + currentIndex = 0; + document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); +}); + +document.addEventListener('DOMContentLoaded', function () { + applySettings(); +}); + +const tvCode = `${getMovieCode()}`; + +const twoLetterLangCodes = [ + { code: 'aa', name: 'Afar' }, + { code: 'ab', name: 'Abkhazian' }, + { code: 'ae', name: 'Avestan' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'ak', name: 'Akan' }, + { code: 'am', name: 'Amharic' }, + { code: 'an', name: 'Aragonese' }, + { code: 'ar', name: 'Arabic' }, + { code: 'as', name: 'Assamese' }, + { code: 'av', name: 'Avaric' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'ba', name: 'Bashkir' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'bh', name: 'Bihari languages' }, + { code: 'bi', name: 'Bislama' }, + { code: 'bm', name: 'Bambara' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bo', name: 'Tibetan' }, + { code: 'br', name: 'Breton' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'ca', name: 'Catalan; Valencian' }, + { code: 'ce', name: 'Chechen' }, + { code: 'ch', name: 'Chamorro' }, + { code: 'co', name: 'Corsican' }, + { code: 'cr', name: 'Cree' }, + { code: 'cs', name: 'Czech' }, + { + code: 'cu', + name: 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', + }, + { code: 'cv', name: 'Chuvash' }, + { code: 'cy', name: 'Welsh' }, + { code: 'da', name: 'Danish' }, + { code: 'de', name: 'German' }, + { code: 'dv', name: 'Divehi; Dhivehi; Maldivian' }, + { code: 'dz', name: 'Dzongkha' }, + { code: 'ee', name: 'Ewe' }, + { code: 'el', name: 'Greek, Modern (1453-)' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'es', name: 'Spanish; Castilian' }, + { code: 'et', name: 'Estonian' }, + { code: 'eu', name: 'Basque' }, + { code: 'fa', name: 'Persian' }, + { code: 'ff', name: 'Fulah' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fj', name: 'Fijian' }, + { code: 'fo', name: 'Faroese' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Western Frisian' }, + { code: 'ga', name: 'Irish' }, + { code: 'gd', name: 'Gaelic; Scomttish Gaelic' }, + { code: 'gl', name: 'Galician' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'gv', name: 'Manx' }, + { code: 'ha', name: 'Hausa' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'ho', name: 'Hiri Motu' }, + { code: 'hr', name: 'Croatian' }, + { code: 'ht', name: 'Haitian; Haitian Creole' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'hy', name: 'Armenian' }, + { code: 'hz', name: 'Herero' }, + { + code: 'ia', + name: 'Interlingua (International Auxiliary Language Association)', + }, + { code: 'id', name: 'Indonesian' }, + { code: 'ie', name: 'Interlingue; Occidental' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ii', name: 'Sichuan Yi; Nuosu' }, + { code: 'ik', name: 'Inupiaq' }, + { code: 'io', name: 'Ido' }, + { code: 'is', name: 'Icelandic' }, + { code: 'it', name: 'Italian' }, + { code: 'iu', name: 'Inuktitut' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'ka', name: 'Georgian' }, + { code: 'kg', name: 'Kongo' }, + { code: 'ki', name: 'Kikuyu; Gikuyu' }, + { code: 'kj', name: 'Kuanyama; Kwanyama' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'kl', name: 'Kalaallisut; Greenlandic' }, + { code: 'km', name: 'Central Khmer' }, + { code: 'kn', name: 'Kannada' }, + { code: 'ko', name: 'Korean' }, + { code: 'kr', name: 'Kanuri' }, + { code: 'ks', name: 'Kashmiri' }, + { code: 'ku', name: 'Kurdish' }, + { code: 'kv', name: 'Komi' }, + { code: 'kw', name: 'Cornish' }, + { code: 'ky', name: 'Kirghiz; Kyrgyz' }, + { code: 'la', name: 'Latin' }, + { code: 'lb', name: 'Luxembourgish; Letzeburgesch' }, + { code: 'lg', name: 'Ganda' }, + { code: 'li', name: 'Limburgan; Limburger; Limburgish' }, + { code: 'ln', name: 'Lingala' }, + { code: 'lo', name: 'Lao' }, + { code: 'lt', name: 'Lithuanian' }, + { code: 'lu', name: 'Luba-Katanga' }, + { code: 'lv', name: 'Latvian' }, + { code: 'mg', name: 'Malagasy' }, + { code: 'mh', name: 'Marshallese' }, + { code: 'mi', name: 'Maori' }, + { code: 'mk', name: 'Macedonian' }, + { code: 'ml', name: 'Malayalam' }, + { code: 'mn', name: 'Mongolian' }, + { code: 'mr', name: 'Marathi' }, + { code: 'ms', name: 'Malay' }, + { code: 'mt', name: 'Maltese' }, + { code: 'my', name: 'Burmese' }, + { code: 'na', name: 'Nauru' }, + { + code: 'nb', + name: 'Bokmål, Norwegian; Norwegian Bokmål', + }, + { code: 'nd', name: 'Ndebele, North; North Ndebele' }, + { code: 'ne', name: 'Nepali' }, + { code: 'ng', name: 'Ndonga' }, + { code: 'nl', name: 'Dutch; Flemish' }, + { code: 'nn', name: 'Norwegian Nynorsk; Nynorsk, Norwegian' }, + { code: 'no', name: 'Norwegian' }, + { code: 'nr', name: 'Ndebele, South; South Ndebele' }, + { code: 'nv', name: 'Navajo; Navaho' }, + { code: 'ny', name: 'Chichewa; Chewa; Nyanja' }, + { code: 'oc', name: 'Occitan (post 1500)' }, + { code: 'oj', name: 'Ojibwa' }, + { code: 'om', name: 'Oromo' }, + { code: 'or', name: 'Oriya' }, + { code: 'os', name: 'Ossetian; Ossetic' }, + { code: 'pa', name: 'Panjabi; Punjabi' }, + { code: 'pi', name: 'Pali' }, + { code: 'pl', name: 'Polish' }, + { code: 'ps', name: 'Pushto; Pashto' }, + { code: 'pt', name: 'Portuguese' }, + { code: 'qu', name: 'Quechua' }, + { code: 'rm', name: 'Romansh' }, + { code: 'rn', name: 'Rundi' }, + { code: 'ro', name: 'Romanian; Moldavian; Moldovan' }, + { code: 'ru', name: 'Russian' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'sa', name: 'Sanskrit' }, + { code: 'sc', name: 'Sardinian' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'se', name: 'Northern Sami' }, + { code: 'sg', name: 'Sango' }, + { code: 'si', name: 'Sinhala; Sinhalese' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'sm', name: 'Samoan' }, + { code: 'sn', name: 'Shona' }, + { code: 'so', name: 'Somali' }, + { code: 'sq', name: 'Albanian' }, + { code: 'sr', name: 'Serbian' }, + { code: 'ss', name: 'Swati' }, + { code: 'st', name: 'Sotho, Southern' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sv', name: 'Swedish' }, + { code: 'sw', name: 'Swahili' }, + { code: 'ta', name: 'Tamil' }, + { code: 'te', name: 'Telugu' }, + { code: 'tg', name: 'Tajik' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'tl', name: 'Tagalog' }, + { code: 'tn', name: 'Tswana' }, + { code: 'to', name: 'Tonga (Tonga Islands)' }, + { code: 'tr', name: 'Turkish' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tt', name: 'Tatar' }, + { code: 'tw', name: 'Twi' }, + { code: 'ty', name: 'Tahitian' }, + { code: 'ug', name: 'Uighur; Uyghur' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'uz', name: 'Uzbek' }, + { code: 've', name: 'Venda' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'vo', name: 'Volapük' }, + { code: 'wa', name: 'Walloon' }, + { code: 'wo', name: 'Wolof' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'za', name: 'Zhuang; Chuang' }, + { code: 'zh', name: 'Chinese' }, + { code: 'zu', name: 'Zulu' }, +]; + +async function fetchTvDetails(tvSeriesId) { + showSpinner(); + const baseUrl = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}`; + const urlWithAppend = `${baseUrl}?${generateMovieNames()}${tvCode}&append_to_response=credits,keywords,similar,videos,external_ids`; + + try { + const tvDetailsPromise = fetch(urlWithAppend).then(response => { + if (!response.ok) throw new Error('Failed to fetch TV series details'); + return response.json(); + }); + + const tvSeriesDetails = await tvDetailsPromise; + const imdbId = tvSeriesDetails.external_ids.imdb_id; + + if (imdbId) { + const imdbRatingPromise = fetchTVRatings(imdbId); + const imdbRating = await imdbRatingPromise; + populateTvSeriesDetails(tvSeriesDetails, imdbRating); + } else { + populateTvSeriesDetails(tvSeriesDetails, 'IMDb rating'); + } + + updateBrowserURL(tvSeriesDetails.name); + } catch (error) { + document.getElementById('movie-details-container').innerHTML = ` +
+

TV series details currently unavailable - please try again

+
`; + console.log('Error fetching TV series details:', error); + } finally { + hideSpinner(); + } +} + +async function fetchTVRatings(imdbId) { + showSpinner(); + + if (!imdbId) { + return 'IMDb rating'; + } + + const apiKeys = [await getMovieCode2(), '58efe859', '60a09d79', '956e468a', 'bd55ada4', 'cbfc076', 'dc091ff2', '6e367eef', '2a2a3080', 'd20a931f']; + + const baseURL = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}`; + + async function tryFetch(apiKey, timeout = 5000) { + const url = `${baseURL}${apiKey}`; + return new Promise(resolve => { + const timer = setTimeout(() => resolve(null), timeout); + fetch(url) + .then(response => { + if (!response.ok) throw new Error('API limit reached or other error'); + return response.json(); + }) + .then(data => { + clearTimeout(timer); + if (!data || data.Error) throw new Error('Data fetch error'); + resolve(data); + }) + .catch(() => { + clearTimeout(timer); + resolve(null); + }); + }); + } + + const requests = apiKeys.map(key => tryFetch(key)); + const responses = await Promise.all(requests); + const data = responses.find(response => response !== null); + + hideSpinner(); + return data && data.imdbRating ? data.imdbRating : 'View on IMDb'; +} + +function getLanguageName(code) { + const language = twoLetterLangCodes.find(lang => lang.code === code); + return language ? language.name : 'Unknown Language'; +} + +function getCountryName(code) { + const regionNames = new Intl.DisplayNames(['en'], { type: 'region' }); + return regionNames.of(code); +} + +async function populateTvSeriesDetails(tvSeries, imdbRating) { + const title = tvSeries.name || 'Title not available'; + document.getElementById('movie-title').textContent = title; + document.title = tvSeries.name + ' - TV Series Details'; + + const posterPath = `https://image.tmdb.org/t/p/w780${tvSeries.poster_path}`; + if (tvSeries.poster_path) { + document.getElementById('movie-image').src = posterPath; + document.getElementById('movie-image').alt = `Poster of ${title}`; + } else { + const noImageTitle = document.createElement('h2'); + noImageTitle.textContent = 'TV Show Image Not Available'; + noImageTitle.style.textAlign = 'center'; + document.getElementById('movie-image').replaceWith(noImageTitle); + } + + let detailsHTML = `

Overview: ${tvSeries.overview || 'Overview not available.'}

`; + + detailsHTML += `

Original Title: ${tvSeries.original_name || 'Not available'}

`; + + detailsHTML += `

Tagline: ${tvSeries.tagline || 'Not available'}

`; + + const genres = tvSeries.genres && tvSeries.genres.length ? tvSeries.genres.map(genre => genre.name).join(', ') : 'Genres not available'; + detailsHTML += `

Genres: ${genres}

`; + + detailsHTML += `

First Air Date: ${tvSeries.first_air_date || 'Not available'}

`; + + detailsHTML += `

Last Air Date: ${tvSeries.last_air_date || 'Not available'}

`; + + detailsHTML += `

Status: ${tvSeries.status || 'Not available'}

`; + + const type = tvSeries.type || 'Not available'; + detailsHTML += `

Type: ${type}

`; + + const networks = + tvSeries.networks && tvSeries.networks.length ? tvSeries.networks.map(network => network.name).join(', ') : 'Information not available'; + detailsHTML += `

Networks: ${networks}

`; + + const voteAverage = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + const voteCount = tvSeries.vote_count ? tvSeries.vote_count.toLocaleString() : 'N/A'; + detailsHTML += `

MovieVerse User Rating: ${( + voteAverage / 2 + ).toFixed(1)}/5.0 (based on ${voteCount} votes)

`; + + if (tvSeries.external_ids && tvSeries.external_ids.imdb_id) { + const imdbId = tvSeries.external_ids.imdb_id; + const imdbUrl = `https://www.imdb.com/title/${imdbId}/`; + detailsHTML += `

IMDb Rating: ${imdbRating}

`; + } else { + detailsHTML += `

IMDb Rating: IMDb rating not available

`; + } + + let tmdbRating = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + if (tmdbRating === 'N/A') { + detailsHTML += `

TMDB Rating: ${tmdbRating}

`; + } else { + detailsHTML += `

TMDB Rating: ${tmdbRating}/10.0

`; + } + + const homepage = tvSeries.homepage ? `Visit homepage` : 'Not available'; + detailsHTML += `

Homepage: ${homepage}

`; + + if (tvSeries.origin_country && tvSeries.origin_country.length > 0) { + const countryNames = tvSeries.origin_country.map(code => getCountryName(code)).join(', '); + detailsHTML += `

Country of Origin: ${countryNames}

`; + } else { + detailsHTML += `

Country of Origin: Information not available

`; + } + + const languageName = getLanguageName(tvSeries.original_language); + detailsHTML += `

Original Language: ${languageName}

`; + + const productionCountries = + tvSeries.production_countries && tvSeries.production_countries.length > 0 + ? tvSeries.production_countries.map(country => getCountryName(country.iso_3166_1)).join(', ') + : 'Information not available'; + detailsHTML += `

Production Countries: ${productionCountries}

`; + + detailsHTML += `

Seasons: ${tvSeries.number_of_seasons || 0}, Episodes: ${tvSeries.number_of_episodes || 0}

`; + + if (tvSeries.last_episode_to_air) { + const lastEpisode = tvSeries.last_episode_to_air; + + detailsHTML += `
+ Last Episode: ${lastEpisode.name || 'Title not available'} - ${ + lastEpisode.overview || 'Overview not available.' + } +
`; + + if (lastEpisode.still_path) { + detailsHTML += `
+ ${
+                                  lastEpisode.name
+                                } Still Image +
`; + } + } + + if (tvSeries.created_by && tvSeries.created_by.length > 0) { + const creatorsSection = document.createElement('div'); + creatorsSection.classList.add('creators-section'); + + const creatorsTitle = document.createElement('p'); + creatorsTitle.innerHTML = 'Creators:'; + creatorsSection.appendChild(creatorsTitle); + + const creatorsList = document.createElement('div'); + creatorsList.classList.add('creators-list'); + creatorsList.style.display = 'flex'; + creatorsList.style.flexWrap = 'wrap'; + creatorsList.style.justifyContent = 'center'; + creatorsList.style.gap = '2px'; + + tvSeries.created_by.forEach(creator => { + const creatorLink = document.createElement('a'); + creatorLink.classList.add('creator-link'); + creatorLink.href = 'javascript:void(0);'; + creatorLink.setAttribute('onclick', `handleCreatorClick(${creator.id}, '${creator.name.replace(/'/g, "\\'")}');`); + + const creatorItem = document.createElement('div'); + creatorItem.classList.add('creator-item'); + + const creatorImage = document.createElement('img'); + creatorImage.classList.add('creator-image'); + + if (creator.profile_path) { + creatorImage.src = IMGPATH + creator.profile_path; + creatorImage.alt = `${creator.name} Profile Picture`; + } else { + creatorImage.alt = 'Image Not Available'; + creatorImage.style.objectFit = 'cover'; + creatorImage.src = 'https://movie-verse.com/images/user-default.png'; + creatorImage.style.filter = 'grayscale(100%)'; + } + + creatorItem.appendChild(creatorImage); + + const creatorDetails = document.createElement('div'); + creatorDetails.classList.add('creator-details'); + + const creatorName = document.createElement('p'); + creatorName.classList.add('creator-name'); + creatorName.textContent = creator.name; + creatorDetails.appendChild(creatorName); + + creatorItem.appendChild(creatorDetails); + creatorLink.appendChild(creatorItem); + creatorsList.appendChild(creatorLink); + }); + + creatorsSection.appendChild(creatorsList); + detailsHTML += creatorsSection.outerHTML; + } else { + const noCreatorsElement = document.createElement('p'); + noCreatorsElement.innerHTML = `Creators: Information not available`; + detailsHTML += noCreatorsElement.outerHTML; + } + + if (tvSeries.credits && tvSeries.credits.cast && tvSeries.credits.cast.length > 0) { + const castSection = document.createElement('div'); + castSection.classList.add('cast-section'); + + const castTitle = document.createElement('p'); + castTitle.innerHTML = 'Notable Cast:'; + castSection.appendChild(castTitle); + + const castList = document.createElement('div'); + castList.classList.add('cast-list'); + castList.style.display = 'flex'; + castList.style.flexWrap = 'wrap'; + castList.style.justifyContent = 'center'; + castList.style.gap = '2px'; + + tvSeries.credits.cast.slice(0, 12).forEach(castMember => { + const castMemberLink = document.createElement('a'); + castMemberLink.classList.add('cast-member-link'); + castMemberLink.href = 'javascript:void(0);'; + castMemberLink.setAttribute('onclick', `selectActorId(${castMember.id}, '${castMember.name.replace(/'/g, "\\'")}');`); + + const castMemberItem = document.createElement('div'); + castMemberItem.classList.add('cast-member-item'); + + const castMemberImage = document.createElement('img'); + castMemberImage.classList.add('cast-member-image'); + + if (castMember.profile_path) { + castMemberImage.src = IMGPATH + castMember.profile_path; + castMemberImage.alt = `${castMember.name} Profile Picture`; + } else { + castMemberImage.alt = 'Image Not Available'; + castMemberImage.style.objectFit = 'cover'; + castMemberImage.src = 'https://movie-verse.com/images/user-default.png'; + castMemberImage.style.filter = 'grayscale(100%)'; + } + + castMemberItem.appendChild(castMemberImage); + + const castMemberDetails = document.createElement('div'); + castMemberDetails.classList.add('cast-member-details'); + + const castMemberName = document.createElement('p'); + castMemberName.classList.add('cast-member-name'); + castMemberName.textContent = castMember.name; + castMemberDetails.appendChild(castMemberName); + + const castMemberRole = document.createElement('p'); + castMemberRole.classList.add('cast-member-role'); + castMemberRole.textContent = castMember.character ? `(as ${castMember.character})` : ''; + castMemberRole.style.fontStyle = 'italic'; + castMemberDetails.appendChild(castMemberRole); + + castMemberItem.appendChild(castMemberDetails); + castMemberLink.appendChild(castMemberItem); + castList.appendChild(castMemberLink); + }); + + castSection.appendChild(castList); + detailsHTML += castSection.outerHTML; + } else { + const noCastElement = document.createElement('p'); + noCastElement.innerHTML = `Cast: Information not available`; + detailsHTML += noCastElement.outerHTML; + } + + if (tvSeries.similar && tvSeries.similar.results && tvSeries.similar.results.length > 0) { + const similarTvSeriesSection = document.createElement('div'); + similarTvSeriesSection.classList.add('similar-tv-series-section'); + + const similarTvSeriesTitle = document.createElement('p'); + similarTvSeriesTitle.innerHTML = 'Similar TV Series:'; + similarTvSeriesSection.appendChild(similarTvSeriesTitle); + + const similarTvSeriesList = document.createElement('div'); + similarTvSeriesList.classList.add('similar-tv-series-list'); + similarTvSeriesList.style.display = 'flex'; + similarTvSeriesList.style.flexWrap = 'wrap'; + similarTvSeriesList.style.justifyContent = 'center'; + similarTvSeriesList.style.gap = '10px'; + + let similarTvSeries = tvSeries.similar.results.sort((a, b) => b.popularity - a.popularity); + similarTvSeries = similarTvSeries.slice(0, 18); + + similarTvSeries.forEach(similarTv => { + const similarTvLink = document.createElement('a'); + similarTvLink.classList.add('similar-tv-link'); + similarTvLink.href = 'javascript:void(0);'; + similarTvLink.setAttribute('onclick', `selectTvSeriesId(${similarTv.id});`); + + const similarTvItem = document.createElement('div'); + similarTvItem.classList.add('similar-tv-item'); + + const similarTvImage = document.createElement('img'); + similarTvImage.classList.add('similar-tv-image'); + + if (similarTv.poster_path) { + similarTvImage.src = IMGPATH + similarTv.poster_path; + similarTvImage.alt = `${similarTv.name} Poster`; + } else { + similarTvImage.alt = 'Image Not Available'; + similarTvImage.src = 'https://movie-verse.com/images/movie-default.jpg'; + similarTvImage.style.filter = 'grayscale(100%)'; + similarTvImage.style.objectFit = 'cover'; + } + + similarTvItem.appendChild(similarTvImage); + + const similarTvDetails = document.createElement('div'); + similarTvDetails.classList.add('similar-tv-details'); + + const similarTvName = document.createElement('p'); + similarTvName.classList.add('similar-tv-name'); + similarTvName.textContent = similarTv.name; + similarTvDetails.appendChild(similarTvName); + + similarTvItem.appendChild(similarTvDetails); + similarTvLink.appendChild(similarTvItem); + similarTvSeriesList.appendChild(similarTvLink); + }); + + similarTvSeriesSection.appendChild(similarTvSeriesList); + detailsHTML += similarTvSeriesSection.outerHTML; + } else { + const noSimilarTvSeriesElement = document.createElement('p'); + noSimilarTvSeriesElement.innerHTML = `Similar TV Series: Information not available`; + detailsHTML += noSimilarTvSeriesElement.outerHTML; + } + + if (tvSeries.production_companies && tvSeries.production_companies.length) { + const companiesSection = document.createElement('div'); + companiesSection.classList.add('companies-section'); + + const companiesTitle = document.createElement('p'); + companiesTitle.innerHTML = 'Production Companies:'; + companiesSection.appendChild(companiesTitle); + + const companiesList = document.createElement('div'); + companiesList.classList.add('companies-list'); + companiesList.style.display = 'flex'; + companiesList.style.flexWrap = 'wrap'; + companiesList.style.justifyContent = 'center'; + companiesList.style.gap = '5px'; + + let productionCompanies = tvSeries.production_companies.slice(0, 6); + + productionCompanies.forEach(company => { + const companyLink = document.createElement('a'); + companyLink.classList.add('company-link'); + companyLink.href = 'javascript:void(0);'; + companyLink.setAttribute('onclick', `selectCompanyId(${company.id});`); + + const companyItem = document.createElement('div'); + companyItem.classList.add('company-item'); + + const companyLogo = document.createElement('img'); + companyLogo.classList.add('company-logo'); + + if (company.logo_path) { + companyLogo.src = IMGPATH + company.logo_path; + companyLogo.alt = `${company.name} Logo`; + companyLogo.style.backgroundColor = 'white'; + } else { + companyLogo.alt = 'Logo Not Available'; + companyLogo.src = 'https://movie-verse.com/images/company-default.png'; + companyLogo.style.filter = 'grayscale(100%)'; + } + + companyItem.appendChild(companyLogo); + + const companyDetails = document.createElement('div'); + companyDetails.classList.add('company-details'); + + const companyName = document.createElement('p'); + companyName.classList.add('company-name'); + companyName.textContent = company.name; + companyDetails.appendChild(companyName); + + companyItem.appendChild(companyDetails); + companyLink.appendChild(companyItem); + companiesList.appendChild(companyLink); + }); + + companiesSection.appendChild(companiesList); + detailsHTML += companiesSection.outerHTML; + } else { + const noCompaniesElement = document.createElement('p'); + noCompaniesElement.innerHTML = `Production Companies: Information not available`; + detailsHTML += noCompaniesElement.outerHTML; + } + + const tvSeriesTitleEncoded = encodeURIComponent(title); + const streamingProviders = await fetchTvSeriesStreamingLinks(tvSeries.id); + const streamingHTML = + streamingProviders.length > 0 + ? streamingProviders + .map(provider => { + let providerLink = `https://www.google.com/search?q=watch+${tvSeriesTitleEncoded}+on+${encodeURIComponent(provider.provider_name)}`; + switch (provider.provider_name.toLowerCase()) { + case 'netflix': + providerLink = `https://www.netflix.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'disney plus': + providerLink = `https://www.disneyplus.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hbo max': + providerLink = `https://www.hbomax.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hulu': + providerLink = `https://www.hulu.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'amazon prime video': + providerLink = `https://www.amazon.com/s?k=${tvSeriesTitleEncoded}`; + break; + case 'apple tv plus': + providerLink = `https://tv.apple.com/search?term=${tvSeriesTitleEncoded}`; + break; + case 'stan': + providerLink = `https://www.stan.com.au/search?q=${tvSeriesTitleEncoded}`; + break; + case 'player': + providerLink = `https://player.pl/szukaj?search=${tvSeriesTitleEncoded}`; + break; + } + + return ``; + }) + .join('') + + `` + : 'No streaming options available.'; + + detailsHTML += `

Streaming Options: ${streamingHTML}

`; + + let keywordsHTML = tvSeries.keywords + ? tvSeries.keywords.results + .map( + kw => `${kw.name}` + ) + .join(', ') + : 'None Available'; + + if (tvSeries.keywords && tvSeries.keywords.results && tvSeries.keywords.results.length) { + detailsHTML += `

Keywords: ${keywordsHTML}

`; + } else { + detailsHTML += `

Keywords: None Available

`; + } + + const mediaUrl = `https://${getMovieVerseData()}/3/tv/${tvSeries.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; + } + + let imageWrapper = document.getElementById('image-wrapper'); + if (!imageWrapper) { + imageWrapper = document.createElement('div'); + imageWrapper.id = 'image-wrapper'; + imageWrapper.style = ` + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + `; + mediaContainer.appendChild(imageWrapper); + } + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + imageWrapper.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + } + + let modalOpen = false; + + imageElement.addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + modalOpen = true; + const modalHtml = ` +
+ + Media Image + + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + + const modal = document.getElementById('image-modal'); + const modalImage = modal.querySelector('img'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + modalOpen = false; + imageElement.src = modalImage.src.replace('w1280', 'w780'); + } + }); + + const prevModalButton = document.getElementById('prevModalButton'); + prevModalButton.onmouseover = () => (prevModalButton.style.backgroundColor = '#ff8623'); + prevModalButton.onmouseout = () => (prevModalButton.style.backgroundColor = '#7378c5'); + prevModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, -1); + + const nextModalButton = document.getElementById('nextModalButton'); + nextModalButton.onmouseover = () => (nextModalButton.style.backgroundColor = '#ff8623'); + nextModalButton.onmouseout = () => (nextModalButton.style.backgroundColor = '#7378c5'); + nextModalButton.onclick = () => navigateMediaAndModal(images, imageElement, modalImage, 1); + }); + + function navigateMediaAndModal(images, imgElement1, imgElement2, direction) { + imgElement1.style.opacity = '0'; + imgElement2.style.opacity = '0'; + currentIndex = (currentIndex + direction + images.length) % images.length; + + const newSrc1 = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const newSrc2 = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + const tempImage1 = new Image(); + const tempImage2 = new Image(); + tempImage1.src = newSrc1; + tempImage2.src = newSrc2; + + tempImage1.onload = () => { + tempImage2.onload = () => { + setTimeout(() => { + imgElement1.src = newSrc1; + imgElement2.src = newSrc2; + imgElement1.style.opacity = '1'; + imgElement2.style.opacity = '1'; + }, 500); + }; + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + let prevButton = document.getElementById('prev-media-button'); + let nextButton = document.getElementById('next-media-button'); + if (!prevButton || !nextButton) { + prevButton = document.createElement('button'); + nextButton = document.createElement('button'); + prevButton.id = 'prev-media-button'; + nextButton.id = 'next-media-button'; + prevButton.innerHTML = ''; + nextButton.innerHTML = ''; + + [prevButton, nextButton].forEach(button => { + button.style = ` + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: #7378c5; + color: white; + border-radius: 8px; + height: 30px; + width: 30px; + border: none; + cursor: pointer; + `; + button.onmouseover = () => (button.style.backgroundColor = '#ff8623'); + button.onmouseout = () => (button.style.backgroundColor = '#7378c5'); + }); + + prevButton.style.left = '0'; + nextButton.style.right = '0'; + + imageWrapper.appendChild(prevButton); + imageWrapper.appendChild(nextButton); + } + + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + let rotationInterval; + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } else if (images.length > 1) { + startRotationInterval(); + } + + function startRotationInterval() { + rotationInterval = setInterval(() => { + if (!modalOpen) { + navigateMedia(images, imageElement, 1); + } + }, 3000); + } + + function resetRotationInterval() { + clearInterval(rotationInterval); + startRotationInterval(); + } + + function navigateMedia(images, imgElement, direction) { + currentIndex = (currentIndex + direction + images.length) % images.length; + imgElement.style.opacity = '0'; + + const newSrc = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + const tempImage = new Image(); + tempImage.src = newSrc; + + tempImage.onload = () => { + setTimeout(() => { + imgElement.src = newSrc; + imgElement.style.opacity = '1'; + }, 420); + }; + + sessionStorage.setItem('currentIndex', currentIndex); + updateDots(currentIndex); + resetRotationInterval(); + } + + const indicatorContainer = document.createElement('div'); + indicatorContainer.style = ` + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 15px; + `; + + const maxDotsPerLine = 10; + let currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + + images.forEach((_, index) => { + const dot = document.createElement('div'); + dot.className = 'indicator'; + dot.style = ` + width: 8px; + height: 8px; + margin: 0 5px; + background-color: ${index === currentIndex ? '#ff8623' : '#bbb'}; + border-radius: 50%; + cursor: pointer; + margin-bottom: 5px; + `; + dot.addEventListener('click', () => { + navigateMedia(images, imageElement, index - currentIndex); + updateDots(index); + }); + + currentLine.appendChild(dot); + + if ((index + 1) % maxDotsPerLine === 0 && index !== images.length - 1) { + indicatorContainer.appendChild(currentLine); + currentLine = document.createElement('div'); + currentLine.style.display = 'flex'; + } + }); + + if (currentLine.children.length > 0) { + indicatorContainer.appendChild(currentLine); + } + + mediaContainer.appendChild(indicatorContainer); + + function updateDots(newIndex) { + const dots = document.querySelectorAll('.indicator'); + dots.forEach((dot, index) => { + dot.style.backgroundColor = index === newIndex ? '#ff8623' : '#bbb'; + }); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + document.getElementById('movie-description').innerHTML = detailsHTML; + document.getElementById('movie-description').appendChild(mediaTitle); + document.getElementById('movie-description').appendChild(mediaContainer); + + document.getElementById('last-episode-image').addEventListener('click', function () { + let imageUrl = this.src.replace('w780', 'w1280'); + + const modalHtml = ` +
+ Media Image + × +
+ `; + document.body.insertAdjacentHTML('beforeend', modalHtml); + const modal = document.getElementById('image-modal'); + const closeModalBtn = document.getElementById('removeBtn'); + + closeModalBtn.onclick = function () { + modal.remove(); + }; + + modal.addEventListener('click', function (event) { + if (event.target === this) { + this.remove(); + } + }); + }); + + if (tvSeries.videos.results.find(video => video.type === 'Trailer')?.key) { + const trailerKey = tvSeries.videos.results.find(video => video.type === 'Trailer')?.key; + const trailerUrl = trailerKey ? `https://www.youtube.com/embed/${trailerKey}` : null; + + const trailerButton = document.createElement('button'); + trailerButton.textContent = 'Watch Trailer'; + trailerButton.id = 'trailer-button'; + trailerButton.style = ` + background-color: #7378c5; + color: white; + padding: 10px 20px; + border: none; + border-radius: 8px; + cursor: pointer; + margin-top: 10px; + font: inherit; + `; + + const iframeContainer = document.createElement('div'); + iframeContainer.id = 'trailer-iframe-container'; + iframeContainer.style = ` + display: none; + overflow: hidden; + margin-top: 10px; + max-height: 0; + transition: max-height 0.5s ease-in-out; + border: none; + border-radius: 8px; + `; + + trailerButton.addEventListener('click', () => { + if (iframeContainer.style.display === 'none') { + if (trailerUrl) { + const iframe = document.createElement('iframe'); + iframe.src = trailerUrl; + iframe.title = 'YouTube video player'; + iframe.frameborder = '0'; + iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'; + iframe.allowFullscreen = true; + iframeContainer.appendChild(iframe); + iframe.style.borderRadius = '16px'; + iframe.style.border = 'none'; + iframe.style.width = '400px'; + iframe.style.height = '315px'; + trailerButton.textContent = 'Close Trailer'; + } else { + iframeContainer.innerHTML = '

Trailer not available.

'; + } + iframeContainer.style.display = 'block'; + setTimeout(() => { + iframeContainer.style.maxHeight = '350px'; + }, 10); + } else { + iframeContainer.style.maxHeight = '0'; + setTimeout(() => { + iframeContainer.style.display = 'none'; + iframeContainer.innerHTML = ''; + trailerButton.textContent = 'Watch Trailer'; + }, 500); + } + }); + + document.getElementById('movie-description').appendChild(trailerButton); + document.getElementById('movie-description').appendChild(iframeContainer); + } +} + +async function fetchTvSeriesStreamingLinks(tvSeriesId) { + const url = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const results = data.results || {}; + let providersMap = {}; + + Object.values(results).forEach(region => { + if (region.flatrate) { + region.flatrate.forEach(provider => { + providersMap[provider.provider_id] = provider; + }); + } + }); + + return Object.values(providersMap).slice(0, 7); + } catch (error) { + console.error('Error fetching TV series streaming links:', error); + return []; + } +} + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} + +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + + localStorage.setItem('selectedActorId', actorId); + window.location.href = 'actor-details.html'; +} + +function selectTvSeriesId(tvSeriesId) { + localStorage.setItem('selectedTvSeriesId', tvSeriesId); + window.location.href = 'tv-details.html'; +} + +function selectCompanyId(companyId) { + localStorage.setItem('selectedCompanyId', companyId); + window.location.href = 'company-details.html'; +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +function handleKeywordClick(keyword) { + localStorage.setItem('searchQuery', keyword); + window.location.href = 'search.html'; +} + +function handleCreatorClick(creatorId, creatorName) { + localStorage.setItem('selectedDirectorId', creatorId); + document.title = `${creatorName} - Director's Details`; + updateUniqueDirectorsViewed(creatorId); + updateDirectorVisitCount(creatorId, creatorName); + window.location.href = 'director-details.html'; +} + +document.addEventListener('DOMContentLoaded', () => { + const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + if (tvSeriesId) { + fetchTvDetails(tvSeriesId); + } else { + fetchTvDetails(100088); + } + + document.getElementById('clear-search-btn').style.display = 'none'; + + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; + const movieRating = savedRatings[tvSeriesId] || 0; + setStarRating(movieRating); +}); + +async function showMovieOfTheDay() { + const year = new Date().getFullYear(); + const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`; + + try { + const response = await fetch(url); + const data = await response.json(); + const movies = data.results; + + if (movies.length > 0) { + const randomMovie = movies[Math.floor(Math.random() * movies.length)]; + localStorage.setItem('selectedMovieId', randomMovie.id); + window.location.href = 'movie-details.html'; + } else { + fallbackMovieSelection(); + } + } catch (error) { + console.log('Error fetching movie:', error); + fallbackMovieSelection(); + } +} + +function fallbackMovieSelection() { + const fallbackMovies = [ + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, + 424, 98, + ]; + const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); + window.location.href = 'movie-details.html'; +} + +function applySettings() { + const savedBg = localStorage.getItem('backgroundImage'); + const savedTextColor = localStorage.getItem('textColor'); + const savedFontSize = localStorage.getItem('fontSize'); + + if (savedBg) { + document.body.style.backgroundImage = `url('${savedBg}')`; + } + if (savedTextColor) { + applyTextColor(savedTextColor); + } + if (savedFontSize) { + const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; + document.body.style.fontSize = size; + } +} + +function getMovieCode2() { + const encodedKey = 'MmJhOGU1MzY='; + return atob(encodedKey); +} + +function getMovieName() { + const moviename = 'YXBpa2V5PQ=='; + return atob(moviename); +} + +function getMovieActor() { + const actor = 'd3d3Lm9tZGJhcGkuY29t'; + return atob(actor); +} + +function applyTextColor(color) { + document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { + element.style.color = color; + }); +} + +function updateBrowserURL(title) { + const nameSlug = createNameSlug(title); + const newURL = window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + nameSlug; + window.history.replaceState({ path: newURL }, '', newURL); +} + +function createNameSlug(title) { + return title + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]/g, ''); +} diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/user-profile.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/user-profile.js new file mode 100644 index 00000000..be5a35ad --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/react/js/user-profile.js @@ -0,0 +1,720 @@ +import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js'; +import { + getFirestore, + doc, + getDoc, + setDoc, + query, + collection, + where, + getDocs, + serverTimestamp, + deleteDoc, +} from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js'; +import { getAverageMovieRating } from './ratings-module.js'; +import { getTriviaStats } from './triviaModule.js'; + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +function translateFBC(value) { + return atob(value); +} + +function getFBConfig1() { + const fbConfig1 = 'QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=='; + return translateFBC(fbConfig1); +} + +function getFBConfig2() { + const fbConfig2 = 'bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t'; + return translateFBC(fbConfig2); +} + +function getFBConfig3() { + const fbConfig3 = 'bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20='; + return translateFBC(fbConfig3); +} + +function getFBConfig4() { + const fbConfig4 = 'ODAyOTQzNzE4ODcx'; + return translateFBC(fbConfig4); +} + +function getFBConfig5() { + const fbConfig5 = 'MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI='; + return translateFBC(fbConfig5); +} + +const firebaseConfig = { + apiKey: getFBConfig1(), + authDomain: getFBConfig2(), + projectId: 'movieverse-app', + storageBucket: getFBConfig3(), + messagingSenderId: getFBConfig4(), + appId: getFBConfig5(), +}; + +const app = initializeApp(firebaseConfig); +const db = getFirestore(app); + +document.addEventListener('DOMContentLoaded', function () { + showSpinner(); + handleProfileDisplay(); + setupEventListeners(); + setupSearchListeners(); + hideSpinner(); +}); + +function updateProgressCircles(movieRating, triviaScore) { + const movieRatingPercent = movieRating; + const triviaScorePercent = triviaScore; + + setProgress(document.getElementById('avgMovieRatingCircle'), document.getElementById('avgMovieRatingText'), movieRatingPercent); + setProgress(document.getElementById('avgTriviaScoreCircle'), document.getElementById('avgTriviaScoreText'), triviaScorePercent); +} + +function setProgress(circle, text, percent) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (percent / 100) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', percent > 50 ? '#4CAF50' : '#2196F3'); + text.textContent = `${Math.round(percent)}%`; + text.style.opacity = 1; + }, 10); +} + +function handleProfileDisplay() { + showSpinner(); + + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const welcomeMessage = document.getElementById('welcomeMessage'); + const signInPrompt = document.getElementById('signInPrompt'); + const viewMyProfileBtn = document.getElementById('viewMyProfileBtn'); + const profileContainer = document.getElementById('profileContainer'); + profileContainer.style.display = 'none'; + + if (isSignedIn && userEmail) { + loadProfile(userEmail); + viewMyProfileBtn.disabled = false; + viewMyProfileBtn.style.display = 'block'; + } else { + welcomeMessage.textContent = 'Please sign in to view your profile'; + signInPrompt.style.display = 'block'; + viewMyProfileBtn.disabled = true; + viewMyProfileBtn.style.display = 'none'; + } + + document.getElementById('viewMyProfileBtn').addEventListener('click', () => { + loadCurrentUserProfile(); + }); + + function loadCurrentUserProfile() { + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (currentUserEmail) { + loadProfile(currentUserEmail); + } else { + console.error('No user is currently signed in'); + } + } + + hideSpinner(); +} + +function setupSearchListeners() { + try { + const searchUserInput = document.getElementById('searchUserInput'); + const searchUserResults = document.getElementById('searchUserResults'); + + searchUserInput.addEventListener('input', () => { + const searchText = searchUserInput.value.trim(); + + if (searchText) { + performSearch(searchText); + } else { + searchUserResults.innerHTML = ''; + searchUserResults.style.display = 'none'; + } + }); + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + } +} + +async function performSearch(searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + const db = getFirestore(); + showSpinner(); + + try { + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); + const querySnapshot = await getDocs(userQuery); + + searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { + searchUserResults.innerHTML = `
No User with Username "${searchText}" found
`; + searchUserResults.style.display = 'block'; + } else { + searchUserResults.style.display = 'block'; + querySnapshot.forEach(doc => { + const user = doc.data(); + const userDiv = document.createElement('div'); + userDiv.className = 'user-search-result'; + userDiv.style.cursor = 'pointer'; + userDiv.addEventListener('click', () => loadProfile(doc.id)); + + const img = document.createElement('img'); + img.src = user.profileImage || '../../images/user-default.png'; + img.style.width = '33%'; + img.style.borderRadius = '8px'; + userDiv.appendChild(img); + + const textDiv = document.createElement('div'); + textDiv.style.width = '67%'; + textDiv.style.textAlign = 'left'; + textDiv.innerHTML = `${user.username}

Bio: ${ + user.bio || 'Not Set' + }

`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + } + hideSpinner(); + } catch (error) { + console.error('Error during search: ', error); + searchUserResults.innerHTML = `
Error in searching: ${error.message}
`; + searchUserResults.style.display = 'block'; + hideSpinner(); + } +} + +document.getElementById('container1').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlyViewingProfile'); + + if (!userEmail) { + console.error('No user email found'); + return; + } + + try { + const rating = parseInt(localStorage.getItem('currentAverageRating'), 10); + const averageRating = rating.toFixed(1); + + const triviaStats = parseInt(localStorage.getItem('currentAverageTriviaScore'), 10); + const averageTriviaScore = triviaStats.toFixed(1); + + updateProgressCircles(averageRating, averageTriviaScore, 'container1'); + } catch (error) { + console.error('Error updating progress circles:', error); + } +}); + +document.getElementById('container2').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlyViewingProfile'); + + if (!userEmail) { + console.error('No user email found'); + return; + } + + try { + const rating = parseInt(localStorage.getItem('currentAverageRating'), 10); + const averageRating = rating.toFixed(1); + + const triviaStats = parseInt(localStorage.getItem('currentAverageTriviaScore'), 10); + const averageTriviaScore = triviaStats.toFixed(1); + + updateProgressCircles(averageRating, averageTriviaScore, 'container2'); + } catch (error) { + console.error('Error updating progress circles:', error); + } +}); + +async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMovieVerseUser')) { + showSpinner(); + try { + document.getElementById('viewMyProfileBtn').disabled = false; + + if (!userEmail) return; + + const welcomeMessage = document.getElementById('welcomeMessage'); + const profileContainer = document.getElementById('profileContainer'); + const changeProfileImageBtn = document.getElementById('changeProfileImageBtn'); + const editProfileBtn = document.getElementById('editProfileBtn'); + const removeProfileImageBtn = document.getElementById('removeProfileImage'); + const profileImage = document.getElementById('profileImage'); + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) + ) { + changeProfileImageBtn.style.display = 'none'; + editProfileBtn.style.display = 'none'; + profileImage.removeAttribute('onclick'); + profileImage.style.cursor = 'default'; + profileImage.title = 'Sign in to change profile image'; + } else { + changeProfileImageBtn.style.display = ''; + editProfileBtn.style.display = ''; + profileImage.setAttribute('onclick', 'document.getElementById("imageUpload").click()'); + profileImage.style.cursor = 'pointer'; + profileImage.title = 'Click to change profile image'; + } + + const rating = await getAverageMovieRating(userEmail); + const convertRatingToPercent = (rating / 5) * 100; + const averageRating = convertRatingToPercent.toFixed(1); + + const triviaStats = await getTriviaStats(userEmail); + + let averageTriviaScore = 0; + if (triviaStats.totalAttempted > 0) { + averageTriviaScore = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; + } + + localStorage.setItem('currentlyViewingProfile', userEmail); + + updateProgressCircles(averageRating, averageTriviaScore); + + localStorage.setItem('currentAverageRating', averageRating); + localStorage.setItem('currentAverageTriviaScore', averageTriviaScore); + + profileContainer.style.display = 'block'; + + const docRef = doc(db, 'profiles', userEmail); + const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + let followUnfollowBtn = document.getElementById('followUnfollowBtn'); + if (!followUnfollowBtn) { + followUnfollowBtn = document.createElement('button'); + followUnfollowBtn.id = 'followUnfollowBtn'; + followUnfollowBtn.style.width = '100%'; + profileContainer.appendChild(followUnfollowBtn); + } + + if (currentUserEmail && userEmail !== currentUserEmail && isSignedIn) { + const followingRef = doc(db, 'profiles', currentUserEmail, 'following', userEmail); + const followersRef = doc(db, 'profiles', userEmail, 'followers', currentUserEmail); + + const followSnap = await getDoc(followingRef); + let isFollowing = followSnap.exists(); + + followUnfollowBtn.textContent = isFollowing ? 'Unfollow' : 'Follow'; + followUnfollowBtn.style.display = 'block'; + + followUnfollowBtn.onclick = async () => { + if (isFollowing) { + await deleteDoc(followingRef); + await deleteDoc(followersRef); + followUnfollowBtn.textContent = 'Follow'; + isFollowing = false; + await displayUserList('followers', userEmail); + } else { + const timestamp = serverTimestamp(); + await setDoc(followingRef, { timestamp: timestamp }); + await setDoc(followersRef, { timestamp: timestamp }); + followUnfollowBtn.textContent = 'Unfollow'; + isFollowing = true; + await displayUserList('followers', userEmail); + } + }; + } else { + followUnfollowBtn.style.display = 'none'; + } + + try { + const docSnap = await getDoc(docRef); + let profile = { + username: 'N/A', + dob: 'N/A', + bio: 'N/A', + favoriteGenres: 'N/A', + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: 'N/A', + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }; + + if (docSnap.exists()) { + profile = { ...profile, ...docSnap.data() }; + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } + + document.getElementById('usernameDisplay').innerHTML = `Username: ${profile.username}`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: ${profile.dob}`; + document.getElementById('bioDisplay').innerHTML = `Bio: ${profile.bio}`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: ${profile.favoriteGenres}`; + document.getElementById('locationDisplay').innerHTML = `Location: ${profile.location}`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: ${profile.favoriteMovie}`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: ${profile.hobbies}`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: ${profile.favoriteActor}`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: ${profile.favoriteDirector}`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: ${profile.personalQuote}`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } + + hideSpinner(); + + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); + } else { + const imageUrl = profile.profileImage || '../../images/user-default.png'; + document.getElementById('profileImage').src = imageUrl; + + if ( + userEmail !== localStorage.getItem('currentlySignedInMovieVerseUser') || + !localStorage.getItem('currentlySignedInMovieVerseUser') || + !JSON.parse(localStorage.getItem('isSignedIn')) || + profile.profileImage === '../../images/user-default.png' + ) { + removeProfileImageBtn.style.display = 'none'; + } else { + removeProfileImageBtn.style.display = 'inline'; + } + + document.getElementById('usernameDisplay').innerHTML = `Username: N/A`; + document.getElementById('dobDisplay').innerHTML = `Date of Birth: N/A`; + document.getElementById('bioDisplay').innerHTML = `Bio: N/A`; + document.getElementById('favoriteGenresDisplay').innerHTML = `Favorite Genres: N/A`; + document.getElementById('locationDisplay').innerHTML = `Location: N/A`; + document.getElementById('favoriteMovieDisplay').innerHTML = `Favorite Movie: N/A`; + document.getElementById('hobbiesDisplay').innerHTML = `Hobbies: N/A`; + document.getElementById('favoriteActorDisplay').innerHTML = `Favorite Actor: N/A`; + document.getElementById('favoriteDirectorDisplay').innerHTML = `Favorite Director: N/A`; + document.getElementById('personalQuoteDisplay').innerHTML = `Personal Quote: N/A`; + window.document.title = `${profile.username !== 'N/A' ? profile.username : 'User'}'s Profile - The MovieVerse`; + + if (userEmail === localStorage.getItem('currentlySignedInMovieVerseUser')) { + welcomeMessage.textContent = `Welcome, ${profile.username}!`; + } else { + welcomeMessage.textContent = `Viewing ${profile.username}'s profile`; + } + + hideSpinner(); + + await Promise.all([displayUserList('following', userEmail), displayUserList('followers', userEmail)]); + } + } catch (error) { + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + + document.getElementById('viewMyProfileBtn').disabled = true; + } + } catch (error) { + console.error('Error fetching user list: ', error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = + "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } + + document.getElementById('viewMyProfileBtn').disabled = true; + } +} + +async function displayUserList(listType, userEmail) { + const db = getFirestore(); + const listRef = collection(db, 'profiles', userEmail, listType); + const userListSpan = document.getElementById(`${listType}List`); + + let loadingInterval; + function startLoadingAnimation() { + let dots = ''; + loadingInterval = setInterval(() => { + dots = dots.length < 3 ? dots + '.' : ''; + userListSpan.textContent = `Loading${dots}`; + }, 500); + } + + function stopLoadingAnimation() { + clearInterval(loadingInterval); + userListSpan.innerHTML = ''; + } + + startLoadingAnimation(); + + try { + const snapshot = await getDocs(listRef); + stopLoadingAnimation(); + + if (snapshot.empty) { + userListSpan.textContent = 'N/A'; + } else { + for (let docSnapshot of snapshot.docs) { + const userRef = doc(db, 'profiles', docSnapshot.id); + const userSnap = await getDoc(userRef); + if (userSnap.exists()) { + const userData = userSnap.data(); + + const userLink = document.createElement('a'); + userLink.textContent = userData.username; + userLink.href = '#'; + userLink.id = 'userLink'; + userLink.style.cursor = 'pointer'; + userLink.onclick = () => loadProfile(docSnapshot.id); + + userListSpan.appendChild(userLink); + userListSpan.appendChild(document.createTextNode(', ')); + } + } + + if (userListSpan.lastChild) { + userListSpan.removeChild(userListSpan.lastChild); + } + } + } catch (error) { + console.error('Error fetching user list:', error); + stopLoadingAnimation(); + userListSpan.innerHTML = 'Error loading data'; + } +} + +async function saveProfileChanges() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) return; + + const profileRef = doc(db, 'profiles', userEmail); + const currentDoc = await getDoc(profileRef); + const currentProfile = currentDoc.exists() ? currentDoc.data() : null; + + const newUsername = document.getElementById('editUsername').value.trim(); + + if (currentProfile && currentProfile.username && currentProfile.username !== 'N/A' && !newUsername) { + alert('You cannot delete your username. Please enter a valid username.'); + document.getElementById('editUsername').value = currentProfile.username; + return; + } + + const profile = { + username: newUsername || currentProfile.username, + dob: document.getElementById('editDob').value, + bio: document.getElementById('editBio').value, + favoriteGenres: document + .getElementById('editFavoriteGenres') + .value.split(',') + .map(genre => genre.trim()), + location: document.getElementById('editLocation').value, + favoriteMovie: document.getElementById('editFavoriteMovie').value, + hobbies: document + .getElementById('editHobbies') + .value.split(',') + .map(hobby => hobby.trim()), + favoriteActor: document.getElementById('editFavoriteActor').value, + favoriteDirector: document.getElementById('editFavoriteDirector').value, + personalQuote: document.getElementById('editPersonalQuote').value, + }; + + try { + await setDoc(profileRef, profile, { merge: true }); + console.log('Profile updated successfully.'); + closeModal(); + loadProfile(); + } catch (error) { + console.log('Error updating profile: ', error); + } +} + +async function removeProfileImage() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) return; + + const defaultImageUrl = '../../images/user-default.png'; + + try { + await setDoc(doc(db, 'profiles', userEmail), { profileImage: defaultImageUrl }, { merge: true }); + document.getElementById('profileImage').src = defaultImageUrl; + document.getElementById('removeProfileImage').style.display = 'none'; + } catch (error) { + console.log('Error removing image: ', error); + } +} + +async function uploadImage() { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) { + alert("You're not signed in."); + return; + } + + const fileInput = document.getElementById('imageUpload'); + const file = fileInput.files[0]; + if (!file) { + alert('No file selected. Please choose an image.'); + return; + } + + try { + const base64Image = await resizeImageAndConvertToBase64(file, 1024, 1024); + + await setDoc(doc(db, 'profiles', userEmail), { profileImage: base64Image }, { merge: true }); + + document.getElementById('profileImage').src = base64Image; + console.log('Image processed and Firestore updated'); + window.location.reload(); + } catch (error) { + console.log('Error during image processing:', error); + alert('Error during image processing: ' + error.message); + } +} + +function resizeImageAndConvertToBase64(file, maxWidth, maxHeight) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = e => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement('canvas'); + let width = img.width; + let height = img.height; + + if (width > height) { + if (width > maxWidth) { + height *= maxWidth / width; + width = maxWidth; + } + } else { + if (height > maxHeight) { + width *= maxHeight / height; + height = maxHeight; + } + } + + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0, width, height); + const dataUrl = canvas.toDataURL('image/jpeg', 0.7); + resolve(dataUrl); + }; + img.src = e.target.result; + }; + reader.onerror = error => reject(error); + reader.readAsDataURL(file); + }); +} + +function setupEventListeners() { + document.getElementById('saveChanges').addEventListener('click', async () => { + await saveProfileChanges(); + }); + + document.getElementById('cancelEdit').addEventListener('click', () => { + closeModal(); + }); + + const imageUploadInput = document.getElementById('imageUpload'); + imageUploadInput.addEventListener('change', uploadImage); + + document.getElementById('editProfileBtn').addEventListener('click', async () => { + const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (!userEmail) { + alert("You're not signed in."); + return; + } + + try { + const docRef = doc(db, 'profiles', userEmail); + const docSnap = await getDoc(docRef); + + let profile = { + username: 'N/A', + dob: '', + bio: 'N/A', + favoriteGenres: [], + location: 'N/A', + favoriteMovie: 'N/A', + hobbies: ['N/A'], + favoriteActor: 'N/A', + favoriteDirector: 'N/A', + personalQuote: 'N/A', + profileImage: '../../images/user-default.png', + }; + + if (docSnap.exists()) { + profile = docSnap.data(); + profile.hobbies = profile.hobbies.length > 0 ? profile.hobbies : ['N/A']; + } + + document.getElementById('editUsername').value = profile.username; + document.getElementById('editDob').value = profile.dob; + const defaultDOB = new Date(); + defaultDOB.setFullYear(defaultDOB.getFullYear() - 18); + const defaultDOBString = defaultDOB.toISOString().split('T')[0]; + + document.getElementById('editDob').value = profile.dob || defaultDOBString; + document.getElementById('editBio').value = profile.bio; + document.getElementById('editFavoriteGenres').value = profile.favoriteGenres.join(', '); + document.getElementById('editLocation').value = profile.location; + document.getElementById('editFavoriteMovie').value = profile.favoriteMovie; + document.getElementById('editHobbies').value = profile.hobbies.join(', '); + document.getElementById('editFavoriteActor').value = profile.favoriteActor; + document.getElementById('editFavoriteDirector').value = profile.favoriteDirector; + document.getElementById('editPersonalQuote').value = profile.personalQuote; + document.getElementById('profileImage').src = profile.profileImage || '../../images/user-default.png'; + document.getElementById('editProfileModal').style.display = 'block'; + } catch (error) { + console.log('Error accessing Firestore: ', error); + } + }); + + document.getElementById('imageUpload').addEventListener('change', async () => { + await uploadImage(); + }); + + document.getElementById('removeProfileImage').addEventListener('click', async () => { + await removeProfileImage(); + }); +} diff --git a/MovieVerse-Mobile/www/index.js b/MovieVerse-Mobile/www/index.js index 2e90def6..68445014 100644 --- a/MovieVerse-Mobile/www/index.js +++ b/MovieVerse-Mobile/www/index.js @@ -1,22 +1,22 @@ -const director_main = document.getElementById('director-spotlight'); -const form = document.getElementById('form'); -const search = document.getElementById('search'); -const searchButton = document.getElementById('button-search'); -const searchTitle = document.getElementById('search-title'); -const otherTitle = document.getElementById('other1'); +const director_main = document.getElementById("director-spotlight"); +const form = document.getElementById("form"); +const search = document.getElementById("search"); +const searchButton = document.getElementById("button-search"); +const searchTitle = document.getElementById("search-title"); +const otherTitle = document.getElementById("other1"); function showSpinner() { - document.getElementById('myModal').classList.add('modal-visible'); + document.getElementById("myModal").classList.add("modal-visible"); } function hideSpinner() { - document.getElementById('myModal').classList.remove('modal-visible'); + document.getElementById("myModal").classList.remove("modal-visible"); } -document.addEventListener('DOMContentLoaded', function () { - const pagination = document.getElementById('most-popular-pagination'); - const genresContainer = document.querySelector('.genres'); - const mainContainer = document.getElementById('most-popular'); +document.addEventListener("DOMContentLoaded", function () { + const pagination = document.getElementById("most-popular-pagination"); + const genresContainer = document.querySelector(".genres"); + const mainContainer = document.getElementById("most-popular"); function movePagination() { if (window.innerWidth <= 767) { @@ -27,14 +27,16 @@ document.addEventListener('DOMContentLoaded', function () { } movePagination(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { let currentPageMostPopular = 1; const totalPages = 320; - const mostPopularMain = document.getElementById('most-popular'); - const paginationContainer = document.getElementById('most-popular-pagination'); + const mostPopularMain = document.getElementById("most-popular"); + const paginationContainer = document.getElementById( + "most-popular-pagination", + ); const fetchAndUpdateMostPopular = () => { const mostPopularUrl = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}`; @@ -43,12 +45,16 @@ document.addEventListener('DOMContentLoaded', function () { }; const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageMostPopular > 1, () => { - currentPageMostPopular--; - fetchAndUpdateMostPopular(); - }); + const prevButton = createNavigationButton( + "<", + currentPageMostPopular > 1, + () => { + currentPageMostPopular--; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(prevButton); let startPage = Math.max(currentPageMostPopular - 2, 1); @@ -58,7 +64,8 @@ document.addEventListener('DOMContentLoaded', function () { if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -66,22 +73,27 @@ document.addEventListener('DOMContentLoaded', function () { } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPageMostPopular < totalPages, () => { - currentPageMostPopular++; - fetchAndUpdateMostPopular(); - }); + const nextButton = createNavigationButton( + ">", + currentPageMostPopular < totalPages, + () => { + currentPageMostPopular++; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(nextButton); }; const createNavigationButton = (text, enabled, clickHandler) => { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { button.onclick = clickHandler; @@ -90,12 +102,12 @@ document.addEventListener('DOMContentLoaded', function () { return button; }; - const createPageButton = pageNum => { - const button = document.createElement('button'); + const createPageButton = (pageNum) => { + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { button.onclick = function () { @@ -104,7 +116,7 @@ document.addEventListener('DOMContentLoaded', function () { }; if (pageNum === currentPageMostPopular) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -113,7 +125,12 @@ document.addEventListener('DOMContentLoaded', function () { fetchAndUpdateMostPopular(); }); -function setupPagination(mainElementId, paginationContainerId, genresContainerId, baseUrl) { +function setupPagination( + mainElementId, + paginationContainerId, + genresContainerId, + baseUrl, +) { let currentPage = 1; let totalPages = 10; @@ -168,7 +185,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId mainElement.innerHTML = `

No movies found on this page.

`; } } catch (error) { - console.log('Error fetching data: ', error); + console.log("Error fetching data: ", error); mainElement.innerHTML = `

No movies found on this page.

`; } finally { hideSpinner(); @@ -177,9 +194,9 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPage > 1, () => { + const prevButton = createNavigationButton("<", currentPage > 1, () => { currentPage--; fetchAndUpdate(); }); @@ -194,7 +211,8 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -202,45 +220,50 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPage < totalPages, () => { - currentPage++; - fetchAndUpdate(); - }); + const nextButton = createNavigationButton( + ">", + currentPage < totalPages, + () => { + currentPage++; + fetchAndUpdate(); + }, + ); paginationContainer.appendChild(nextButton); }; function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { - button.addEventListener('click', () => { - currentPage = typeof pageNum === 'number' ? pageNum : currentPage; + button.addEventListener("click", () => { + currentPage = typeof pageNum === "number" ? pageNum : currentPage; fetchAndUpdate(); }); if (pageNum === currentPage) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -250,7 +273,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId fetchAndUpdate(); let resizeTimer; - window.addEventListener('resize', () => { + window.addEventListener("resize", () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(movePagination, 250); }); @@ -265,16 +288,21 @@ async function fetchAndDisplayMovies(url, count, mainElement) { showMovies(movies, mainElement); } -document.addEventListener('DOMContentLoaded', async () => { +document.addEventListener("DOMContentLoaded", async () => { let currentPageRecommended = 1; const totalPagesRecommended = 60; - const recommendedMain = document.getElementById('recommended'); - const paginationContainerRecommended = document.getElementById('recommended-pagination'); - const genresContainer = document.getElementById('recommendedDIV'); + const recommendedMain = document.getElementById("recommended"); + const paginationContainerRecommended = document.getElementById( + "recommended-pagination", + ); + const genresContainer = document.getElementById("recommendedDIV"); function movePagination() { if (window.innerWidth <= 767) { - recommendedMain.parentNode.insertBefore(paginationContainerRecommended, recommendedMain); + recommendedMain.parentNode.insertBefore( + paginationContainerRecommended, + recommendedMain, + ); } else { genresContainer.appendChild(paginationContainerRecommended); } @@ -287,7 +315,7 @@ document.addEventListener('DOMContentLoaded', async () => { const mostCommonGenre = getMostCommonGenre(); const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); - recommendedMain.innerHTML = ''; + recommendedMain.innerHTML = ""; if (!mostVisitedMovieGenre || !mostCommonGenre) { recommendedMain.innerHTML = `
@@ -302,17 +330,29 @@ document.addEventListener('DOMContentLoaded', async () => { const commonGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostCommonGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; const visitedGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostVisitedMovieGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; - await fetchAndDisplayMovies(commonGenreUrl, totalMoviesToDisplay, recommendedMain); - await fetchAndDisplayMovies(visitedGenreUrl, totalMoviesToDisplay, recommendedMain); + await fetchAndDisplayMovies( + commonGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); + await fetchAndDisplayMovies( + visitedGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); updatePaginationDisplayRecommended(); hideSpinner(); } function updatePaginationDisplayRecommended() { - paginationContainerRecommended.innerHTML = ''; + paginationContainerRecommended.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageRecommended > 1, () => generateRecommendations(currentPageRecommended - 1)); + const prevButton = createNavigationButton( + "<", + currentPageRecommended > 1, + () => generateRecommendations(currentPageRecommended - 1), + ); paginationContainerRecommended.appendChild(prevButton); let startPage = Math.max(currentPageRecommended - 2, 1); @@ -321,43 +361,57 @@ document.addEventListener('DOMContentLoaded', async () => { if (endPage === totalPagesRecommended) startPage = Math.max(endPage - 4, 1); if (startPage > 1) { - paginationContainerRecommended.appendChild(createPageButton(1, generateRecommendations)); - if (startPage > 2) paginationContainerRecommended.appendChild(createPageButton('...')); + paginationContainerRecommended.appendChild( + createPageButton(1, generateRecommendations), + ); + if (startPage > 2) + paginationContainerRecommended.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { - paginationContainerRecommended.appendChild(createPageButton(i, generateRecommendations, i === currentPageRecommended)); + paginationContainerRecommended.appendChild( + createPageButton( + i, + generateRecommendations, + i === currentPageRecommended, + ), + ); } if (endPage < totalPagesRecommended) { - if (endPage < totalPagesRecommended - 1) paginationContainerRecommended.appendChild(createPageButton('...')); - paginationContainerRecommended.appendChild(createPageButton(totalPagesRecommended, generateRecommendations)); + if (endPage < totalPagesRecommended - 1) + paginationContainerRecommended.appendChild(createPageButton("...")); + paginationContainerRecommended.appendChild( + createPageButton(totalPagesRecommended, generateRecommendations), + ); } - const nextButton = createNavigationButton('>', currentPageRecommended < totalPagesRecommended, () => - generateRecommendations(currentPageRecommended + 1) + const nextButton = createNavigationButton( + ">", + currentPageRecommended < totalPagesRecommended, + () => generateRecommendations(currentPageRecommended + 1), ); paginationContainerRecommended.appendChild(nextButton); } function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum, fetchFunction, isActive) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button' + (isActive ? ' active' : ''); + button.className = "page-button" + (isActive ? " active" : ""); - if (pageNum !== '...') { - button.addEventListener('click', () => fetchFunction(pageNum)); + if (pageNum !== "...") { + button.addEventListener("click", () => fetchFunction(pageNum)); } else { button.disabled = true; } @@ -367,7 +421,7 @@ document.addEventListener('DOMContentLoaded', async () => { movePagination(); await generateRecommendations(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); async function getMovies(url, mainElement, page = 1) { @@ -398,102 +452,149 @@ async function getMovies(url, mainElement, page = 1) { } async function getAdditionalPosters(movieId) { - const response = await fetch(`https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`); + const response = await fetch( + `https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`, + ); const data = await response.json(); - return data.posters.map(poster => poster.file_path); + return data.posters.map((poster) => poster.file_path); } function rotateImages(imageElements, interval = 3000) { - const uniqueImageElements = Array.from(imageElements).filter((el, index, self) => index === self.findIndex(e => e.src === el.src)); + const uniqueImageElements = Array.from(imageElements).filter( + (el, index, self) => index === self.findIndex((e) => e.src === el.src), + ); if (uniqueImageElements.length <= 1) return; let currentIndex = 0; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; setTimeout(() => { setInterval(() => { - uniqueImageElements[currentIndex].style.opacity = '0'; + uniqueImageElements[currentIndex].style.opacity = "0"; currentIndex = (currentIndex + 1) % uniqueImageElements.length; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; }, interval); }, 0); } async function showMovies(movies, mainElement) { - mainElement.innerHTML = ''; + mainElement.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - const observer = new IntersectionObserver( + // Observer for background image loading and rotation setup + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch additional posters and set up rotation in the background const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); + const movieImageContainer = movieEl.querySelector(".movie-images"); allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); - const imagePromises = allPosters.map((poster, index) => { + // Load images in the background + allPosters.forEach((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; - img.loading = index === 0 ? 'eager' : 'lazy'; + img.loading = index === 0 ? "eager" : "lazy"; img.alt = `${movieEl.dataset.title} poster ${index + 1}`; img.width = 300; img.height = 435; - img.style.position = 'absolute'; + img.style.position = "absolute"; img.style.top = 0; img.style.left = 0; - img.style.transition = 'opacity 1s ease-in-out'; - img.style.opacity = '0'; - img.classList.add('poster-img'); + img.style.transition = "opacity 1s ease-in-out"; + img.style.opacity = "0"; + img.classList.add("poster-img"); movieImageContainer.appendChild(img); - return new Promise(resolve => { - img.onload = () => resolve(img); - }); + img.onload = () => { + if (index === 0) img.style.opacity = "1"; // Show the first image + }; }); - const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); - await Promise.race([Promise.all(imagePromises), maxWait]); - - movieImageContainer.querySelector('.poster-img').style.opacity = '1'; - + // Start rotating images in the background rotateImages(Array.from(movieImageContainer.children)); observer.unobserve(movieEl); } } }, { - rootMargin: '50px 0px', + rootMargin: "50px 0px", threshold: 0.1, - } + }, ); - movies.forEach(movie => { - let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; - - const movieEl = document.createElement('div'); - movieEl.style.zIndex = '1000'; - movieEl.classList.add('movie'); + movies.forEach((movie, index) => { + let { + id, + poster_path, + title, + vote_average, + vote_count, + overview, + genre_ids, + } = movie; + + const movieEl = document.createElement("div"); + movieEl.style.zIndex = "1000"; + movieEl.classList.add("movie"); movieEl.dataset.id = id; movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; - const words = title.split(' '); + const words = title.split(" "); if (words.length >= 8) { - words[7] = '...'; - title = words.slice(0, 8).join(' '); + words[7] = "..."; + title = words.slice(0, 8).join(" "); } - const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); - const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); + const voteAvg = vote_count === 0 ? "Unrated" : vote_average.toFixed(1); + const ratingClass = + vote_count === 0 ? "unrated" : getClassByRate(vote_average); - if (overview === '') { - overview = 'No overview available.'; + if (overview === "") { + overview = "No overview available."; } movieEl.innerHTML = ` @@ -511,37 +612,44 @@ async function showMovies(movies, mainElement) { ${overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); + + // Observe for background image loading and rotation + imageObserver.observe(movieEl); }); } function updateFavoriteGenre(genre_ids) { if (genre_ids && genre_ids.length > 0) { - const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenres = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; favoriteGenres.push(genre_ids[0]); - localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + localStorage.setItem("favoriteGenres", JSON.stringify(favoriteGenres)); } } function updateUniqueMoviesViewed(movieId) { - let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + let viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; if (!viewedMovies.includes(movieId)) { viewedMovies.push(movieId); - localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); + localStorage.setItem("uniqueMoviesViewed", JSON.stringify(viewedMovies)); } } async function ensureGenreMapIsAvailable() { - if (!localStorage.getItem('genreMap')) { + if (!localStorage.getItem("genreMap")) { await fetchGenreMap(); } } @@ -556,9 +664,9 @@ async function fetchGenreMap() { map[genre.id] = genre.name; return map; }, {}); - localStorage.setItem('genreMap', JSON.stringify(genreMap)); + localStorage.setItem("genreMap", JSON.stringify(genreMap)); } catch (error) { - console.log('Error fetching genre map:', error); + console.log("Error fetching genre map:", error); } } @@ -567,49 +675,51 @@ async function rotateUserStats() { const stats = [ { - label: 'Your Current Time', + label: "Your Current Time", getValue: () => { const now = new Date(); let hours = now.getHours(); let minutes = now.getMinutes(); - hours = hours < 10 ? '0' + hours : hours; - minutes = minutes < 10 ? '0' + minutes : minutes; + hours = hours < 10 ? "0" + hours : hours; + minutes = minutes < 10 ? "0" + minutes : minutes; return `${hours}:${minutes}`; }, }, - { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, - { label: 'Most Visited Director', getValue: getMostVisitedDirector }, - { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { label: "Most Visited Movie", getValue: getMostVisitedMovie }, + { label: "Most Visited Director", getValue: getMostVisitedDirector }, + { label: "Most Visited Actor", getValue: getMostVisitedActor }, { - label: 'Movies Discovered', + label: "Movies Discovered", getValue: () => { - const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + const viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; return viewedMovies.length; }, }, { - label: 'Favorite Movies', + label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritedMovies = + JSON.parse(localStorage.getItem("moviesFavorited")) || []; return favoritedMovies.length; }, }, { - label: 'Favorite Genre', + label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMapString = localStorage.getItem('genreMap'); + const genreMapString = localStorage.getItem("genreMap"); if (!genreMapString) { - console.log('No genre map found in localStorage.'); - return 'Not Available'; + console.log("No genre map found in localStorage."); + return "Not Available"; } let genreMap; try { genreMap = JSON.parse(genreMapString); } catch (e) { - console.log('Error parsing genre map:', e); - return 'Not Available'; + console.log("Error parsing genre map:", e); + return "Not Available"; } let genreObject; @@ -618,74 +728,81 @@ async function rotateUserStats() { acc[genre.id] = genre.name; return acc; }, {}); - } else if (typeof genreMap === 'object' && genreMap !== null) { + } else if (typeof genreMap === "object" && genreMap !== null) { genreObject = genreMap; } else { - console.log('genreMap is neither an array nor a proper object:', genreMap); - return 'Not Available'; + console.log( + "genreMap is neither an array nor a proper object:", + genreMap, + ); + return "Not Available"; } - return genreObject[mostCommonGenreCode] || 'Not Available'; + return genreObject[mostCommonGenreCode] || "Not Available"; }, }, { - label: 'Watchlists Created', - getValue: () => localStorage.getItem('watchlistsCreated') || 0, + label: "Watchlists Created", + getValue: () => localStorage.getItem("watchlistsCreated") || 0, }, { - label: 'Average Movie Rating', - getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + label: "Average Movie Rating", + getValue: () => localStorage.getItem("averageMovieRating") || "Not Rated", }, { - label: 'Directors Discovered', + label: "Directors Discovered", getValue: () => { - const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + const viewedDirectors = + JSON.parse(localStorage.getItem("uniqueDirectorsViewed")) || []; return viewedDirectors.length; }, }, { - label: 'Actors Discovered', + label: "Actors Discovered", getValue: () => { - const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + const viewedActors = + JSON.parse(localStorage.getItem("uniqueActorsViewed")) || []; return viewedActors.length; }, }, - { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + { label: "Your Trivia Accuracy", getValue: getTriviaAccuracy }, ]; let currentStatIndex = 0; function updateStatDisplay() { const currentStat = stats[currentStatIndex]; - document.getElementById('stats-label').textContent = currentStat.label + ':'; - document.getElementById('stats-display').textContent = currentStat.getValue(); + document.getElementById("stats-label").textContent = + currentStat.label + ":"; + document.getElementById("stats-display").textContent = + currentStat.getValue(); currentStatIndex = (currentStatIndex + 1) % stats.length; } updateStatDisplay(); - const localTimeDiv = document.getElementById('local-time'); + const localTimeDiv = document.getElementById("local-time"); let statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.addEventListener('click', () => { + localTimeDiv.addEventListener("click", () => { clearInterval(statRotationInterval); updateStatDisplay(); statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + localTimeDiv.scrollIntoView({ behavior: "smooth" }); }); } function updateMovieVisitCount(movieId, movieTitle) { - let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; if (!movieVisits[movieId]) { movieVisits[movieId] = { count: 0, title: movieTitle }; } movieVisits[movieId].count += 1; - localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem("movieVisits", JSON.stringify(movieVisits)); } function getMostVisitedMovie() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; - let mostVisitedMovie = ''; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; + let mostVisitedMovie = ""; let maxVisits = 0; for (const movieId in movieVisits) { @@ -695,11 +812,11 @@ function getMostVisitedMovie() { } } - return mostVisitedMovie || 'Not Available'; + return mostVisitedMovie || "Not Available"; } async function getMostVisitedMovieGenre() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; let mostVisitedGenre = null; let maxVisits = 0; @@ -722,8 +839,8 @@ async function fetchGenreForMovie(movieId) { } function getMostVisitedActor() { - const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; - let mostVisitedActor = ''; + const actorVisits = JSON.parse(localStorage.getItem("actorVisits")) || {}; + let mostVisitedActor = ""; let maxVisits = 0; for (const actorId in actorVisits) { @@ -733,12 +850,13 @@ function getMostVisitedActor() { } } - return mostVisitedActor || 'Not Available'; + return mostVisitedActor || "Not Available"; } function getMostVisitedDirector() { - const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; - let mostVisitedDirector = ''; + const directorVisits = + JSON.parse(localStorage.getItem("directorVisits")) || {}; + let mostVisitedDirector = ""; let maxVisits = 0; for (const directorId in directorVisits) { @@ -747,16 +865,16 @@ function getMostVisitedDirector() { maxVisits = directorVisits[directorId].count; } } - return mostVisitedDirector || 'Not Available'; + return mostVisitedDirector || "Not Available"; } function getTriviaAccuracy() { - let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + let triviaStats = JSON.parse(localStorage.getItem("triviaStats")) || { totalCorrect: 0, totalAttempted: 0, }; if (triviaStats.totalAttempted === 0) { - return 'No trivia attempted'; + return "No trivia attempted"; } let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; @@ -764,13 +882,14 @@ function getTriviaAccuracy() { } function getMostCommonGenre() { - const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenresArray = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; const genreCounts = favoriteGenresArray.reduce((acc, genre) => { acc[genre] = (acc[genre] || 0) + 1; return acc; }, {}); - let mostCommonGenre = ''; + let mostCommonGenre = ""; let maxCount = 0; for (const genre in genreCounts) { @@ -780,16 +899,16 @@ function getMostCommonGenre() { } } - return mostCommonGenre || 'Not Available'; + return mostCommonGenre || "Not Available"; } const movieCode = { - part1: 'YzVhMjBjODY=', - part2: 'MWFjZjdiYjg=', - part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', + part1: "YzVhMjBjODY=", + part2: "MWFjZjdiYjg=", + part3: "ZDllOTg3ZGNjN2YxYjU1OA==", }; -document.addEventListener('DOMContentLoaded', rotateUserStats); +document.addEventListener("DOMContentLoaded", rotateUserStats); async function showMovieOfTheDay() { const year = new Date().getFullYear(); @@ -802,26 +921,28 @@ async function showMovieOfTheDay() { if (movies.length > 0) { const randomMovie = movies[Math.floor(Math.random() * movies.length)]; - localStorage.setItem('selectedMovieId', randomMovie.id); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomMovie.id); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } else { fallbackMovieSelection(); } } catch (error) { - console.log('Error fetching movie:', error); + console.log("Error fetching movie:", error); fallbackMovieSelection(); } } function fallbackMovieSelection() { const fallbackMovies = [ - 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, - 424, 98, + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, + 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, 424, + 98, ]; - const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + const randomFallbackMovie = + fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; - localStorage.setItem('selectedMovieId', randomFallbackMovie); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomFallbackMovie); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } function calculateMoviesToDisplay() { @@ -855,71 +976,75 @@ function calculateMoviesToDisplay() { function getClassByRate(vote) { if (vote >= 8) { - return 'green'; + return "green"; } else if (vote >= 5) { - return 'orange'; + return "orange"; } else { - return 'red'; + return "red"; } } -form.addEventListener('submit', e => { +form.addEventListener("submit", (e) => { e.preventDefault(); - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; }); function toggleNav() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - sideNav.classList.toggle('manual-toggle'); + sideNav.classList.toggle("manual-toggle"); adjustNavBar(); } function removeNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if (sideNav.classList.contains("manual-toggle")) { + sideNav.classList.remove("manual-toggle"); } adjustNavBar(); } function adjustNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0px'; + if (sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0px"; } else { - sideNav.style.left = '-250px'; + sideNav.style.left = "-250px"; } } -document.addEventListener('mousemove', function (event) { - const sideNav = document.getElementById('side-nav'); +document.addEventListener("mousemove", function (event) { + const sideNav = document.getElementById("side-nav"); - if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0'; + if (event.clientX < 10 && !sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0"; } }); -document.addEventListener('click', function (event) { - const sideNav = document.getElementById('side-nav'); - const navToggle = document.getElementById('nav-toggle'); +document.addEventListener("click", function (event) { + const sideNav = document.getElementById("side-nav"); + const navToggle = document.getElementById("nav-toggle"); - if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if ( + !sideNav.contains(event.target) && + !navToggle.contains(event.target) && + sideNav.classList.contains("manual-toggle") + ) { + sideNav.classList.remove("manual-toggle"); adjustNavBar(); } }); -document.getElementById('side-nav').addEventListener('mouseleave', function () { - const sideNav = document.getElementById('side-nav'); +document.getElementById("side-nav").addEventListener("mouseleave", function () { + const sideNav = document.getElementById("side-nav"); - if (!sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '-250px'; + if (!sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "-250px"; } }); @@ -928,32 +1053,32 @@ const IMGPATH = `https://image.tmdb.org/t/p/w500`; const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; const directors = [ - { name: 'Alfred Hitchcock', id: '2636' }, - { name: 'Steven Spielberg', id: '488' }, - { name: 'Martin Scorsese', id: '1032' }, - { name: 'Quentin Tarantino', id: '138' }, - { name: 'Christopher Nolan', id: '525' }, - { name: 'Stanley Kubrick', id: '240' }, - { name: 'Bong Joon-ho', id: '21684' }, - { name: 'David Fincher', id: '7467' }, - { name: 'James Cameron', id: '2710' }, - { name: 'Francis Ford Coppola', id: '1776' }, - { name: 'Tim Burton', id: '510' }, - { name: 'Ridley Scott', id: '578' }, - { name: 'Joel Coen', id: '1223' }, - { name: 'Spike Lee', id: '5281' }, - { name: 'Woody Allen', id: '1243' }, - { name: 'Peter Jackson', id: '108' }, - { name: 'Oliver Stone', id: '1152' }, - { name: 'David Lynch', id: '5602' }, - { name: 'Roman Polanski', id: '3556' }, - { name: 'Wes Anderson', id: '5655' }, - { name: 'Sergio Leone', id: '4385' }, - { name: 'Akira Kurosawa', id: '5026' }, - { name: 'Federico Fellini', id: '4415' }, - { name: 'John Ford', id: '8500' }, - { name: 'Fritz Lang', id: '68' }, - { name: 'Frank Capra', id: '2662' }, + { name: "Alfred Hitchcock", id: "2636" }, + { name: "Steven Spielberg", id: "488" }, + { name: "Martin Scorsese", id: "1032" }, + { name: "Quentin Tarantino", id: "138" }, + { name: "Christopher Nolan", id: "525" }, + { name: "Stanley Kubrick", id: "240" }, + { name: "Bong Joon-ho", id: "21684" }, + { name: "David Fincher", id: "7467" }, + { name: "James Cameron", id: "2710" }, + { name: "Francis Ford Coppola", id: "1776" }, + { name: "Tim Burton", id: "510" }, + { name: "Ridley Scott", id: "578" }, + { name: "Joel Coen", id: "1223" }, + { name: "Spike Lee", id: "5281" }, + { name: "Woody Allen", id: "1243" }, + { name: "Peter Jackson", id: "108" }, + { name: "Oliver Stone", id: "1152" }, + { name: "David Lynch", id: "5602" }, + { name: "Roman Polanski", id: "3556" }, + { name: "Wes Anderson", id: "5655" }, + { name: "Sergio Leone", id: "4385" }, + { name: "Akira Kurosawa", id: "5026" }, + { name: "Federico Fellini", id: "4415" }, + { name: "John Ford", id: "8500" }, + { name: "Fritz Lang", id: "68" }, + { name: "Frank Capra", id: "2662" }, ]; let currentDirectorIndex = 0; @@ -972,7 +1097,8 @@ setInterval(changeDirector, 3600000); function updateDirectorSpotlight() { const director = directors[currentDirectorIndex]; - document.getElementById('spotlight-director-name').textContent = director.name; + document.getElementById("spotlight-director-name").textContent = + director.name; const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_people=${ director.id @@ -981,7 +1107,26 @@ function updateDirectorSpotlight() { } function getMovieVerseData(input) { - return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); + return String.fromCharCode( + 97, + 112, + 105, + 46, + 116, + 104, + 101, + 109, + 111, + 118, + 105, + 101, + 100, + 98, + 46, + 111, + 114, + 103, + ); } function generateMovieNames(input) { @@ -1005,21 +1150,59 @@ async function getDirectorSpotlight(url) { } function showMoviesDirectorSpotlight(movies) { - director_main.innerHTML = ''; + director_main.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - movies.forEach(movie => { + movies.forEach((movie, index) => { const { id, poster_path, title, vote_average, genre_ids } = movie; - const movieEl = document.createElement('div'); + const movieEl = document.createElement("div"); - movieEl.classList.add('movie'); - movieEl.style.zIndex = '1000'; + movieEl.classList.add("movie"); + movieEl.style.zIndex = "1000"; + // Movie image and fallback in case the image is unavailable const movieImage = poster_path ? `${title}` : `
Image Not Available
`; - const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : 'Unrated'; - const ratingClass = vote_average > 0 ? getClassByRate(vote_average) : 'unrated'; + const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : "Unrated"; + const ratingClass = + vote_average > 0 ? getClassByRate(vote_average) : "unrated"; movieEl.innerHTML = ` ${movieImage} @@ -1032,26 +1215,29 @@ function showMoviesDirectorSpotlight(movies) { ${movie.overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); director_main.appendChild(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); }); } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); + localStorage.setItem("isSignedIn", JSON.stringify(false)); + alert("You have been signed out."); } else { - window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; + window.location.href = "MovieVerse-Frontend/html/sign-in.html"; return; } @@ -1059,213 +1245,215 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const signInText = document.getElementById("signInOutText"); + const signInIcon = document.getElementById("signInIcon"); + const signOutIcon = document.getElementById("signOutIcon"); if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; + signInText.textContent = "Sign Out"; + signInIcon.style.display = "none"; + signOutIcon.style.display = "inline-block"; } else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; + signInText.textContent = "Sign In"; + signInIcon.style.display = "inline-block"; + signOutIcon.style.display = "none"; } - const mobileSignInText = document.getElementById('mobileSignInOutText'); - const mobileSignInIcon = document.getElementById('mobileSignInIcon'); - const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); + const mobileSignInText = document.getElementById("mobileSignInOutText"); + const mobileSignInIcon = document.getElementById("mobileSignInIcon"); + const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); if (isSignedIn) { - mobileSignInText.textContent = 'Sign Out'; - mobileSignInIcon.style.display = 'none'; - mobileSignOutIcon.style.display = 'inline-block'; + mobileSignInText.textContent = "Sign Out"; + mobileSignInIcon.style.display = "none"; + mobileSignOutIcon.style.display = "inline-block"; } else { - mobileSignInText.textContent = 'Sign In'; - mobileSignInIcon.style.display = 'inline-block'; - mobileSignOutIcon.style.display = 'none'; + mobileSignInText.textContent = "Sign In"; + mobileSignInIcon.style.display = "inline-block"; + mobileSignOutIcon.style.display = "none"; } } setupPagination( - 'award-winning', - 'award-winning-pagination', - 'award-winning-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` + "award-winning", + "award-winning-pagination", + "award-winning-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, ); setupPagination( - 'hidden-gems', - 'hidden-gems-pagination', - 'hidden-gems-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` + "hidden-gems", + "hidden-gems-pagination", + "hidden-gems-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, ); setupPagination( - 'western', - 'western-pagination', - 'western-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` + "western", + "western-pagination", + "western-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'war', - 'war-pagination', - 'war-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` + "war", + "war-pagination", + "war-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'vietnamese', - 'vietnamese-pagination', - 'vietnamese-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` + "vietnamese", + "vietnamese-pagination", + "vietnamese-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, ); setupPagination( - 'korean', - 'korean-pagination', - 'korean-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` + "korean", + "korean-pagination", + "korean-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, ); setupPagination( - 'musical', - 'musical-pagination', - 'musical-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` + "musical", + "musical-pagination", + "musical-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'drama', - 'drama-pagination', - 'drama-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` + "drama", + "drama-pagination", + "drama-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'indian', - 'indian-pagination', - 'indian-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` + "indian", + "indian-pagination", + "indian-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, ); setupPagination( - 'action', - 'action-pagination', - 'action-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` + "action", + "action-pagination", + "action-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'horror', - 'horror-pagination', - 'horror-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` + "horror", + "horror-pagination", + "horror-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'documentary', - 'documentary-pagination', - 'documentary-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` + "documentary", + "documentary-pagination", + "documentary-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'animation', - 'animation-pagination', - 'animation-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` + "animation", + "animation-pagination", + "animation-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'sci-fi', - 'sci-fi-pagination', - 'sci-fi-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` + "sci-fi", + "sci-fi-pagination", + "sci-fi-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'romantic', - 'romantic-pagination', - 'romantic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` + "romantic", + "romantic-pagination", + "romantic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'thriller', - 'thriller-pagination', - 'thriller-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` + "thriller", + "thriller-pagination", + "thriller-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'mystery', - 'mystery-pagination', - 'mystery-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` + "mystery", + "mystery-pagination", + "mystery-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'comedy', - 'comedy-pagination', - 'comedy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` + "comedy", + "comedy-pagination", + "comedy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'fantasy', - 'fantasy-pagination', - 'fantasy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` + "fantasy", + "fantasy-pagination", + "fantasy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'family', - 'family-pagination', - 'family-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` + "family", + "family-pagination", + "family-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'tv-series', - 'tv-series-pagination', - 'tv-series-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` + "tv-series", + "tv-series-pagination", + "tv-series-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'crime', - 'crime-pagination', - 'crime-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` + "crime", + "crime-pagination", + "crime-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'classic', - 'classic-pagination', - 'classic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` + "classic", + "classic-pagination", + "classic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, ); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + document + .getElementById("googleSignInBtn") + .addEventListener("click", handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; } -document.addEventListener('DOMContentLoaded', () => { - const notificationBtn = document.getElementById('notificationBtn'); +document.addEventListener("DOMContentLoaded", () => { + const notificationBtn = document.getElementById("notificationBtn"); - notificationBtn.addEventListener('click', () => { - window.location.href = 'MovieVerse-Frontend/html/notifications.html'; + notificationBtn.addEventListener("click", () => { + window.location.href = "MovieVerse-Frontend/html/notifications.html"; }); }); diff --git a/index.html b/index.html index 28238b43..74a10688 100644 --- a/index.html +++ b/index.html @@ -56,7 +56,6 @@ - - diff --git a/index.js b/index.js index 2e90def6..68445014 100644 --- a/index.js +++ b/index.js @@ -1,22 +1,22 @@ -const director_main = document.getElementById('director-spotlight'); -const form = document.getElementById('form'); -const search = document.getElementById('search'); -const searchButton = document.getElementById('button-search'); -const searchTitle = document.getElementById('search-title'); -const otherTitle = document.getElementById('other1'); +const director_main = document.getElementById("director-spotlight"); +const form = document.getElementById("form"); +const search = document.getElementById("search"); +const searchButton = document.getElementById("button-search"); +const searchTitle = document.getElementById("search-title"); +const otherTitle = document.getElementById("other1"); function showSpinner() { - document.getElementById('myModal').classList.add('modal-visible'); + document.getElementById("myModal").classList.add("modal-visible"); } function hideSpinner() { - document.getElementById('myModal').classList.remove('modal-visible'); + document.getElementById("myModal").classList.remove("modal-visible"); } -document.addEventListener('DOMContentLoaded', function () { - const pagination = document.getElementById('most-popular-pagination'); - const genresContainer = document.querySelector('.genres'); - const mainContainer = document.getElementById('most-popular'); +document.addEventListener("DOMContentLoaded", function () { + const pagination = document.getElementById("most-popular-pagination"); + const genresContainer = document.querySelector(".genres"); + const mainContainer = document.getElementById("most-popular"); function movePagination() { if (window.innerWidth <= 767) { @@ -27,14 +27,16 @@ document.addEventListener('DOMContentLoaded', function () { } movePagination(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { let currentPageMostPopular = 1; const totalPages = 320; - const mostPopularMain = document.getElementById('most-popular'); - const paginationContainer = document.getElementById('most-popular-pagination'); + const mostPopularMain = document.getElementById("most-popular"); + const paginationContainer = document.getElementById( + "most-popular-pagination", + ); const fetchAndUpdateMostPopular = () => { const mostPopularUrl = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}`; @@ -43,12 +45,16 @@ document.addEventListener('DOMContentLoaded', function () { }; const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageMostPopular > 1, () => { - currentPageMostPopular--; - fetchAndUpdateMostPopular(); - }); + const prevButton = createNavigationButton( + "<", + currentPageMostPopular > 1, + () => { + currentPageMostPopular--; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(prevButton); let startPage = Math.max(currentPageMostPopular - 2, 1); @@ -58,7 +64,8 @@ document.addEventListener('DOMContentLoaded', function () { if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -66,22 +73,27 @@ document.addEventListener('DOMContentLoaded', function () { } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPageMostPopular < totalPages, () => { - currentPageMostPopular++; - fetchAndUpdateMostPopular(); - }); + const nextButton = createNavigationButton( + ">", + currentPageMostPopular < totalPages, + () => { + currentPageMostPopular++; + fetchAndUpdateMostPopular(); + }, + ); paginationContainer.appendChild(nextButton); }; const createNavigationButton = (text, enabled, clickHandler) => { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { button.onclick = clickHandler; @@ -90,12 +102,12 @@ document.addEventListener('DOMContentLoaded', function () { return button; }; - const createPageButton = pageNum => { - const button = document.createElement('button'); + const createPageButton = (pageNum) => { + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { button.onclick = function () { @@ -104,7 +116,7 @@ document.addEventListener('DOMContentLoaded', function () { }; if (pageNum === currentPageMostPopular) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -113,7 +125,12 @@ document.addEventListener('DOMContentLoaded', function () { fetchAndUpdateMostPopular(); }); -function setupPagination(mainElementId, paginationContainerId, genresContainerId, baseUrl) { +function setupPagination( + mainElementId, + paginationContainerId, + genresContainerId, + baseUrl, +) { let currentPage = 1; let totalPages = 10; @@ -168,7 +185,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId mainElement.innerHTML = `

No movies found on this page.

`; } } catch (error) { - console.log('Error fetching data: ', error); + console.log("Error fetching data: ", error); mainElement.innerHTML = `

No movies found on this page.

`; } finally { hideSpinner(); @@ -177,9 +194,9 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } const updatePaginationDisplay = () => { - paginationContainer.innerHTML = ''; + paginationContainer.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPage > 1, () => { + const prevButton = createNavigationButton("<", currentPage > 1, () => { currentPage--; fetchAndUpdate(); }); @@ -194,7 +211,8 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId if (startPage > 1) { paginationContainer.appendChild(createPageButton(1)); - if (startPage > 2) paginationContainer.appendChild(createPageButton('...')); + if (startPage > 2) + paginationContainer.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { @@ -202,45 +220,50 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId } if (endPage < totalPages) { - if (endPage < totalPages - 1) paginationContainer.appendChild(createPageButton('...')); + if (endPage < totalPages - 1) + paginationContainer.appendChild(createPageButton("...")); paginationContainer.appendChild(createPageButton(totalPages)); } - const nextButton = createNavigationButton('>', currentPage < totalPages, () => { - currentPage++; - fetchAndUpdate(); - }); + const nextButton = createNavigationButton( + ">", + currentPage < totalPages, + () => { + currentPage++; + fetchAndUpdate(); + }, + ); paginationContainer.appendChild(nextButton); }; function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button'; + button.className = "page-button"; - if (pageNum === '...') { + if (pageNum === "...") { button.disabled = true; } else { - button.addEventListener('click', () => { - currentPage = typeof pageNum === 'number' ? pageNum : currentPage; + button.addEventListener("click", () => { + currentPage = typeof pageNum === "number" ? pageNum : currentPage; fetchAndUpdate(); }); if (pageNum === currentPage) { - button.classList.add('active'); + button.classList.add("active"); } } return button; @@ -250,7 +273,7 @@ function setupPagination(mainElementId, paginationContainerId, genresContainerId fetchAndUpdate(); let resizeTimer; - window.addEventListener('resize', () => { + window.addEventListener("resize", () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(movePagination, 250); }); @@ -265,16 +288,21 @@ async function fetchAndDisplayMovies(url, count, mainElement) { showMovies(movies, mainElement); } -document.addEventListener('DOMContentLoaded', async () => { +document.addEventListener("DOMContentLoaded", async () => { let currentPageRecommended = 1; const totalPagesRecommended = 60; - const recommendedMain = document.getElementById('recommended'); - const paginationContainerRecommended = document.getElementById('recommended-pagination'); - const genresContainer = document.getElementById('recommendedDIV'); + const recommendedMain = document.getElementById("recommended"); + const paginationContainerRecommended = document.getElementById( + "recommended-pagination", + ); + const genresContainer = document.getElementById("recommendedDIV"); function movePagination() { if (window.innerWidth <= 767) { - recommendedMain.parentNode.insertBefore(paginationContainerRecommended, recommendedMain); + recommendedMain.parentNode.insertBefore( + paginationContainerRecommended, + recommendedMain, + ); } else { genresContainer.appendChild(paginationContainerRecommended); } @@ -287,7 +315,7 @@ document.addEventListener('DOMContentLoaded', async () => { const mostCommonGenre = getMostCommonGenre(); const mostVisitedMovieGenre = await getMostVisitedMovieGenre(); - recommendedMain.innerHTML = ''; + recommendedMain.innerHTML = ""; if (!mostVisitedMovieGenre || !mostCommonGenre) { recommendedMain.innerHTML = `
@@ -302,17 +330,29 @@ document.addEventListener('DOMContentLoaded', async () => { const commonGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostCommonGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; const visitedGenreUrl = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${mostVisitedMovieGenre}&sort_by=popularity.desc&vote_count.gte=10&page=${currentPageRecommended}`; - await fetchAndDisplayMovies(commonGenreUrl, totalMoviesToDisplay, recommendedMain); - await fetchAndDisplayMovies(visitedGenreUrl, totalMoviesToDisplay, recommendedMain); + await fetchAndDisplayMovies( + commonGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); + await fetchAndDisplayMovies( + visitedGenreUrl, + totalMoviesToDisplay, + recommendedMain, + ); updatePaginationDisplayRecommended(); hideSpinner(); } function updatePaginationDisplayRecommended() { - paginationContainerRecommended.innerHTML = ''; + paginationContainerRecommended.innerHTML = ""; - const prevButton = createNavigationButton('<', currentPageRecommended > 1, () => generateRecommendations(currentPageRecommended - 1)); + const prevButton = createNavigationButton( + "<", + currentPageRecommended > 1, + () => generateRecommendations(currentPageRecommended - 1), + ); paginationContainerRecommended.appendChild(prevButton); let startPage = Math.max(currentPageRecommended - 2, 1); @@ -321,43 +361,57 @@ document.addEventListener('DOMContentLoaded', async () => { if (endPage === totalPagesRecommended) startPage = Math.max(endPage - 4, 1); if (startPage > 1) { - paginationContainerRecommended.appendChild(createPageButton(1, generateRecommendations)); - if (startPage > 2) paginationContainerRecommended.appendChild(createPageButton('...')); + paginationContainerRecommended.appendChild( + createPageButton(1, generateRecommendations), + ); + if (startPage > 2) + paginationContainerRecommended.appendChild(createPageButton("...")); } for (let i = startPage; i <= endPage; i++) { - paginationContainerRecommended.appendChild(createPageButton(i, generateRecommendations, i === currentPageRecommended)); + paginationContainerRecommended.appendChild( + createPageButton( + i, + generateRecommendations, + i === currentPageRecommended, + ), + ); } if (endPage < totalPagesRecommended) { - if (endPage < totalPagesRecommended - 1) paginationContainerRecommended.appendChild(createPageButton('...')); - paginationContainerRecommended.appendChild(createPageButton(totalPagesRecommended, generateRecommendations)); + if (endPage < totalPagesRecommended - 1) + paginationContainerRecommended.appendChild(createPageButton("...")); + paginationContainerRecommended.appendChild( + createPageButton(totalPagesRecommended, generateRecommendations), + ); } - const nextButton = createNavigationButton('>', currentPageRecommended < totalPagesRecommended, () => - generateRecommendations(currentPageRecommended + 1) + const nextButton = createNavigationButton( + ">", + currentPageRecommended < totalPagesRecommended, + () => generateRecommendations(currentPageRecommended + 1), ); paginationContainerRecommended.appendChild(nextButton); } function createNavigationButton(text, enabled, clickHandler) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.innerHTML = text; button.disabled = !enabled; - button.className = 'nav-button'; + button.className = "nav-button"; if (enabled) { - button.addEventListener('click', clickHandler); + button.addEventListener("click", clickHandler); } return button; } function createPageButton(pageNum, fetchFunction, isActive) { - const button = document.createElement('button'); + const button = document.createElement("button"); button.textContent = pageNum; - button.className = 'page-button' + (isActive ? ' active' : ''); + button.className = "page-button" + (isActive ? " active" : ""); - if (pageNum !== '...') { - button.addEventListener('click', () => fetchFunction(pageNum)); + if (pageNum !== "...") { + button.addEventListener("click", () => fetchFunction(pageNum)); } else { button.disabled = true; } @@ -367,7 +421,7 @@ document.addEventListener('DOMContentLoaded', async () => { movePagination(); await generateRecommendations(); - window.addEventListener('resize', movePagination); + window.addEventListener("resize", movePagination); }); async function getMovies(url, mainElement, page = 1) { @@ -398,102 +452,149 @@ async function getMovies(url, mainElement, page = 1) { } async function getAdditionalPosters(movieId) { - const response = await fetch(`https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`); + const response = await fetch( + `https://${getMovieVerseData()}/3/movie/${movieId}/images?${generateMovieNames()}${getMovieCode()}`, + ); const data = await response.json(); - return data.posters.map(poster => poster.file_path); + return data.posters.map((poster) => poster.file_path); } function rotateImages(imageElements, interval = 3000) { - const uniqueImageElements = Array.from(imageElements).filter((el, index, self) => index === self.findIndex(e => e.src === el.src)); + const uniqueImageElements = Array.from(imageElements).filter( + (el, index, self) => index === self.findIndex((e) => e.src === el.src), + ); if (uniqueImageElements.length <= 1) return; let currentIndex = 0; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; setTimeout(() => { setInterval(() => { - uniqueImageElements[currentIndex].style.opacity = '0'; + uniqueImageElements[currentIndex].style.opacity = "0"; currentIndex = (currentIndex + 1) % uniqueImageElements.length; - uniqueImageElements[currentIndex].style.opacity = '1'; + uniqueImageElements[currentIndex].style.opacity = "1"; }, interval); }, 0); } async function showMovies(movies, mainElement) { - mainElement.innerHTML = ''; + mainElement.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - const observer = new IntersectionObserver( + // Observer for background image loading and rotation setup + const imageObserver = new IntersectionObserver( async (entries, observer) => { for (const entry of entries) { if (entry.isIntersecting) { const movieEl = entry.target; const movieId = movieEl.dataset.id; + // Fetch additional posters and set up rotation in the background const additionalPosters = await getAdditionalPosters(movieId); let allPosters = [movieEl.dataset.posterPath, ...additionalPosters]; - - const movieImageContainer = movieEl.querySelector('.movie-images'); + const movieImageContainer = movieEl.querySelector(".movie-images"); allPosters = allPosters.sort(() => 0.5 - Math.random()).slice(0, 10); - const imagePromises = allPosters.map((poster, index) => { + // Load images in the background + allPosters.forEach((poster, index) => { const img = new Image(); img.src = `${IMGPATH + poster}`; - img.loading = index === 0 ? 'eager' : 'lazy'; + img.loading = index === 0 ? "eager" : "lazy"; img.alt = `${movieEl.dataset.title} poster ${index + 1}`; img.width = 300; img.height = 435; - img.style.position = 'absolute'; + img.style.position = "absolute"; img.style.top = 0; img.style.left = 0; - img.style.transition = 'opacity 1s ease-in-out'; - img.style.opacity = '0'; - img.classList.add('poster-img'); + img.style.transition = "opacity 1s ease-in-out"; + img.style.opacity = "0"; + img.classList.add("poster-img"); movieImageContainer.appendChild(img); - return new Promise(resolve => { - img.onload = () => resolve(img); - }); + img.onload = () => { + if (index === 0) img.style.opacity = "1"; // Show the first image + }; }); - const maxWait = new Promise(resolve => setTimeout(resolve, 3000)); - await Promise.race([Promise.all(imagePromises), maxWait]); - - movieImageContainer.querySelector('.poster-img').style.opacity = '1'; - + // Start rotating images in the background rotateImages(Array.from(movieImageContainer.children)); observer.unobserve(movieEl); } } }, { - rootMargin: '50px 0px', + rootMargin: "50px 0px", threshold: 0.1, - } + }, ); - movies.forEach(movie => { - let { id, poster_path, title, vote_average, vote_count, overview, genre_ids } = movie; - - const movieEl = document.createElement('div'); - movieEl.style.zIndex = '1000'; - movieEl.classList.add('movie'); + movies.forEach((movie, index) => { + let { + id, + poster_path, + title, + vote_average, + vote_count, + overview, + genre_ids, + } = movie; + + const movieEl = document.createElement("div"); + movieEl.style.zIndex = "1000"; + movieEl.classList.add("movie"); movieEl.dataset.id = id; movieEl.dataset.posterPath = poster_path; movieEl.dataset.title = title; - const words = title.split(' '); + const words = title.split(" "); if (words.length >= 8) { - words[7] = '...'; - title = words.slice(0, 8).join(' '); + words[7] = "..."; + title = words.slice(0, 8).join(" "); } - const voteAvg = vote_count === 0 ? 'Unrated' : vote_average.toFixed(1); - const ratingClass = vote_count === 0 ? 'unrated' : getClassByRate(vote_average); + const voteAvg = vote_count === 0 ? "Unrated" : vote_average.toFixed(1); + const ratingClass = + vote_count === 0 ? "unrated" : getClassByRate(vote_average); - if (overview === '') { - overview = 'No overview available.'; + if (overview === "") { + overview = "No overview available."; } movieEl.innerHTML = ` @@ -511,37 +612,44 @@ async function showMovies(movies, mainElement) { ${overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); mainElement.appendChild(movieEl); - observer.observe(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); + + // Observe for background image loading and rotation + imageObserver.observe(movieEl); }); } function updateFavoriteGenre(genre_ids) { if (genre_ids && genre_ids.length > 0) { - const favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenres = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; favoriteGenres.push(genre_ids[0]); - localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + localStorage.setItem("favoriteGenres", JSON.stringify(favoriteGenres)); } } function updateUniqueMoviesViewed(movieId) { - let viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + let viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; if (!viewedMovies.includes(movieId)) { viewedMovies.push(movieId); - localStorage.setItem('uniqueMoviesViewed', JSON.stringify(viewedMovies)); + localStorage.setItem("uniqueMoviesViewed", JSON.stringify(viewedMovies)); } } async function ensureGenreMapIsAvailable() { - if (!localStorage.getItem('genreMap')) { + if (!localStorage.getItem("genreMap")) { await fetchGenreMap(); } } @@ -556,9 +664,9 @@ async function fetchGenreMap() { map[genre.id] = genre.name; return map; }, {}); - localStorage.setItem('genreMap', JSON.stringify(genreMap)); + localStorage.setItem("genreMap", JSON.stringify(genreMap)); } catch (error) { - console.log('Error fetching genre map:', error); + console.log("Error fetching genre map:", error); } } @@ -567,49 +675,51 @@ async function rotateUserStats() { const stats = [ { - label: 'Your Current Time', + label: "Your Current Time", getValue: () => { const now = new Date(); let hours = now.getHours(); let minutes = now.getMinutes(); - hours = hours < 10 ? '0' + hours : hours; - minutes = minutes < 10 ? '0' + minutes : minutes; + hours = hours < 10 ? "0" + hours : hours; + minutes = minutes < 10 ? "0" + minutes : minutes; return `${hours}:${minutes}`; }, }, - { label: 'Most Visited Movie', getValue: getMostVisitedMovie }, - { label: 'Most Visited Director', getValue: getMostVisitedDirector }, - { label: 'Most Visited Actor', getValue: getMostVisitedActor }, + { label: "Most Visited Movie", getValue: getMostVisitedMovie }, + { label: "Most Visited Director", getValue: getMostVisitedDirector }, + { label: "Most Visited Actor", getValue: getMostVisitedActor }, { - label: 'Movies Discovered', + label: "Movies Discovered", getValue: () => { - const viewedMovies = JSON.parse(localStorage.getItem('uniqueMoviesViewed')) || []; + const viewedMovies = + JSON.parse(localStorage.getItem("uniqueMoviesViewed")) || []; return viewedMovies.length; }, }, { - label: 'Favorite Movies', + label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritedMovies = + JSON.parse(localStorage.getItem("moviesFavorited")) || []; return favoritedMovies.length; }, }, { - label: 'Favorite Genre', + label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMapString = localStorage.getItem('genreMap'); + const genreMapString = localStorage.getItem("genreMap"); if (!genreMapString) { - console.log('No genre map found in localStorage.'); - return 'Not Available'; + console.log("No genre map found in localStorage."); + return "Not Available"; } let genreMap; try { genreMap = JSON.parse(genreMapString); } catch (e) { - console.log('Error parsing genre map:', e); - return 'Not Available'; + console.log("Error parsing genre map:", e); + return "Not Available"; } let genreObject; @@ -618,74 +728,81 @@ async function rotateUserStats() { acc[genre.id] = genre.name; return acc; }, {}); - } else if (typeof genreMap === 'object' && genreMap !== null) { + } else if (typeof genreMap === "object" && genreMap !== null) { genreObject = genreMap; } else { - console.log('genreMap is neither an array nor a proper object:', genreMap); - return 'Not Available'; + console.log( + "genreMap is neither an array nor a proper object:", + genreMap, + ); + return "Not Available"; } - return genreObject[mostCommonGenreCode] || 'Not Available'; + return genreObject[mostCommonGenreCode] || "Not Available"; }, }, { - label: 'Watchlists Created', - getValue: () => localStorage.getItem('watchlistsCreated') || 0, + label: "Watchlists Created", + getValue: () => localStorage.getItem("watchlistsCreated") || 0, }, { - label: 'Average Movie Rating', - getValue: () => localStorage.getItem('averageMovieRating') || 'Not Rated', + label: "Average Movie Rating", + getValue: () => localStorage.getItem("averageMovieRating") || "Not Rated", }, { - label: 'Directors Discovered', + label: "Directors Discovered", getValue: () => { - const viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + const viewedDirectors = + JSON.parse(localStorage.getItem("uniqueDirectorsViewed")) || []; return viewedDirectors.length; }, }, { - label: 'Actors Discovered', + label: "Actors Discovered", getValue: () => { - const viewedActors = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + const viewedActors = + JSON.parse(localStorage.getItem("uniqueActorsViewed")) || []; return viewedActors.length; }, }, - { label: 'Your Trivia Accuracy', getValue: getTriviaAccuracy }, + { label: "Your Trivia Accuracy", getValue: getTriviaAccuracy }, ]; let currentStatIndex = 0; function updateStatDisplay() { const currentStat = stats[currentStatIndex]; - document.getElementById('stats-label').textContent = currentStat.label + ':'; - document.getElementById('stats-display').textContent = currentStat.getValue(); + document.getElementById("stats-label").textContent = + currentStat.label + ":"; + document.getElementById("stats-display").textContent = + currentStat.getValue(); currentStatIndex = (currentStatIndex + 1) % stats.length; } updateStatDisplay(); - const localTimeDiv = document.getElementById('local-time'); + const localTimeDiv = document.getElementById("local-time"); let statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.addEventListener('click', () => { + localTimeDiv.addEventListener("click", () => { clearInterval(statRotationInterval); updateStatDisplay(); statRotationInterval = setInterval(updateStatDisplay, 3000); - localTimeDiv.scrollIntoView({ behavior: 'smooth' }); + localTimeDiv.scrollIntoView({ behavior: "smooth" }); }); } function updateMovieVisitCount(movieId, movieTitle) { - let movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + let movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; if (!movieVisits[movieId]) { movieVisits[movieId] = { count: 0, title: movieTitle }; } movieVisits[movieId].count += 1; - localStorage.setItem('movieVisits', JSON.stringify(movieVisits)); + localStorage.setItem("movieVisits", JSON.stringify(movieVisits)); } function getMostVisitedMovie() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; - let mostVisitedMovie = ''; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; + let mostVisitedMovie = ""; let maxVisits = 0; for (const movieId in movieVisits) { @@ -695,11 +812,11 @@ function getMostVisitedMovie() { } } - return mostVisitedMovie || 'Not Available'; + return mostVisitedMovie || "Not Available"; } async function getMostVisitedMovieGenre() { - const movieVisits = JSON.parse(localStorage.getItem('movieVisits')) || {}; + const movieVisits = JSON.parse(localStorage.getItem("movieVisits")) || {}; let mostVisitedGenre = null; let maxVisits = 0; @@ -722,8 +839,8 @@ async function fetchGenreForMovie(movieId) { } function getMostVisitedActor() { - const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; - let mostVisitedActor = ''; + const actorVisits = JSON.parse(localStorage.getItem("actorVisits")) || {}; + let mostVisitedActor = ""; let maxVisits = 0; for (const actorId in actorVisits) { @@ -733,12 +850,13 @@ function getMostVisitedActor() { } } - return mostVisitedActor || 'Not Available'; + return mostVisitedActor || "Not Available"; } function getMostVisitedDirector() { - const directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; - let mostVisitedDirector = ''; + const directorVisits = + JSON.parse(localStorage.getItem("directorVisits")) || {}; + let mostVisitedDirector = ""; let maxVisits = 0; for (const directorId in directorVisits) { @@ -747,16 +865,16 @@ function getMostVisitedDirector() { maxVisits = directorVisits[directorId].count; } } - return mostVisitedDirector || 'Not Available'; + return mostVisitedDirector || "Not Available"; } function getTriviaAccuracy() { - let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { + let triviaStats = JSON.parse(localStorage.getItem("triviaStats")) || { totalCorrect: 0, totalAttempted: 0, }; if (triviaStats.totalAttempted === 0) { - return 'No trivia attempted'; + return "No trivia attempted"; } let accuracy = (triviaStats.totalCorrect / triviaStats.totalAttempted) * 100; @@ -764,13 +882,14 @@ function getTriviaAccuracy() { } function getMostCommonGenre() { - const favoriteGenresArray = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + const favoriteGenresArray = + JSON.parse(localStorage.getItem("favoriteGenres")) || []; const genreCounts = favoriteGenresArray.reduce((acc, genre) => { acc[genre] = (acc[genre] || 0) + 1; return acc; }, {}); - let mostCommonGenre = ''; + let mostCommonGenre = ""; let maxCount = 0; for (const genre in genreCounts) { @@ -780,16 +899,16 @@ function getMostCommonGenre() { } } - return mostCommonGenre || 'Not Available'; + return mostCommonGenre || "Not Available"; } const movieCode = { - part1: 'YzVhMjBjODY=', - part2: 'MWFjZjdiYjg=', - part3: 'ZDllOTg3ZGNjN2YxYjU1OA==', + part1: "YzVhMjBjODY=", + part2: "MWFjZjdiYjg=", + part3: "ZDllOTg3ZGNjN2YxYjU1OA==", }; -document.addEventListener('DOMContentLoaded', rotateUserStats); +document.addEventListener("DOMContentLoaded", rotateUserStats); async function showMovieOfTheDay() { const year = new Date().getFullYear(); @@ -802,26 +921,28 @@ async function showMovieOfTheDay() { if (movies.length > 0) { const randomMovie = movies[Math.floor(Math.random() * movies.length)]; - localStorage.setItem('selectedMovieId', randomMovie.id); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomMovie.id); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } else { fallbackMovieSelection(); } } catch (error) { - console.log('Error fetching movie:', error); + console.log("Error fetching movie:", error); fallbackMovieSelection(); } } function fallbackMovieSelection() { const fallbackMovies = [ - 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, - 424, 98, + 432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, + 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, 424, + 98, ]; - const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + const randomFallbackMovie = + fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; - localStorage.setItem('selectedMovieId', randomFallbackMovie); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + localStorage.setItem("selectedMovieId", randomFallbackMovie); + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; } function calculateMoviesToDisplay() { @@ -855,71 +976,75 @@ function calculateMoviesToDisplay() { function getClassByRate(vote) { if (vote >= 8) { - return 'green'; + return "green"; } else if (vote >= 5) { - return 'orange'; + return "orange"; } else { - return 'red'; + return "red"; } } -form.addEventListener('submit', e => { +form.addEventListener("submit", (e) => { e.preventDefault(); - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; }); function toggleNav() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - sideNav.classList.toggle('manual-toggle'); + sideNav.classList.toggle("manual-toggle"); adjustNavBar(); } function removeNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if (sideNav.classList.contains("manual-toggle")) { + sideNav.classList.remove("manual-toggle"); } adjustNavBar(); } function adjustNavBar() { - const sideNav = document.getElementById('side-nav'); + const sideNav = document.getElementById("side-nav"); - if (sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0px'; + if (sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0px"; } else { - sideNav.style.left = '-250px'; + sideNav.style.left = "-250px"; } } -document.addEventListener('mousemove', function (event) { - const sideNav = document.getElementById('side-nav'); +document.addEventListener("mousemove", function (event) { + const sideNav = document.getElementById("side-nav"); - if (event.clientX < 10 && !sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '0'; + if (event.clientX < 10 && !sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "0"; } }); -document.addEventListener('click', function (event) { - const sideNav = document.getElementById('side-nav'); - const navToggle = document.getElementById('nav-toggle'); +document.addEventListener("click", function (event) { + const sideNav = document.getElementById("side-nav"); + const navToggle = document.getElementById("nav-toggle"); - if (!sideNav.contains(event.target) && !navToggle.contains(event.target) && sideNav.classList.contains('manual-toggle')) { - sideNav.classList.remove('manual-toggle'); + if ( + !sideNav.contains(event.target) && + !navToggle.contains(event.target) && + sideNav.classList.contains("manual-toggle") + ) { + sideNav.classList.remove("manual-toggle"); adjustNavBar(); } }); -document.getElementById('side-nav').addEventListener('mouseleave', function () { - const sideNav = document.getElementById('side-nav'); +document.getElementById("side-nav").addEventListener("mouseleave", function () { + const sideNav = document.getElementById("side-nav"); - if (!sideNav.classList.contains('manual-toggle')) { - sideNav.style.left = '-250px'; + if (!sideNav.classList.contains("manual-toggle")) { + sideNav.style.left = "-250px"; } }); @@ -928,32 +1053,32 @@ const IMGPATH = `https://image.tmdb.org/t/p/w500`; const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; const directors = [ - { name: 'Alfred Hitchcock', id: '2636' }, - { name: 'Steven Spielberg', id: '488' }, - { name: 'Martin Scorsese', id: '1032' }, - { name: 'Quentin Tarantino', id: '138' }, - { name: 'Christopher Nolan', id: '525' }, - { name: 'Stanley Kubrick', id: '240' }, - { name: 'Bong Joon-ho', id: '21684' }, - { name: 'David Fincher', id: '7467' }, - { name: 'James Cameron', id: '2710' }, - { name: 'Francis Ford Coppola', id: '1776' }, - { name: 'Tim Burton', id: '510' }, - { name: 'Ridley Scott', id: '578' }, - { name: 'Joel Coen', id: '1223' }, - { name: 'Spike Lee', id: '5281' }, - { name: 'Woody Allen', id: '1243' }, - { name: 'Peter Jackson', id: '108' }, - { name: 'Oliver Stone', id: '1152' }, - { name: 'David Lynch', id: '5602' }, - { name: 'Roman Polanski', id: '3556' }, - { name: 'Wes Anderson', id: '5655' }, - { name: 'Sergio Leone', id: '4385' }, - { name: 'Akira Kurosawa', id: '5026' }, - { name: 'Federico Fellini', id: '4415' }, - { name: 'John Ford', id: '8500' }, - { name: 'Fritz Lang', id: '68' }, - { name: 'Frank Capra', id: '2662' }, + { name: "Alfred Hitchcock", id: "2636" }, + { name: "Steven Spielberg", id: "488" }, + { name: "Martin Scorsese", id: "1032" }, + { name: "Quentin Tarantino", id: "138" }, + { name: "Christopher Nolan", id: "525" }, + { name: "Stanley Kubrick", id: "240" }, + { name: "Bong Joon-ho", id: "21684" }, + { name: "David Fincher", id: "7467" }, + { name: "James Cameron", id: "2710" }, + { name: "Francis Ford Coppola", id: "1776" }, + { name: "Tim Burton", id: "510" }, + { name: "Ridley Scott", id: "578" }, + { name: "Joel Coen", id: "1223" }, + { name: "Spike Lee", id: "5281" }, + { name: "Woody Allen", id: "1243" }, + { name: "Peter Jackson", id: "108" }, + { name: "Oliver Stone", id: "1152" }, + { name: "David Lynch", id: "5602" }, + { name: "Roman Polanski", id: "3556" }, + { name: "Wes Anderson", id: "5655" }, + { name: "Sergio Leone", id: "4385" }, + { name: "Akira Kurosawa", id: "5026" }, + { name: "Federico Fellini", id: "4415" }, + { name: "John Ford", id: "8500" }, + { name: "Fritz Lang", id: "68" }, + { name: "Frank Capra", id: "2662" }, ]; let currentDirectorIndex = 0; @@ -972,7 +1097,8 @@ setInterval(changeDirector, 3600000); function updateDirectorSpotlight() { const director = directors[currentDirectorIndex]; - document.getElementById('spotlight-director-name').textContent = director.name; + document.getElementById("spotlight-director-name").textContent = + director.name; const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_people=${ director.id @@ -981,7 +1107,26 @@ function updateDirectorSpotlight() { } function getMovieVerseData(input) { - return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); + return String.fromCharCode( + 97, + 112, + 105, + 46, + 116, + 104, + 101, + 109, + 111, + 118, + 105, + 101, + 100, + 98, + 46, + 111, + 114, + 103, + ); } function generateMovieNames(input) { @@ -1005,21 +1150,59 @@ async function getDirectorSpotlight(url) { } function showMoviesDirectorSpotlight(movies) { - director_main.innerHTML = ''; + director_main.innerHTML = ""; + + // Inject CSS for the sliding-up animation effect with delay support + const style = document.createElement("style"); + style.innerHTML = ` + .movie { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; + } + .movie.visible { + opacity: 1; + transform: translateY(0); + } + `; + document.head.appendChild(style); + + // Observer to trigger the slide-up animation with a staggered delay + const slideObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + const movieEl = entry.target; + + // Apply a staggered delay based on the card's index + movieEl.style.transitionDelay = `${index * 100}ms`; // Adjust delay as needed + movieEl.classList.add("visible"); + + slideObserver.unobserve(movieEl); + } + }); + }, + { + rootMargin: "50px 0px", + threshold: 0.1, + }, + ); - movies.forEach(movie => { + movies.forEach((movie, index) => { const { id, poster_path, title, vote_average, genre_ids } = movie; - const movieEl = document.createElement('div'); + const movieEl = document.createElement("div"); - movieEl.classList.add('movie'); - movieEl.style.zIndex = '1000'; + movieEl.classList.add("movie"); + movieEl.style.zIndex = "1000"; + // Movie image and fallback in case the image is unavailable const movieImage = poster_path ? `${title}` : `
Image Not Available
`; - const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : 'Unrated'; - const ratingClass = vote_average > 0 ? getClassByRate(vote_average) : 'unrated'; + const voteAvg = vote_average > 0 ? vote_average.toFixed(1) : "Unrated"; + const ratingClass = + vote_average > 0 ? getClassByRate(vote_average) : "unrated"; movieEl.innerHTML = ` ${movieImage} @@ -1032,26 +1215,29 @@ function showMoviesDirectorSpotlight(movies) { ${movie.overview}
`; - movieEl.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', id); + movieEl.addEventListener("click", () => { + localStorage.setItem("selectedMovieId", id); updateUniqueMoviesViewed(id); updateFavoriteGenre(genre_ids); updateMovieVisitCount(id, title); - window.location.href = 'MovieVerse-Frontend/html/movie-details.html'; + window.location.href = "MovieVerse-Frontend/html/movie-details.html"; }); director_main.appendChild(movieEl); + + // Observe for the slide-up animation + slideObserver.observe(movieEl); }); } function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); + localStorage.setItem("isSignedIn", JSON.stringify(false)); + alert("You have been signed out."); } else { - window.location.href = 'MovieVerse-Frontend/html/sign-in.html'; + window.location.href = "MovieVerse-Frontend/html/sign-in.html"; return; } @@ -1059,213 +1245,215 @@ function handleSignInOut() { } function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); + const isSignedIn = JSON.parse(localStorage.getItem("isSignedIn")) || false; + const signInText = document.getElementById("signInOutText"); + const signInIcon = document.getElementById("signInIcon"); + const signOutIcon = document.getElementById("signOutIcon"); if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; + signInText.textContent = "Sign Out"; + signInIcon.style.display = "none"; + signOutIcon.style.display = "inline-block"; } else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; + signInText.textContent = "Sign In"; + signInIcon.style.display = "inline-block"; + signOutIcon.style.display = "none"; } - const mobileSignInText = document.getElementById('mobileSignInOutText'); - const mobileSignInIcon = document.getElementById('mobileSignInIcon'); - const mobileSignOutIcon = document.getElementById('mobileSignOutIcon'); + const mobileSignInText = document.getElementById("mobileSignInOutText"); + const mobileSignInIcon = document.getElementById("mobileSignInIcon"); + const mobileSignOutIcon = document.getElementById("mobileSignOutIcon"); if (isSignedIn) { - mobileSignInText.textContent = 'Sign Out'; - mobileSignInIcon.style.display = 'none'; - mobileSignOutIcon.style.display = 'inline-block'; + mobileSignInText.textContent = "Sign Out"; + mobileSignInIcon.style.display = "none"; + mobileSignOutIcon.style.display = "inline-block"; } else { - mobileSignInText.textContent = 'Sign In'; - mobileSignInIcon.style.display = 'inline-block'; - mobileSignOutIcon.style.display = 'none'; + mobileSignInText.textContent = "Sign In"; + mobileSignInIcon.style.display = "inline-block"; + mobileSignOutIcon.style.display = "none"; } } setupPagination( - 'award-winning', - 'award-winning-pagination', - 'award-winning-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000` + "award-winning", + "award-winning-pagination", + "award-winning-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=1000`, ); setupPagination( - 'hidden-gems', - 'hidden-gems-pagination', - 'hidden-gems-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10` + "hidden-gems", + "hidden-gems-pagination", + "hidden-gems-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=vote_average.desc&vote_count.gte=100&vote_average.gte=7&popularity.lte=10`, ); setupPagination( - 'western', - 'western-pagination', - 'western-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8` + "western", + "western-pagination", + "western-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=37&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'war', - 'war-pagination', - 'war-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8` + "war", + "war-pagination", + "war-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10752&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'vietnamese', - 'vietnamese-pagination', - 'vietnamese-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc` + "vietnamese", + "vietnamese-pagination", + "vietnamese-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=vi&sort_by=popularity.desc`, ); setupPagination( - 'korean', - 'korean-pagination', - 'korean-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8` + "korean", + "korean-pagination", + "korean-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=ko&sort_by=vote_average.desc,popularity.desc&vote_count.gte=10&vote_average.gte=8`, ); setupPagination( - 'musical', - 'musical-pagination', - 'musical-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8` + "musical", + "musical-pagination", + "musical-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10402&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'drama', - 'drama-pagination', - 'drama-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8` + "drama", + "drama-pagination", + "drama-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=18&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'indian', - 'indian-pagination', - 'indian-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc` + "indian", + "indian-pagination", + "indian-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_original_language=hi&sort_by=popularity.desc`, ); setupPagination( - 'action', - 'action-pagination', - 'action-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8` + "action", + "action-pagination", + "action-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=28&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'horror', - 'horror-pagination', - 'horror-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8` + "horror", + "horror-pagination", + "horror-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=27&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'documentary', - 'documentary-pagination', - 'documentary-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8` + "documentary", + "documentary-pagination", + "documentary-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=99&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'animation', - 'animation-pagination', - 'animation-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8` + "animation", + "animation-pagination", + "animation-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=16&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'sci-fi', - 'sci-fi-pagination', - 'sci-fi-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8` + "sci-fi", + "sci-fi-pagination", + "sci-fi-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=878&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'romantic', - 'romantic-pagination', - 'romantic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8` + "romantic", + "romantic-pagination", + "romantic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10749&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'thriller', - 'thriller-pagination', - 'thriller-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8` + "thriller", + "thriller-pagination", + "thriller-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=53&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'mystery', - 'mystery-pagination', - 'mystery-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8` + "mystery", + "mystery-pagination", + "mystery-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=9648&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'comedy', - 'comedy-pagination', - 'comedy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8` + "comedy", + "comedy-pagination", + "comedy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=35&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'fantasy', - 'fantasy-pagination', - 'fantasy-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8` + "fantasy", + "fantasy-pagination", + "fantasy-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=14&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'family', - 'family-pagination', - 'family-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8` + "family", + "family-pagination", + "family-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10751&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'tv-series', - 'tv-series-pagination', - 'tv-series-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8` + "tv-series", + "tv-series-pagination", + "tv-series-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=10770&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'crime', - 'crime-pagination', - 'crime-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8` + "crime", + "crime-pagination", + "crime-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=80&sort_by=popularity.desc&vote_count.gte=8`, ); setupPagination( - 'classic', - 'classic-pagination', - 'classic-div', - `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980` + "classic", + "classic-pagination", + "classic-div", + `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&sort_by=popularity.desc&release_date.lte=1980`, ); -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + document + .getElementById("googleSignInBtn") + .addEventListener("click", handleSignInOut); }); function handleSearch() { - const searchQuery = document.getElementById('search').value; + const searchQuery = document.getElementById("search").value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'MovieVerse-Frontend/html/search.html'; + localStorage.setItem("searchQuery", searchQuery); + window.location.href = "MovieVerse-Frontend/html/search.html"; } -document.addEventListener('DOMContentLoaded', () => { - const notificationBtn = document.getElementById('notificationBtn'); +document.addEventListener("DOMContentLoaded", () => { + const notificationBtn = document.getElementById("notificationBtn"); - notificationBtn.addEventListener('click', () => { - window.location.href = 'MovieVerse-Frontend/html/notifications.html'; + notificationBtn.addEventListener("click", () => { + window.location.href = "MovieVerse-Frontend/html/notifications.html"; }); });