From daafe29d1c34dcd4fd5fc475e08a88e3bdacb410 Mon Sep 17 00:00:00 2001 From: Son Nguyen Date: Sat, 25 May 2024 08:19:18 +0700 Subject: [PATCH] Update: Enhanced app functionalities (#196) --- MovieVerse-Frontend/html/privacy-policy.html | 446 ++++++------- MovieVerse-Frontend/html/user-profile.html | 1 - MovieVerse-Frontend/js/movie-timeline.js | 2 + MovieVerse-Mobile/app/js/LICENSE | 172 ++++- MovieVerse-Mobile/app/js/chatbot.js | 68 +- MovieVerse-Mobile/app/js/favorites.js | 95 ++- MovieVerse-Mobile/app/js/movie-timeline.js | 71 ++- MovieVerse-Mobile/app/js/search.js | 62 +- MovieVerse-Mobile/machine-learning/LICENSE | 21 + .../assets/www/MovieVerse-Frontend/LICENSE | 172 ++++- .../www/MovieVerse-Frontend/css/LICENSE | 172 ++++- .../www/MovieVerse-Frontend/html/LICENSE | 172 ++++- .../www/MovieVerse-Frontend/html/about.html | 10 +- .../html/actor-details.html | 10 +- .../MovieVerse-Frontend/html/analytics.html | 10 +- .../MovieVerse-Frontend/html/api_fails.html | 10 +- .../www/MovieVerse-Frontend/html/chat.html | 10 +- .../www/MovieVerse-Frontend/html/chatbot.html | 10 +- .../html/company-details.html | 10 +- .../html/create-account.html | 10 +- .../html/director-details.html | 10 +- .../MovieVerse-Frontend/html/favorites.html | 10 +- .../MovieVerse-Frontend/html/feedback.html | 10 +- .../html/movie-details.html | 10 +- .../MovieVerse-Frontend/html/movie-match.html | 10 +- .../html/movie-timeline.html | 10 +- .../html/notifications.html | 10 +- .../www/MovieVerse-Frontend/html/offline.html | 10 +- .../html/privacy-policy.html | 456 ++++++------- .../html/reset-password.html | 10 +- .../www/MovieVerse-Frontend/html/search.html | 10 +- .../MovieVerse-Frontend/html/settings.html | 10 +- .../www/MovieVerse-Frontend/html/sign-in.html | 10 +- .../www/MovieVerse-Frontend/html/support.html | 10 +- .../html/terms-of-service.html | 10 +- .../www/MovieVerse-Frontend/html/trivia.html | 10 +- .../MovieVerse-Frontend/html/tv-details.html | 10 +- .../html/user-profile.html | 11 +- .../assets/www/MovieVerse-Frontend/js/LICENSE | 172 ++++- .../www/MovieVerse-Frontend/js/favorites.js | 12 + .../MovieVerse-Frontend/js/movie-timeline.js | 2 + .../www/MovieVerse-Frontend/react/LICENSE | 172 ++++- .../www/MovieVerse-Frontend/tests/LICENSE | 172 ++++- .../ios/www/MovieVerse-Frontend/LICENSE | 172 ++++- .../ios/www/MovieVerse-Frontend/css/LICENSE | 172 ++++- .../ios/www/MovieVerse-Frontend/html/LICENSE | 172 ++++- .../www/MovieVerse-Frontend/html/about.html | 10 +- .../html/actor-details.html | 10 +- .../MovieVerse-Frontend/html/analytics.html | 10 +- .../MovieVerse-Frontend/html/api_fails.html | 10 +- .../www/MovieVerse-Frontend/html/chat.html | 10 +- .../www/MovieVerse-Frontend/html/chatbot.html | 10 +- .../html/company-details.html | 10 +- .../html/create-account.html | 10 +- .../html/director-details.html | 10 +- .../MovieVerse-Frontend/html/favorites.html | 10 +- .../MovieVerse-Frontend/html/feedback.html | 10 +- .../html/movie-details.html | 10 +- .../MovieVerse-Frontend/html/movie-match.html | 10 +- .../html/movie-timeline.html | 10 +- .../html/notifications.html | 10 +- .../www/MovieVerse-Frontend/html/offline.html | 10 +- .../html/privacy-policy.html | 456 ++++++------- .../html/reset-password.html | 10 +- .../www/MovieVerse-Frontend/html/search.html | 10 +- .../MovieVerse-Frontend/html/settings.html | 10 +- .../www/MovieVerse-Frontend/html/sign-in.html | 10 +- .../www/MovieVerse-Frontend/html/support.html | 10 +- .../html/terms-of-service.html | 10 +- .../www/MovieVerse-Frontend/html/trivia.html | 10 +- .../MovieVerse-Frontend/html/tv-details.html | 10 +- .../html/user-profile.html | 11 +- .../ios/www/MovieVerse-Frontend/js/LICENSE | 172 ++++- .../www/MovieVerse-Frontend/js/favorites.js | 12 + .../MovieVerse-Frontend/js/movie-timeline.js | 2 + .../ios/www/MovieVerse-Frontend/react/LICENSE | 172 ++++- .../ios/www/MovieVerse-Frontend/tests/LICENSE | 172 ++++- .../http-client.private.env.json | 5 + .../www/MovieVerse-Frontend/html/about.html | 10 +- .../html/actor-details.html | 10 +- .../MovieVerse-Frontend/html/analytics.html | 10 +- .../MovieVerse-Frontend/html/api_fails.html | 10 +- .../www/MovieVerse-Frontend/html/chat.html | 10 +- .../www/MovieVerse-Frontend/html/chatbot.html | 10 +- .../html/company-details.html | 10 +- .../html/create-account.html | 10 +- .../html/director-details.html | 10 +- .../MovieVerse-Frontend/html/favorites.html | 10 +- .../MovieVerse-Frontend/html/feedback.html | 10 +- .../html/movie-details.html | 10 +- .../MovieVerse-Frontend/html/movie-match.html | 10 +- .../html/movie-timeline.html | 10 +- .../html/notifications.html | 10 +- .../www/MovieVerse-Frontend/html/offline.html | 10 +- .../html/privacy-policy.html | 456 ++++++------- .../html/reset-password.html | 10 +- .../www/MovieVerse-Frontend/html/search.html | 10 +- .../MovieVerse-Frontend/html/settings.html | 10 +- .../www/MovieVerse-Frontend/html/sign-in.html | 10 +- .../www/MovieVerse-Frontend/html/support.html | 10 +- .../html/terms-of-service.html | 10 +- .../www/MovieVerse-Frontend/html/trivia.html | 10 +- .../MovieVerse-Frontend/html/tv-details.html | 10 +- .../html/user-profile.html | 11 +- .../MovieVerse-Frontend/js/movie-timeline.js | 2 + MovieVerse-Mobile/www/js/LICENSE | 172 ++++- MovieVerse-Mobile/www/js/about.js | 37 +- MovieVerse-Mobile/www/js/actor-details.js | 198 +++++- MovieVerse-Mobile/www/js/add-to-favorites.js | 29 +- MovieVerse-Mobile/www/js/analytics.js | 37 +- MovieVerse-Mobile/www/js/chat-auxiliary.js | 48 +- MovieVerse-Mobile/www/js/chat.js | 98 ++- MovieVerse-Mobile/www/js/chatbot.js | 402 +++++++----- MovieVerse-Mobile/www/js/christopher-nolan.js | 37 +- MovieVerse-Mobile/www/js/comments-tv.js | 161 +++++ MovieVerse-Mobile/www/js/comments.js | 19 +- MovieVerse-Mobile/www/js/company-details.js | 49 +- MovieVerse-Mobile/www/js/create-account.js | 18 +- MovieVerse-Mobile/www/js/director-details.js | 192 +++++- MovieVerse-Mobile/www/js/favorites.js | 515 +++++++++------ MovieVerse-Mobile/www/js/firebase.js | 50 ++ MovieVerse-Mobile/www/js/inception.js | 50 +- .../www/js/leonardo-dicarprio.js | 37 +- MovieVerse-Mobile/www/js/movie-details.js | 600 +++++++++++------- MovieVerse-Mobile/www/js/movie-match.js | 37 +- MovieVerse-Mobile/www/js/movie-timeline.js | 123 +++- MovieVerse-Mobile/www/js/notifications.js | 64 +- MovieVerse-Mobile/www/js/quiz.js | 212 ++----- MovieVerse-Mobile/www/js/ratings-module.js | 80 +++ MovieVerse-Mobile/www/js/search.js | 300 +++++++-- MovieVerse-Mobile/www/js/service-worker.js | 68 +- MovieVerse-Mobile/www/js/settings.js | 261 +++++--- MovieVerse-Mobile/www/js/triviaModule.js | 69 ++ MovieVerse-Mobile/www/js/tv-details.js | 324 ++++++++-- MovieVerse-Mobile/www/js/user-profile.js | 176 ++++- 135 files changed, 6846 insertions(+), 2775 deletions(-) create mode 100644 MovieVerse-Mobile/machine-learning/LICENSE create mode 100644 MovieVerse-Mobile/www/MovieVerse-APIs/http-client.private.env.json create mode 100644 MovieVerse-Mobile/www/js/comments-tv.js create mode 100644 MovieVerse-Mobile/www/js/firebase.js create mode 100644 MovieVerse-Mobile/www/js/ratings-module.js create mode 100644 MovieVerse-Mobile/www/js/triviaModule.js diff --git a/MovieVerse-Frontend/html/privacy-policy.html b/MovieVerse-Frontend/html/privacy-policy.html index 2e3fe7f2..bbe36f6d 100644 --- a/MovieVerse-Frontend/html/privacy-policy.html +++ b/MovieVerse-Frontend/html/privacy-policy.html @@ -202,6 +202,14 @@ #translate_control { bottom: 70px; } + + #form1 { + margin-top: 5px !important; + } + } + + #form1 { + margin-top: 20px; } @@ -248,7 +256,7 @@ }, { passive: true }); }) -
+

The MovieVerse @@ -293,7 +301,7 @@

-
+
Privacy Policy
@@ -349,6 +357,224 @@

Cookies and Web Beacons

+ + - \ No newline at end of file diff --git a/MovieVerse-Frontend/js/movie-timeline.js b/MovieVerse-Frontend/js/movie-timeline.js index a69d9e14..37f491bf 100644 --- a/MovieVerse-Frontend/js/movie-timeline.js +++ b/MovieVerse-Frontend/js/movie-timeline.js @@ -419,6 +419,7 @@ function createLoadMoreButton(startYear, endYear, mainElement) { 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(); @@ -430,6 +431,7 @@ async function fetchMoviesByTimePeriod(startYear, endYear, append = false) { else { showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, false); } + hideSpinner(); } document.getElementById('load-movies').addEventListener('click', () => { diff --git a/MovieVerse-Mobile/app/js/LICENSE b/MovieVerse-Mobile/app/js/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/app/js/LICENSE +++ b/MovieVerse-Mobile/app/js/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/app/js/chatbot.js b/MovieVerse-Mobile/app/js/chatbot.js index 800a1f5f..9df8ce8b 100644 --- a/MovieVerse-Mobile/app/js/chatbot.js +++ b/MovieVerse-Mobile/app/js/chatbot.js @@ -10,6 +10,7 @@ const movieCode = { function getMovieCode() { return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); } function generateMovieNames(input) { @@ -167,11 +168,34 @@ async function rotateUserStats() { 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() { @@ -204,26 +228,12 @@ function getMostVisitedActor() { 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`; } @@ -250,6 +260,34 @@ function getMostCommonGenre() { 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)); +} + function calculateMoviesToDisplay() { const screenWidth = window.innerWidth; if (screenWidth <= 689.9) return 10; // 1 movie per row diff --git a/MovieVerse-Mobile/app/js/favorites.js b/MovieVerse-Mobile/app/js/favorites.js index 55518565..c9e83327 100644 --- a/MovieVerse-Mobile/app/js/favorites.js +++ b/MovieVerse-Mobile/app/js/favorites.js @@ -559,18 +559,35 @@ async function populateCreateModalWithFavorites() { } 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 { - showSpinner(); - e.preventDefault(); + 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()); + } - const name = document.getElementById('new-watchlist-name').value; - 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'); - const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); - const querySnapshot = await getDocs(q); - let maxOrder = querySnapshot.docs.reduce((max, docSnapshot) => Math.max(max, docSnapshot.data().order || 0), 0); + 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')); @@ -586,7 +603,6 @@ document.getElementById('create-watchlist-form').addEventListener('submit', asyn }); } else { - const localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; localWatchlists.push({ id: `local-${new Date().getTime()}`, userEmail: "", @@ -599,20 +615,10 @@ document.getElementById('create-watchlist-form').addEventListener('submit', asyn }); localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); } - - closeModal('create-watchlist-modal'); - loadWatchLists(); - hideSpinner(); - window.location.reload(); } catch (error) { if (error.code === 'resource-exhausted') { console.log('Firebase quota exceeded. Using localStorage for watchlists.'); - const name = document.getElementById('new-watchlist-name').value; - 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 localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; localWatchlists.push({ id: `local-${new Date().getTime()}`, userEmail: "", @@ -624,12 +630,17 @@ document.getElementById('create-watchlist-form').addEventListener('submit', asyn createdAt: new Date().toISOString() }); localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); - closeModal('create-watchlist-modal'); - loadWatchLists(); - hideSpinner(); - window.location.reload(); + } + 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) { @@ -1368,11 +1379,15 @@ async function loadWatchLists() { if (favorites.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-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."; @@ -1395,7 +1410,7 @@ async function loadWatchLists() { else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-watchlist'; + favoritesDiv.id = 'favorite-movies'; favoritesDiv.innerHTML = '

Favorite Movies

No favorite movies added yet.

'; displaySection.appendChild(favoritesDiv); } @@ -1403,11 +1418,15 @@ async function loadWatchLists() { if (favoritesTVSeries.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-tvseries-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."; @@ -1430,7 +1449,7 @@ async function loadWatchLists() { else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-tvseries-watchlist'; + favoritesDiv.id = 'favorite-tv-series'; favoritesDiv.innerHTML = '

Favorite TV Series

No favorite TV series added yet.

'; displaySection.appendChild(favoritesDiv); } @@ -1464,7 +1483,7 @@ async function loadWatchLists() { if (favorites.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-watchlist'; + favoritesDiv.id = 'favorite-movies'; const title = document.createElement('h3'); title.textContent = "Favorite Movies"; @@ -1491,7 +1510,7 @@ async function loadWatchLists() { else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-watchlist'; + favoritesDiv.id = 'favorite-movies'; favoritesDiv.innerHTML = '

Favorite Movies

No favorite movies added yet.

'; displaySection.appendChild(favoritesDiv); } @@ -1499,7 +1518,7 @@ async function loadWatchLists() { if (favoritesTVSeries.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-tvseries-watchlist'; + favoritesDiv.id = 'favorite-tv-series'; const title = document.createElement('h3'); title.textContent = "Favorite TV Series"; @@ -1524,6 +1543,14 @@ async function loadWatchLists() { 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); @@ -1743,6 +1770,10 @@ function createWatchListDiv(watchlist) { 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; diff --git a/MovieVerse-Mobile/app/js/movie-timeline.js b/MovieVerse-Mobile/app/js/movie-timeline.js index eabe2e25..37f491bf 100644 --- a/MovieVerse-Mobile/app/js/movie-timeline.js +++ b/MovieVerse-Mobile/app/js/movie-timeline.js @@ -330,8 +330,24 @@ function updateMovies() { } } -function showMovies(movies, mainElement) { - mainElement.innerHTML = ''; +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'; + header.textContent = `Movies from ${startYear} to ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.innerHTML = ''; + centerContainer1.appendChild(header); + centerContainer1.appendChild(mainElement); + } + movies.forEach(movie => { const movieEl = document.createElement('div'); movieEl.classList.add('movie'); @@ -368,19 +384,54 @@ function showMovies(movies, mainElement) { movieEl.style.cursor = 'pointer'; mainElement.appendChild(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.appendChild(mainElement); + + createLoadMoreButton(startYear, endYear, mainElement); + hideSpinner(); } -document.getElementById('clear-search-btn').addEventListener('click', () => { - location.reload(); -}); +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); +} -async function fetchMoviesByTimePeriod(startYear, endYear) { - const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31`; +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 numberOfMovies = calculateMoviesToDisplay(); - const moviesToShow = data.results.slice(0, numberOfMovies); - showMovies(moviesToShow, document.getElementById('results')); + 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', () => { diff --git a/MovieVerse-Mobile/app/js/search.js b/MovieVerse-Mobile/app/js/search.js index c4f9c0b1..cd665e18 100644 --- a/MovieVerse-Mobile/app/js/search.js +++ b/MovieVerse-Mobile/app/js/search.js @@ -404,7 +404,7 @@ function attachEventListeners() { movieFilters.style.display = 'none'; tvFilters.style.display = 'none'; peopleFilters.style.display = 'none'; - toggleFiltersBtn.textContent = 'Filter Results'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; }); tvBtn.addEventListener('click', () => { @@ -414,7 +414,7 @@ function attachEventListeners() { movieFilters.style.display = 'none'; tvFilters.style.display = 'none'; peopleFilters.style.display = 'none'; - toggleFiltersBtn.textContent = 'Filter Results'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; }); peopleBtn.addEventListener('click', () => { @@ -424,7 +424,7 @@ function attachEventListeners() { movieFilters.style.display = 'none'; tvFilters.style.display = 'none'; peopleFilters.style.display = 'none'; - toggleFiltersBtn.textContent = 'Filter Results'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; }); toggleFiltersBtn.addEventListener('click', () => { @@ -529,10 +529,26 @@ document.addEventListener('DOMContentLoaded', function() { toggleFiltersBtn.textContent = 'Close Filters'; } else { - toggleFiltersBtn.textContent = 'Filter Results'; + 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'); @@ -540,6 +556,10 @@ document.addEventListener('DOMContentLoaded', function() { }); }); +let movieSortChanged = false; +let tvSortChanged = false; +let peopleSortChanged = false; + function attachArrowKeyNavigation() { const categories = ['movie', 'tv', 'person']; let currentIndex = 0; @@ -580,6 +600,23 @@ 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); @@ -591,6 +628,17 @@ async function showResults(category) { 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); @@ -652,6 +700,12 @@ async function showResults(category) { }); } + if ((category === 'movie' && movieSortChanged) || + (category === 'tv' && tvSortChanged) || + (category === 'person' && peopleSortChanged)) { + data.results = sortResults(data.results, sortValue); + } + displayResults(data.results, category, searchQuery); } catch (error) { diff --git a/MovieVerse-Mobile/machine-learning/LICENSE b/MovieVerse-Mobile/machine-learning/LICENSE new file mode 100644 index 00000000..19d3d823 --- /dev/null +++ b/MovieVerse-Mobile/machine-learning/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Son Nguyen Hoang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/LICENSE b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/LICENSE +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/css/LICENSE b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/css/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/css/LICENSE +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/css/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/LICENSE b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/LICENSE +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/about.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/about.html index 915c6280..d619cff3 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/about.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/about.html @@ -274,9 +274,9 @@

- - - + + +

@@ -487,9 +487,9 @@

Useful Links:

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -522,9 +522,9 @@

Useful Links:

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/actor-details.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/actor-details.html index 9cf910bc..6953ef9d 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/actor-details.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/actor-details.html @@ -301,9 +301,9 @@

- - - + + + @@ -390,9 +390,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -468,9 +468,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/analytics.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/analytics.html index 10c4f815..abd29fb9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/analytics.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/analytics.html @@ -344,9 +344,9 @@

- - - + + + @@ -537,9 +537,9 @@

Highly Rated Movies Over Years

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -571,9 +571,9 @@

Highly Rated Movies Over Years

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/api_fails.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/api_fails.html index 80e3184f..d629ccd9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/api_fails.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/api_fails.html @@ -514,9 +514,9 @@

Chat - - - + + + @@ -692,9 +692,9 @@

Chat - - - + + + @@ -660,9 +660,9 @@

Recent & Suggested Chats

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -723,9 +723,9 @@

Recent & Suggested Chats

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/chatbot.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/chatbot.html index 40b2a891..181fee47 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/chatbot.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/chatbot.html @@ -325,9 +325,9 @@

- - - + + + @@ -798,9 +798,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -832,9 +832,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/company-details.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/company-details.html index f70294c3..df9c1c97 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/company-details.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/company-details.html @@ -305,9 +305,9 @@

- - - + + + @@ -396,9 +396,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -430,9 +430,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/create-account.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/create-account.html index 47a7d740..e4a3ead6 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/create-account.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/create-account.html @@ -321,9 +321,9 @@

- - - + + + @@ -739,9 +739,9 @@

Create Account

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -773,9 +773,9 @@

Create Account

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/director-details.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/director-details.html index 23839b49..5b1ff846 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/director-details.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/director-details.html @@ -586,9 +586,9 @@

- - - + + + @@ -681,9 +681,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -715,9 +715,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/favorites.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/favorites.html index 08cdac01..86b50567 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/favorites.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/favorites.html @@ -504,9 +504,9 @@

How to Use MovieVerse Watchlists

- - - + + + @@ -801,9 +801,9 @@

How to Use MovieVerse Watchlists

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -835,9 +835,9 @@

How to Use MovieVerse Watchlists

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/feedback.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/feedback.html index 2eb1f580..f3e7972a 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/feedback.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/feedback.html @@ -581,9 +581,9 @@

Chat - - - + + + @@ -1095,9 +1095,9 @@

Chat - - - + + + @@ -867,9 +867,9 @@

Add a Comment for This Movie

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -901,9 +901,9 @@

Add a Comment for This Movie

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-match.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-match.html index d0a7a52a..d87e80e6 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-match.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-match.html @@ -700,9 +700,9 @@

Find Your Movie Match

- - - + + + @@ -838,9 +838,9 @@

Find Your Movie Match

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -872,9 +872,9 @@

Find Your Movie Match

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-timeline.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-timeline.html index 0feef768..0a211647 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-timeline.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/movie-timeline.html @@ -316,9 +316,9 @@

- - - + + + @@ -412,9 +412,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', 'back-to-top-btn' @@ -449,9 +449,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', 'back-to-top-btn' diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/notifications.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/notifications.html index cc233067..67737631 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/notifications.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/notifications.html @@ -359,9 +359,9 @@

- - - + + + @@ -1253,9 +1253,9 @@

Popular Directors

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -1287,9 +1287,9 @@

Popular Directors

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/offline.html b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/offline.html index 2569eb2c..2787aec0 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/offline.html +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/html/offline.html @@ -281,9 +281,9 @@

Chat - - - + + + @@ -775,9 +775,9 @@

The MovieVerse @@ -285,15 +293,15 @@

- - - + + +
-
+
Privacy Policy
@@ -349,6 +357,224 @@

Cookies and Web Beacons

+ + - \ No newline at end of file diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/LICENSE b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/LICENSE +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/js/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 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 06efb125..c9e83327 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 @@ -1384,6 +1384,10 @@ async function loadWatchLists() { 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."; @@ -1419,6 +1423,10 @@ async function loadWatchLists() { 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."; @@ -1762,6 +1770,10 @@ function createWatchListDiv(watchlist) { 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; 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 a69d9e14..37f491bf 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 @@ -419,6 +419,7 @@ function createLoadMoreButton(startYear, endYear, mainElement) { 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(); @@ -430,6 +431,7 @@ async function fetchMoviesByTimePeriod(startYear, endYear, append = false) { else { showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, false); } + hideSpinner(); } document.getElementById('load-movies').addEventListener('click', () => { diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/LICENSE b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/LICENSE +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/react/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/tests/LICENSE b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/tests/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/tests/LICENSE +++ b/MovieVerse-Mobile/platforms/android/app/src/main/assets/www/MovieVerse-Frontend/tests/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/LICENSE b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/LICENSE +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/css/LICENSE b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/css/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/css/LICENSE +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/css/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/LICENSE b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/LICENSE +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/about.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/about.html index 915c6280..d619cff3 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/about.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/about.html @@ -274,9 +274,9 @@

- - - + + + @@ -487,9 +487,9 @@

Useful Links:

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -522,9 +522,9 @@

Useful Links:

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/actor-details.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/actor-details.html index 9cf910bc..6953ef9d 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/actor-details.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/actor-details.html @@ -301,9 +301,9 @@

- - - + + + @@ -390,9 +390,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -468,9 +468,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/analytics.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/analytics.html index 10c4f815..abd29fb9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/analytics.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/analytics.html @@ -344,9 +344,9 @@

- - - + + + @@ -537,9 +537,9 @@

Highly Rated Movies Over Years

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -571,9 +571,9 @@

Highly Rated Movies Over Years

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/api_fails.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/api_fails.html index 80e3184f..d629ccd9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/api_fails.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/api_fails.html @@ -514,9 +514,9 @@

Chat - - - + + + @@ -692,9 +692,9 @@

Chat - - - + + + @@ -660,9 +660,9 @@

Recent & Suggested Chats

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -723,9 +723,9 @@

Recent & Suggested Chats

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/chatbot.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/chatbot.html index 40b2a891..181fee47 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/chatbot.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/chatbot.html @@ -325,9 +325,9 @@

- - - + + + @@ -798,9 +798,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -832,9 +832,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/company-details.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/company-details.html index f70294c3..df9c1c97 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/company-details.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/company-details.html @@ -305,9 +305,9 @@

- - - + + + @@ -396,9 +396,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -430,9 +430,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/create-account.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/create-account.html index 47a7d740..e4a3ead6 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/create-account.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/create-account.html @@ -321,9 +321,9 @@

- - - + + + @@ -739,9 +739,9 @@

Create Account

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -773,9 +773,9 @@

Create Account

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/director-details.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/director-details.html index 23839b49..5b1ff846 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/director-details.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/director-details.html @@ -586,9 +586,9 @@

- - - + + + @@ -681,9 +681,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -715,9 +715,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/favorites.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/favorites.html index 08cdac01..86b50567 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/favorites.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/favorites.html @@ -504,9 +504,9 @@

How to Use MovieVerse Watchlists

- - - + + + @@ -801,9 +801,9 @@

How to Use MovieVerse Watchlists

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -835,9 +835,9 @@

How to Use MovieVerse Watchlists

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/feedback.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/feedback.html index 2eb1f580..f3e7972a 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/feedback.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/feedback.html @@ -581,9 +581,9 @@

Chat - - - + + + @@ -1095,9 +1095,9 @@

Chat - - - + + + @@ -867,9 +867,9 @@

Add a Comment for This Movie

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -901,9 +901,9 @@

Add a Comment for This Movie

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-match.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-match.html index d0a7a52a..d87e80e6 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-match.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-match.html @@ -700,9 +700,9 @@

Find Your Movie Match

- - - + + + @@ -838,9 +838,9 @@

Find Your Movie Match

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -872,9 +872,9 @@

Find Your Movie Match

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-timeline.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-timeline.html index 0feef768..0a211647 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-timeline.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/movie-timeline.html @@ -316,9 +316,9 @@

- - - + + + @@ -412,9 +412,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', 'back-to-top-btn' @@ -449,9 +449,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', 'back-to-top-btn' diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/notifications.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/notifications.html index cc233067..67737631 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/notifications.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/notifications.html @@ -359,9 +359,9 @@

- - - + + + @@ -1253,9 +1253,9 @@

Popular Directors

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -1287,9 +1287,9 @@

Popular Directors

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/offline.html b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/offline.html index 2569eb2c..2787aec0 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/offline.html +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/html/offline.html @@ -281,9 +281,9 @@

Chat - - - + + + @@ -775,9 +775,9 @@

The MovieVerse @@ -285,15 +293,15 @@

- - - + + +
-
+
Privacy Policy
@@ -349,6 +357,224 @@

Cookies and Web Beacons

+ + - \ No newline at end of file diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/LICENSE b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/LICENSE +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 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 06efb125..c9e83327 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/js/favorites.js @@ -1384,6 +1384,10 @@ async function loadWatchLists() { 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."; @@ -1419,6 +1423,10 @@ async function loadWatchLists() { 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."; @@ -1762,6 +1770,10 @@ function createWatchListDiv(watchlist) { 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; 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 a69d9e14..37f491bf 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 @@ -419,6 +419,7 @@ function createLoadMoreButton(startYear, endYear, mainElement) { 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(); @@ -430,6 +431,7 @@ async function fetchMoviesByTimePeriod(startYear, endYear, append = false) { else { showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, false); } + hideSpinner(); } document.getElementById('load-movies').addEventListener('click', () => { diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/LICENSE b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/LICENSE +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/react/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/tests/LICENSE b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/tests/LICENSE index a0ef1b39..19bed0c9 100644 --- a/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/tests/LICENSE +++ b/MovieVerse-Mobile/platforms/ios/www/MovieVerse-Frontend/tests/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2024 Son Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/www/MovieVerse-APIs/http-client.private.env.json b/MovieVerse-Mobile/www/MovieVerse-APIs/http-client.private.env.json new file mode 100644 index 00000000..9e585cd2 --- /dev/null +++ b/MovieVerse-Mobile/www/MovieVerse-APIs/http-client.private.env.json @@ -0,0 +1,5 @@ +{ + "dev": { + "name": "value" + } +} \ No newline at end of file diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/about.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/about.html index 915c6280..d619cff3 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/about.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/about.html @@ -274,9 +274,9 @@

- - - + + + @@ -487,9 +487,9 @@

Useful Links:

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -522,9 +522,9 @@

Useful Links:

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/actor-details.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/actor-details.html index 9cf910bc..6953ef9d 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/actor-details.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/actor-details.html @@ -301,9 +301,9 @@

- - - + + + @@ -390,9 +390,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -468,9 +468,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/analytics.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/analytics.html index 10c4f815..abd29fb9 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/analytics.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/analytics.html @@ -344,9 +344,9 @@

- - - + + + @@ -537,9 +537,9 @@

Highly Rated Movies Over Years

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -571,9 +571,9 @@

Highly Rated Movies Over Years

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/api_fails.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/api_fails.html index 80e3184f..d629ccd9 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/api_fails.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/api_fails.html @@ -514,9 +514,9 @@

Chat - - - + + + @@ -692,9 +692,9 @@

Chat - - - + + + @@ -660,9 +660,9 @@

Recent & Suggested Chats

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -723,9 +723,9 @@

Recent & Suggested Chats

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/chatbot.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/chatbot.html index 40b2a891..181fee47 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/chatbot.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/chatbot.html @@ -325,9 +325,9 @@

- - - + + + @@ -798,9 +798,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -832,9 +832,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/company-details.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/company-details.html index f70294c3..df9c1c97 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/company-details.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/company-details.html @@ -305,9 +305,9 @@

- - - + + + @@ -396,9 +396,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -430,9 +430,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/create-account.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/create-account.html index 47a7d740..e4a3ead6 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/create-account.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/create-account.html @@ -321,9 +321,9 @@

- - - + + + @@ -739,9 +739,9 @@

Create Account

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -773,9 +773,9 @@

Create Account

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/director-details.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/director-details.html index 23839b49..5b1ff846 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/director-details.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/director-details.html @@ -586,9 +586,9 @@

- - - + + + @@ -681,9 +681,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -715,9 +715,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/favorites.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/favorites.html index 08cdac01..86b50567 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/favorites.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/favorites.html @@ -504,9 +504,9 @@

How to Use MovieVerse Watchlists

- - - + + + @@ -801,9 +801,9 @@

How to Use MovieVerse Watchlists

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -835,9 +835,9 @@

How to Use MovieVerse Watchlists

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/feedback.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/feedback.html index 2eb1f580..f3e7972a 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/feedback.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/feedback.html @@ -581,9 +581,9 @@

Chat - - - + + + @@ -1095,9 +1095,9 @@

Chat - - - + + + @@ -867,9 +867,9 @@

Add a Comment for This Movie

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -901,9 +901,9 @@

Add a Comment for This Movie

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-match.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-match.html index d0a7a52a..d87e80e6 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-match.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-match.html @@ -700,9 +700,9 @@

Find Your Movie Match

- - - + + + @@ -838,9 +838,9 @@

Find Your Movie Match

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -872,9 +872,9 @@

Find Your Movie Match

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-timeline.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-timeline.html index 0feef768..0a211647 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-timeline.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/movie-timeline.html @@ -316,9 +316,9 @@

- - - + + + @@ -412,9 +412,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', 'back-to-top-btn' @@ -449,9 +449,9 @@

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', 'back-to-top-btn' diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/notifications.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/notifications.html index cc233067..67737631 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/notifications.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/notifications.html @@ -359,9 +359,9 @@

- - - + + + @@ -1253,9 +1253,9 @@

Popular Directors

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; @@ -1287,9 +1287,9 @@

Popular Directors

const buttonIds = [ 'chat-button', 'settings-btn', + 'movie-of-the-day-btn', 'movie-match-btn3', 'movie-timeline-btn', - 'movie-of-the-day-btn', 'discussions-btn', 'trivia-btn', ]; diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/offline.html b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/offline.html index 2569eb2c..2787aec0 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/html/offline.html +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/html/offline.html @@ -281,9 +281,9 @@

Chat - - - + + + @@ -775,9 +775,9 @@

The MovieVerse @@ -285,15 +293,15 @@

- - - + + +
-
+
Privacy Policy
@@ -349,6 +357,224 @@

Cookies and Web Beacons

+ + - \ No newline at end of file diff --git a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js index a69d9e14..37f491bf 100644 --- a/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js +++ b/MovieVerse-Mobile/www/MovieVerse-Frontend/js/movie-timeline.js @@ -419,6 +419,7 @@ function createLoadMoreButton(startYear, endYear, mainElement) { 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(); @@ -430,6 +431,7 @@ async function fetchMoviesByTimePeriod(startYear, endYear, append = false) { else { showMovies(moviesToShow, document.getElementById('results'), startYear, endYear, false); } + hideSpinner(); } document.getElementById('load-movies').addEventListener('click', () => { diff --git a/MovieVerse-Mobile/www/js/LICENSE b/MovieVerse-Mobile/www/js/LICENSE index 19d3d823..19bed0c9 100644 --- a/MovieVerse-Mobile/www/js/LICENSE +++ b/MovieVerse-Mobile/www/js/LICENSE @@ -1,21 +1,151 @@ -MIT License - -Copyright (c) 2023 Son Nguyen Hoang - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Creative Commons Attribution-NonCommercial 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. BY-NC Compatible License means a license listed at https://creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + +d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +h. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +i. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + +j. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + a. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ShareAlike. + + 1. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + a. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC Compatible License. + + b. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + c. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Copyright or Sui Generis Database Rights, then the database in which You have Copyright or Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/MovieVerse-Mobile/www/js/about.js b/MovieVerse-Mobile/www/js/about.js index 82a03f56..f26e588f 100644 --- a/MovieVerse-Mobile/www/js/about.js +++ b/MovieVerse-Mobile/www/js/about.js @@ -164,7 +164,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -172,11 +172,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/actor-details.js b/MovieVerse-Mobile/www/js/actor-details.js index ee2667f5..1b7c45c0 100644 --- a/MovieVerse-Mobile/www/js/actor-details.js +++ b/MovieVerse-Mobile/www/js/actor-details.js @@ -135,7 +135,7 @@ async function fetchActorDetails(actorId) { } } -function populateActorDetails(actor, credits) { +async function populateActorDetails(actor, credits) { const actorImage = document.getElementById('actor-image'); const actorName = document.getElementById('actor-name'); const actorDescription = document.getElementById('actor-description'); @@ -169,17 +169,18 @@ function populateActorDetails(actor, credits) { } actorDescription.innerHTML = ` -

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

-

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

-

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

+

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 || 'N/A'}

-

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

-

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

+

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' : 'N/A'}

`; + gender.innerHTML = `

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

`; actorDescription.appendChild(gender); const popularity = document.createElement('div'); @@ -209,6 +210,150 @@ function populateActorDetails(actor, credits) { }); 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 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; + `; + mediaContainer.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w1280${images[0].file_path}`; + } + + imageElement.addEventListener('click', function() { + const imageUrl = this.src; + const modalHtml = ` +
+ + × +
+ `; + 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(); + } + }); + }); + + 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'; + + mediaContainer.appendChild(prevButton); + mediaContainer.appendChild(nextButton); + } + + let currentIndex = 0; + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + function navigateMedia(images, imgElement, direction) { + currentIndex += direction; + if (currentIndex < 0) { + currentIndex = images.length - 1; + } else if (currentIndex >= images.length) { + currentIndex = 0; + } + imgElement.style.opacity = '0'; + setTimeout(() => { + imgElement.src = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + imgElement.style.opacity = '1'; + }, 420); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } + applySettings(); } @@ -270,7 +415,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -278,11 +423,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/add-to-favorites.js b/MovieVerse-Mobile/www/js/add-to-favorites.js index 52d40f02..0df2c998 100644 --- a/MovieVerse-Mobile/www/js/add-to-favorites.js +++ b/MovieVerse-Mobile/www/js/add-to-favorites.js @@ -60,7 +60,7 @@ export async function checkAndUpdateFavoriteButton() { try { if (!userEmail) { console.log('User is not signed in. Checking local storage for favorites.'); - const localFavorites = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; updateFavoriteButton(movieId, localFavorites); return; } @@ -81,7 +81,7 @@ export async function checkAndUpdateFavoriteButton() { catch (error) { if (error.code === 'resource-exhausted') { console.log('Firebase quota exceeded. Checking local storage for favorites.'); - const localFavorites = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; updateFavoriteButton(movieId, localFavorites); } else { console.error('An error occurred:', error); @@ -129,7 +129,7 @@ export async function toggleFavorite() { try { if (!userEmail) { console.log('User is not signed in. Using localStorage for favorites.'); - let favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; if (favoritesMovies.includes(movieId)) { @@ -146,7 +146,7 @@ export async function toggleFavorite() { } } - localStorage.setItem('favoritesMovies', JSON.stringify(favoritesMovies)); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); console.log('Favorites movies updated successfully in localStorage'); @@ -196,10 +196,13 @@ export async function toggleFavorite() { 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('favoritesMovies')) || []; + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; if (favoritesMovies.includes(movieId)) { @@ -216,16 +219,26 @@ export async function toggleFavorite() { } } - localStorage.setItem('favoritesMovies', JSON.stringify(favoritesMovies)); + 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 { + } + 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)); + } +} \ No newline at end of file diff --git a/MovieVerse-Mobile/www/js/analytics.js b/MovieVerse-Mobile/www/js/analytics.js index 2639ff14..82b83a28 100644 --- a/MovieVerse-Mobile/www/js/analytics.js +++ b/MovieVerse-Mobile/www/js/analytics.js @@ -576,7 +576,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -584,11 +584,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/chat-auxiliary.js b/MovieVerse-Mobile/www/js/chat-auxiliary.js index be1e8ac2..e0096978 100644 --- a/MovieVerse-Mobile/www/js/chat-auxiliary.js +++ b/MovieVerse-Mobile/www/js/chat-auxiliary.js @@ -5,35 +5,24 @@ document.addEventListener('DOMContentLoaded', function() { const localTime = document.getElementById('local-time'); function toggleVisibility() { - const query = searchBar.value.trim(); - if (query) { - if (window.innerWidth > 800) { - myHeading.style.position = 'fixed'; - myHeading.style.top = '28px'; - localTime.style.display = 'none'; - myHeading.style.zIndex = '0.05'; - searchBar.style.marginTop = '16px'; - searchButton.style.marginTop = '16px'; - } - } - else { - myHeading.style.position = ''; - myHeading.style.top = ''; - myHeading.style.zIndex = ''; - localTime.style.display = ''; - searchBar.style.marginTop = ''; - searchButton.style.marginTop = ''; + 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(); - - const clearSearchBtn = document.getElementById('clear-search'); - clearSearchBtn.addEventListener('click', function() { - searchBar.value = ''; - toggleVisibility(); - }); }); document.addEventListener('DOMContentLoaded', function() { @@ -41,6 +30,9 @@ document.addEventListener('DOMContentLoaded', function() { 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(); @@ -51,9 +43,13 @@ document.addEventListener('DOMContentLoaded', function() { clearSearchBtn.addEventListener('click', function() { searchInput.value = ''; searchResultsContainer.innerHTML = ''; - document.getElementById('local-time').style.display = ''; toggleButtons(); searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; }); toggleButtons(); diff --git a/MovieVerse-Mobile/www/js/chat.js b/MovieVerse-Mobile/www/js/chat.js index a8955822..7c9f6f1c 100644 --- a/MovieVerse-Mobile/www/js/chat.js +++ b/MovieVerse-Mobile/www/js/chat.js @@ -21,7 +21,14 @@ document.addEventListener('DOMContentLoaded', () => { signInMessage.style.marginBottom = '20px'; signInMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'; document.getElementById('footer').style.display = 'none'; - document.body.appendChild(signInMessage); + + const adContainer2 = document.getElementById('ad-container2'); + if (adContainer2) { + document.body.insertBefore(signInMessage, adContainer2); + } + else { + document.body.appendChild(signInMessage); + } } else { mainElement.style.display = ''; @@ -31,6 +38,7 @@ document.addEventListener('DOMContentLoaded', () => { setupSearchListeners(); }); + const firebaseConfig = { apiKey: atob("QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=="), authDomain: atob("bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t"), @@ -65,8 +73,15 @@ sendButton.addEventListener('click', async () => { messageInput.value = ''; const userElement = document.querySelector(`.user[data-email="${selectedUserEmail}"]`); - if (userElement) { + + if (!userElement) { + const newUserElement = await createUserElement(selectedUserEmail); + userListDiv.prepend(newUserElement); + selectUser(newUserElement); + } + else { userListDiv.prepend(userElement); + selectUser(userElement); } } catch (error) { @@ -75,6 +90,44 @@ sendButton.addEventListener('click', async () => { } }); +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(); @@ -87,10 +140,10 @@ function formatMessage(message, isCurrentUser, timestamp) { messageElement.classList.add('message'); messageElement.textContent = isCurrentUser ? `You: ${message}` : `${selectedUserEmail}: ${message}`; - // Ensure the timestamp is correctly handled if (timestamp && timestamp.toDate) { messageElement.dataset.timestamp = timestamp.toDate().toISOString(); - } else { + } + else { console.log('Timestamp is not in the expected format:', timestamp); messageElement.dataset.timestamp = 'Unknown time'; } @@ -242,15 +295,23 @@ async function performSearch(searchText, isNewSearch = false) { lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; } - querySnapshot.forEach((doc) => { + 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 = user.profileImage || '../../images/user-default.png'; + img.src = imageUrl; img.style.width = '33%'; img.style.borderRadius = '8px'; userDiv.appendChild(img); @@ -262,7 +323,7 @@ async function performSearch(searchText, isNewSearch = false) { userDiv.appendChild(textDiv); searchUserResults.appendChild(userDiv); - }); + } searchUserResults.style.display = 'block'; hideSpinner(); @@ -271,6 +332,7 @@ async function performSearch(searchText, isNewSearch = false) { const loadMoreButton = document.createElement('button'); loadMoreButton.textContent = 'Load More'; loadMoreButton.id = 'loadMoreButton'; + loadMoreButton.style.marginBottom = '20px'; loadMoreButton.addEventListener('click', () => performSearch(searchText)); searchUserResults.appendChild(loadMoreButton); @@ -346,7 +408,7 @@ async function loadUserList() { users = users.slice(0, userLimit); userListDiv.innerHTML = ''; - users.forEach(user => { + for (const user of users) { const userElement = document.createElement('div'); userElement.classList.add('user'); userElement.setAttribute('data-email', user.email); @@ -363,8 +425,16 @@ async function loadUserList() { 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 = user.profileImage || '../../images/user-default.png'; + img.src = imageUrl; img.style.width = '50px'; img.style.borderRadius = '25px'; img.style.marginRight = '10px'; @@ -375,7 +445,7 @@ async function loadUserList() { userElement.appendChild(emailDiv); userListDiv.appendChild(userElement); - }); + } hideSpinner(); } @@ -391,14 +461,6 @@ async function loadUserList() { } } -// onSnapshot(collection(db, "messages"), (snapshot) => { -// snapshot.docChanges().forEach((change) => { -// if (change.type === 'added') { -// loadUserList(); -// } -// }); -// }); - function showSpinner() { document.getElementById('myModal').classList.add('modal-visible'); } diff --git a/MovieVerse-Mobile/www/js/chatbot.js b/MovieVerse-Mobile/www/js/chatbot.js index ab5046b1..9df8ce8b 100644 --- a/MovieVerse-Mobile/www/js/chatbot.js +++ b/MovieVerse-Mobile/www/js/chatbot.js @@ -10,6 +10,7 @@ const movieCode = { function getMovieCode() { return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); + return atob(movieCode.part1) + atob(movieCode.part2) + atob(movieCode.part3); } function generateMovieNames(input) { @@ -84,7 +85,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -92,11 +93,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, @@ -142,11 +168,34 @@ async function rotateUserStats() { 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() { @@ -179,26 +228,12 @@ function getMostVisitedActor() { 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`; } @@ -225,6 +260,34 @@ function getMostCommonGenre() { 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)); +} + function calculateMoviesToDisplay() { const screenWidth = window.innerWidth; if (screenWidth <= 689.9) return 10; // 1 movie per row @@ -459,6 +522,7 @@ async function fetchMovieTrailer(movieName) { 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(); @@ -489,6 +553,7 @@ async function fetchPersonDetails(name, type) { const response = await fetch(searchUrl); const data = await response.json(); const person = data.results[0]; + if (person) { localStorage.setItem(type === 'director' ? 'selectedDirectorId' : 'selectedActorId', person.id); window.location.href = type === 'director' ? 'director-details.html' : 'actor-details.html'; @@ -509,6 +574,7 @@ async function fetchCompanyDetails(companyName) { const response = await fetch(searchUrl); const data = await response.json(); const company = data.results[0]; + if (company) { localStorage.setItem('selectedCompanyId', company.id); window.location.href = 'company-details.html'; @@ -525,6 +591,7 @@ async function fetchCompanyDetails(companyName) { async function movieVerseResponse(message) { const lowerMessage = message.toLowerCase(); + if (lowerMessage.startsWith("do you know about ") || lowerMessage.startsWith("tell me about ") || lowerMessage.startsWith("what is ")) { const movieName = lowerMessage.replace(/^(do you know about|show me|tell me about|what is) /, ''); return await fetchMovieDetailsFromTMDB(movieName); @@ -556,174 +623,258 @@ async function movieVerseResponse(message) { } if (lowerMessage.includes("hello") || lowerMessage.includes("hi") || lowerMessage.includes("hey")) { return "Hello! How can I assist you with MovieVerse today?"; - } else if (lowerMessage.includes("bye") || lowerMessage.includes("goodbye")) { + } + else if (lowerMessage.includes("bye") || lowerMessage.includes("goodbye")) { return "Goodbye! Thank you for using MovieVerse Assistant and have a nice day!"; - } else if (lowerMessage.includes("how are you")) { + } + else if (lowerMessage.includes("how are you")) { return "I'm your digital MovieVerse assistant, ready to help! How can I assist you with movie info?"; - } else if (lowerMessage.includes("search movie")) { + } + else if (lowerMessage.includes("search movie")) { return "To find information about a movie, please provide its name or keyword related to it."; - } else if (lowerMessage.includes("imdb rating")) { + } + else if (lowerMessage.includes("imdb rating")) { return "You can search for a movie, and I'll provide its IMDb rating among other details. Please provide the movie name!"; - } else if (lowerMessage.includes("movie description") || lowerMessage.includes("tell me about")) { + } + else if (lowerMessage.includes("movie description") || lowerMessage.includes("tell me about")) { return "Sure, please provide the movie name you want to learn about, and I'll fetch its description for you!"; - } else if (lowerMessage.includes("how many movies")) { + } + else if (lowerMessage.includes("how many movies")) { return "MovieVerse has a vast MovieVerse-Databases of millions of movies. You can search for any movie, and I'll try to fetch details for you!"; - } else if (lowerMessage.includes("latest movies")) { + } + else if (lowerMessage.includes("latest movies")) { return "I can provide information on recent movie releases. However, for the most up-to-date releases, consider checking the 'Latest Movies' section of MovieVerse!"; - } else if (lowerMessage.includes("recommend a movie") || lowerMessage.includes("suggestion")) { + } + else if (lowerMessage.includes("recommend a movie") || lowerMessage.includes("suggestion")) { return "Certainly! How about watching 'Inception'? It's a critically acclaimed movie with a captivating plot!"; - } else if (lowerMessage.includes("how does this work") || lowerMessage.includes("how to use")) { + } + else if (lowerMessage.includes("how does this work") || lowerMessage.includes("how to use")) { return "Simply type in your query related to a movie, and I'll provide details from our MovieVerse MovieVerse-Databases. You can ask about IMDb ratings, descriptions, and more!"; - } else if (lowerMessage.includes("who created this") || lowerMessage.includes("developer")) { + } + else if (lowerMessage.includes("who created this") || lowerMessage.includes("developer")) { return "MovieVerse is the result of the hard work of dedicated developers passionate about movies. We hope you find it helpful!"; - } else if (lowerMessage.includes("top rated movies")) { + } + else if (lowerMessage.includes("top rated movies")) { return "Our top-rated movies include 'The Shawshank Redemption', 'The Godfather', and 'The Dark Knight'. Would you like a detailed list?"; - } else if (lowerMessage.includes("genre")) { + } + else if (lowerMessage.includes("genre")) { return "We have movies spanning various genres: Action, Drama, Comedy, Romance, Thriller, and more! Which genre are you interested in?"; - } else if (lowerMessage.includes("actor") || lowerMessage.includes("actress")) { + } + else if (lowerMessage.includes("actor") || lowerMessage.includes("actress")) { return "Sure, which actor or actress are you interested in? Provide a name, and I'll fetch the movies they've starred in!"; - } else if (lowerMessage.includes("director")) { + } + else if (lowerMessage.includes("director")) { return "Great! Which director's filmography are you interested in?"; - } else if (lowerMessage.includes("animated movies")) { + } + else if (lowerMessage.includes("animated movies")) { return "We have a wide collection of animated movies! Some popular ones include 'Toy Story', 'Frozen', and 'Spirited Away'."; - } else if (lowerMessage.includes("thank you") || lowerMessage.includes("thanks")) { + } + else if (lowerMessage.includes("thank you") || lowerMessage.includes("thanks")) { return "You're welcome! If you have any more questions, feel free to ask. Enjoy your movie experience!"; - } else if (lowerMessage.includes("subscription") || lowerMessage.includes("membership")) { + } + else if (lowerMessage.includes("subscription") || lowerMessage.includes("membership")) { return "MovieVerse offers different subscription tiers. For detailed information, you might want to check our 'Subscription' section."; - } else if (lowerMessage.includes("watch movie")) { + } + else if (lowerMessage.includes("watch movie")) { return "While MovieVerse provides detailed information on movies, to watch them, you might need to visit specific streaming platforms or theaters!"; - } else if (lowerMessage.includes("are you a bot")) { + } + else if (lowerMessage.includes("are you a bot")) { return "Yes, I'm the MovieVerse digital assistant. How can I help you further?"; - } else if (lowerMessage.includes("documentary")) { + } + else if (lowerMessage.includes("documentary")) { return "We have an extensive collection of documentaries. From nature to history and science, what topic interests you?"; - } else if (lowerMessage.includes("foreign films")) { + } + else if (lowerMessage.includes("foreign films")) { return "MovieVerse has films from all around the world. Looking for any specific region or language?"; - } else if (lowerMessage.includes("classic movies")) { + } + else if (lowerMessage.includes("classic movies")) { return "Ah, classics! Some all-time favorites include 'Casablanca', 'Gone with the Wind', and 'Citizen Kane'. Would you like more recommendations?"; - } else if (lowerMessage.includes("family movies")) { + } + else if (lowerMessage.includes("family movies")) { return "We have plenty of family-friendly movies. 'The Lion King', 'Finding Nemo', and 'Toy Story' are a few favorites. Looking for anything specific?"; - } else if (lowerMessage.includes("comedy")) { + } + else if (lowerMessage.includes("comedy")) { return "In need of a good laugh? We've got comedies like 'Dumb and Dumber', 'Bridesmaids', and 'Anchorman' to name a few!"; - } else if (lowerMessage.includes("action movies")) { + } + else if (lowerMessage.includes("action movies")) { return "For adrenaline junkies, we've got action-packed movies like 'Die Hard', 'Mad Max: Fury Road', and 'The Dark Knight'. Ready to dive in?"; - } else if (lowerMessage.includes("horror")) { + } + else if (lowerMessage.includes("horror")) { return "Looking for a scare? Consider watching 'The Exorcist', 'Psycho', or 'Get Out'. Don't forget to keep the lights on!"; - } else if (lowerMessage.includes("romance")) { + } + else if (lowerMessage.includes("romance")) { return "Feeling romantic? Check out 'The Notebook', 'Pride and Prejudice', or 'Before Sunrise'. Love is in the air!"; - } else if (lowerMessage.includes("sci-fi")) { + } + else if (lowerMessage.includes("sci-fi")) { return "For sci-fi enthusiasts, we recommend 'Blade Runner', 'Star Wars', or 'Interstellar'. Ready to travel through space and time?"; - } else if (lowerMessage.includes("trailers")) { + } + else if (lowerMessage.includes("trailers")) { return "Want to see what's coming up? Our 'Trailers' section has the latest teasers and previews of upcoming films!"; - } else if (lowerMessage.includes("membership benefits")) { + } + else if (lowerMessage.includes("membership benefits")) { return "Members get exclusive access to early releases, high-definition streaming, and ad-free experience. Interested in upgrading?"; - } else if (lowerMessage.includes("create an account")) { + } + else if (lowerMessage.includes("create an account")) { return "Creating an account is easy! Just head to the 'Sign Up' section on our website and follow the steps."; - } else if (lowerMessage.includes("forgot password")) { + } + else if (lowerMessage.includes("forgot password")) { return "No worries! Just click on the 'Forgot Password' link on the login page, and we'll guide you through the reset process."; - } else if (lowerMessage.includes("movie ratings")) { + } + else if (lowerMessage.includes("movie ratings")) { return "Our ratings are sourced from critics and viewers like you. They provide a combined score to help you pick the best movies!"; - } else if (lowerMessage.includes("how do you work")) { + } + else if (lowerMessage.includes("how do you work")) { return "I'm here to answer your questions about MovieVerse and movies in general. Just ask away!"; - } else if (lowerMessage.includes("are you real")) { + } + else if (lowerMessage.includes("are you real")) { return "I'm a virtual assistant powered by code. While I'm not real, I'm here to help!"; - } else if (lowerMessage.includes("oscar winners")) { + } + else if (lowerMessage.includes("oscar winners")) { return "Looking for Oscar winners? We have a dedicated section for 'Academy Award Winners'. Check it out for a list of acclaimed films!"; - } else if (lowerMessage.includes("in theaters now")) { + } + else if (lowerMessage.includes("in theaters now")) { return "Our 'Now Showing' section provides a list of movies currently playing in theaters. Planning a movie outing?"; - } else if (lowerMessage.includes("coming soon")) { + } + else if (lowerMessage.includes("coming soon")) { return "Anticipating new releases? Head over to our 'Coming Soon' tab to check out movies hitting the theaters soon!"; - } else if (lowerMessage.includes("movie runtime")) { + } + else if (lowerMessage.includes("movie runtime")) { return "Please specify the movie you're inquiring about, and I'll fetch its runtime for you!"; - } else if (lowerMessage.includes("indie films")) { + } + else if (lowerMessage.includes("indie films")) { return "Indie films offer unique storytelling. Some of our favorites include 'Moonlight', 'Lady Bird', and 'Whiplash'. Would you like to explore more indie titles?"; - } else if (lowerMessage.includes("film festivals")) { + } + else if (lowerMessage.includes("film festivals")) { return "We have a collection of movies that have made waves in film festivals. From Cannes to Sundance, which festival's winners are you interested in?"; - } else if (lowerMessage.includes("animation studios")) { + } + else if (lowerMessage.includes("animation studios")) { return "From Pixar to Studio Ghibli, we have movies from renowned animation studios. Any particular studio you're fond of?"; - } else if (lowerMessage.includes("musicals")) { + } + else if (lowerMessage.includes("musicals")) { return "Sing your heart out! 'La La Land', 'The Greatest Showman', or classics like 'The Sound of Music' are all available. Ready for a song and dance?"; - } else if (lowerMessage.includes("kid movies")) { + } + else if (lowerMessage.includes("kid movies")) { return "For the little ones, we have 'Despicable Me', 'Frozen', and many more. Anything in particular they enjoy?"; - } else if (lowerMessage.includes("adaptations")) { + } + else if (lowerMessage.includes("adaptations")) { return "Books turned movies? We have 'Harry Potter', 'The Hunger Games', and classics like 'To Kill a Mockingbird'. Interested in a specific adaptation?"; - } else if (lowerMessage.includes("based on true stories")) { + } + else if (lowerMessage.includes("based on true stories")) { return "The truth can be stranger than fiction! Check out 'The Imitation Game', 'Schindler's List', or 'Catch Me If You Can'. Any specific era or event you're interested in?"; - } else if (lowerMessage.includes("customer support")) { + } + else if (lowerMessage.includes("customer support")) { return "Having issues? Our customer support team is here to help. You can reach out via the 'Support' section on our website."; - } else if (lowerMessage.includes("subscription cancel")) { + } + else if (lowerMessage.includes("subscription cancel")) { return "We're sad to see you go. To cancel your subscription, please go to the 'Account Settings' section."; - } else if (lowerMessage.includes("refunds")) { + } + else if (lowerMessage.includes("refunds")) { return "For refund queries, please get in touch with our customer support. They'll guide you through the process."; - } else if (lowerMessage.includes("device compatibility")) { + } + else if (lowerMessage.includes("device compatibility")) { return "MovieVerse is compatible with a range of devices, from smartphones and tablets to desktops and smart TVs. Any specific device you're asking about?"; - } else if (lowerMessage.includes("movie suggestions based on mood")) { + } + else if (lowerMessage.includes("movie suggestions based on mood")) { return "Of course! Let me know your mood, and I'll suggest a movie accordingly!"; - } else if (lowerMessage.includes("movie for date night")) { + } + else if (lowerMessage.includes("movie for date night")) { return "How about a romantic comedy? 'Pride & Prejudice' or something light-hearted like '500 Days of Summer'?"; - } else if (lowerMessage.includes("is there a series section")) { + } + else if (lowerMessage.includes("is there a series section")) { return "Yes, apart from movies, we also have a collection of TV series. From 'Breaking Bad' to 'Stranger Things', binge away!"; - } else if (lowerMessage.includes("award-winning movies")) { + } + else if (lowerMessage.includes("award-winning movies")) { return "Looking for critically acclaimed cinema? Check our 'Award Winners' section for movies that have received major accolades!"; - } else if (lowerMessage.includes("do you have classics from the 80s")) { + } + else if (lowerMessage.includes("do you have classics from the 80s")) { return "Absolutely! The 80s were iconic. Dive into classics like 'E.T.', 'The Breakfast Club', or 'Back to the Future'. Ready for some nostalgia?"; - } else if (lowerMessage.includes("movie suggestions based on genre")) { + } + else if (lowerMessage.includes("movie suggestions based on genre")) { return "Sure! Let me know your favorite genre, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie suggestions based on actor")) { + } + else if (lowerMessage.includes("movie suggestions based on actor")) { return "Of course! Let me know your favorite actor, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie suggestions based on director")) { + } + else if (lowerMessage.includes("movie suggestions based on director")) { return "Of course! Let me know your favorite director, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie suggestions based on year")) { + } + else if (lowerMessage.includes("movie suggestions based on year")) { return "Of course! Let me know your favorite year, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie") || lowerMessage.includes("movies")) { + } + else if (lowerMessage.includes("movie") || lowerMessage.includes("movies")) { return "You can search for a movie using the search field above!"; - } else if (lowerMessage.includes("1900s")) { + } + else if (lowerMessage.includes("1900s")) { return "Movies in the 1900s include: A Trip to the Moon, The Great Train Robbery, etc."; - } else if (lowerMessage.includes("1910s")) { + } + else if (lowerMessage.includes("1910s")) { return "Movies in the 1910s include: The Birth of a Nation, Intolerance, etc."; - } else if (lowerMessage.includes("1920s")) { + } + else if (lowerMessage.includes("1920s")) { return "Movies in the 1920s include: The Kid, The Gold Rush, etc."; - } else if (lowerMessage.includes("1930s")) { + } + else if (lowerMessage.includes("1930s")) { return "Movies in the 1930s include: King Kong, Snow White and the Seven Dwarfs, etc."; - } else if (lowerMessage.includes("1940s")) { + } + else if (lowerMessage.includes("1940s")) { return "Movies in the 1940s include: Citizen Kane, Casablanca, etc."; - } else if (lowerMessage.includes("1950s")) { + } + else if (lowerMessage.includes("1950s")) { return "Movies in the 1950s include: Sunset Boulevard, Singin' in the Rain, etc."; - } else if (lowerMessage.includes("1960s")) { + } + else if (lowerMessage.includes("1960s")) { return "Movies in the 1960s include: Psycho, The Apartment, etc."; - } else if (lowerMessage.includes("1970s")) { + } + else if (lowerMessage.includes("1970s")) { return "Movies in the 1970s include: The Godfather, Star Wars, etc."; - } else if (lowerMessage.includes("1980s")) { + } + else if (lowerMessage.includes("1980s")) { return "Movies in the 1980s include: Back to the Future, The Shining, etc."; - } else if (lowerMessage.includes("1990s")) { + } + else if (lowerMessage.includes("1990s")) { return "Movies in the 1990s include: The Silence of the Lambs, Titanic, etc."; - } else if (lowerMessage.includes("2000s")) { + } + else if (lowerMessage.includes("2000s")) { return "Movies in the 2000s include: The Lord of the Rings: The Return of the King, The Dark Knight, etc."; - } else if (lowerMessage.includes("2010s")) { + } + else if (lowerMessage.includes("2010s")) { return "Movies in the 2010s include: Inception, The Avengers, etc."; - } else if (lowerMessage.includes("2020s")) { + } + else if (lowerMessage.includes("2020s")) { return "Movies in the 2020s include: Tenet, Soul, etc."; - } else if (lowerMessage.includes("2022")) { + } + else if (lowerMessage.includes("2022")) { return "Movies in 2022 include: Thor: Love and Thunder, Doctor Strange in the Multiverse of Madness, etc."; - } else if (lowerMessage.includes("2023")) { + } + else if (lowerMessage.includes("2023")) { return "Movies in 2023 include: The Flash, Black Panther: Wakanda Forever, etc."; - } else if (lowerMessage.includes("2024")) { + } + else if (lowerMessage.includes("2024")) { return "Movies in 2024 include: Indiana Jones 5, The Batman, etc."; - } else if (lowerMessage.includes("movieverse analytics") || lowerMessage.includes("movieverse stats") || lowerMessage.includes("movieverse insights")) { + } + else if (lowerMessage.includes("movieverse analytics") || lowerMessage.includes("movieverse stats") || lowerMessage.includes("movieverse insights")) { return "MovieVerse Analytics provides insights into user activity, popular movies, and more. You can access it by pressing the About button on the top right, then selecting MovieVerse Analytics at the bottom of the page."; - } else if (lowerMessage.includes("most visited director")) { + } + else if (lowerMessage.includes("most visited director")) { return `The most visited director is ${getMostVisitedDirector()}.`; - } else if (lowerMessage.includes("trivia accuracy")) { + } + else if (lowerMessage.includes("trivia accuracy")) { return `Your trivia accuracy is ${getTriviaAccuracy()}.`; - } else if (lowerMessage.includes("most common genre") || lowerMessage.includes("favorite genre")) { + } + else if (lowerMessage.includes("most common genre") || lowerMessage.includes("favorite genre")) { return `Your most common genre is ${getMostCommonGenre()}.`; - } else if (lowerMessage.includes("movie of the day")) { + } + else if (lowerMessage.includes("movie of the day")) { showMovieOfTheDay(); return "Searching for the movie of the day. Please wait..."; - } else if (lowerMessage.includes("sign in") || lowerMessage.includes("sign out")) { + } + else if (lowerMessage.includes("sign in") || lowerMessage.includes("sign out")) { return "Please click the Sign In/Out button at the top to sign in or out."; - } else if (lowerMessage.includes("sign up")) { + } + else if (lowerMessage.includes("sign up")) { return "Please click the Sign In button at the top to create an account."; - } else { + } + else { return "Sorry, I didn't catch that or find any movies with that name in our databases. Can you rephrase, check your spelling, or ask another question?"; } } @@ -732,9 +883,11 @@ const movieee = `https://${getMovieVerseData()}/3`; async function fetchMovieDetailsFromTMDB(movieName) { const url = `${movieee}/search/movie?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(movieName)}`; + try { const response = await fetch(url); const data = await response.json(); + if (data.results.length > 0) { const movie = data.results[0]; localStorage.setItem('selectedMovieId', movie.id); @@ -777,45 +930,6 @@ async function showMovieOfTheDay() { } } -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)]; diff --git a/MovieVerse-Mobile/www/js/christopher-nolan.js b/MovieVerse-Mobile/www/js/christopher-nolan.js index a84dae47..1424a4dc 100644 --- a/MovieVerse-Mobile/www/js/christopher-nolan.js +++ b/MovieVerse-Mobile/www/js/christopher-nolan.js @@ -352,7 +352,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -360,11 +360,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/comments-tv.js b/MovieVerse-Mobile/www/js/comments-tv.js new file mode 100644 index 00000000..9b7044a7 --- /dev/null +++ b/MovieVerse-Mobile/www/js/comments-tv.js @@ -0,0 +1,161 @@ +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 movie/TV show 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; // Add some space between comments + `; + 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/js/comments.js b/MovieVerse-Mobile/www/js/comments.js index e8915a6c..ba5dc79a 100644 --- a/MovieVerse-Mobile/www/js/comments.js +++ b/MovieVerse-Mobile/www/js/comments.js @@ -1,17 +1,6 @@ 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"; - -const firebaseConfig = { - apiKey: "AIzaSyDL6kQnSfUdD8Ut8HFrp9kuivqz1xdXm7k", - authDomain: "movieverse-app.firebaseapp.com", - projectId: "movieverse-app", - storageBucket: "movieverse-app.appspot.com", - messagingSenderId: "802943718871", - appId: "1:802943718871:web:48bc916cc99e2724212792" -}; - -const app = initializeApp(firebaseConfig); -const db = getFirestore(app); +import { app, db } from './firebase.js'; const commentForm = document.getElementById("comment-form"); commentForm.addEventListener("submit", async (e) => { @@ -36,9 +25,9 @@ commentForm.addEventListener("submit", async (e) => { } }); -var modal = document.getElementById("comment-modal"); -var btn = document.getElementById("toggle-comment-modal"); -var span = document.getElementsByClassName("close")[0]; +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"; diff --git a/MovieVerse-Mobile/www/js/company-details.js b/MovieVerse-Mobile/www/js/company-details.js index 95ea8c7a..ac8ff7c1 100644 --- a/MovieVerse-Mobile/www/js/company-details.js +++ b/MovieVerse-Mobile/www/js/company-details.js @@ -91,7 +91,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -99,11 +99,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, @@ -372,8 +397,8 @@ async function fetchCompanyDetails(companyId) { 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}`; } @@ -386,9 +411,9 @@ async function fetchCompanyDetails(companyId) { const fullCountryName = twoLetterCountryCodes.find(country => country.code === company.origin_country)?.name; - document.getElementById('company-name').textContent = company.name || 'Name Not Available'; - document.getElementById('company-headquarters').textContent = company.headquarters || 'Headquarters Not Available'; - document.getElementById('company-country').textContent = fullCountryName || 'Country Not Available'; + 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 || '#'; @@ -398,7 +423,7 @@ async function fetchCompanyDetails(companyId) { companyWebsite.textContent = homepage; } else { - companyWebsite.textContent = 'Website Not Available'; + companyWebsite.textContent = 'Information Unavailable'; } updateBrowserURL(company.name); @@ -796,4 +821,4 @@ function updateBrowserURL(title) { function createNameSlug(title) { return title.toLowerCase().replace(/ /g, '-').replace(/[^\w-]/g, ''); -} \ No newline at end of file +} diff --git a/MovieVerse-Mobile/www/js/create-account.js b/MovieVerse-Mobile/www/js/create-account.js index 8717e7e2..bc5c32ac 100644 --- a/MovieVerse-Mobile/www/js/create-account.js +++ b/MovieVerse-Mobile/www/js/create-account.js @@ -1,5 +1,5 @@ import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js"; -import { getFirestore, collection, addDoc, getDocs, query, where } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.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; @@ -92,6 +92,22 @@ document.getElementById('createAccountForm').addEventListener('submit', async (e 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'; } diff --git a/MovieVerse-Mobile/www/js/director-details.js b/MovieVerse-Mobile/www/js/director-details.js index cb9cf339..3803dcf4 100644 --- a/MovieVerse-Mobile/www/js/director-details.js +++ b/MovieVerse-Mobile/www/js/director-details.js @@ -130,7 +130,7 @@ async function fetchDirectorDetails(directorId) { } } -function populateDirectorDetails(director, credits) { +async function populateDirectorDetails(director, credits) { const directorImage = document.getElementById('director-image'); const directorName = document.getElementById('director-name'); const directorDescription = document.getElementById('director-description'); @@ -164,11 +164,12 @@ function populateDirectorDetails(director, credits) { } directorDescription.innerHTML = ` -

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

-

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

-

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

+

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 || 'N/A'}

+

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

Known For: Directing

`; @@ -198,6 +199,150 @@ function populateDirectorDetails(director, credits) { 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 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; + `; + mediaContainer.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w1280${images[0].file_path}`; + } + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } + + imageElement.addEventListener('click', function() { + const imageUrl = this.src; + const modalHtml = ` +
+ + × +
+ `; + 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(); + } + }); + }); + + 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'; + + mediaContainer.appendChild(prevButton); + mediaContainer.appendChild(nextButton); + } + + let currentIndex = 0; + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + function navigateMedia(images, imgElement, direction) { + currentIndex += direction; + if (currentIndex < 0) { + currentIndex = images.length - 1; + } + else if (currentIndex >= images.length) { + currentIndex = 0; + } + imgElement.style.opacity = '0'; + setTimeout(() => { + imgElement.src = `https://image.tmdb.org/t/p/w1280${images[currentIndex].file_path}`; + imgElement.style.opacity = '1'; + }, 420); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + applySettings(); } @@ -259,7 +404,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -267,11 +412,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/favorites.js b/MovieVerse-Mobile/www/js/favorites.js index f3e4c7eb..c9e83327 100644 --- a/MovieVerse-Mobile/www/js/favorites.js +++ b/MovieVerse-Mobile/www/js/favorites.js @@ -141,7 +141,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -149,11 +149,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, @@ -356,7 +381,7 @@ async function populateCreateModalWithFavorites() { let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || ''; if (!currentUserEmail) { - const favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; let container = document.getElementById('favorites-container'); @@ -364,7 +389,8 @@ async function populateCreateModalWithFavorites() { container = document.createElement('div'); container.id = 'favorites-container'; document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); - } else { + } + else { container.innerHTML = ''; } @@ -377,10 +403,11 @@ async function populateCreateModalWithFavorites() { moviesContainer.style.marginTop = '-20px'; container.appendChild(moviesContainer); - if (favoritesMovies.length === 0) { + if (moviesFavorited.length === 0) { moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; - } else { - for (const movieId of favoritesMovies) { + } + else { + for (const movieId of moviesFavorited) { const movieTitle = await getMovieTitle(movieId); appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); } @@ -417,13 +444,14 @@ async function populateCreateModalWithFavorites() { container = document.createElement('div'); container.id = 'favorites-container'; createForm.insertBefore(container, createForm.querySelector('button[type="submit"]')); - } else { + } + else { container.innerHTML = ''; } if (!userSnapshot.empty) { const userData = userSnapshot.docs[0].data(); - const favoritesMovies = userData.favoritesMovies || []; + const moviesFavorited = userData.favoritesMovies || []; const favoritesTVSeries = userData.favoritesTVSeries || []; let moviesLabel = document.createElement('label'); @@ -435,10 +463,11 @@ async function populateCreateModalWithFavorites() { moviesContainer.style.marginTop = '-20px'; container.appendChild(moviesContainer); - if (favoritesMovies.length === 0) { + if (moviesFavorited.length === 0) { moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; - } else { - for (const movieId of favoritesMovies) { + } + else { + for (const movieId of moviesFavorited) { const movieTitle = await getMovieTitle(movieId); appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); } @@ -455,20 +484,22 @@ async function populateCreateModalWithFavorites() { if (favoritesTVSeries.length === 0) { tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; - } else { + } + else { for (const seriesId of favoritesTVSeries) { const seriesTitle = await getTVSeriesTitle(seriesId); appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); } } - } else { + } + 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 favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; let container = document.getElementById('favorites-container'); @@ -476,7 +507,8 @@ async function populateCreateModalWithFavorites() { container = document.createElement('div'); container.id = 'favorites-container'; document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); - } else { + } + else { container.innerHTML = ''; } @@ -489,10 +521,11 @@ async function populateCreateModalWithFavorites() { moviesContainer.style.marginTop = '-20px'; container.appendChild(moviesContainer); - if (favoritesMovies.length === 0) { + if (moviesFavorited.length === 0) { moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; - } else { - for (const movieId of favoritesMovies) { + } + else { + for (const movieId of moviesFavorited) { const movieTitle = await getMovieTitle(movieId); appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); } @@ -509,7 +542,8 @@ async function populateCreateModalWithFavorites() { if (favoritesTVSeries.length === 0) { tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; - } else { + } + else { for (const seriesId of favoritesTVSeries) { const seriesTitle = await getTVSeriesTitle(seriesId); appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); @@ -517,21 +551,43 @@ async function populateCreateModalWithFavorites() { } } } + 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 { - showSpinner(); - e.preventDefault(); + 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()); + } - const name = document.getElementById('new-watchlist-name').value; - 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'); - const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); - const querySnapshot = await getDocs(q); - let maxOrder = querySnapshot.docs.reduce((max, docSnapshot) => Math.max(max, docSnapshot.data().order || 0), 0); + 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')); @@ -545,8 +601,8 @@ document.getElementById('create-watchlist-form').addEventListener('submit', asyn createdAt: new Date().toISOString(), order: maxOrder + 1, }); - } else { - const localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + } + else { localWatchlists.push({ id: `local-${new Date().getTime()}`, userEmail: "", @@ -559,20 +615,10 @@ document.getElementById('create-watchlist-form').addEventListener('submit', asyn }); localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); } - - closeModal('create-watchlist-modal'); - loadWatchLists(); - hideSpinner(); - window.location.reload(); } catch (error) { if (error.code === 'resource-exhausted') { console.log('Firebase quota exceeded. Using localStorage for watchlists.'); - const name = document.getElementById('new-watchlist-name').value; - 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 localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; localWatchlists.push({ id: `local-${new Date().getTime()}`, userEmail: "", @@ -584,12 +630,17 @@ document.getElementById('create-watchlist-form').addEventListener('submit', asyn createdAt: new Date().toISOString() }); localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); - closeModal('create-watchlist-modal'); - loadWatchLists(); - hideSpinner(); - window.location.reload(); + } + 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) { @@ -630,7 +681,6 @@ function appendCheckbox(container, id, title, name, isChecked = false) { container.appendChild(item); } - document.getElementById('create-watchlist-btn').addEventListener('click', function() { document.getElementById('create-watchlist-form').reset(); populateCreateModalWithFavorites(); @@ -652,7 +702,7 @@ async function populateEditModal() { let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); let watchlists = []; - let favoritesMovies = []; + let moviesFavorited = []; let favoritesTVSeries = []; if (currentUserEmail) { @@ -668,12 +718,13 @@ async function populateEditModal() { if (!usersSnapshot.empty) { const userData = usersSnapshot.docs[0].data(); - favoritesMovies = userData.favoritesMovies || []; + moviesFavorited = userData.favoritesMovies || []; favoritesTVSeries = userData.favoritesTVSeries || []; } - } else { + } + else { watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; } @@ -749,10 +800,11 @@ async function populateEditModal() { initialMoviesSelection = watchlist.movies.slice(); initialTVSeriesSelection = watchlist.tvSeries.slice(); - if (!favoritesMovies || favoritesMovies.length === 0) { + if (!moviesFavorited || moviesFavorited.length === 0) { moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; - } else { - for (const movieId of favoritesMovies) { + } + else { + for (const movieId of moviesFavorited) { const movieTitle = await getMovieTitle(movieId); const isChecked = watchlist.movies.includes(movieId); appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); @@ -761,7 +813,8 @@ async function populateEditModal() { if (!favoritesTVSeries || favoritesTVSeries.length === 0) { tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; - } else { + } + else { for (const seriesId of favoritesTVSeries) { const seriesTitle = await getTVSeriesTitle(seriesId); const isChecked = watchlist.tvSeries.includes(seriesId); @@ -799,7 +852,7 @@ async function populateEditModal() { if (error.code === 'resource-exhausted') { console.log('Firebase quota exceeded. Using localStorage for watchlists.'); let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - let favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + let moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; const editForm = document.getElementById('edit-watchlist-form'); @@ -874,10 +927,11 @@ async function populateEditModal() { initialMoviesSelection = watchlist.movies.slice(); initialTVSeriesSelection = watchlist.tvSeries.slice(); - if (!favoritesMovies || favoritesMovies.length === 0) { + if (!moviesFavorited || moviesFavorited.length === 0) { moviesContainer.innerHTML = '

No Favorite Movies Added Yet.

'; - } else { - for (const movieId of favoritesMovies) { + } + else { + for (const movieId of moviesFavorited) { const movieTitle = await getMovieTitle(movieId); const isChecked = watchlist.movies.includes(movieId); appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); @@ -886,7 +940,8 @@ async function populateEditModal() { if (!favoritesTVSeries || favoritesTVSeries.length === 0) { tvSeriesContainer.innerHTML = '

No Favorite TV Series Added Yet.

'; - } else { + } + else { for (const seriesId of favoritesTVSeries) { const seriesTitle = await getTVSeriesTitle(seriesId); const isChecked = watchlist.tvSeries.includes(seriesId); @@ -921,12 +976,16 @@ async function populateEditModal() { 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'); @@ -946,13 +1005,15 @@ document.getElementById('edit-watchlist-form').addEventListener('submit', async if (moviesSelectionChanged) { selectedMovies = currentMoviesSelection; - } else { + } + else { selectedMovies = initialMoviesSelection; } if (tvSeriesSelectionChanged) { selectedTVSeries = currentTVSeriesSelection; - } else { + } + else { selectedTVSeries = initialTVSeriesSelection; } @@ -967,7 +1028,8 @@ document.getElementById('edit-watchlist-form').addEventListener('submit', async movies: selectedMovies, tvSeries: selectedTVSeries }); - } else { + } + else { let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); if (watchlistIndex !== -1) { @@ -1010,13 +1072,15 @@ document.getElementById('edit-watchlist-form').addEventListener('submit', async if (moviesSelectionChanged) { selectedMovies = currentMoviesSelection; - } else { + } + else { selectedMovies = initialMoviesSelection; } if (tvSeriesSelectionChanged) { selectedTVSeries = currentTVSeriesSelection; - } else { + } + else { selectedTVSeries = initialTVSeriesSelection; } @@ -1107,6 +1171,11 @@ async function populateDeleteModal() { deleteForm.appendChild(deleteButton); } } + document.addEventListener('keydown', function(event) { + if (event.key === "Escape") { + closeModal('delete-watchlist-modal'); + } + }); } async function deleteSelectedWatchlists() { @@ -1162,7 +1231,9 @@ async function fetchMovieDetails(movieId) { try { const response = await fetch(url); const movie = await response.json(); - return createMovieCard(movie); + const movieCard = createMovieCard(movie); + movieCard.setAttribute('data-movie-title', movie.title); + return movieCard; } catch (error) { const errorDiv = document.createElement('div'); @@ -1175,21 +1246,40 @@ 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} -
-

${movie.title}

- ${movie.vote_average.toFixed(1)} +
+

${movieTitle}

+ ${voteAvg}
-
-

Movie Overview:

- ${movie.overview} +
+

Movie Overview:

+ ${overview}
`; + movieEl.addEventListener('click', () => { localStorage.setItem('selectedMovieId', movie.id); - window.location.href = 'movie-details.html'; + updateUniqueMoviesViewed(movie.id); + updateFavoriteGenre(movie.genre_ids); updateMovieVisitCount(movie.id, movie.title); + window.location.href = 'movie-details.html'; }); return movieEl; @@ -1222,97 +1312,6 @@ function handleSearch() { window.location.href = 'search.html'; } -async function getMovies(url) { - 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)); - } - else { - searchResultsMain.innerHTML = `

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

`; - } -} - -function showMovies(movies){ - searchResultsMain.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); - }); - - searchResultsMain.appendChild(movieE1); - }); -} - -function calculateMoviesToDisplay() { - const screenWidth = window.innerWidth; - if (screenWidth <= 689.9) return 10; - if (screenWidth <= 1021.24) return 20; - if (screenWidth <= 1353.74) return 21; - if (screenWidth <= 1684.9) return 20; - if (screenWidth <= 2017.49) return 20; - if (screenWidth <= 2349.99) return 18; - if (screenWidth <= 2681.99) return 21; - if (screenWidth <= 3014.49) return 24; - if (screenWidth <= 3345.99) return 27; - if (screenWidth <= 3677.99) return 20; - if (screenWidth <= 4009.99) return 22; - if (screenWidth <= 4340.99) return 24; - if (screenWidth <= 4673.49) return 26; - if (screenWidth <= 5005.99) return 28; - if (screenWidth <= 5337.99) return 30; - if (screenWidth <= 5669.99) return 32; - if (screenWidth <= 6001.99) return 34; - if (screenWidth <= 6333.99) return 36; - if (screenWidth <= 6665.99) return 38; - if (screenWidth <= 6997.99) return 40; - if (screenWidth <= 7329.99) return 42; - if (screenWidth <= 7661.99) return 44; - if (screenWidth <= 7993.99) return 46; - if (screenWidth <= 8325.99) return 48; - return 20; -} - async function loadWatchLists() { const displaySection = document.getElementById('watchlists-display-section'); @@ -1328,7 +1327,8 @@ async function loadWatchLists() { if (watchlists.length === 0) { displaySection.innerHTML = '

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

'; - } else { + } + else { 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) { @@ -1339,11 +1339,14 @@ async function loadWatchLists() { displaySection.appendChild(watchlistDiv); } } - } else { + } + 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 { + } + else { localWatchlists.sort((a, b) => (b.pinned === a.pinned) ? 0 : b.pinned ? 1 : -1); for (const watchlist of localWatchlists) { const watchlistDiv = await createWatchListDiv(watchlist); @@ -1357,6 +1360,7 @@ async function loadWatchLists() { let favorites = []; let favoritesTVSeries = []; + if (currentUserEmail) { const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", currentUserEmail)); const userSnapshot = await getDocs(usersRef); @@ -1366,19 +1370,24 @@ async function loadWatchLists() { favorites = userData.favoritesMovies || []; favoritesTVSeries = userData.favoritesTVSeries || []; } - } else { - favorites = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + } + 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 = 'favorites-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."; @@ -1397,10 +1406,11 @@ async function loadWatchLists() { favoritesDiv.appendChild(moviesContainer); displaySection.appendChild(favoritesDiv); - } else { + } + else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-watchlist'; + favoritesDiv.id = 'favorite-movies'; favoritesDiv.innerHTML = '

Favorite Movies

No favorite movies added yet.

'; displaySection.appendChild(favoritesDiv); } @@ -1408,11 +1418,15 @@ async function loadWatchLists() { if (favoritesTVSeries.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-tvseries-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."; @@ -1431,10 +1445,11 @@ async function loadWatchLists() { favoritesDiv.appendChild(moviesContainer); displaySection.appendChild(favoritesDiv); - } else { + } + else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-tvseries-watchlist'; + favoritesDiv.id = 'favorite-tv-series'; favoritesDiv.innerHTML = '

Favorite TV Series

No favorite TV series added yet.

'; displaySection.appendChild(favoritesDiv); } @@ -1444,9 +1459,11 @@ async function loadWatchLists() { 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 { + } + else { localWatchlists.sort((a, b) => (b.pinned === a.pinned) ? 0 : b.pinned ? 1 : -1); for (const watchlist of localWatchlists) { const watchlistDiv = await createWatchListDiv(watchlist); @@ -1460,13 +1477,13 @@ async function loadWatchLists() { let favorites = []; let favoritesTVSeries = []; - favorites = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + 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 = 'favorites-watchlist'; + favoritesDiv.id = 'favorite-movies'; const title = document.createElement('h3'); title.textContent = "Favorite Movies"; @@ -1489,10 +1506,11 @@ async function loadWatchLists() { favoritesDiv.appendChild(moviesContainer); displaySection.appendChild(favoritesDiv); - } else { + } + else { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-watchlist'; + favoritesDiv.id = 'favorite-movies'; favoritesDiv.innerHTML = '

Favorite Movies

No favorite movies added yet.

'; displaySection.appendChild(favoritesDiv); } @@ -1500,7 +1518,7 @@ async function loadWatchLists() { if (favoritesTVSeries.length > 0) { const favoritesDiv = document.createElement('div'); favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-tvseries-watchlist'; + favoritesDiv.id = 'favorite-tv-series'; const title = document.createElement('h3'); title.textContent = "Favorite TV Series"; @@ -1525,6 +1543,14 @@ async function loadWatchLists() { 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); @@ -1538,12 +1564,14 @@ async function fetchTVSeriesDetails(tvSeriesId) { try { const response = await fetch(url); - const movie = await response.json(); - return createTVSeriesCard(movie); + const series = await response.json(); + const seriesCard = createTVSeriesCard(series); + seriesCard.setAttribute('data-series-title', series.name); + return seriesCard; } catch (error) { const errorDiv = document.createElement('div'); - errorDiv.textContent = 'Error loading movie details. Please try refreshing the page.'; + errorDiv.textContent = 'Error loading series details. Please try refreshing the page.'; return errorDiv; } } @@ -1552,26 +1580,62 @@ function createTVSeriesCard(movie) { const movieEl = document.createElement('div'); movieEl.classList.add('movie'); movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = movie.name; + 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} -
-

${movie.name}

- ${movie.vote_average.toFixed(1)} + ${movie.name} +
+

${movieTitle}

+ ${voteAvg}
-
-

Movie Overview:

- ${movie.overview} +
+

TV Series Overview:

+ ${overview}
`; + movieEl.addEventListener('click', () => { localStorage.setItem('selectedTvSeriesId', movie.id); + updateMovieVisitCount(movie.id, movie.name); + updateUniqueMoviesViewed(movie.id); + updateFavoriteGenre(movie.genres_ids); window.location.href = 'tv-details.html'; - updateMovieVisitCount(movie.id, movie.title); }); 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'); } @@ -1640,12 +1704,64 @@ function addWatchListControls(watchlistDiv, watchlistId) { 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'; @@ -1654,6 +1770,10 @@ function createWatchListDiv(watchlist) { 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; @@ -1760,6 +1880,7 @@ async function moveWatchList(watchlistDiv, moveUp) { async function pinWatchList(watchlistDiv, watchlistId) { showSpinner(); + const isPinned = watchlistDiv.classList.contains('pinned'); const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); diff --git a/MovieVerse-Mobile/www/js/firebase.js b/MovieVerse-Mobile/www/js/firebase.js new file mode 100644 index 00000000..590efb98 --- /dev/null +++ b/MovieVerse-Mobile/www/js/firebase.js @@ -0,0 +1,50 @@ +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); +} + +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() +}; + +export const app = !getApps().length ? initializeApp(firebaseConfig) : getApp(); + +export const db = getFirestore(app); diff --git a/MovieVerse-Mobile/www/js/inception.js b/MovieVerse-Mobile/www/js/inception.js index daa459e3..410660ef 100644 --- a/MovieVerse-Mobile/www/js/inception.js +++ b/MovieVerse-Mobile/www/js/inception.js @@ -24,18 +24,7 @@ const searchTitle = document.getElementById("search-title"); let trailerUrlGlobal; let initialMainContent; - -function getClassByRate(vote){ - if (vote >= 8) { - return 'green'; - } - else if (vote >= 5) { - return 'orange'; - } - else { - return 'red'; - } -} +let trailerButton; form.addEventListener('submit', (e) => { e.preventDefault(); @@ -100,7 +89,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -108,11 +97,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/leonardo-dicarprio.js b/MovieVerse-Mobile/www/js/leonardo-dicarprio.js index 3057460f..13e252ac 100644 --- a/MovieVerse-Mobile/www/js/leonardo-dicarprio.js +++ b/MovieVerse-Mobile/www/js/leonardo-dicarprio.js @@ -251,7 +251,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -259,11 +259,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/movie-details.js b/MovieVerse-Mobile/www/js/movie-details.js index b46b07ce..1769cbc2 100644 --- a/MovieVerse-Mobile/www/js/movie-details.js +++ b/MovieVerse-Mobile/www/js/movie-details.js @@ -27,12 +27,13 @@ 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 IMGPATH = "https://image.tmdb.org/t/p/w780"; const favoriteButton = document.getElementById("favorite-btn"); const searchTitle = document.getElementById("search-title"); let trailerUrlGlobal; let initialMainContent; +let trailerButton; function getClassByRate(vote){ if (vote >= 8) { @@ -59,108 +60,6 @@ function handleSearch() { window.location.href = 'search.html'; } -function calculateMoviesToDisplay() { - const screenWidth = window.innerWidth; - if (screenWidth <= 689.9) return 10; - if (screenWidth <= 1021.24) return 20; - if (screenWidth <= 1353.74) return 21; - if (screenWidth <= 1684.9) return 20; - if (screenWidth <= 2017.49) return 20; - if (screenWidth <= 2349.99) return 18; - if (screenWidth <= 2681.99) return 21; - if (screenWidth <= 3014.49) return 24; - if (screenWidth <= 3345.99) return 27; - if (screenWidth <= 3677.99) return 20; - if (screenWidth <= 4009.99) return 22; - if (screenWidth <= 4340.99) return 24; - if (screenWidth <= 4673.49) return 26; - if (screenWidth <= 5005.99) return 28; - if (screenWidth <= 5337.99) return 30; - if (screenWidth <= 5669.99) return 32; - if (screenWidth <= 6001.99) return 34; - if (screenWidth <= 6333.99) return 36; - if (screenWidth <= 6665.99) return 38; - if (screenWidth <= 6997.99) return 40; - if (screenWidth <= 7329.99) return 42; - if (screenWidth <= 7661.99) return 44; - if (screenWidth <= 7993.99) return 46; - if (screenWidth <= 8325.99) return 48; - return 20; -} - -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)); - document.getElementById('clear-search-btn').style.display = 'block'; - } - else { - main.innerHTML = `

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

`; - document.getElementById('clear-search-btn').style.display = 'none'; - } -} - -function clearMovieDetails() { - const movieDetailsContainer = document.getElementById('movie-details-container'); - if (movieDetailsContainer) { - movieDetailsContainer.innerHTML = ''; - } -} - -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}` - : `
Movie 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(); -} - async function ensureGenreMapIsAvailable() { if (!localStorage.getItem('genreMap')) { await fetchGenreMap(); @@ -177,6 +76,7 @@ async function fetchGenreMap() { return map; }, {}); localStorage.setItem('genreMap', JSON.stringify(genreMap)); + console.log(genreMap) } catch (error) { console.log('Error fetching genre map:', error); @@ -211,7 +111,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -219,11 +119,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, @@ -269,12 +194,19 @@ async function rotateUserStats() { 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() { @@ -354,39 +286,6 @@ function getMostCommonGenre() { 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)) { @@ -416,6 +315,7 @@ function updateDirectorVisitCount(directorId, directorName) { } document.addEventListener('DOMContentLoaded', () => { + showSpinner(); initialMainContent = document.getElementById('main').innerHTML; const movieId = localStorage.getItem('selectedMovieId'); @@ -426,15 +326,7 @@ document.addEventListener('DOMContentLoaded', () => { fetchMovieDetails(1011985) } - 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(); + hideSpinner(); }); function handleSignInOut() { @@ -472,8 +364,10 @@ function updateSignInButtonState() { } document.addEventListener("DOMContentLoaded", function() { + showSpinner(); updateSignInButtonState(); document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); + hideSpinner(); }); const twoLetterLangCodes = [ @@ -681,7 +575,6 @@ async function fetchMovieDetails(movieId) { 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`; - const imdbUrl = `https://${getMovieVerseData()}/3/movie/${movieId}?${generateMovieNames()}${code}&append_to_response=external_ids`; try { const response = await fetch(url); @@ -821,45 +714,67 @@ function getRatingDetails(rating) { } async function fetchMovieRatings(imdbId, tmdbMovieData) { - const omdbCode = `${getMovieCode2()}`; - const omdb = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}${omdbCode}`; + showSpinner(); - try { - const response = await fetch(omdb); - const data = await response.json(); + const apiKeys = [ + await getMovieCode2(), + '58efe859', + '60a09d79', + '956e468a' + ]; - let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + const baseURL = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}`; - if (imdbRating === 'N/A' && tmdbMovieData.vote_average) { - imdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; + 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; + } + } - const rtRatingObj = data.Ratings.find(rating => rating.Source === "Rotten Tomatoes"); - let rtRating = rtRatingObj ? rtRatingObj.Value : 'N/A'; + let data; + for (const key of apiKeys) { + data = await tryFetch(key); + if (data) break; + } - let metascore = data.Metascore ? `${data.Metascore}/100` : 'N/A'; - let awards = data.Awards; - let rated = data.Rated ? data.Rated : 'Rating information unavailable'; + if (!data) { + populateMovieDetails(tmdbMovieData, tmdbMovieData.vote_average, 'N/A', 'Metascore information unavailable, click to search on Metacritics', 'Awards information unavailable'); + return; + } - if (awards === 'N/A') { - awards = 'No awards information available'; - } + let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; + if (imdbRating === 'N/A' || imdbRating === '0.0') { + imdbRating = 'N/A'; + } - if (metascore === 'N/A/100') { - const metacriticsRatingValue = imdbRating !== 'N/A' ? parseFloat(imdbRating) : (tmdbMovieData.vote_average / 2); - metascore = calculateFallbackMetacriticsRating(metacriticsRatingValue, tmdbMovieData.vote_average) + '/100'; - } + let rtRating = 'N/A'; - 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); + 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'; } - catch (error) { - const fallbackImdbRating = (tmdbMovieData.vote_average / 2).toFixed(1) * 2; - populateMovieDetails(tmdbMovieData, fallbackImdbRating, 'N/A', 'No metascore information available', '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); + hideSpinner(); } function updateBrowserURL(title) { @@ -935,8 +850,12 @@ function getYouTubeVideoId(url) { } function positionTrailerButton() { - if (!trailerButton) + showSpinner(); + if (!trailerButton) { + document.getElementById('movie-description').style.marginTop = '-20px'; return; + } + document.getElementById('movie-description').style.marginTop = '-60px'; if (window.innerWidth <= 900) { const movieDescription = document.getElementById('movie-description'); @@ -946,6 +865,7 @@ function positionTrailerButton() { const movieRating = document.getElementById('movie-rating'); movieRating.parentNode.insertBefore(trailerButton, movieRating.nextSibling); } + hideSpinner(); } document.addEventListener('DOMContentLoaded', positionTrailerButton); @@ -1003,7 +923,6 @@ function createMetacriticSlug(title) { async function fetchStreamingLinks(movieId) { const url = `https://${getMovieVerseData()}/3/movie/${movieId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; - console.log(url) try { const response = await fetch(url); const data = await response.json(); @@ -1027,12 +946,10 @@ async function fetchStreamingLinks(movieId) { } async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, rated) { - document.getElementById('movie-image').src = `https://image.tmdb.org/t/p/w1280${movie.poster_path}`; + showSpinner(); 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 streamingProviders = await fetchStreamingLinks(movie.id); const movieTitleEncoded = encodeURIComponent(movie.title); @@ -1069,42 +986,23 @@ async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awar } return `
- ${provider.provider_name} - `; - }).join('') : 'No streaming options available.'; - - 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)}` : '#'; + ${provider.provider_name} + `; + }).join('') + ` + JustWatch + ` : '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 = ` - IMDB Rating: ${imdbRating} - `; - document.getElementById('movie-rating').style.marginTop = '129px'; + document.getElementById('movie-rating').innerHTML = ``; document.title = movie.title + " - Movie Details"; - const movieImage = document.getElementById('movie-image'); const movieDescription = document.getElementById('movie-description'); - - const metascoreElement = metascore ? `

Metascore: ${metascore}

` : ''; + 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'; - noImageText.style.height = '800px'; - document.querySelector('.movie-left').appendChild(noImageText); - } - - const fullLanguage = twoLetterLangCodes.find(lang => lang.code === movie.original_language).name; const overview = movie.overview ? movie.overview : 'No overview available'; const genres = movie.genres.map(genre => genre.name).join(', '); const releaseDate = movie.release_date ? movie.release_date : 'Release date not available'; @@ -1115,35 +1013,30 @@ async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awar const languages = movie.spoken_languages.map(lang => lang.name).join(', '); const countries = movie.production_countries.map(country => country.name).join(', '); - const originalLanguage = fullLanguage ? fullLanguage : 'Language Info Not Available'; const popularityScore = movie.popularity.toFixed(0); - const status = movie.status ? movie.status : 'Status Info Not Available'; - 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'; + keywords = 'No keywords have been added'; } 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'; + 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} @@ -1155,10 +1048,10 @@ async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awar

Languages: ${languages}

Countries of Production: ${countries}

Popularity Score: ${popularityText}

-

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

+

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

${awardsElement} +

TMDb Rating: ${tmdbRating}/10.0

${metascoreElement} -

Rotten Tomatoes: ${rtRating}

`; if (movie.credits && movie.credits.crew) { @@ -1188,7 +1081,7 @@ async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awar const topTenCast = movie.credits.cast.slice(0, 10); topTenCast.forEach((actor, index) => { const actorLink = document.createElement('a'); - actorLink.innerHTML = `${actor.name}`; + actorLink.innerHTML = `${actor.name}`; castHeading.appendChild(actorLink); if (index < topTenCast.length - 1) { castHeading.appendChild(document.createTextNode(', ')); @@ -1232,13 +1125,239 @@ async function populateMovieDetails(movie, imdbRating, rtRating, metascore, awar 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); - updateMoviesFavorited(movie.id); - applySettings(); + 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; + `; + + 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; + `; + + 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; + `; + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + imageWrapper.appendChild(imageElement); + mediaContainer.appendChild(imageWrapper); + + imageElement.addEventListener('click', function() { + let imageUrl = this.src.replace('w780', 'w1280'); + const modalHtml = ` +
+ Movie 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(); + } + }); + }); + + 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); + mediaContainer.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); + mediaContainer.appendChild(nextButton); + + let currentIndex = 0; + function navigateMedia(images, imgElement, direction) { + currentIndex += direction; + if (currentIndex < 0) { + currentIndex = images.length - 1; + } + else if (currentIndex >= images.length) { + currentIndex = 0; + } + imgElement.style.opacity = '0'; + setTimeout(() => { + imgElement.src = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + imgElement.style.opacity = '1'; + }, 420); + } + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } + + const movieImage = document.getElementById('movie-image'); + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + movieImage.loading = 'lazy'; + } + else { + movieImage.style.display = 'none'; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageText.style.textAlign = 'center'; + noImageText.style.height = '800px'; + document.querySelector('.movie-left').appendChild(noImageText); + } + + hideSpinner(); +} + +function createImdbRatingCircle(imdbRating, imdbId) { + if (imdbRating === 'N/A' || imdbRating === null || imdbRating === undefined) { + 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() { @@ -1248,14 +1367,31 @@ function getSavedTextColor() { function handleDirectorClick(directorId, directorName) { localStorage.setItem('selectedDirectorId', directorId); document.title = `${directorName} - Director's Details`; - window.location.href = 'director-details.html'; updateUniqueDirectorsViewed(directorId); updateDirectorVisitCount(directorId, directorName); + window.location.href = 'director-details.html'; } -function selectActorId(actorId) { +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' + window.location.href = 'actor-details.html'; } function handleCompanyClick(companyId, companyName) { @@ -1384,4 +1520,4 @@ function applyTextColor(color) { .forEach(element => { element.style.color = color; }); -} \ No newline at end of file +} diff --git a/MovieVerse-Mobile/www/js/movie-match.js b/MovieVerse-Mobile/www/js/movie-match.js index db700bb5..db6cf0e0 100644 --- a/MovieVerse-Mobile/www/js/movie-match.js +++ b/MovieVerse-Mobile/www/js/movie-match.js @@ -87,7 +87,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -95,11 +95,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, diff --git a/MovieVerse-Mobile/www/js/movie-timeline.js b/MovieVerse-Mobile/www/js/movie-timeline.js index d2563437..37f491bf 100644 --- a/MovieVerse-Mobile/www/js/movie-timeline.js +++ b/MovieVerse-Mobile/www/js/movie-timeline.js @@ -22,7 +22,6 @@ document.getElementById('end-year').addEventListener('keydown', function(event) } }); - const movieCode = { part1: 'YzVhMjBjODY=', part2: 'MWFjZjdiYjg=', @@ -94,7 +93,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -102,11 +101,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, @@ -306,8 +330,24 @@ function updateMovies() { } } -function showMovies(movies, mainElement) { - mainElement.innerHTML = ''; +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'; + header.textContent = `Movies from ${startYear} to ${endYear}`; + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.innerHTML = ''; + centerContainer1.appendChild(header); + centerContainer1.appendChild(mainElement); + } + movies.forEach(movie => { const movieEl = document.createElement('div'); movieEl.classList.add('movie'); @@ -316,15 +356,25 @@ function showMovies(movies, mainElement) { : `
Image Not Available
`; const voteAvg = movie.vote_average.toFixed(1); const ratingClass = getClassByRate(movie.vote_average); + let title = movie.title; + const words = title.split(' '); + if (words.length >= 9) { + words[8] = '...'; + title = words.slice(0, 9).join(' '); + } + let overview = movie.overview; + if (overview === '') { + overview = 'No overview available.'; + } movieEl.innerHTML = ` ${movieImage}
-

${movie.title}

+

${title}

${voteAvg}

Overview:

- ${movie.overview} + ${overview}
`; movieEl.addEventListener('click', () => { localStorage.setItem('selectedMovieId', movie.id); @@ -334,19 +384,54 @@ function showMovies(movies, mainElement) { movieEl.style.cursor = 'pointer'; mainElement.appendChild(movieEl); }); + const centerContainer1 = document.getElementById('center-container1'); + centerContainer1.appendChild(mainElement); + + createLoadMoreButton(startYear, endYear, mainElement); + hideSpinner(); } -document.getElementById('clear-search-btn').addEventListener('click', () => { - location.reload(); -}); +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'; -async function fetchMoviesByTimePeriod(startYear, endYear) { - const url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31`; + 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 numberOfMovies = calculateMoviesToDisplay(); - const moviesToShow = data.results.slice(0, numberOfMovies); - showMovies(moviesToShow, document.getElementById('results')); + 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', () => { diff --git a/MovieVerse-Mobile/www/js/notifications.js b/MovieVerse-Mobile/www/js/notifications.js index e7d0a074..39223f01 100644 --- a/MovieVerse-Mobile/www/js/notifications.js +++ b/MovieVerse-Mobile/www/js/notifications.js @@ -21,22 +21,8 @@ async function fetchReleasesByCategory(elementId, startDate, endDate, isLastVisi list.innerHTML = ''; let movies = await fetchMovies(startDate, endDate); - if (movies.length < 5 && !isLastVisit) { - const expandedStartDate = new Date(startDate.getFullYear(), startDate.getMonth() - 1, startDate.getDate()); - movies = await fetchMovies(expandedStartDate, endDate); - } - if (movies.length === 0) { - if (isLastVisit) { - const noMoviesText = document.createElement('li'); - noMoviesText.textContent = "No New Movies Released Since Your Last Visit"; - list.appendChild(noMoviesText); - } - else { - const veryExpandedStartDate = new Date(startDate.getFullYear() - 1, startDate.getMonth(), startDate.getDate()); - movies = await fetchMovies(veryExpandedStartDate, endDate); - } - } + movies = movies.sort((a, b) => new Date(b.release_date) - new Date(a.release_date)); populateList(elementId, movies.slice(0, 5)); } @@ -45,15 +31,15 @@ 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()}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&release_date.gte=${formattedStartDate}&release_date.lte=${formattedEndDate}`; + 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.filter(movie => movie.popularity > 0); + return data.results; } catch (error) { - console.error('Failed to fetch movies for', elementId + ':', error); + console.log('Failed to fetch movies for', elementId + ':', error); return []; } } @@ -62,23 +48,42 @@ 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 favoriteGenres = localStorage.getItem('favoriteGenre'); - if (!favoriteGenres) { - throw new Error('No favorite genres found in localStorage.'); - } - const genresArray = JSON.parse(favoriteGenres); - const genreId = genresArray[0]; + const genreId = mostVisitedMovieGenre || mostCommonGenre; if (!genreId) { throw new Error('Genre ID is not valid.'); } - url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=${genreId}`; + url = `https://${getMovieVerseData()}/3/discover/movie?${generateMovieNames()}${getMovieCode()}&with_genres=${genreId}`; } catch (error) { - console.error('Fetching recommended movies failed or data issues:', error); + console.log('Fetching recommended movies failed or data issues:', error); url = `https://${getMovieVerseData()}/3/movie/popular?${generateMovieNames()}${getMovieCode()}&language=en-US&page=1`; } @@ -88,7 +93,7 @@ async function fetchRecommendedReleases() { populateList('recommendedReleases', data.results.slice(0, 5)); } catch (error) { - console.error('Failed to fetch movies:', error); + console.log('Failed to fetch movies:', error); } } @@ -107,7 +112,6 @@ function populateList(elementId, movies) { title.textContent = movie.title; title.style.color = 'black'; li.appendChild(title); - list.appendChild(li); }); } @@ -140,7 +144,6 @@ function populateActors() { const name = document.createElement('span'); name.textContent = actor.name; li.appendChild(name); - list.appendChild(li); }); } @@ -171,5 +174,4 @@ function populateDirectors() { list.appendChild(li); }); - -} \ No newline at end of file +} diff --git a/MovieVerse-Mobile/www/js/quiz.js b/MovieVerse-Mobile/www/js/quiz.js index 539ddba3..a674b85e 100644 --- a/MovieVerse-Mobile/www/js/quiz.js +++ b/MovieVerse-Mobile/www/js/quiz.js @@ -1,3 +1,5 @@ +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" }, @@ -71,6 +73,61 @@ const questionBank = [ { 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 = { @@ -87,25 +144,6 @@ function generateMovieNames(input) { return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); } -const IMGPATH = "https://image.tmdb.org/t/p/w1280"; -const main = document.getElementById("main"); -const search = document.getElementById("search"); -const searchButton = document.getElementById("button-search"); -const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; -const searchTitle = document.getElementById("trivia-label"); - -function getClassByRate(vote){ - if (vote >= 8) { - return 'green'; - } - else if (vote >= 5) { - return 'orange'; - } - else { - return 'red'; - } -} - const form = document.getElementById("form"); form.addEventListener('submit', (e) => { @@ -121,118 +159,6 @@ function handleSearch() { window.location.href = 'search.html'; } -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; - }); - - document.getElementById('clear-search-btn').style.display = 'block'; - - if (allMovies.length > 0) { - showMovies(allMovies.slice(0, numberOfMovies)); - } - else { - main.innerHTML = `

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

