多线程下载91porn视频,跳过广告,清除页面广告。
// ==UserScript== // @name 91-plus // @namespace jiuyi // @version 19 // @author uh58fg // @description 多线程下载91porn视频,跳过广告,清除页面广告。 // @license WTFPL // @icon https://img-blog.csdnimg.cn/20181221195058594.gif // @match *.com/view_video.php?* // @match *.com/uvideos.php?* // @match *.com/index.php // @require https://cdnjs.cloudflare.com/ajax/libs/hls.js/8.0.0-beta.3/hls.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/dplayer/1.26.0/DPlayer.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.runtime.global.prod.js // @connect * // @grant GM_addStyle // @grant GM_getValue // @grant GM_openInTab // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant unsafeWindow // @grant window.close // ==/UserScript== (e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const t=document.createElement("style");t.textContent=e,document.head.append(t)})(' .row2[data-v-1eda6002]{display:flex;justify-content:flex-end}.big-btn[data-v-1eda6002]{position:relative;display:inline-flex;justify-content:center;align-items:center;margin-left:1rem;font-size:1.6rem;min-width:10rem;color:#fff;cursor:pointer;border-radius:4px;border:1px solid #eeeeee;background-color:#3d8ac7;opacity:1;transition:.3s all;padding:.5rem 1rem}.big-btn[data-v-1eda6002]:hover{opacity:.9}.big-btn.disable[data-v-1eda6002]{cursor:default;background-color:#ddd;color:#000}.m-p-input-container[data-v-1eda6002]{display:flex;justify-content:flex-end}.m-p-tips[data-v-1eda6002]{width:100%;color:#999;text-align:left;font-style:italic;word-break:break-all}.m-p-tips.error-tips[data-v-1eda6002]{color:#dc5350}.info[data-v-1eda6002]{display:flex;justify-content:center;align-items:center;gap:1rem;margin-bottom:1rem}.info .options[data-v-1eda6002]{margin-right:1rem;display:flex;flex-direction:column;align-items:flex-end}.info .option[data-v-1eda6002]{cursor:pointer;display:flex;justify-content:center;align-items:center;color:#fff;margin-bottom:.3rem}.info .option label[data-v-1eda6002]{margin:0}.info .option input[data-v-1eda6002]{margin:0 0 0 1rem;width:1.4rem;height:1.4rem}.progress[data-v-1eda6002]{flex:1;border-radius:.8rem;opacity:1;height:1.5rem;background:#FCFDFF;box-sizing:border-box;border:.1rem solid #FFFFFF;box-shadow:inset 0 -1rem 4rem #fffc,inset 0 1rem 4rem #2d4c7266;position:relative}.progress .bar[data-v-1eda6002]{height:100%;left:0;top:0;position:absolute;background:linear-gradient(90deg,#9CDCFF 0%,#0ACD76 100%);border-radius:.8rem}[data-v-fb31b46a]::-webkit-scrollbar{width:10px}[data-v-fb31b46a]::-webkit-scrollbar-thumb{background:#4e4e4e;border-radius:25px}.showBtn[data-v-fb31b46a]{cursor:pointer;position:fixed;top:1rem;right:1rem;color:#fff;z-index:99999;background:gray;padding:.6rem 1rem;border-radius:.3rem}.content[data-v-fb31b46a]{z-index:9999;background:#0f0f0f;position:fixed;left:0;top:0;width:100vw;min-width:100vw;height:100vh;box-sizing:border-box;padding:1rem;display:flex;gap:2rem;text-align:start}.content .close[data-v-fb31b46a]{cursor:pointer;position:absolute;top:1rem;right:2rem;width:2rem;height:2rem;line-height:4rem;text-align:center;color:#fff}.content .close[data-v-fb31b46a]:before{position:absolute;content:"";width:.2rem;height:2rem;background:white;transform:rotate(45deg);top:calc(50% - .45rem);left:50%}.content .close[data-v-fb31b46a]:after{content:"";position:absolute;width:.2rem;height:2rem;background:white;transform:rotate(-45deg);top:calc(50% - .45rem);left:50%}.content .home-icon[data-v-fb31b46a]{cursor:pointer;right:2rem;position:absolute}.content .big-title[data-v-fb31b46a]{position:relative;display:flex;align-items:center;justify-content:center;height:5rem;font-weight:700;color:#fff;letter-spacing:2px;background:#212121;font-size:2rem}.content .video-wrapper[data-v-fb31b46a]{width:60vw;overflow:auto;padding-bottom:2rem}.content .video-wrapper .my-video[data-v-fb31b46a],.content .video-wrapper #dplayer[data-v-fb31b46a]{width:100%;max-height:70vh}.content .video-wrapper .title[data-v-fb31b46a]{margin-top:1rem;font-weight:700;font-size:2rem;color:#fff;margin-bottom:1rem}.content .video-wrapper .author[data-v-fb31b46a]{margin-right:2rem;font-weight:700;font-size:1.4rem;margin-bottom:2rem;display:inline-block}.content .left[data-v-fb31b46a]{flex:1;border:1px solid gray;border-radius:.5rem;overflow:hidden;position:relative;font-size:1.8rem}.content .left .comments[data-v-fb31b46a]{color:#fff;height:calc(100% - 6rem);padding-bottom:4rem;overflow:auto}.content .left .comments .item[data-v-fb31b46a]{margin-bottom:5px;padding:10px;border-bottom:1px solid #3f3f3f;text-align:start}.content .left .comments .item .title[data-v-fb31b46a]{font-size:1.4rem}.content .left .comments .item .title span[data-v-fb31b46a]{margin-right:10px}.content .left .comments .item .quote[data-v-fb31b46a]{margin-top:.5rem;font-size:1.8rem;padding:.5rem .5rem .5rem 1rem;border:1px dashed gray}.content .right[data-v-fb31b46a]{flex:1;border:1px solid gray;border-radius:.5rem;overflow:hidden}.content .right .list[data-v-fb31b46a]{color:#fff;height:calc(100% - 6rem);padding:1rem 1rem 4rem;overflow:auto}.ml20[data-v-fb31b46a]{margin-left:20px} '); (function (vue) { 'use strict'; var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)(); var _GM_openInTab = /* @__PURE__ */ (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)(); var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)(); var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)(); var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); var _monkeyWindow = /* @__PURE__ */ (() => window)(); const page = _unsafeWindow || window; const PageMediaSource = page.MediaSource; const PageURL = page.URL; const mediaSourceMap = /* @__PURE__ */ new Map(); const objectURLMap = /* @__PURE__ */ new Map(); const endListeners = /* @__PURE__ */ new Set(); let originCreateObjectURL = null; let originAddSourceBuffer = null; let originEndOfStream = null; let inited = false; function copyBuffer(data) { try { if (data instanceof ArrayBuffer) return data.slice(0); if (ArrayBuffer.isView(data)) { return new Uint8Array(data.buffer, data.byteOffset, data.byteLength).slice().buffer; } } catch (e) { } return null; } function parseMime(mimeCodecs) { const raw = String(mimeCodecs || ""); const [essence = "video/mp4", codecsPart = ""] = raw.split(";"); const [type = "video", format = "mp4"] = essence.trim().split("/"); return { type: type || "video", format: format || "mp4", codecs: codecsPart.trim().replace(/codecs=/i, "").replace(/["']/g, "") }; } function rememberObjectUrl(object, objectURL) { if (!(PageMediaSource && object instanceof PageMediaSource) || objectURLMap.has(object)) return; object.__objURL__ = objectURL; objectURLMap.set(object, objectURL); } function ensureInfo(mediaSource) { let info = mediaSourceMap.get(mediaSource); if (info) return info; info = { mediaSource, sourceBuffer: [], endOfStream: false, mediaUrl: "" }; mediaSourceMap.set(mediaSource, info); return info; } function proxyMediaSource() { if (!originAddSourceBuffer || !originEndOfStream || !originCreateObjectURL) return; PageURL.createObjectURL = new Proxy(originCreateObjectURL, { apply(target, ctx, args) { const objectURL = Reflect.apply(target, ctx, args); rememberObjectUrl(args[0], objectURL); return objectURL; } }); PageMediaSource.prototype.addSourceBuffer = new Proxy(originAddSourceBuffer, { apply(target, ctx, args) { const info = ensureInfo(ctx); const mimeCodecs = args[0] || ""; const sourceBuffer = Reflect.apply(target, ctx, args); const sourceBufferItem = { mimeCodecs, bufferData: [], mediaInfo: parseMime(mimeCodecs) }; info.sourceBuffer.push(sourceBufferItem); const originAppendBuffer = sourceBuffer.appendBuffer; sourceBuffer.appendBuffer = new Proxy(originAppendBuffer, { apply(bufTarget, bufCtx, bufArgs) { const buffer = bufArgs[0]; if (!info.endOfStream) { const copied = copyBuffer(buffer); if (copied) sourceBufferItem.bufferData.push(copied); } const objectURL = objectURLMap.get(ctx); if (objectURL) info.mediaUrl = objectURL; if (!mediaSourceMap.has(ctx)) mediaSourceMap.set(ctx, info); return Reflect.apply(bufTarget, bufCtx, bufArgs); } }); return sourceBuffer; } }); PageMediaSource.prototype.endOfStream = new Proxy(originEndOfStream, { apply(target, ctx, args) { const info = mediaSourceMap.get(ctx); if (info && !info.endOfStream) { info.endOfStream = true; const objectURL = objectURLMap.get(ctx); if (objectURL) info.mediaUrl = objectURL; endListeners.forEach((listener) => { try { listener(info); } catch (e) { } }); } return Reflect.apply(target, ctx, args); } }); } function initMediaSource() { if (inited) return true; if (!PageMediaSource || !(PageURL == null ? void 0 : PageURL.createObjectURL)) { return false; } originCreateObjectURL = PageURL.createObjectURL; originAddSourceBuffer = PageMediaSource.prototype.addSourceBuffer; originEndOfStream = PageMediaSource.prototype.endOfStream; proxyMediaSource(); inited = true; return true; } function onMediaEnd(listener) { endListeners.add(listener); return () => endListeners.delete(listener); } function findMediaSource(mediaEl) { if (!mediaEl) return null; const curSrc = mediaEl.currentSrc || mediaEl.src; if (!curSrc) return null; for (const info of mediaSourceMap.values()) { const objectURL = info.mediaSource.__objURL__ || info.mediaUrl; if (objectURL && objectURL === curSrc) return info; } return null; } function safeFilename(value) { const normalized = Array.from(String(value || "video"), (character) => { const codePoint = character.codePointAt(0) ?? 0; return codePoint < 32 || '<>:"/\\|?*'.includes(character) ? " " : character; }).join("").replace(/\s+/g, " ").trim(); return (normalized || "video").slice(0, 180); } function collectMediaFiles(mediaEl, title) { const info = findMediaSource(mediaEl); if (!info) return []; const readyBuffers = info.sourceBuffer.filter((item) => item.bufferData.length > 0); const files = []; readyBuffers.forEach((item) => { const kind = item.mediaInfo.type || "video"; const ext = item.mediaInfo.format || "mp4"; const base = safeFilename(title || document.title || "video"); const filename = readyBuffers.length > 1 ? `${base}_${kind}.${ext}` : `${base}.${ext}`; const blob = new Blob(item.bufferData, { type: kind === "audio" ? "audio/mp4" : "video/mp4" }); files.push({ filename, blob, url: PageURL.createObjectURL(blob) }); item.bufferData = []; }); return files; } const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _hoisted_1$1 = { class: "video-downloader" }; const _hoisted_2$1 = { class: "info" }; const _hoisted_3$1 = { class: "options" }; const _hoisted_4$1 = { class: "option" }; const _hoisted_5$1 = { class: "option" }; const _hoisted_6$1 = { class: "option" }; const _hoisted_7$1 = { class: "wrapper" }; const _hoisted_8$1 = { class: "m-p-input-container" }; const _hoisted_9$1 = { key: 1, class: "big-btn disable" }; const _hoisted_10$1 = { key: 2, class: "big-btn disable" }; const CONF_KEY = "porn-plus"; const _sfc_main$1 = { __name: "video-downloader", props: { title: { type: String, default: "" }, url: { type: String, default: "" }, mediaType: { type: String, default: "" }, getMedia: { type: Function, required: true } }, setup(__props) { const props = __props; const pageURL = (_unsafeWindow == null ? void 0 : _unsafeWindow.URL) || URL; const conf = vue.reactive({ autoDownload: true, autoSave: true, autoClose: false }); const progress = vue.ref(0); const show = vue.ref(false); const tips = vue.ref("等待开始下载"); const phase = vue.ref("idle"); let armed = false; let directStarted = false; let collected = false; let saving = false; let pollTimer = 0; let files = []; let stopEndListen = () => { }; vue.watch(conf, (value) => { localStorage.setItem(CONF_KEY, JSON.stringify(value)); }, { deep: true }); vue.watch(progress, (value) => { document.title = `${Number(value).toFixed(0)}% ${props.title}`; }); vue.watch(() => conf.autoDownload, (enabled) => { if (enabled && phase.value === "idle") start(); }); function loadConf() { const raw = localStorage.getItem(CONF_KEY); if (!raw) return; try { Object.assign(conf, JSON.parse(raw)); } catch (e) { } } function safeFilename2(value) { const normalized = Array.from(String(value || "video"), (character) => { const codePoint = character.codePointAt(0) ?? 0; return codePoint < 32 || '<>:"/\\|?*'.includes(character) ? " " : character; }).join("").replace(/\s+/g, " ").trim(); return (normalized || "video").slice(0, 180); } function filenameFromTitle(ext = "mp4") { var _a, _b; const base = safeFilename2(((_b = (_a = window.info) == null ? void 0 : _a.video) == null ? void 0 : _b.name) || "video").replace(new RegExp(`\\.${ext}$`, "i"), ""); return `${base || "video"}.${ext}`; } function isHls() { if (props.mediaType === "customHls") return true; return String(props.url || "").toLowerCase().includes("m3u8"); } function clickDownload(url, filename) { const doc = (_unsafeWindow == null ? void 0 : _unsafeWindow.document) || document; const anchor = doc.createElement("a"); anchor.href = url; anchor.download = filename; doc.body.appendChild(anchor); anchor.click(); anchor.remove(); } function closePage() { window.opener = null; window.open("", "_self", ""); window.close(); } function releaseFilesLater() { const pending = files.slice(); setTimeout(() => { pending.forEach((file) => { if (String(file.url).startsWith("blob:")) pageURL.revokeObjectURL(file.url); }); }, 6e4); } function downloadName(filename) { const ext = (String(filename || "").match(/\.([a-z0-9]{2,5})$/i) || [])[1] || "mp4"; return filenameFromTitle(ext); } function requestBytes(url) { let fetchUrl = url; if (url.startsWith("http://") && location.href.startsWith("https://")) { fetchUrl = url.replace("http://", "https://"); } return new Promise((resolve, reject) => { _GM_xmlhttpRequest({ method: "GET", url: fetchUrl, responseType: "arraybuffer", onprogress(event) { if (event.lengthComputable && event.total) { progress.value = Math.min(99, event.loaded / event.total * 100); } }, onload(response) { if (response.status >= 200 && response.status < 300 && response.response) { resolve(response.response); return; } reject(new Error(String(response.status || "request failed"))); }, onerror(error) { reject(error || new Error("request failed")); }, ontimeout() { reject(new Error("timeout")); } }); }); } function namedObjectUrl(bytes, filename) { const page2 = _unsafeWindow || window; const source = new Uint8Array(bytes); const copy = new page2.Uint8Array(source.byteLength); const chunkSize = 2 * 1024 * 1024; for (let offset = 0; offset < source.byteLength; offset += chunkSize) { copy.set(source.subarray(offset, Math.min(source.byteLength, offset + chunkSize)), offset); } const type = filename.toLowerCase().endsWith(".m4a") || filename.toLowerCase().endsWith(".mp3") ? "audio/mp4" : "video/mp4"; const file = new page2.File([copy], filename, { type }); return page2.URL.createObjectURL(file); } async function saveNamed(file, filename) { const url = String(file.url || ""); if (url.startsWith("blob:")) { clickDownload(url, filename); return; } const bytes = await requestBytes(url); clickDownload(namedObjectUrl(bytes, filename), filename); } async function save() { if (!files.length || phase.value === "saved" || saving) return; saving = true; tips.value = "正在保存"; try { for (const file of files) { const filename = downloadName(file.filename); tips.value = `正在保存 ${filename}`; try { await saveNamed(file, filename); } catch (error) { console.error(error); if (!file.url || String(file.url).startsWith("blob:")) throw error; clickDownload(file.url, filename); } } phase.value = "saved"; progress.value = 100; tips.value = "已开始保存"; document.title = `下载完成 ${props.title}`; releaseFilesLater(); if (conf.autoClose) setTimeout(closePage, 1500); } catch (error) { console.error(error); phase.value = "error"; tips.value = "保存失败"; } finally { saving = false; } } function finishWithFiles(nextFiles) { if (collected) { if (conf.autoSave) save(); return; } if (!nextFiles.length) { phase.value = "error"; tips.value = "没有可保存的媒体数据"; stopPolling(); return; } collected = true; files = nextFiles; progress.value = 100; phase.value = "ready"; tips.value = conf.autoSave ? "媒体已就绪,正在保存" : "媒体已就绪,点击保存"; document.title = `下载完成 ${props.title}`; stopPolling(); if (conf.autoSave) save(); } function updateBufferedProgress(video) { if (!Number.isFinite(video.duration) || video.duration <= 0 || !video.buffered.length) return; const end = video.buffered.end(video.buffered.length - 1); progress.value = Math.min(99, Math.max(progress.value, end / video.duration * 100)); } function tryCollect(video) { var _a, _b; if (collected || directStarted) return; const info = findMediaSource(video); if (!info) { tips.value = "等待播放器建立媒体流"; return; } if (!info.endOfStream) { tips.value = "媒体缓冲中,就绪后自动保存"; updateBufferedProgress(video); return; } finishWithFiles(collectMediaFiles(video, ((_b = (_a = window.info) == null ? void 0 : _a.video) == null ? void 0 : _b.name) || "")); } function startDirect(src) { if (directStarted) return; directStarted = true; stopPolling(); collected = true; files = [{ url: src, filename: filenameFromTitle("mp4") }]; phase.value = "ready"; tips.value = conf.autoSave ? "开始保存" : "点击保存"; if (conf.autoSave) save(); } function tick() { if (!armed || collected) return; const video = props.getMedia(); if (!video) return; const src = video.currentSrc || video.src; if (!src) return; if (src.startsWith("blob:") || src.toLowerCase().includes("m3u8")) { if (src.startsWith("blob:")) tryCollect(video); else tips.value = "等待播放器建立媒体流"; return; } startDirect(src); } function stopPolling() { if (pollTimer) { clearInterval(pollTimer); pollTimer = 0; } } function start() { var _a; if (phase.value === "saved") return; if (phase.value === "ready") { if (conf.autoSave) save(); return; } if (armed && phase.value === "waiting") return; if (phase.value === "error") { armed = false; directStarted = false; collected = false; } armed = true; phase.value = "waiting"; tips.value = "正在准备下载"; if (!isHls() && props.url) { startDirect(props.url); return; } const video = props.getMedia(); if (video && ((_a = findMediaSource(video)) == null ? void 0 : _a.endOfStream)) { tryCollect(video); return; } if (!pollTimer) pollTimer = setInterval(tick, 300); tick(); } vue.onMounted(() => { initMediaSource(); loadConf(); stopEndListen = onMediaEnd((info) => { if (!armed || collected || directStarted) return; const video = props.getMedia(); if (!video) return; const src = video.currentSrc || video.src; const objectURL = info.mediaSource.__objURL__ || info.mediaUrl; if (src && objectURL === src) tryCollect(video); }); if (conf.autoDownload) start(); }); vue.onBeforeUnmount(() => { stopPolling(); stopEndListen(); if (phase.value !== "saved") { files.forEach((file) => { if (String(file.url).startsWith("blob:")) pageURL.revokeObjectURL(file.url); }); } }); return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [ vue.createElementVNode("div", _hoisted_2$1, [ vue.createElementVNode("div", { class: "progress", onClick: _cache[0] || (_cache[0] = ($event) => show.value = !show.value) }, [ vue.createElementVNode("div", { class: "bar", style: vue.normalizeStyle({ width: progress.value + "%" }) }, null, 4) ]), vue.createElementVNode("div", _hoisted_3$1, [ vue.createElementVNode("div", _hoisted_4$1, [ _cache[4] || (_cache[4] = vue.createElementVNode("label", { for: "a1" }, "自动下载", -1)), vue.withDirectives(vue.createElementVNode("input", { id: "a1", type: "checkbox", "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => conf.autoDownload = $event) }, null, 512), [ [vue.vModelCheckbox, conf.autoDownload] ]) ]), vue.createElementVNode("div", _hoisted_5$1, [ _cache[5] || (_cache[5] = vue.createElementVNode("label", { for: "a2" }, "下载完成后自动保存", -1)), vue.withDirectives(vue.createElementVNode("input", { id: "a2", type: "checkbox", "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => conf.autoSave = $event) }, null, 512), [ [vue.vModelCheckbox, conf.autoSave] ]) ]), vue.createElementVNode("div", _hoisted_6$1, [ _cache[6] || (_cache[6] = vue.createElementVNode("label", { for: "a3" }, "保存后自动关闭", -1)), vue.withDirectives(vue.createElementVNode("input", { id: "a3", type: "checkbox", "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => conf.autoClose = $event) }, null, 512), [ [vue.vModelCheckbox, conf.autoClose] ]) ]) ]) ]), vue.createElementVNode("div", _hoisted_7$1, [ vue.createElementVNode("section", _hoisted_8$1, [ phase.value === "idle" || phase.value === "error" ? (vue.openBlock(), vue.createElementBlock("div", { key: 0, class: "big-btn", onClick: start }, "下载")) : phase.value === "waiting" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$1, "准备中")) : phase.value === "saved" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$1, "下载完成")) : vue.createCommentVNode("", true), phase.value === "ready" ? (vue.openBlock(), vue.createElementBlock("div", { key: 3, class: "big-btn", onClick: save }, [..._cache[7] || (_cache[7] = [ vue.createElementVNode("span", null, "保存", -1) ])])) : vue.createCommentVNode("", true) ]), vue.createElementVNode("div", { class: vue.normalizeClass(["m-p-tips", { "error-tips": phase.value === "error" }]) }, " 进度:" + vue.toDisplayString(Number(progress.value).toFixed(0)) + "%," + vue.toDisplayString(tips.value), 3) ]) ]); }; } }; const VideoDownloader = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-1eda6002"]]); const _hoisted_1 = { class: "content" }; const _hoisted_2 = { class: "left" }; const _hoisted_3 = { class: "big-title" }; const _hoisted_4 = { class: "comments" }; const _hoisted_5 = { class: "item" }; const _hoisted_6 = { class: "title" }; const _hoisted_7 = ["href"]; const _hoisted_8 = { key: 0, class: "quote" }; const _hoisted_9 = { class: "replay" }; const _hoisted_10 = { class: "video-wrapper" }; const _hoisted_11 = ["src"]; const _hoisted_12 = { class: "title" }; const _hoisted_13 = { class: "author", target: "_blank" }; const _hoisted_14 = ["href"]; const _hoisted_15 = { class: "right" }; const _hoisted_16 = { class: "big-title" }; const _sfc_main = { __name: "App", setup(__props) { const dpRef = vue.ref(null); const dp = vue.ref(null); const h5Video = vue.ref(null); const recommendRef = vue.ref(null); const data = vue.reactive({ comments: [], info: window.info, show: true }); vue.watch(() => data.show, (n, o) => { var _a; if (n) { pauseOriginVideo(); document.body.style.overflow = "hidden"; } else { (_a = dp.value) == null ? void 0 : _a.pause(); document.body.style.overflow = "unset"; } }, { immediate: true }); vue.onMounted(() => { recommendRef.value.append($("h3").next().next()[0]); $("br").remove(); initComments(); initVideo(); checkOriginVideoIsPlay(); }); function pauseOriginVideo() { if ($(".vjs-playing").length) { $("#player_one_html5_api").click(); } } function checkOriginVideoIsPlay() { setInterval(() => { if (data.show) { pauseOriginVideo(); } }, 3e3); } function initComments() { $.ajax({ url: `${location.origin}/show_comments2.php?VID=${data.info.video.vid}&start=1&comment_per_page=30`, success(r) { let h = $(r); h.each(function() { if (this.tagName === "TABLE") { let a = $(this).find("a:first"); let name = a.text().trim(); let url = a[0].href + "&type=public"; let time = $(this).find(".comment-info").contents()[4]; let body = $(this).find(".comment-body"); let quote = body.find(".comment_quote").text().replaceAll(" ", "").replaceAll("\n", ""); body.find(".comment_quote").remove(); let replay = body.find("a").remove().end().text().trim(); if (replay.includes("请不要发广告或与视频无关的评论") || quote.includes("请不要发广告或与视频无关的评论")) ; else { data.comments.push({ name, time: $(time).text(), quote, replay, url }); } } }); } }); } function initVideo() { let config = { url: data.info.video.url, type: data.info.video.type }; if (config.type === "customHls") { if (!dpRef.value) return; config.customType = { customHls: function(video, player) { const hls = new _monkeyWindow.Hls({ autoStartLoad: true, startPosition: 0, // 后台标签页不会自动播放,默认只向前缓冲约 30 秒,整片永远等不到结束 maxBufferLength: 60 * 60 * 24, maxMaxBufferLength: 60 * 60 * 24, maxBufferSize: 1024 * 1024 * 1024, startFragPrefetch: true }); hls.loadSource(video.src); hls.attachMedia(video); hls.startLoad(0); } }; dp.value = new _monkeyWindow.DPlayer({ container: dpRef.value, autoplay: true, video: config }); if (!document.hidden) { dp.value.seek(10); } } else { if (h5Video.value) { h5Video.value.currentTime = 10; } } } function goHome() { location.href = "https://91porn.com/index.php"; } function getPlayingVideo() { var _a, _b; if (data.info.video.type === "customHls") { return ((_a = dp.value) == null ? void 0 : _a.video) || ((_b = dpRef.value) == null ? void 0 : _b.querySelector("video")) || null; } return h5Video.value; } return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1, [ vue.createElementVNode("div", _hoisted_2, [ vue.createElementVNode("div", _hoisted_3, [ _cache[3] || (_cache[3] = vue.createTextVNode(" 评论 ", -1)), (vue.openBlock(), vue.createElementBlock("svg", { onClick: goHome, class: "home-icon", width: "24", height: "24", viewBox: "0 0 48 48", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, [..._cache[2] || (_cache[2] = [ vue.createElementVNode("path", { d: "M9 18V42H39V18L24 6L9 18Z", fill: "none", stroke: "#ffffff", "stroke-width": "4", "stroke-linecap": "round", "stroke-linejoin": "round" }, null, -1), vue.createElementVNode("path", { d: "M19 29V42H29V29H19Z", fill: "none", stroke: "#ffffff", "stroke-width": "4", "stroke-linejoin": "round" }, null, -1), vue.createElementVNode("path", { d: "M9 42H39", stroke: "#ffffff", "stroke-width": "4", "stroke-linecap": "round" }, null, -1) ])])) ]), vue.createElementVNode("div", _hoisted_4, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(data.comments, (item) => { return vue.openBlock(), vue.createElementBlock("div", _hoisted_5, [ vue.createElementVNode("div", _hoisted_6, [ vue.createElementVNode("a", { href: item.url, target: "_blank" }, vue.toDisplayString(item.name), 9, _hoisted_7), vue.createElementVNode("span", null, vue.toDisplayString(item.time), 1) ]), item.quote ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_8, vue.toDisplayString(item.quote), 1)) : vue.createCommentVNode("", true), vue.createElementVNode("div", _hoisted_9, vue.toDisplayString(item.replay), 1) ]); }), 256)) ]) ]), vue.createElementVNode("div", _hoisted_10, [ vue.createElementVNode("div", { id: "dplayer", ref_key: "dpRef", ref: dpRef }, null, 512), vue.createElementVNode("video", { ref_key: "h5Video", ref: h5Video, src: data.info.video.url, controls: "", preload: "", autoplay: "", class: "my-video" }, null, 8, _hoisted_11), vue.createElementVNode("div", _hoisted_12, vue.toDisplayString(data.info.video.name), 1), vue.createElementVNode("div", _hoisted_13, " 添加时间: " + vue.toDisplayString(data.info.video.date), 1), data.info.author.name ? (vue.openBlock(), vue.createElementBlock("a", { key: 0, href: data.info.author.url, class: "author", target: "_blank" }, " 作者: " + vue.toDisplayString(data.info.author.name), 9, _hoisted_14)) : vue.createCommentVNode("", true), vue.createElementVNode("div", null, vue.toDisplayString(data.info.author.desc), 1), vue.createVNode(VideoDownloader, { title: data.info.video.name, url: data.info.video.url, "media-type": data.info.video.type, "get-media": getPlayingVideo }, null, 8, ["title", "url", "media-type"]) ]), vue.createElementVNode("div", _hoisted_15, [ vue.createElementVNode("div", _hoisted_16, [ _cache[4] || (_cache[4] = vue.createTextVNode(" 本月热播 ", -1)), vue.createElementVNode("div", { class: "close", onClick: _cache[0] || (_cache[0] = ($event) => data.show = !data.show) }) ]), vue.createElementVNode("div", { class: "list", ref_key: "recommendRef", ref: recommendRef }, null, 512) ]) ], 512), [ [vue.vShow, data.show] ]), vue.withDirectives(vue.createElementVNode("div", { class: "showBtn", onClick: _cache[1] || (_cache[1] = ($event) => data.show = !data.show) }, "展开脚本", 512), [ [vue.vShow, !data.show] ]) ], 64); }; } }; const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-fb31b46a"]]); initMediaSource(); window.info = { author: { name: "", url: "", vid: "" }, video: { name: "", url: "", vid: "" } // videoUrl:'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', }; function init() { if (window.info.videoUrl) return; const videoWrapper = $("#player_one_html5_api"); const userWrapper = $(".title-yakov"); if ((userWrapper == null ? void 0 : userWrapper.length) === 2) { let href = userWrapper[1].firstElementChild.href; let start = href.indexOf("UID"); let uid = href.substring(start + 4); window.info.author = { name: userWrapper.find(".title").text(), desc: $("#v_desc").text().replace("91版主提醒您:不要下载任何app,它们可能是诈骗app。如果被骗了,请联系我们,全面打击诈骗", ""), url: `https://91porn.com/uvideos.php?UID=${uid}&type=public`, uid }; openAuthorHomeOnceToday(); } if (!videoWrapper[0]) { document.title = "作为游客,你每天只可观看15个视频"; } else { window.info.video = { name: document.title.replace(/Chinese homemade video/gi, "").trim(), url: videoWrapper.find("source")[0].src, vid: $("#favorite #VID").text(), date: $(".title-yakov")[0].innerText }; if (window.info.video.url.toLowerCase().indexOf("m3u8") === -1) { window.info.video.type = "auto"; } else { window.info.video.type = "customHls"; } vue.createApp(App).mount( (() => { const app = document.createElement("div"); document.body.append(app); return app; })() ); } console.log(window.info); } const AUTHOR_HOME_KEY = "author-home-opened"; function todayText() { const date = /* @__PURE__ */ new Date(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${date.getFullYear()}-${month}-${day}`; } function openedAuthorsToday() { const today = todayText(); const stored = _GM_getValue(AUTHOR_HOME_KEY, {}); const opened = {}; if (stored && typeof stored === "object") { Object.entries(stored).forEach(([uid, date]) => { if (date === today) opened[uid] = date; }); } return opened; } function markAuthorOpened(uid) { if (!uid) return; const opened = openedAuthorsToday(); opened[uid] = todayText(); _GM_setValue(AUTHOR_HOME_KEY, opened); } function authorUid() { try { return new URL(window.info.author.url, location.href).searchParams.get("UID") || ""; } catch (e) { return String(window.info.author.uid || "").split("&")[0]; } } function openAuthorHomeOnceToday() { const uid = authorUid(); if (!uid || openedAuthorsToday()[uid]) return; markAuthorOpened(uid); _GM_openInTab(`${location.origin}/uvideos.php?UID=${encodeURIComponent(uid)}&type=public`, { active: false, insert: true, setParent: true }); } function listVideoUrls() { const seen = /* @__PURE__ */ new Set(); const urls = []; document.querySelectorAll('a[href*="view_video.php"]').forEach((anchor) => { let url; try { url = new URL(anchor.href, location.href); } catch (e) { return; } if (!url.pathname.endsWith("/view_video.php")) return; const viewkey = url.searchParams.get("viewkey"); if (!viewkey || seen.has(viewkey)) return; seen.add(viewkey); urls.push(url.href); }); return urls; } function pagingUrl(offset) { var _a, _b; const nav = document.querySelector("div.pagingnav"); if (!nav) return ""; const current = Number((_b = (_a = nav.querySelector("span.pagingnav")) == null ? void 0 : _a.textContent) == null ? void 0 : _b.trim()); if (!Number.isInteger(current)) return ""; const target = current + offset; if (target < 1) return ""; const link = [...nav.querySelectorAll("a")].find((anchor) => { try { return Number(new URL(anchor.href, location.href).searchParams.get("page")) === target; } catch (e) { return false; } }); return link ? new URL(link.href, location.href).href : ""; } function nextPageUrl() { return pagingUrl(1); } function bindListPagingKeys() { window.addEventListener("keydown", (event) => { if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return; if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return; const target = event.target; if (target && (target.isContentEditable || /^(input|textarea|select)$/i.test(target.tagName))) return; const url = pagingUrl(event.key === "ArrowLeft" ? -1 : 1); if (!url) return; event.preventDefault(); event.stopPropagation(); location.href = url; }, true); } function previewMp4Url(overlay) { var _a, _b, _c, _d; const id = ((_a = (overlay.id || "").match(/playvthumb_(\d+)/)) == null ? void 0 : _a[1]) || ((_d = (_c = (_b = overlay.querySelector("img")) == null ? void 0 : _b.src) == null ? void 0 : _c.match(/\/(\d+)\.jpe?g/i)) == null ? void 0 : _d[1]); if (!id) return ""; return `https://vthumb.killcovid2021.com/thumb/${id}.mp4`; } function mountListPreview(overlay) { if (overlay.querySelector("video.plus-preview")) return; const img = overlay.querySelector("img"); const src = previewMp4Url(overlay); if (!src) return; const video = document.createElement("video"); video.className = "plus-preview img-responsive"; video.muted = true; video.defaultMuted = true; video.loop = true; video.autoplay = true; video.playsInline = true; video.preload = "auto"; video.src = src; const place = () => { if (!img) return; video.style.left = `${img.offsetLeft}px`; video.style.top = `${img.offsetTop}px`; video.style.width = `${img.offsetWidth}px`; video.style.height = `${img.offsetHeight}px`; }; video.addEventListener("loadedmetadata", place); video.addEventListener("playing", () => { place(); if (img) img.style.opacity = "0"; }); video.addEventListener("error", () => { video.remove(); if (img) img.style.opacity = ""; }); overlay.insertBefore(video, overlay.firstChild); place(); if (img && !img.complete) img.addEventListener("load", place, { once: true }); video.play().catch(() => { }); } function autoPlayListPreviews() { document.querySelectorAll(".thumb-overlay").forEach((overlay) => { mountListPreview(overlay); overlay.addEventListener("mouseleave", () => { setTimeout(() => mountListPreview(overlay), 50); }); }); } function durationSeconds(text) { const parts = String(text || "").trim().split(":").map((part) => Number(part)); if (!parts.length || parts.some((part) => !Number.isFinite(part))) return 0; return parts.reduce((total, part) => total * 60 + part, 0); } function sortListByDuration() { const cards = []; document.querySelectorAll(".well .duration").forEach((el) => { var _a; const card = (_a = el.closest(".well")) == null ? void 0 : _a.parentElement; if (card && !cards.includes(card)) cards.push(card); }); if (cards.length < 2) return; const parent = cards[0].parentElement; if (!parent) return; cards.sort((a, b) => { var _a, _b; return durationSeconds((_a = b.querySelector(".duration")) == null ? void 0 : _a.textContent) - durationSeconds((_b = a.querySelector(".duration")) == null ? void 0 : _b.textContent); }); cards.forEach((card) => parent.append(card)); } function initListDownload() { markAuthorOpened(new URL(location.href).searchParams.get("UID") || ""); sortListByDuration(); bindListPagingKeys(); autoPlayListPreviews(); const button = document.createElement("button"); button.type = "button"; button.textContent = "下载本页全部视频"; button.style.cssText = [ "position:fixed", "top:1rem", "right:1rem", "z-index:99999", "cursor:pointer", "color:#fff", "background:#3D8AC7", "border:0", "border-radius:.3rem", "padding:.6rem 1rem", "font-size:1.6rem" ].join(";"); button.addEventListener("click", () => { const urls = listVideoUrls(); if (!urls.length) { button.textContent = "没有找到视频"; return; } urls.forEach((url) => { _GM_openInTab(url, { active: false, insert: true, setParent: true }); }); const nextUrl = nextPageUrl(); if (!nextUrl) { button.textContent = `已打开 ${urls.length} 个视频,已经是最后一页`; return; } button.textContent = `已打开 ${urls.length} 个视频,正在前往下一页`; location.href = nextUrl; }); document.body.append(button); } try { let style2 = ` .ad_img{display:none;} .thumb-overlay{position:relative;} .thumb-overlay video.plus-preview{position:absolute;object-fit:contain;z-index:1;pointer-events:none;margin:0;} .thumb-overlay .hd-text-icon,.thumb-overlay .duration{z-index:2;} `; let addStyle2 = document.createElement("style"); addStyle2.rel = "stylesheet"; addStyle2.type = "text/css"; addStyle2.innerHTML = style2; document.head.append(addStyle2); $("iframe").hide(); let l = window.location; if (l.pathname === "/index.php") { } else if (l.pathname === "/uvideos.php") { initListDownload(); } else if (l.pathname === "/view_video.php") { init(); } } catch (e) { console.log("init报错了", e); } })(Vue);