Skip to content

Commit

Permalink
TrustedHTML script, extension UI changes & improvements in File Syste…
Browse files Browse the repository at this point in the history
…m API

- The console script now works also on pages with TrustedHTML (every usage of innerHTML has been removed)
- The console script now supports using the File System API
- When using the File System API,  the already-cached files will be written to the disk and, if possible, the next files. This is done to avoid a SecurityException that might be triggered if a source is created without user action
- When choosing a folder using the File System API, the script will automatically create the new file and write the cached chunks to the file system
- Now, only one file at a time will be created on the user's drive. This should help fixing some bugs (even if probably it wasn't related, but better safe than sorry). If more than one file needs to be created, they'll be created later
- Before creating the file on the system, the title must be marked as final. This helps ensuring the file has a readable name there
- It's now possible to disable the download of the content when the video ends, or the automatic closure of the stream while using the File System API
- The content title is now shown also in the extension UI
- Bumped version to 1.1.0
  • Loading branch information
dinoosauro committed Dec 26, 2024
1 parent bfa0ec1 commit 3806e64
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 52 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package-lock.json
Output-Chromium.zip
Output-Firefox.zip
Output-Firefox
Output-Chromium
.DS_Store
ConsoleScript-UI.js
ConsoleScript-Console.js
Expand Down
71 changes: 55 additions & 16 deletions GenerateConsoleScript.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,37 @@ function addDownloader() {
const listContainer = Object.assign(document.createElement("div"), {
style: "position: fixed; top: 55px; right: 15px; max-width: 45vw; padding: 10px; max-height: 70vh; border-radius: 8px; background-color: #151515; display: none; z-index: 99999999; overflow: scroll"
});
/**
* The directory where the files of the current page will be created.
* This is saved also on the script since it's used when writing a single file in the FS.
* @type FileSystemDirectoryHandle
*/
let fsPicker = undefined;
/**
* The button that shows or hides the list
*/
const downloadSwitch = Object.assign(document.createElement("div"), {
style: "position: fixed; top: 15px; right: 15px; display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 8px; background-color: #151515; z-index: 99999999",
onclick: () => {
listContainer.innerHTML = "";
for (const child of listContainer.children) child.remove();
listContainer.style.display = listContainer.style.display === "none" ? "block" : "none";
if (listContainer.style.display === "none") return;
// We'll now create the instructions to download the video
listContainer.append(Object.assign(document.createElement("p"), {
textContent: "Click on a name to read it as a Blob. Click again to download it (you have five seconds to click it again before it's deleted).",
textContent: "Click on a name to read it as a Blob. Click again to download it (you have five seconds to click it again before it's deleted), or, if you've enabled the File System API (entries in italic), to close the stream.",
style: globalStyles.text
}), document.createElement("br"));
for (const item of $ActionHandler({ action: "getDownloads" }).content) {
// If possible, we'll also create the button to use the File System API
(typeof window.showDirectoryPicker === "function") && listContainer.append(Object.assign(document.createElement("button"), {
textContent: "Write the current (and if possible the next) files in a folder (FS API)",
style: `width: fit-content; ${globalStyles.button}`,
onclick: async () => {
const picker = await window.showDirectoryPicker({ id: "MediaCachePicker", mode: "readwrite" });
fsPicker = picker;
$ActionHandler({ action: "fileSystem", content: picker });
}
}), document.createElement("br"), document.createElement("br"));
for (const item of $ActionHandler({ action: "getDownloads", everything: true }).content) {
/**
* The container for the link and the delete button
*/
Expand All @@ -56,9 +72,15 @@ function addDownloader() {
*/
const link = Object.assign(document.createElement("label"), {
textContent: `${item.title} [${item.mimeType}]`,
style: globalStyles.text
style: `${globalStyles.text} ${item.writable ? "font-style: italic" : ""}`
});
link.onclick = () => {
if (item.writable) { // The File System API is being used, so we'll close the stream
$ActionHandler({ action: "fsFinalize", content: item.id });
div.remove();
return;
}
// We'll create a new link so that the file can be downloaded
const newLink = Object.assign(document.createElement("a"), {
textContent: `${item.title} [${item.mimeType}]`,
download: item.title,
Expand All @@ -68,15 +90,29 @@ function addDownloader() {
setTimeout(() => { URL.revokeObjectURL(newLink.href); }, 5000);
newLink.click();
}
const button = Object.assign(document.createElement("button"), {
textContent: "Delete",
style: `width: fit-content; ${globalStyles.button}`,
onclick: () => {
$ActionHandler({ action: "deleteThis", content: { id: item.id } });
div.remove();
}
});
div.append(link, button);
div.append(link);
if (!item.writable) { // Delete the file
const button = Object.assign(document.createElement("button"), {
textContent: "Delete",
style: `width: fit-content; ${globalStyles.button}`,
onclick: () => {
$ActionHandler({ action: "deleteThis", content: { id: item.id } });
div.remove();
}
});
div.append(button);
}
if (fsPicker && !item.writable) { // It's possible to write the file into the File System, but user authorization is required (since there's no writable – it needs to be created. The script automatically tries to create a new writable, but sometimes it fails due to the lack of user interaction). So, we'll display a button to force writing it.
const button = Object.assign(document.createElement("button"), {
textContent: "Write on FS",
style: `width: fit-content; ${globalStyles.button}`,
onclick: async () => {
const file = await fsPicker.getFileHandle(item.title, { create: true });
$ActionHandler({ action: "fileSystemSingleOperation", content: { file, handle: fsPicker, id: item.id } });
}
});
div.append(button);
}
listContainer.append(div);
}
/**
Expand All @@ -95,10 +131,13 @@ function addDownloader() {
});
listContainer.append(document.createElement("br"), hideEverything);
},
innerHTML: `<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.5 16.9997C15.7761 16.9997 16 17.2236 16 17.4997C16 17.7452 15.8231 17.9494 15.5899 17.9917L15.5 17.9997H4.5C4.22386 17.9997 4 17.7759 4 17.4997C4 17.2543 4.17688 17.0501 4.41012 17.0078L4.5 16.9997H15.5ZM10.0001 2.00195C10.2456 2.00195 10.4497 2.17896 10.492 2.41222L10.5 2.5021L10.496 14.296L14.1414 10.6476C14.3148 10.4739 14.5842 10.4544 14.7792 10.5892L14.8485 10.647C15.0222 10.8204 15.0418 11.0898 14.907 11.2848L14.8492 11.3541L10.3574 15.8541C10.285 15.9267 10.1957 15.9724 10.1021 15.9911L9.99608 16.0008C9.83511 16.0008 9.69192 15.9247 9.60051 15.8065L5.14386 11.3547C4.94846 11.1595 4.94823 10.8429 5.14336 10.6475C5.3168 10.4739 5.58621 10.4544 5.78117 10.5892L5.85046 10.647L9.496 14.288L9.5 2.50181C9.50008 2.22567 9.724 2.00195 10.0001 2.00195Z" fill="#fafafa"/>
</svg>`
});
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
for (const item of [["width", "20"], ["height", "20"], ["viewBox", "0 0 20 20"], ["fill", "none"], ["xmlns", "http://www.w3.org/2000/svg"]]) svg.setAttribute(item[0], item[1]);
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
for (const item of [["d", "M15.5 16.9997C15.7761 16.9997 16 17.2236 16 17.4997C16 17.7452 15.8231 17.9494 15.5899 17.9917L15.5 17.9997H4.5C4.22386 17.9997 4 17.7759 4 17.4997C4 17.2543 4.17688 17.0501 4.41012 17.0078L4.5 16.9997H15.5ZM10.0001 2.00195C10.2456 2.00195 10.4497 2.17896 10.492 2.41222L10.5 2.5021L10.496 14.296L14.1414 10.6476C14.3148 10.4739 14.5842 10.4544 14.7792 10.5892L14.8485 10.647C15.0222 10.8204 15.0418 11.0898 14.907 11.2848L14.8492 11.3541L10.3574 15.8541C10.285 15.9267 10.1957 15.9724 10.1021 15.9911L9.99608 16.0008C9.83511 16.0008 9.69192 15.9247 9.60051 15.8065L5.14386 11.3547C4.94846 11.1595 4.94823 10.8429 5.14336 10.6475C5.3168 10.4739 5.58621 10.4544 5.78117 10.5892L5.85046 10.647L9.496 14.288L9.5 2.50181C9.50008 2.22567 9.724 2.00195 10.0001 2.00195Z"], ["fill", "#fafafa"]]) path.setAttribute(item[0], item[1]);
svg.append(path);
downloadSwitch.append(svg);
downloadSwitch.style.display = document.fullscreenElement ? "none" : "flex";
document.addEventListener("fullscreenchange", () => { // If there's something in full screen, hide the download button
downloadSwitch.style.display = document.fullscreenElement ? "none" : "flex";
Expand Down
4 changes: 4 additions & 0 deletions background.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@
files: ['script.js'],
world: "MAIN"
});
browserToUse.tabs.sendMessage(ids[0].id, { // Update user preferences
action: "updateChoices",
content: await browserToUse.storage.sync.get(["finalize_fs_stream_when_video_finishes", "delete_entries_when_video_finishes", "download_content_when_video_finishes"])
});
await getPromise(); // Check again
resolve();
}
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "MediaCache",
"description": "Cache the video/audio content displayed by various websites, and download it",
"version": "1.0.2",
"version": "1.1.0",
"action": {
"default_popup": "./ui/ui.html"
},
Expand Down
Loading

0 comments on commit 3806e64

Please sign in to comment.