2 Copyright (C) 2019 Kai Uwe Broulik <kde@privat.broulik.de>
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.
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.
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/>.
19 // Gets the currently viewed tab
20 static getCurrentTab() {
21 return new Promise((resolve, reject) => {
26 const error = chrome.runtime.lastError;
28 return reject(error.message);
33 return reject("NO_TAB");
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"
50 const error = chrome.runtime.lastError;
52 return reject(error.message);
64 return new Promise((resolve, reject) => {
67 TabUtils.getCurrentTabFramesUrls()
70 const settings = result[0];
71 const currentUrls = result[1];
73 const mprisSettings = settings.mpris;
74 if (!mprisSettings.enabled) {
75 return reject("MPRIS_DISABLED");
78 if (!currentUrls) { // can this happen?
79 return reject("NO_URLS");
82 const origins = currentUrls.map((url) => {
84 return new URL(url).origin;
86 console.warn("Invalid url", url);
89 }).filter((origin) => {
93 if (origins.length === 0) {
94 return reject("NO_ORIGINS");
97 const uniqueOrigins = [...new Set(origins)];
99 const websiteSettings = mprisSettings.websiteSettings || {};
106 for (const origin of uniqueOrigins) {
108 if (typeof MPRIS_WEBSITE_SETTINGS[origin] === "boolean") {
109 allowed = MPRIS_WEBSITE_SETTINGS[origin];
111 if (typeof websiteSettings[origin] === "boolean") {
112 allowed = websiteSettings[origin];
115 response.origins[origin] = allowed;
124 setAllowed(origin, allowed) {
125 return SettingsUtils.get().then((settings) => {
126 const mprisSettings = settings.mpris;
127 if (!mprisSettings.enabled) {
128 return reject("MPRIS_DISABLED");
131 let websiteSettings = mprisSettings.websiteSettings || {};
133 let implicitAllowed = true;
134 if (typeof MPRIS_WEBSITE_SETTINGS[origin] === "boolean") {
135 implicitAllowed = MPRIS_WEBSITE_SETTINGS[origin];
138 if (allowed !== implicitAllowed) {
139 websiteSettings[origin] = allowed;
141 delete websiteSettings[origin];
144 mprisSettings.websiteSettings = websiteSettings;
146 return SettingsUtils.set({
153 document.addEventListener("DOMContentLoaded", () => {
155 sendMessage("browserAction", "getStatus").then((status) => {
157 switch (status.portStatus) {
158 case "UNSUPPORTED_OS":
159 document.getElementById("unsupported_os_error").classList.remove("hidden");
162 case "STARTUP_FAILED": {
163 document.getElementById("startup_error").classList.remove("hidden");
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");
176 document.getElementById("main").classList.remove("hidden");
178 let errorText = status.portLastErrorMessage;
179 if (errorText === "UNKNOWN") {
180 errorText = chrome.i18n.getMessage("general_error_unknown");
184 document.getElementById("runtime_error_text").innerText = errorText;
185 document.getElementById("runtime_error").classList.remove("hidden");
187 // There's some content, hide dummy placeholder
188 document.getElementById("dummy-main").classList.add("hidden");
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") {
201 // do we need to do something with the port here?
203 sendMessage("browserAction", "ready");
206 // MPris blocker checkboxes
207 const blocker = new MPrisBlocker();
208 blocker.getAllowed().then((result) => {
209 const origins = result.origins;
211 if (Object.entries(origins).length === 0) { // "isEmpty"
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");
226 TabUtils.getCurrentTab().then((tab) => {
227 return sendMessage("mpris", "hasTabPlayer", {
230 }).then((playerIds) => {
231 if (playerIds.length > 0) {
232 return resolve("HAS_PLAYER");
235 reject("NO_PLAYER_NO_BLOCKED");
238 // There's some content, hide dummy placeholder
239 document.getElementById("dummy-main").classList.add("hidden");
241 let blacklistInfoElement = document.querySelector(".mpris-blacklist-info");
242 blacklistInfoElement.classList.remove("hidden");
244 let originsListElement = blacklistInfoElement.querySelector("ul.mpris-blacklist-origins");
246 for (const origin in origins) {
247 const originAllowed = origins[origin];
249 let blockListElement = document.createElement("li");
251 let labelElement = document.createElement("label");
252 labelElement.innerText = origin;
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
261 const allowed = checkboxElement.checked;
262 blocker.setAllowed(origin, allowed).then(() => {
263 checkboxElement.checked = allowed;
265 console.warn("Failed to change media controls settings:", err);
269 labelElement.insertBefore(checkboxElement, labelElement.firstChild);
271 blockListElement.appendChild(labelElement);
273 originsListElement.appendChild(blockListElement);
276 console.log("Not showing media controls settings because", err);
279 console.warn("Failed to check for whether media controls are blocked", err);