您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Anonymizes file names when posting on 4chan
当前为
- // ==UserScript==
- // @name 4chan anonymize file names
- // @namespace a508vdvu3inxqz4zeagu
- // @match https://boards.4chan.org/*
- // @match https://boards.4channel.org/*
- // @grant none
- // @version 1.1
- // @description Anonymizes file names when posting on 4chan
- // @inject-into content
- // @run-at document-start
- // ==/UserScript==
- (function () {
- "use strict";
- const { window, document, Set, String, Math, Date, performance, MutationObserver } = globalThis;
- const File = window.File;
- // Changes the file name to a random plausible timestamp
- const genFileName = (oldName) => {
- const minute = 60 * 1_000_000; // microseconds
- const year = minute * 60 * 24 * 365;
- const now = Math.floor((performance.timeOrigin + performance.now()) * 1000);
- // Random timestamp 1 minute to 1 year in the past
- let newName = String(now - Math.floor(Math.random() * (year - minute + 1) + minute));
- const dot = oldName.lastIndexOf(".");
- if (dot !== -1) {
- // Copy over file extension
- newName += oldName.substring(dot).toLowerCase();
- }
- return newName;
- };
- // Set up UI elements (2 paired checkboxes)
- const checkbox = document.createElement("input");
- const label = document.createElement("label");
- const checkboxQR = document.createElement("input");
- const labelQR = document.createElement("label");
- checkbox.type = checkboxQR.type = "checkbox";
- label.title = labelQR.title = "Send actual filename when uploading";
- label.append(checkbox, " Filename");
- labelQR.append(checkboxQR, " Filename");
- // Turn off file name rewriting via the checkboxes
- let rewritingEnabled = true;
- const checkboxListener = function () {
- rewritingEnabled = !this.checked;
- // Transfer state to the other checkbox since it's global
- if (this === checkbox) {
- checkboxQR.checked = this.checked;
- } else {
- checkbox.checked = this.checked;
- }
- };
- checkbox.addEventListener("input", checkboxListener);
- checkboxQR.addEventListener("input", checkboxListener);
- // Watch for forms being serialized, and change file names.
- window.addEventListener("formdata", ({ formData }) => {
- // Use global var instead of unregistering/re-registering this listener.
- // Keeping it in place ensures we always run first.
- if (!rewritingEnabled) {
- return;
- }
- // Gather keys pointing to at least 1 file entry.
- const fileEntries = new Set();
- for (const [key, val] of formData) {
- if (val instanceof File) {
- fileEntries.add(key);
- }
- }
- // For each key...
- for (const key of fileEntries) {
- // Get all entry values
- const values = formData.getAll(key);
- // Remove them
- formData.delete(key);
- // Re-add them
- for (const val of values) {
- // ... with a new file name, if it is a File.
- if (val instanceof File) {
- formData.append(key, val, genFileName(val.name));
- } else {
- formData.append(key, val);
- }
- }
- }
- }, { capture: true, passive: true });
- const tryAddQuickReply = () => {
- if (!labelQR.isConnected) {
- document.getElementById("qrFile")?.after(" ", labelQR);
- }
- };
- // Insert post form checkbox on load
- window.addEventListener("DOMContentLoaded", () => {
- document.getElementById("postFile").after(" ", label);
- tryAddQuickReply();
- // Wait for quick reply form to show up
- new MutationObserver(tryAddQuickReply).observe(document.body, { childList: true });
- });
- })();