`; - document.getElementById('clear-search-btn').style.display = 'none'; - } -} - -document.getElementById('clear-search-btn').addEventListener('click', () => { - location.reload(); -}); - -function clearMovieDetails() { - const movieDetailsContainer = document.getElementById('quiz-container'); - if (movieDetailsContainer) { - movieDetailsContainer.innerHTML = ''; - } - document.getElementById('regenerate-questions').style.display = 'none'; - document.getElementById('submit').style.display = 'none'; -} - -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); - }); -} - -function calculateMoviesToDisplay() { - const screenWidth = window.innerWidth; - if (screenWidth <= 689.9) return 10; - if (screenWidth <= 1021.24) return 20; - if (screenWidth <= 1353.74) return 21; - if (screenWidth <= 1684.9) return 20; - if (screenWidth <= 2017.49) return 20; - if (screenWidth <= 2349.99) return 18; - if (screenWidth <= 2681.99) return 21; - if (screenWidth <= 3014.49) return 24; - if (screenWidth <= 3345.99) return 27; - if (screenWidth <= 3677.99) return 20; - if (screenWidth <= 4009.99) return 22; - if (screenWidth <= 4340.99) return 24; - if (screenWidth <= 4673.49) return 26; - if (screenWidth <= 5005.99) return 28; - if (screenWidth <= 5337.99) return 30; - if (screenWidth <= 5669.99) return 32; - if (screenWidth <= 6001.99) return 34; - if (screenWidth <= 6333.99) return 36; - if (screenWidth <= 6665.99) return 38; - if (screenWidth <= 6997.99) return 40; - if (screenWidth <= 7329.99) return 42; - if (screenWidth <= 7661.99) return 44; - if (screenWidth <= 7993.99) return 46; - if (screenWidth <= 8325.99) return 48; - return 20; -} - -document.addEventListener('DOMContentLoaded', () => { - document.getElementById('clear-search-btn').style.display = 'none'; -}); - function generateRandomQuestions() { const questionsToDisplay = 10; const shuffledQuestions = questionBank.sort(() => 0.5 - Math.random()); @@ -262,24 +188,6 @@ function generateRandomQuestions() { }); } -function updateTriviaStats(correctAnswers, totalQuestions) { - let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { totalCorrect: 0, totalAttempted: 0 }; - - triviaStats.totalCorrect += correctAnswers; - triviaStats.totalAttempted += totalQuestions; - - localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); -} - -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`; -} - document.getElementById('regenerate-questions').addEventListener('click', generateRandomQuestions); generateRandomQuestions(); @@ -389,7 +297,9 @@ function calculateAndDisplayResults() { } }); - updateTriviaStats(score, totalQuestions); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser') || null; + + updateTriviaStats(currentUserEmail, score, totalQuestions); displayResults(score); } @@ -428,4 +338,4 @@ function showModal() { modal.style.display = "none"; } }); -} \ No newline at end of file +} diff --git a/MovieVerse-Mobile/www/js/ratings-module.js b/MovieVerse-Mobile/www/js/ratings-module.js new file mode 100644 index 00000000..37bd576f --- /dev/null +++ b/MovieVerse-Mobile/www/js/ratings-module.js @@ -0,0 +1,80 @@ +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/js/search.js b/MovieVerse-Mobile/www/js/search.js index b6ada7c1..cd665e18 100644 --- a/MovieVerse-Mobile/www/js/search.js +++ b/MovieVerse-Mobile/www/js/search.js @@ -34,6 +34,8 @@ document.addEventListener('DOMContentLoaded', () => { attachArrowKeyNavigation(); fetchGenreMap(); fetchTvGenreMap(); + fetchLanguages(); + fetchTvLanguages(); document.getElementById('form1').addEventListener('submit', function(event) { event.preventDefault(); @@ -41,6 +43,58 @@ document.addEventListener('DOMContentLoaded', () => { }); }); +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}`; @@ -123,7 +177,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -131,11 +185,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, @@ -181,11 +260,19 @@ async function rotateUserStats() { 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() { @@ -279,12 +366,15 @@ function attachEventListeners() { 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'); @@ -314,7 +404,7 @@ function attachEventListeners() { movieFilters.style.display = 'none'; tvFilters.style.display = 'none'; peopleFilters.style.display = 'none'; - toggleFiltersBtn.textContent = 'Filter Results'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; }); tvBtn.addEventListener('click', () => { @@ -324,7 +414,7 @@ function attachEventListeners() { movieFilters.style.display = 'none'; tvFilters.style.display = 'none'; peopleFilters.style.display = 'none'; - toggleFiltersBtn.textContent = 'Filter Results'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; }); peopleBtn.addEventListener('click', () => { @@ -334,7 +424,7 @@ function attachEventListeners() { movieFilters.style.display = 'none'; tvFilters.style.display = 'none'; peopleFilters.style.display = 'none'; - toggleFiltersBtn.textContent = 'Filter Results'; + toggleFiltersBtn.textContent = 'Filter & Sort Results'; }); toggleFiltersBtn.addEventListener('click', () => { @@ -355,6 +445,7 @@ function attachEventListeners() { ratingValueSpan.textContent = `Rating: ${ratingMovieFilter.value} and above`; showResults('movie'); }); + languageFilter.addEventListener('change', () => showResults('movie')); genreTvFilter.addEventListener('change', () => showResults('tv')); yearTvFilter.addEventListener('change', () => showResults('tv')); @@ -362,14 +453,15 @@ function attachEventListeners() { 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"]'); @@ -378,6 +470,7 @@ function attachEventListeners() { genreMovieFilter.selectedIndex = 0; yearMovieFilter.value = ''; ratingMovieFilter.value = 5; + languageFilter.selectedIndex = 0; setFilterDisplayValues(); showResults('movie'); }); @@ -386,12 +479,14 @@ function attachEventListeners() { 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'); @@ -434,10 +529,26 @@ document.addEventListener('DOMContentLoaded', function() { toggleFiltersBtn.textContent = 'Close Filters'; } else { - toggleFiltersBtn.textContent = 'Filter Results'; + 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'); @@ -445,6 +556,10 @@ document.addEventListener('DOMContentLoaded', function() { }); }); +let movieSortChanged = false; +let tvSortChanged = false; +let peopleSortChanged = false; + function attachArrowKeyNavigation() { const categories = ['movie', 'tv', 'person']; let currentIndex = 0; @@ -485,6 +600,23 @@ 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); @@ -496,6 +628,17 @@ async function showResults(category) { 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); @@ -505,23 +648,32 @@ async function showResults(category) { 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); + (!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); @@ -533,18 +685,27 @@ async function showResults(category) { 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); + (!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) { @@ -619,10 +780,21 @@ function showMovies(items, container, category) { const isMovie = item.title && hasVoteAverage; const isTvSeries = item.name && hasVoteAverage && category === 'tv'; - const title = item.title || item.name || "N/A"; - const overview = item.overview || 'No overview available.'; + let title = item.title || item.name || "N/A"; + const words = title.split(' '); + + if (words.length >= 9) { + words[8] = '...'; + title = words.slice(0, 9).join(' '); + } + + let overview = item.overview || 'No overview available.'; const biography = item.biography || 'Click to view the details of this person.'; + if (overview === '') { + overview = 'No overview available.'; + } + const { id, profile_path, poster_path } = item; const imagePath = profile_path || poster_path ? IMGPATH + (profile_path || poster_path) : null; @@ -650,10 +822,14 @@ function showMovies(items, container, category) { movieContentHTML += `
`; if (isPerson) { - movieContentHTML += `

Details:

${biography}
`; + const roleOverview = item.known_for_department === 'Directing' ? 'Director Overview' : 'Actor Overview'; + movieContentHTML += `

${roleOverview}:

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

TV Series Overview:

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

Overview:

${overview}
`; + movieContentHTML += `

Movie Overview:

${overview}
`; } movieEl.innerHTML = movieContentHTML; @@ -665,10 +841,42 @@ function showMovies(items, container, category) { 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; } @@ -693,43 +901,41 @@ function showMovies(items, container, category) { }); } -function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; +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'; +} - if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); } - else { - window.location.href = 'sign-in.html'; - return; +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; } - updateSignInButtonState(); + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); } -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'; +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; } -} -document.addEventListener("DOMContentLoaded", function() { - updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); -}); + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); +} function getClassByRate(vote) { if (vote >= 8) { @@ -757,4 +963,4 @@ function updateBrowserURL(title) { function createNameSlug(title) { return title.toLowerCase().replace(/ /g, '-').replace(/[^\w-]/g, ''); -} +} \ No newline at end of file diff --git a/MovieVerse-Mobile/www/js/service-worker.js b/MovieVerse-Mobile/www/js/service-worker.js index 499f2f8f..bcc2087d 100644 --- a/MovieVerse-Mobile/www/js/service-worker.js +++ b/MovieVerse-Mobile/www/js/service-worker.js @@ -13,7 +13,6 @@ const urlsToCache = [ '/MovieVerse-Frontend/js/movie-details.js', '/MovieVerse-Frontend/js/movie-timeline.js', '/MovieVerse-Frontend/js/quiz.js', - '/MovieVerse-Frontend/js/movie-details.js', '/MovieVerse-Frontend/js/actor-details.js', '/MovieVerse-Frontend/js/director-details.js', '/MovieVerse-Frontend/html/about.html', @@ -21,40 +20,53 @@ const urlsToCache = [ '/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/settings.html', '/MovieVerse-Frontend/html/privacy-policy.html', '/MovieVerse-Frontend/html/terms-of-service.html', - '/images/black.jpeg', - '/images/blue.jpg', - '/images/brown.jpg', - '/images/green.jpg', - '/images/gold.jpg', - '/images/grey.png', - '/images/orange.jpg', - '/images/pink.png', - '/images/purple.jpg', - '/images/red.jpg', - '/images/rose.png', - '/images/silver.png', - '/images/universe.jpg', - '/images/universe.png', + '/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.png', - '/images/universe-2.png', - '/images/universe-2.jpg', - '/images/universe-3.jpg', - '/images/universe-4.png', - '/images/universe-5.png', - '/images/universe-6.png', - '/images/universe-7.png', - '/images/universe-8.png', - '/images/universe-9.png', - '/images/universe-10.png', - '/images/yellow.jpg', + '/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', diff --git a/MovieVerse-Mobile/www/js/settings.js b/MovieVerse-Mobile/www/js/settings.js index e8da7678..3a302e8c 100644 --- a/MovieVerse-Mobile/www/js/settings.js +++ b/MovieVerse-Mobile/www/js/settings.js @@ -1,10 +1,14 @@ -const DEFAULT_BACKGROUND_IMAGE = '../../images/universe-1.png'; +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(); @@ -13,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => { bgSelect.addEventListener('change', function() { document.body.style.backgroundImage = `url('${this.value}')`; localStorage.setItem('backgroundImage', this.value); + window.location.reload(); }); } @@ -36,24 +41,127 @@ document.addEventListener('DOMContentLoaded', () => { if (resetButton) { resetButton.addEventListener('click', function () { localStorage.removeItem('backgroundImage'); - localStorage.setItem('backgroundImage', '../../images/universe-1.png') + 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 bgSelect = document.getElementById('background-select'); const customImages = JSON.parse(localStorage.getItem('customImages')) || []; const savedTextColor = localStorage.getItem('textColor'); const savedFontSize = localStorage.getItem('fontSize'); if (!savedBg) { - savedBg = '../../images/universe-1.png'; + 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}')`; } - document.body.style.backgroundImage = `url('${savedBg}')`; + const foundImage = customImages.find(image => image.dataURL === savedBg); if (savedTextColor) { @@ -62,6 +170,7 @@ document.addEventListener('DOMContentLoaded', () => { }); textColorInput.value = savedTextColor; } + if (savedFontSize) { const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; document.body.style.fontSize = size; @@ -71,41 +180,20 @@ document.addEventListener('DOMContentLoaded', () => { if (bgSelect) { bgSelect.value = foundImage ? foundImage.dataURL : savedBg; } - else { - return; - } } - const deleteButton = document.getElementById('delete-uploaded-btn'); - if (deleteButton) { - deleteButton.addEventListener('click', function() { - deleteImagesPrompt(); - document.body.style.backgroundImage = `url('${DEFAULT_BACKGROUND_IMAGE}')`; - localStorage.setItem('backgroundImage', DEFAULT_BACKGROUND_IMAGE); - if (bgSelect) { - bgSelect.value = DEFAULT_BACKGROUND_IMAGE; - } - }); - } - else { - return; - } -}) - -function loadCustomBackgrounds() { - const bgSelect = document.getElementById('background-select'); - const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + 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); - }); - } - else { - return; + 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'); @@ -124,25 +212,36 @@ document.addEventListener('DOMContentLoaded', () => { 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; + 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 { - if (file.size > 204800) { // 200KB - resizeImage(file, 204800, (resizedDataUrl) => { - processImageUpload(resizedDataUrl, imageNameInput, bgSelect); - alert('The uploaded image was resized to fit the size limit of 200KB.'); - }); - } - else { - const reader = new FileReader(); - reader.onload = function (e) { - processImageUpload(e.target.result, imageNameInput, bgSelect); - }; - reader.readAsDataURL(file); - } + 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 { @@ -151,7 +250,6 @@ document.addEventListener('DOMContentLoaded', () => { }); }); - function handleQuotaExceedance() { const customImages = JSON.parse(localStorage.getItem('customImages')) || []; if (customImages.length > 0) { @@ -220,37 +318,56 @@ function processImageUpload(dataUrl, imageNameInput, bgSelect) { } 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() { - 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; + 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; + else { + if (height > maxSize) { + width *= maxSize / height; + height = maxSize; + } } - } - canvas.width = width; - canvas.height = height; - ctx.drawImage(img, 0, 0, width, height); + canvas.width = width; + canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + + callback(canvas.toDataURL('image/jpeg'), null); - callback(canvas.toDataURL('image/jpeg')); + 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/js/triviaModule.js b/MovieVerse-Mobile/www/js/triviaModule.js new file mode 100644 index 00000000..4ae5c28c --- /dev/null +++ b/MovieVerse-Mobile/www/js/triviaModule.js @@ -0,0 +1,69 @@ +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()) { + console.log("Fetched trivia stats from Firebase:", docSnap.data()); + 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.error("Firebase quota exceeded, fetching trivia stats from localStorage."); + return JSON.parse(localStorage.getItem('triviaStats')) || {totalCorrect: 0, totalAttempted: 0}; + } + } + } +} diff --git a/MovieVerse-Mobile/www/js/tv-details.js b/MovieVerse-Mobile/www/js/tv-details.js index 706e84fd..ebadb344 100644 --- a/MovieVerse-Mobile/www/js/tv-details.js +++ b/MovieVerse-Mobile/www/js/tv-details.js @@ -20,7 +20,7 @@ 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 IMGPATH = "https://image.tmdb.org/t/p/w780"; const searchTitle = document.getElementById("search-title"); let initialMainContent; @@ -87,7 +87,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -95,11 +95,36 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreArray = JSON.parse(localStorage.getItem('genreMap')) || []; - const genreObject = genreArray.reduce((acc, genre) => { - acc[genre.id] = genre.name; - return acc; - }, {}); + 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'; } }, @@ -233,31 +258,16 @@ document.addEventListener('DOMContentLoaded', rotateUserStats); function setStarRating(rating) { const stars = document.querySelectorAll('.rating .star'); stars.forEach(star => { - star.style.color = star.dataset.value > rating ? 'grey' : 'gold'; + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; }); document.getElementById('rating-value').textContent = `${rating}.0/5.0`; } -document.addEventListener('DOMContentLoaded', () => { - setInitialStarRating(tvSeriesId); -}); - 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 setInitialStarRating(tvSeriesId) { - const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; - const tvSeriesRating = savedRatings[tvSeriesId]; - if (tvSeriesRating) { - setStarRating(tvSeriesRating); - } - else { - setStarRating(0); - } -} - document.querySelectorAll('.rating .star').forEach(star => { star.addEventListener('mouseover', (e) => { setStarRating(e.target.dataset.value); @@ -536,7 +546,6 @@ async function fetchTvDetails(tvSeriesId) { const response = await fetch(urlWithAppend); const tvSeriesDetails = await response.json(); const imdbId = tvSeriesDetails.external_ids.imdb_id; - const imdbRating = await fetchTVRatings(imdbId); populateTvSeriesDetails(tvSeriesDetails, imdbRating); @@ -561,16 +570,14 @@ async function fetchTvDetails(tvSeriesId) { } async function fetchTVRatings(imdbId) { - const omdbCode = `${getMovieCode2()}`; - const omdb = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}${omdbCode}`; + const fff = `60a09d79`; + const link = `https://${getMovieActor()}/?i=${imdbId}&${getMovieName()}${fff}`; try { - const response = await fetch(omdb); + const response = await fetch(link); const data = await response.json(); - let imdbRating = data.imdbRating ? data.imdbRating : 'N/A'; - - return imdbRating; + return imdbRating = data.imdbRating ? data.imdbRating : 'IMDb data unavailable but you can check it out by clicking here'; } catch (error) { console.log('Error fetching TV series ratings:', error); @@ -593,12 +600,14 @@ async function populateTvSeriesDetails(tvSeries, imdbRating) { document.getElementById('movie-title').textContent = title; document.title = tvSeries.name + " - TV Series Details"; - const posterPath = tvSeries.poster_path ? `https://image.tmdb.org/t/p/w1280${tvSeries.poster_path}` : 'path/to/default/poster.jpg'; + const posterPath = tvSeries.poster_path ? `https://image.tmdb.org/t/p/w780${tvSeries.poster_path}` : 'path/to/default/poster.jpg'; document.getElementById('movie-image').src = posterPath; document.getElementById('movie-image').alt = `Poster of ${title}`; 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'; @@ -615,7 +624,7 @@ async function populateTvSeriesDetails(tvSeries, imdbRating) { const voteAverage = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; const voteCount = tvSeries.vote_count ? tvSeries.vote_count.toLocaleString() : 'N/A'; - detailsHTML += `

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

`; + 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; @@ -623,15 +632,34 @@ async function populateTvSeriesDetails(tvSeries, imdbRating) { detailsHTML += `

IMDb Rating: ${imdbRating}

`; } else { - detailsHTML += `

IMDb Rating: N/A

`; + detailsHTML += `

IMDb Rating: IMDb rating not available

`; } - const homepage = tvSeries.homepage ? `Visit` : 'Not available'; + const tmdbRating = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + detailsHTML += `

TMDB Rating: ${tmdbRating}/10.0

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

Homepage: ${homepage}

`; + detailsHTML += `

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

`; + + 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}

`; + if (tvSeries.created_by && tvSeries.created_by.length) { const creatorsLinks = tvSeries.created_by.map(creator => - `${creator.name}` + `${creator.name}` ).join(', '); detailsHTML += `

Directors: ${creatorsLinks}

`; } @@ -641,7 +669,8 @@ async function populateTvSeriesDetails(tvSeries, imdbRating) { if (tvSeries.credits && tvSeries.credits.cast && tvSeries.credits.cast.length) { let castHTML = tvSeries.credits.cast.slice(0, 100).map(castMember => { - return `${castMember.name}`; + const escapedName = castMember.name.replace(/'/g, "\\'"); + return `${castMember.name}`; }).join(', '); detailsHTML += `

Cast: ${castHTML}

`; } @@ -669,19 +698,6 @@ async function populateTvSeriesDetails(tvSeries, imdbRating) { detailsHTML += `

Similar TV Series: Information not available

`; } - detailsHTML += `

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

`; - - 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}

`; - if (tvSeries.last_episode_to_air) { detailsHTML += `

Last Episode: ${tvSeries.last_episode_to_air.name || 'Title not available'} - "${tvSeries.last_episode_to_air.overview || 'Overview not available.'}"

`; } @@ -718,9 +734,11 @@ async function populateTvSeriesDetails(tvSeries, imdbRating) { } return ` - ${provider.provider_name} - `; - }).join('') : 'No streaming options available.'; + ${provider.provider_name} + `; + }).join('') + ` + JustWatch + ` : 'No streaming options available.'; detailsHTML += `

Streaming Options: ${streamingHTML}

`; @@ -732,7 +750,150 @@ async function populateTvSeriesDetails(tvSeries, imdbRating) { detailsHTML += `

Keywords: Information not 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 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'; + mediaContainer.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + imageElement.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(); + } + }); + }); + + 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'; + + mediaContainer.appendChild(prevButton); + mediaContainer.appendChild(nextButton); + } + + let currentIndex = 0; + prevButton.onclick = () => navigateMedia(images, imageElement, -1); + nextButton.onclick = () => navigateMedia(images, imageElement, 1); + + function navigateMedia(images, imgElement, direction) { + currentIndex += direction; + if (currentIndex < 0) { + currentIndex = images.length - 1; + } else if (currentIndex >= images.length) { + currentIndex = 0; + } + imgElement.style.opacity = '0'; + setTimeout(() => { + imgElement.src = `https://image.tmdb.org/t/p/w780${images[currentIndex].file_path}`; + imgElement.style.opacity = '1'; + }, 420); + } + + if (window.innerWidth <= 767) { + mediaContainer.style.width = 'calc(100% - 40px)'; + } + + if (images.length === 0) { + mediaContainer.innerHTML = '

No media available

'; + } + document.getElementById('movie-description').innerHTML = detailsHTML; + document.getElementById('movie-description').appendChild(mediaTitle); + document.getElementById('movie-description').appendChild(mediaContainer); } async function fetchTvSeriesStreamingLinks(tvSeriesId) { @@ -752,15 +913,61 @@ async function fetchTvSeriesStreamingLinks(tvSeriesId) { }); return Object.values(providersMap).slice(0, 7); - } catch (error) { + } + catch (error) { console.error('Error fetching TV series streaming links:', error); return []; } } -function selectActorId(actorId) { +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' + window.location.href = 'actor-details.html'; } function selectTvSeriesId(tvSeriesId) { @@ -781,8 +988,11 @@ function hideSpinner() { document.getElementById('myModal').classList.remove('modal-visible'); } -function handleCreatorClick(creatorId) { +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'; } @@ -797,7 +1007,7 @@ document.addEventListener('DOMContentLoaded', () => { document.getElementById('clear-search-btn').style.display = 'none'; - const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; const movieRating = savedRatings[tvSeriesId] || 0; setStarRating(movieRating); }); diff --git a/MovieVerse-Mobile/www/js/user-profile.js b/MovieVerse-Mobile/www/js/user-profile.js index e4b71556..f5f730f1 100644 --- a/MovieVerse-Mobile/www/js/user-profile.js +++ b/MovieVerse-Mobile/www/js/user-profile.js @@ -1,6 +1,7 @@ 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 { getStorage, ref, uploadBytes, getDownloadURL, deleteObject } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-storage.js"; +import { getAverageMovieRating } from './ratings-module.js'; +import { getTriviaStats } from './triviaModule.js'; function showSpinner() { document.getElementById('myModal').classList.add('modal-visible'); @@ -57,6 +58,33 @@ document.addEventListener('DOMContentLoaded', function() { setupSearchListeners(); }); +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() { const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); @@ -104,6 +132,7 @@ function setupSearchListeners() { searchUserInput.addEventListener('input', () => { const searchText = searchUserInput.value.trim(); + if (searchText) { performSearch(searchText); } @@ -126,19 +155,20 @@ function setupSearchListeners() { } async function performSearch(searchText) { - try { - const searchUserResults = document.getElementById('searchUserResults'); - showSpinner(); + const searchUserResults = document.getElementById('searchUserResults'); + const db = getFirestore(); + showSpinner(); - const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText)); + 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 { + } + else { searchUserResults.style.display = 'block'; querySnapshot.forEach((doc) => { const user = doc.data(); @@ -156,28 +186,76 @@ async function performSearch(searchText) { const textDiv = document.createElement('div'); textDiv.style.width = '67%'; textDiv.style.textAlign = 'left'; - textDiv.innerHTML = `${user.username}

${user.bio || ''}

`; + textDiv.innerHTML = `${user.username}

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

`; userDiv.appendChild(textDiv); searchUserResults.appendChild(userDiv); }); } - hideSpinner(); } catch (error) { - console.error("Error fetching user list: ", error); - if (error.code === 'resource-exhausted') { - const noUserSelected = document.getElementById('search-users-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(); - } + 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 = 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; + } + + 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 = 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; + } + + updateProgressCircles(averageRating, averageTriviaScore, 'container2'); + } + catch (error) { + console.error('Error updating progress circles:', error); + } +}); + async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMovieVerseUser')) { try { showSpinner(); @@ -199,7 +277,8 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo profileImage.removeAttribute('onclick'); profileImage.style.cursor = 'default'; profileImage.title = 'Sign in to change profile image'; - } else { + } + else { changeProfileImageBtn.style.display = ''; editProfileBtn.style.display = ''; profileImage.setAttribute('onclick', 'document.getElementById("imageUpload").click()'); @@ -226,7 +305,7 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo const followersRef = doc(db, 'profiles', userEmail, 'followers', currentUserEmail); const followSnap = await getDoc(followingRef); - const isFollowing = followSnap.exists(); + let isFollowing = followSnap.exists(); followUnfollowBtn.textContent = isFollowing ? 'Unfollow' : 'Follow'; followUnfollowBtn.style.display = 'block'; @@ -236,17 +315,38 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo await deleteDoc(followingRef); await deleteDoc(followersRef); followUnfollowBtn.textContent = 'Follow'; - } else { + 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 { + } + else { followUnfollowBtn.style.display = 'none'; } + 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); + try { const docSnap = await getDoc(docRef); let profile = { @@ -296,7 +396,37 @@ async function loadProfile(userEmail = localStorage.getItem('currentlySignedInMo await displayUserList('followers', userEmail); } else { - console.log("No such profile exists!"); + 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`; + } + + await displayUserList('following', userEmail); + await displayUserList('followers', userEmail); } } catch (error) {