您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在mo的内容页增加图片和视频下载的按钮, 解锁右键功能
当前为
// ==UserScript== // @name mo (LDH) 下载器 // @namespace https://1mether.me/ // @version 0.24 // @description 在mo的内容页增加图片和视频下载的按钮, 解锁右键功能 // @author 乙醚(@locoda) // @match http*://m.tribe-m.jp/* // @match http*://m.ex-m.jp/* // @match http*://m.ldh-m.jp/* // @match http*://m.ldhgirls-m.jp/* // @icon https://www.google.com/s2/favicons?sz=64&domain=ldh.co.jp // @source https://github.com/locoda/mo-downloader // @license MIT // ==/UserScript== (function () { "use strict"; // 删除图片保护 removeProtectImg(); // 在详情页注入按钮 if (window.location.href.includes("detail")) { injectDownloadAllButtons(); } // 根据视频注入按钮 if (window.location.href.includes("movie")) { if (document.querySelector("div.limelight-player")) { injectPerVideoDownloadButton(document); } } // 在时间轴界面设置Listener if (window.location.href.includes("timeline")) { // 等待加载scroll (function init() { var counter = document.querySelector("ldh-infinite-scroll"); if (counter) { customizedTimelinePage(); } else { setTimeout(init, 300); } })(); } })(); function removeProtectImg() { // 移除右键限制 document.oncontextmenu = function () { return true; }; // 移除protectimg限制 document .querySelectorAll(".protectimg") .forEach((node) => node.classList.remove("protectimg")); } // ================================ // = Button Injection Utils = // ================================ function injectDownloadAllButtons() { var article = document.querySelector("article"); if (article.classList.contains("article--news")) { // 新闻页面特殊处理 article = article.querySelector(".article__body"); } attachButtonToArticle(article); } function findEligibleImgs(article) { const keywords = ["uplcmn", "upload"]; return Array.from(article.querySelectorAll("img")) .map((img) => img.src) .filter((img) => keywords.some((k) => img.includes(k))); } function attachButtonToArticle(article) { var imgs = findEligibleImgs(article); // 注入按钮 div var buttonsDiv = document.createElement("div"); buttonsDiv.className = "ldh-mo-dl"; buttonsDiv.style = "margin-top: 0.4em; margin-bottom: 0.4em;"; article.insertBefore(buttonsDiv, article.firstChild); // 图片链接生成按钮 const isMobile = () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent ); if (isMobile()) { injectOneButton(buttonsDiv, "生成图片链接", function () { generateOnClickHandler(buttonsDiv, article); }); } // 图片下载按钮 injectOneButton( buttonsDiv, "下载所有图片 (" + imgs.length + ")", function () { downloadOnClickHandler(article); } ); // 视频下载按钮 if (article.querySelector("div.limelight-player")) { injectOneButton(buttonsDiv, "下载所有视频", function () { downloadVideoOnClickHandler(article); }); injectPerVideoDownloadButton(article); } } function injectPerVideoDownloadButton(div) { div.querySelectorAll("div.limelight-player").forEach((videoDiv) => { var mediaId = videoDiv.id.substring(videoDiv.id.lastIndexOf("_") + 1); injectOneButton(videoDiv.parentElement, "下载这个视频", function () { downloadVideo( mediaId, getPrefixFromArticle(div) || getPrefixFromDocument() ); }); }); } function injectOneButton(element, textOnButton, clickListener) { var btn = document.createElement("BUTTON"); var btnText = document.createTextNode(textOnButton); btn.appendChild(btnText); btn.addEventListener("click", clickListener); btn.style = "background-color: transparent; border: solid #808080 2px; border-radius: 20px; color: #545454; margin: 0.2em"; element.appendChild(btn); } function downloadOnClickHandler(article) { downloadImages(findEligibleImgs(article), getPrefixFromArticle(article)); } function generateOnClickHandler(buttonsDiv, article) { var imgs = findEligibleImgs(article); var textarea = buttonsDiv.querySelector("textarea.ldh-mo-dl"); if (!textarea) { textarea = document.createElement("textarea"); textarea.className = "ldh-mo-dl"; textarea.style = "height: 100px; width: 80%;"; var br = document.createElement("br"); buttonsDiv.insertBefore(br, buttonsDiv.firstChild); buttonsDiv.insertBefore(textarea, buttonsDiv.firstChild); } textarea.value = imgs.join("\n"); textarea.select(); } function downloadVideoOnClickHandler(article) { var elems = article.querySelectorAll("script"); var videos = Array.from(elems) .filter( (v) => v.textContent.includes("mediaId") && !v.textContent.includes("blogTalkData") ) .map( (v) => JSON.parse( v.textContent.substring( v.textContent.indexOf("(") + 1, v.textContent.lastIndexOf(")") ) ).mediaId ); videos.map((video) => downloadVideo(video, getPrefixFromArticle(article))); } function customizedTimelinePage() { // 初始化 document .querySelectorAll("ldh-infinite-scroll article") .forEach((article) => attachButtonToArticle(article)); // const infiniteScrollContainer = document.querySelector("ldh-infinite-scroll"); const config = { childList: true }; const observer = new MutationObserver(function (mutations, observer) { var nodes = mutations.find((r) => Array.from(r.addedNodes).filter((n) => (n.className = "article")) ).addedNodes; nodes.forEach((node) => attachButtonToArticle(node.querySelector("article")) ); removeProtectImg(); }); observer.observe(infiniteScrollContainer, config); } // ======================== // = Download Utils = // ======================== function downloadImages(imgs, prefix = "") { // Thanks to https://github.com/y252328/Instagram_Download_Button imgs.map((img) => fetch(img, { headers: new Headers({ Origin: window.location.origin, }), mode: "cors", cache: "no-cache", }) .then((response) => response.blob()) .then((blob) => dowloadBlob( window.URL.createObjectURL(blob), prefix + img.substring(img.lastIndexOf("/") + 1) ) ) .catch((e) => console.error(e)) ); } function downloadVideo(video, prefix = "") { console.log("downloading " + video + " ..."); const videoRequestURL = "https://production-ps.lvp.llnw.net/r/PlaylistService/media/<mediaId>/getMobilePlaylistByMediaId"; fetch(videoRequestURL.replace("<mediaId>", video), { headers: new Headers({ Origin: window.location.origin, Referer: window.location.origin, }), mode: "cors", cache: "no-cache", }) .then((response) => response.json()) .then( (response) => response.mediaList[0].mobileUrls.find( (v) => v.targetMediaPlatform == "MobileH264" || v.targetMediaPlatform == "Broadband" ).mobileUrl ) .then((mobileUrl) => fetch(mobileUrl.replace("http://", "https://")) .then((response) => response.blob()) .then((blob) => { let tempName = mobileUrl.replace("/root-message-cxf-apache", ""); dowloadBlob( window.URL.createObjectURL(blob), prefix + tempName.substring(tempName.lastIndexOf("/") + 1) ); }) .catch((e) => console.error(e)) ); } function dowloadBlob(blob, filename) { var a = document.createElement("a"); a.download = filename; a.href = blob; document.body.appendChild(a); a.click(); a.remove(); } // ====================== // = Naming Utils = // ====================== function getPrefixFromArticle(article) { var candidate = article.querySelector(".article__head") || article.querySelector(".article__header"); if (candidate) { return sanitizeFileName( candidate.textContent .split(/\s/g) .filter((s) => s) .join("_") + "_" ); } return ""; } function getPrefixFromDocument() { var candidate = document.querySelector(".movie-title-block"); if (candidate) { return sanitizeFileName( candidate.textContent .split(/\s/g) .filter((s) => s) .join("_") + "_" ); } return ""; } function sanitizeFileName(input, replacement = "_") { const illegalRe = /[\/\?<>\\:\*\|"]/g; const controlRe = /[\x00-\x1f\x80-\x9f]/g; const reservedRe = /^\.+$/; const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i; const windowsTrailingRe = /[\. ]+$/; return input .replace(illegalRe, replacement) .replace(controlRe, replacement) .replace(reservedRe, replacement) .replace(windowsReservedRe, replacement) .replace(windowsTrailingRe, replacement); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址