const IS_FIREFOX = (typeof chrome === "undefined"); const IS_CHROME = (typeof browser === "undefined"); class DomManager { constructor() { this.elements = { lastActivityItemDate: document.getElementById("last-activity-item-date"), status: document.getElementById("status"), netflixManagerStatus: document.getElementById("netflixmanager-status"), mainManagerStatus: document.getElementById("mainmanager-status"), backend: document.getElementById("backend"), buildIdentifier: document.getElementById("build-identifier"), authUrl: document.getElementById("auth-url"), lastActivityItemTitle: document.getElementById("last-activity-item-title"), pagesGot: document.getElementById("pages-got"), itemsGot: document.getElementById("items-got"), firstItemTitle: document.getElementById("first-item-title"), firstItemDate: document.getElementById("first-item-date"), lastItemTitle: document.getElementById("last-item-title"), lastItemDate: document.getElementById("last-item-date"), button: document.getElementById("button"), }; this.buttonClickHandlers = []; this.elements.button.onclick = () => { this._handleButtonClick(); }; } setLastActivityDate(date) { this.elements.lastActivityItemDate.innerText = date; } setLastActivityTitle(title) { this.elements.lastActivityItemTitle.innerText = title; } setStatus(status) { this.elements.status.innerText = status; if (status === "Ready") this.elements.button.disabled = false; else this.elements.button.disabled = true; } setNetflixManagerStatus(status) { this.elements.netflixManagerStatus.innerText = status; } setMainManagerStatus(status) { this.elements.mainManagerStatus.innerText = status; } setAuthUrl(authUrl) { this.elements.authUrl.innerText = authUrl; } setBuildIdentifier(buildIdentifier) { this.elements.buildIdentifier.innerText = buildIdentifier; } setBackend(backend) { this.elements.backend.innerText = backend; } setPagesGot(pagesGot) { this.elements.pagesGot.innerText = pagesGot; } setItemsGot(itemsGot) { this.elements.itemsGot.innerText = itemsGot; } setFirstItemTitle(firstItemTitle) { this.elements.firstItemTitle.innerText = firstItemTitle; } setFirstItemDate(firstItemDate) { this.elements.firstItemDate.innerText = firstItemDate; } setLastItemTitle(lastItemTitle) { this.elements.lastItemTitle.innerText = lastItemTitle; } setLastItemDate(lastItemDate) { this.elements.lastItemDate.innerText = lastItemDate; } onButtonClick(cb) { this.buttonClickHandlers.push(cb); } _handleButtonClick() { this.buttonClickHandlers.forEach(cb => { cb(); }); } } class NetflixManager { constructor() { this.page = 0; domManager.setNetflixManagerStatus("Waiting for authUrl and buildIdentifier"); this.fetchAuthUrl(); this.fetchBuildIdentifier(); this.gotAuthUrlFromBackground = false; this.gotBuildIdentifierFromBackground = false; } async fetchAuthUrl() { if (IS_FIREFOX) this.authUrl = await browser.runtime.sendMessage({ type: `getAuthUrl` }); if (IS_CHROME) this.authUrl = await new Promise(resolve => { chrome.runtime.sendMessage({ type: `getAuthUrl` }, response => { resolve(response); }) }); domManager.setAuthUrl(this.authUrl); this.gotAuthUrlFromBackground = true; if (this.gotBuildIdentifierFromBackground && this.gotAuthUrlFromBackground && !this.buildIdentifier && !this.authUrl) domManager.setNetflixManagerStatus("Background does not have auth url and build identifier yet. Please reload the Netflix page on the correct profile."); } async fetchBuildIdentifier() { if (IS_FIREFOX) this.buildIdentifier = await browser.runtime.sendMessage({ type: `getBuildIdentifier` }); if (IS_CHROME) this.buildIdentifier = await new Promise(resolve => { chrome.runtime.sendMessage({ type: `getBuildIdentifier` }, response => { resolve(response); }); }); domManager.setBuildIdentifier(this.buildIdentifier); this.gotBuildIdentifierFromBackground = true; if (this.gotBuildIdentifierFromBackground && this.gotAuthUrlFromBackground && !this.buildIdentifier && !this.authUrl) domManager.setNetflixManagerStatus("Background does not have auth url and build identifier yet. Please reload the Netflix page on the correct profile."); } isReady() { return new Promise(resolve => { let intervalId = setInterval(() => { if (this.authUrl && this.buildIdentifier) { clearInterval(intervalId); domManager.setNetflixManagerStatus("Ready"); resolve(); } else console.log("Auth URL or build identifier not set yet in NetflixManager"); }, 250); }); } getURL() { return `https://www.netflix.com/api/shakti/${this.buildIdentifier}/viewingactivity?language=en-US&authURL=${this.authUrl}&pg=${this.page}`; } getPage() { console.log(`Getting page ${this.page}`); domManager.setNetflixManagerStatus(`Getting page ${this.page}`); return new Promise(resolve => { setTimeout(() => { const URL = this.getURL(); fetch(new Request(URL)) .then(response => { if (response.status === 200) { return response.json(); } else { throw new Error("Something went wrong with the API."); } }) .then(response => { resolve(response); }) .catch(error => { console.error(error); }); }, Math.floor(Math.random() * 750) + 250); }); } } class MainManager { constructor() { this.items = []; domManager.setMainManagerStatus("Fetching last activity item"); this.fetchLastActivityItem(); } async fetchLastActivityItem() { socket.emit("getLastActivityItem", lastActivityItem => { this.lastActivityItem = lastActivityItem; let date = (new Date(this.lastActivityItem.date)).toLocaleString(); let title = this.lastActivityItem.seriesTitle ? `${this.lastActivityItem.seriesTitle} - ${this.lastActivityItem.episodeTitle}` : `${this.lastActivityItem.title}`; domManager.setLastActivityDate(date); domManager.setLastActivityTitle(title); }); } isReady() { return new Promise(resolve => { let intervalId = setInterval(() => { if (this.lastActivityItem) { clearInterval(intervalId); domManager.setMainManagerStatus("Ready"); resolve(); } }, 250); }); } getMore() { return new Promise(async resolve => { let activityPage = await netflixManager.getPage(); domManager.setPagesGot(netflixManager.page + 1); netflixManager.page++; let resolved = false; activityPage.viewedItems.forEach(activityItem => { if (activityItem.date > this.lastActivityItem.date) { this.items.push(activityItem); } else { resolved = true; } }); domManager.setItemsGot(this.items.length); const firstItem = (this.items.length > 0) ? this.items[this.items.length - 1] : null; const lastItem = (this.items.length > 0) ? this.items[0] : null; if (firstItem) { let firstItemDate = (new Date(firstItem.date)).toLocaleString(); let firstItemTitle = firstItem.seriesTitle ? `${firstItem.seriesTitle} - ${firstItem.episodeTitle}` : `${firstItem.title}`; domManager.setFirstItemDate(firstItemDate); domManager.setFirstItemTitle(firstItemTitle); } else { domManager.setFirstItemDate("No item"); domManager.setFirstItemTitle("No item"); } if (lastItem) { let lastItemDate = (new Date(lastItem.date)).toLocaleString(); let lastItemTitle = lastItem.seriesTitle ? `${lastItem.seriesTitle} - ${lastItem.episodeTitle}` : `${lastItem.title}`; domManager.setLastItemDate(lastItemDate); domManager.setLastItemTitle(lastItemTitle); } else { domManager.setLastItemDate("No item"); domManager.setLastItemTitle("No item"); } if (activityPage.viewedItems.length === 0) resolved = true; if (resolved) return resolve(); else this.getMore().then(() => { resolve(); }); }); } } let domManager; let netflixManager; let mainManager; let socket; let init = async () => { let backend; if (IS_FIREFOX) backend = (await browser.storage.local.get("backend")).backend; if (IS_CHROME) backend = await new Promise((resolve, reject) => { chrome.storage.local.get("backend", response => { resolve(response.backend); }); }); socket = io(backend); domManager = new DomManager(); domManager.setBackend(backend); domManager.setStatus("Initializing NetflixManager"); netflixManager = new NetflixManager(); domManager.setStatus("Waiting for NetflixManager"); await netflixManager.isReady(); domManager.setStatus("Initializing MainManager"); mainManager = new MainManager(); domManager.setStatus("Waiting for MainManager"); await mainManager.isReady(); domManager.setStatus("Ready"); domManager.onButtonClick(async () => { console.log("On button click, gonna get the items"); domManager.setStatus("Starting to get items"); await mainManager.getMore(); domManager.setNetflixManagerStatus(`Ready`); domManager.setStatus("Sending items to backend"); console.log("Should be done now!"); console.log(mainManager.items); socket.emit("importNewItems", mainManager.items); domManager.setStatus("Sent items to backend"); }); } init();