update readme
[dotfiles/.git] / .config / BraveSoftware / Brave-Browser / Default / Extensions / cimiefiiaegbelhefglklhhakcgmhkai / 1.7.6_0 / action_popup.js
1 /*
2     Copyright (C) 2019 Kai Uwe Broulik <kde@privat.broulik.de>
3
4     This program is free software; you can redistribute it and/or
5     modify it under the terms of the GNU General Public License as
6     published by the Free Software Foundation; either version 3 of
7     the License, or (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 class TabUtils {
19     // Gets the currently viewed tab
20     static getCurrentTab() {
21         return new Promise((resolve, reject) => {
22             chrome.tabs.query({
23                 active: true,
24                 currentWindow: true
25             }, (tabs) => {
26                 const error = chrome.runtime.lastError;
27                 if (error) {
28                     return reject(error.message);
29                 }
30
31                 const tab = tabs[0];
32                 if (!tab) {
33                     return reject("NO_TAB");
34                 }
35
36                 resolve(tab);
37             });
38         });
39     }
40
41     // Gets the URLs of the currently viewed tab including all of its iframes
42     static getCurrentTabFramesUrls() {
43         return new Promise((resolve, reject) => {
44             TabUtils.getCurrentTab().then((tab) => {
45                 chrome.tabs.executeScript({
46                     allFrames: true, // so we also catch iframe videos
47                     code: `window.location.href`,
48                     runAt: "document_start"
49                 }, (result) => {
50                     const error = chrome.runtime.lastError;
51                     if (error) {
52                         return reject(error.message);
53                     }
54
55                     resolve(result);
56                 });
57             });
58         });
59     }
60 };
61
62 class MPrisBlocker {
63     getAllowed() {
64         return new Promise((resolve, reject) => {
65             Promise.all([
66                 SettingsUtils.get(),
67                 TabUtils.getCurrentTabFramesUrls()
68             ]).then((result) => {
69
70                 const settings = result[0];
71                 const currentUrls = result[1];
72
73                 const mprisSettings = settings.mpris;
74                 if (!mprisSettings.enabled) {
75                     return reject("MPRIS_DISABLED");
76                 }
77
78                 if (!currentUrls) { // can this happen?
79                     return reject("NO_URLS");
80                 }
81
82                 const origins = currentUrls.map((url) => {
83                     try {
84                         return new URL(url).origin;
85                     } catch (e) {
86                         console.warn("Invalid url", url);
87                         return "";
88                     }
89                 }).filter((origin) => {
90                     return !!origin;
91                 });
92
93                 if (origins.length === 0) {
94                     return reject("NO_ORIGINS");
95                 }
96
97                 const uniqueOrigins = [...new Set(origins)];
98
99                 const websiteSettings = mprisSettings.websiteSettings || {};
100
101                 let response = {
102                     origins: {},
103                     mprisSettings
104                 };
105
106                 for (const origin of uniqueOrigins) {
107                     let allowed = true;
108                     if (typeof MPRIS_WEBSITE_SETTINGS[origin] === "boolean") {
109                         allowed = MPRIS_WEBSITE_SETTINGS[origin];
110                     }
111                     if (typeof websiteSettings[origin] === "boolean") {
112                         allowed = websiteSettings[origin];
113                     }
114
115                     response.origins[origin] = allowed;
116                 }
117
118                 resolve(response);
119
120             }, reject);
121         });
122     }
123
124     setAllowed(origin, allowed) {
125         return SettingsUtils.get().then((settings) => {
126             const mprisSettings = settings.mpris;
127             if (!mprisSettings.enabled) {
128                 return reject("MPRIS_DISABLED");
129             }
130
131             let websiteSettings = mprisSettings.websiteSettings || {};
132
133             let implicitAllowed = true;
134             if (typeof MPRIS_WEBSITE_SETTINGS[origin] === "boolean") {
135                 implicitAllowed = MPRIS_WEBSITE_SETTINGS[origin];
136             }
137
138             if (allowed !== implicitAllowed) {
139                 websiteSettings[origin] = allowed;
140             } else {
141                 delete websiteSettings[origin];
142             }
143
144             mprisSettings.websiteSettings = websiteSettings;
145
146             return SettingsUtils.set({
147                 mpris: mprisSettings
148             });
149         });
150     }
151 };
152
153 document.addEventListener("DOMContentLoaded", () => {
154
155     sendMessage("browserAction", "getStatus").then((status) => {
156
157         switch (status.portStatus) {
158         case "UNSUPPORTED_OS":
159             document.getElementById("unsupported_os_error").classList.remove("hidden");
160             break;
161
162         case "STARTUP_FAILED": {
163             document.getElementById("startup_error").classList.remove("hidden");
164
165             const errorText = status.portLastErrorMessage;
166             // Don't show generic error on startup failure. There's already an explanation.
167             if (errorText && errorText !== "UNKNOWN") {
168                 const errorTextItem = document.getElementById("startup_error_text");
169                 errorTextItem.innerText = errorText;
170                 errorTextItem.classList.remove("hidden");
171             }
172             break;
173         }
174
175         default: {
176             document.getElementById("main").classList.remove("hidden");
177
178             let errorText = status.portLastErrorMessage;
179             if (errorText === "UNKNOWN") {
180                 errorText = chrome.i18n.getMessage("general_error_unknown");
181             }
182
183             if (errorText) {
184                 document.getElementById("runtime_error_text").innerText = errorText;
185                 document.getElementById("runtime_error").classList.remove("hidden");
186
187                 // There's some content, hide dummy placeholder
188                 document.getElementById("dummy-main").classList.add("hidden");
189             }
190
191             break;
192         }
193         }
194
195         // HACK so the extension can tell we closed, see "browserAction" "ready" callback in extension.js
196         chrome.runtime.onConnect.addListener((port) => {
197             if (port.name !== "browserActionPort") {
198                 return;
199             }
200
201             // do we need to do something with the port here?
202         });
203         sendMessage("browserAction", "ready");
204     });
205
206     // MPris blocker checkboxes
207     const blocker = new MPrisBlocker();
208     blocker.getAllowed().then((result) => {
209         const origins = result.origins;
210
211         if (Object.entries(origins).length === 0) { // "isEmpty"
212             return;
213         }
214
215         // To keep media controls setting from always showing up, only show them, if:
216         // - There is actually a player anywhere on this tab
217         // or, since when mpris is disabled, there are never any players
218         // - when media controls are disabled for any origin on this tab
219         new Promise((resolve, reject) => {
220             for (let origin in origins) {
221                 if (origins[origin] === false) {
222                     return resolve("HAS_BLOCKED");
223                 }
224             }
225
226             TabUtils.getCurrentTab().then((tab) => {
227                 return sendMessage("mpris", "hasTabPlayer", {
228                     tabId: tab.id
229                 });
230             }).then((playerIds) => {
231                 if (playerIds.length > 0) {
232                     return resolve("HAS_PLAYER");
233                 }
234
235                 reject("NO_PLAYER_NO_BLOCKED");
236             });
237         }).then(() => {
238             // There's some content, hide dummy placeholder
239             document.getElementById("dummy-main").classList.add("hidden");
240
241             let blacklistInfoElement = document.querySelector(".mpris-blacklist-info");
242             blacklistInfoElement.classList.remove("hidden");
243
244             let originsListElement = blacklistInfoElement.querySelector("ul.mpris-blacklist-origins");
245
246             for (const origin in origins) {
247                 const originAllowed = origins[origin];
248
249                 let blockListElement = document.createElement("li");
250
251                 let labelElement = document.createElement("label");
252                 labelElement.innerText = origin;
253
254                 let checkboxElement = document.createElement("input");
255                 checkboxElement.type = "checkbox";
256                 checkboxElement.checked = (originAllowed === true);
257                 checkboxElement.addEventListener("click", (e) => {
258                     // Let us handle (un)checking the checkbox when setAllowed succeeds
259                     e.preventDefault();
260
261                     const allowed = checkboxElement.checked;
262                     blocker.setAllowed(origin, allowed).then(() => {
263                         checkboxElement.checked = allowed;
264                     }, (err) => {
265                         console.warn("Failed to change media controls settings:", err);
266                     });
267                 });
268
269                 labelElement.insertBefore(checkboxElement, labelElement.firstChild);
270
271                 blockListElement.appendChild(labelElement);
272
273                 originsListElement.appendChild(blockListElement);
274             }
275         }, (err) => {
276             console.log("Not showing media controls settings because", err);
277         });
278     }, (err) => {
279         console.warn("Failed to check for whether media controls are blocked", err);
280     });
281 });