// ==UserScript==
// @license MIT
// @name x1080x-preview
// @namespace https://gf.qytechs.cn/zh-CN/scripts/439204-x1080x-preview
// @version 2.12
// @description 显示影片预览图和预览影片
// @author jasmine
// @include /^https:\/\/.*c996\.me\/forum.php?.*tid=\d+(?!.*page=[2-9]).*$/
// @icon https://www.google.com/s2/favicons?domain=www.c996.me
// =============================
// @connect javdb.com
// @connect javbus.com
// @connect ec.sod.co.jp
// @connect cloudfront.net
// @connect r18.com
// @connect www.dmm.co.jp
// @connect www.mgstage.com
// @connect www.bing.com
// =============================
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// =============================
// @resource fancybox_css https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/jquery.fancybox.min.css
// @require https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/jquery.fancybox.min.js
// =============================
// @resource videojs_css https://cdn.jsdelivr.net/npm/[email protected]/dist/video-js.min.css
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/video.min.js
// =============================
// @resource videojs_resolution_switcher_css https://cdn.jsdelivr.net/npm/[email protected]/lib/videojs-resolution-switcher.min.css
// @require https://cdn.jsdelivr.net/npm/[email protected]/lib/videojs-resolution-switcher.min.js
// =============================
// @grant GM_xmlhttpRequest
// @grant GM_download
// @grant GM_notification
// @grant GM_registerMenuCommand
// @grant GM_getResourceText
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_log
// @grant GM_openInTab
// @grant GM_setClipboard
// @grant GM_info
// ==/UserScript==
(function() {
'use strict';
// 菜单列表
var menu_ALL = [
['menu_showGallery', '显示预览图', '显示预览图', true],
['menu_quality', '画面优先', '画面优先', true],
//['menu_JavDB', '搜索JavDB', '搜索JavDB', true],
//['menu_JavBus', '搜索JavBus', '搜索JavBus', true],
], menu_ID = [];
for (let i=0;i<menu_ALL.length;i++){ // 如果读取到的值为 null 就写入默认值
if (GM_getValue(menu_ALL[i][0]) == null) {
GM_setValue(menu_ALL[i][0], menu_ALL[i][3])
};
}
registerMenuCommand();
// 注册(不可用)脚本菜单
function registerMenuCommand() {
if (menu_ID.length > menu_ALL.length){ // 如果菜单ID数组多于菜单数组,说明不是首次添加菜单,需要卸载所有脚本菜单
for (let i=0;i<menu_ID.length;i++){
GM_unregisterMenuCommand(menu_ID[i]);
}
}
for (let i=0;i<menu_ALL.length;i++){ // 循环注册(不可用)脚本菜单
menu_ALL[i][3] = GM_getValue(menu_ALL[i][0]);
menu_ID[i] = GM_registerMenuCommand(`${menu_ALL[i][3]?'✅':'❌'} ${menu_ALL[i][1]}`, function(){menu_switch(`${menu_ALL[i][3]}`,`${menu_ALL[i][0]}`,`${menu_ALL[i][2]}`)});
}
menu_ID[menu_ID.length] = GM_registerMenuCommand('💬 反馈 & 建议', function () {GM_openInTab('https://www.c996.me/forum.php?mod=post&action=reply&fid=38&tid=595067&reppost=2265338&extra=&page=1&from=script', {active: true,insert: true,setParent: true});});
}
// 菜单开关
function menu_switch(menu_status, Name, Tips) {
if (menu_status == 'true'){
GM_setValue(`${Name}`, false);
GM_notification({text: `已关闭 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function(){location.reload();}});
}else{
GM_setValue(`${Name}`, true);
GM_notification({text: `已开启 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function(){location.reload();}});
}
registerMenuCommand(); // 重新注册(不可用)脚本菜单
};
// 返回菜单值
function menu_value(menuName) {
for (let menu of menu_ALL) {
if (menu[0] == menuName) {
return menu[3]
}
}
}
// 日志记录
function record_log(msg) {
let log = GM_getValue("log");
if (log !== "") {
log = log + "\n"
}
GM_setValue("log", log + msg);
GM_log(msg);
}
// 根据xpath查找 一个结果
function _xO(path, obj) {
return obj.evaluate(path, obj, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
// 根据xpath查找 多个结果
function _xM(path, obj) {
var xresult = obj.evaluate(path, obj, null, XPathResult.ANY_TYPE, null);
var xnodes = [];
var xres;
while (xres = xresult.iterateNext()) {
xnodes.push(xres.textContent);
}
return xnodes;
}
// 通用请求
function gmFetch(obj) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: obj.method || 'GET',
// timeout in ms
timeout: obj.timeout,
url: obj.url,
headers: obj.headers,
cookie: obj.cookie,
data: obj.data,
revalidate: obj.revalidate ? true: false,
nocache: obj.nocache ? true: false,
onload: res => {
if (res.status >= 200 && res.status < 400 || res.finalUrl === "http://ec.sod.co.jp/prime/") {
resolve(res);
} else {
reject(res);
}
},
onerror: reject,
ontimeout: reject,
});
});
}
// 请求
function fetch(url, headers={"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"}){
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: url,
method: "GET",
headers: headers,
//timeout: 5000,
onload: function(r){
if (r.status === 200) {
resolve(r.responseText)
} else {
reject("status error: " + r.status)
}
},
onerror: function(e) {
reject('fetch error')
},
ontimeout: function(e) {
reject('fetch timeout')
}
});
})
}
// 检查连接
function checkURL(url, headers={"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"}){
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: url,
method: "HEAD",
headers: headers,
//timeout: 5000,
onload: function(r){
if (r.status === 200) {
resolve(true)
} else {
resolve(false)
}
},
onerror: function(e) {
resolve(false)
},
ontimeout: function(e) {
resolve(false)
}
});
})
}
// 下载文件
function download(url, filename, headers={"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"}){
return new Promise((resolve, reject) => {
GM_download({
url: url,
name: filename,
saveAs: false,
headers: headers,
//timeout: 5000,
onload: function(r){
if (r.status === 200) {
resolve(r.responseText)
} else {
reject("download status error: " + r.status)
}
},
onerror: function(e) {
reject('download error')
},
ontimeout: function(e) {
reject('download timeout')
}
});
})
}
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
// 格式化页面
function parseResponse(html) {
const parser = new DOMParser()
const tree = parser.parseFromString(html, "text/html")
return tree
}
// DMM获取大图
function preview_src(src)
{
if (src.match(/(p[a-z]\.)jpg/)) {
return src.replace(RegExp.$1, 'pl.');
} else if (src.match(/consumer_game/)) {
return src.replace('js-','-');
} else if (src.match(/js\-([0-9]+)\.jpg$/)) {
return src.replace('js-','jp-');
} else if (src.match(/ts\-([0-9]+)\.jpg$/)) {
return src.replace('ts-','tl-');
} else if (src.match(/(\-[0-9]+\.)jpg$/)) {
return src.replace(RegExp.$1, 'jp' + RegExp.$1);
} else {
return src.replace('-','jp-');
}
}
// 从javdb查询预览图
// async function fetchJavDB() {
// log("JavDB: 开始搜索预览图")
// try {
// const content = await fetch("https://javdb.com/search?q=" + videoId + "&f=all")
// const tree = parseResponse(content)
// const secUrls = _xM("//*[@id='videos']/div/div/a/@href", tree);
// const ids = _xM("//*[@id='videos']/div/div/a/div[contains(@class, 'uid')]/text()", tree);
// const index = ids.indexOf(videoId);
// if(index === -1){
// log("JavDB: 没有视频资料");
// return false
// }
// const secUrl = secUrls[index];
// const url = "https://javdb.com" + secUrl;
// const secContent = await fetch(url)
// const secTree = parseResponse(secContent)
// const gallery = _xM("//div[@class='tile-images preview-images']/a[@class='tile-item']/@href", secTree);
// if (gallery.length === 0) {
// log("JavDB: 可能没有预览图");
// return false
// }
// return gallery;
// }
// catch(e){
// log("JavDB: 搜索失败" + e);
// return false
// }
// }
// 从JavBus查询预览图
// async function fetchJavBus() {
// log("JavBus: 开始搜索预览图")
// try {
// const content = await fetch("https://www.javbus.com/" + videoId)
// const tree = parseResponse(content)
// var gallery = _xM("//a[@class='sample-box']/@href", tree);
// if (gallery.length === 0) {
// log("JavBus: 可能没有预览图");
// return false
// }
// return gallery;
// }
// catch(e){
// log("JavBus: 搜索失败" + e);
// return false
// }
// }
// 从SOD查询预览图
// async function fetchSOD() {
// log("SOD: 开始搜索预览图")
// try{
// const content = await fetch("https://ec.sod.co.jp/prime/videos/?id=" + videoId)
// const tree = parseResponse(content)
// const ageCheck = _xM("//div[@class='pkg_age']", tree);
// if (ageCheck.length != 0) {
// GM_notification({
// text: "点击打开SOD官网获取预览图",
// timeout: 3000,
// onclick: function() { window.open("https://ec.sod.co.jp/prime") }
// });
// return false;
// }
// const gallery = _xM("//div[@class='img-gallery']//img/@src", tree);
// if (gallery.length === 0) {
// log("SOD: 可能没有预览图")
// return false;
// }
// return gallery
// }
// catch (e) {
// log("SOD: 搜索失败" + e)
// return false
// }
// }
// 查询预览影片
// async function fetchVideo() {
// log("R18: 开始搜索预览影片")
// try{
// let word = videoId.replace('-', '+')
// const content = await fetch(`https://www.r18.com/common/search/searchword=${word}/`)
// const tree = parseResponse(content)
// let video_tag = tree.querySelector(`li[data-content_id$='${videoId.split('-')[1]}']`).querySelector('.js-view-sample');
// let video_quality = ['high', 'med', 'low']
// let video_label = ['高清', '清晰', '流畅']
// let video_res = ['1500', '1000', '300']
// let video_src = video_quality
// .map(i => video_tag.getAttribute('data-video-' + i))
// .map(function(item, index) {
// return {
// src: item,
// type: 'video/mp4',
// label: video_label[index],
// res: video_res[index]
// }
// })
// .filter(item => item.src !== null)
// let vr_src = video_tag.getAttribute(`data-vr-url`)
// if (vr_src !== null) {
// video_src.push({src: vr_src, type:'video/mp4', label: `VR`, res: `3000`})
// }
// if (video_src.length !== 0) {
// const regex = /^(.*_)([a-z]+)(_w)/i;
// if (video_src[0].src.match(regex)) {
// const highest = video_src[0].src.replace(regex, '$1mhb$3')
// let res = await checkURL(highest)
// if (res) {
// video_src.push({src: highest, type:'video/mp4', label: `HD`, res: `3000`})
// }
// }
// return video_src
// }
// log("R18: 可能没有预览影片")
// return false;
// }
// catch (e) {
// log("R18: 搜索失败" + e)
// return false;
// }
// }
// async function fetchVideoDMM() {
// let includesEditionNumber = (str) => {
// return str != null
// // && str.includes(this.editionNumber.toLowerCase().split('-')[0])
// && str.includes(this.editionNumber.toLowerCase().split('-')[1]);
// }
// let content = await fetch(`https://www.bing.com/search?q=${videoId}+site%3awww.dmm.co.jp`)
// let pattern = /(cid=[\w]+|pid=[\w]+)/g;
// log(content.match(pattern))
// let dmmCid = '';
// for (let match of content.match(pattern)) {
// if (includesEditionNumber(match)) {
// dmmCid = match.replace(/(cid=|pid=)/, '');
// break;
// }
// }
//
// if (dmmCid == '') {
// return;
// }
//
// content = await fetch(`https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=${dmmCid}/mtype=AhRVShI_/service=litevideo/mode=/width=560/height=360/`, {"accept-language": "ja-JP,ja;q=0.9"})
// tree = parseResponse(content)
// let dmm_pattern = /(const args = |const params = )(.*);/g;
// // Very hacky... Didn't find a way to parse the HTML with JS.
// for (let script of tree.getElementsByTagName('script')) {
// if (script.innerText != null && script.innerText.includes('.mp4')) {
// for (let line of script.innerText.split('\n')) {
// let result = dmm_pattern.exec(line)
// if (result) {
// line = result[result.length - 1]
// let videoSrc = JSON.parse(line).src;
// if (!videoSrc.startsWith('http')) {
// videoSrc = 'http:' + videoSrc;
// }
// return videoSrc;
// }
// }
// }
// }
// }
// 获取影片标题
// function getTitle() {
// const ori_title = _xO("//*[@id='pt']/div[2]", document).textContent;
// const title = ori_title.split(" ?").slice(-1)[0].trim();
// return title;
// }
// 获取影片ID
// function getVideoId(title) {
// const regex = /[A-Z]+-\d+/g;
// const id = title.match(regex);
// return String(id);
// }
// 插入预览图
function insertImages(item) {
let source;
if (video_type === "sod") {
source = URL.createObjectURL(item)
}
const a = document.createElement("a");
const img = document.createElement("img");
a.href = source;
a.setAttribute("data-fancybox", "gallery");
a.setAttribute("class", "x1080x-ga-box");
img.setAttribute("class", "x1080x-auto-img");
img.src = source;
a.appendChild(img);
gallery_div.appendChild(a);
}
//下载预览图
// async function downloadSODImages(gallery, headers) {
// for (let index = 0; index < gallery.length; index++) {
// try {
// await download(gallery[index], gallery[index], headers);
// }
// catch(e){
// record_log(e)
// }
// }
// }
//访问预览图
async function accessSODImages(gallery, headers) {
for (let index = 0; index < gallery.length; index++) {
try {
await fetch(gallery[index], headers);
}
catch(e){
record_log(e)
}
}
}
// 浏览器版本
navigator.sayswho= (function(){
let ua= navigator.userAgent;
let tem;
let M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return 'IE '+(tem[1] || '');
}
if(M[1]=== 'Chrome'){
tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem!= null) return tem.slice(1).join(' ').replace('OPR', 'Opera');
}
M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
return M.join(' ');
})();
// 入口
//const res = await fetch("https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=ssis279/mtype=AhRVShI_/service=litevideo/mode=/width=560/height=360/", {"accept-language": "ja-JP,ja;q=0.9"})
//log(res);
//const re = /const args = ({.+});$/gm;
//const hits = [];
//// Iterate hits
//let match = null;
//do {
// match = re.exec(res);
// if(match) {
// hits.push(match[1]);
// }
//} while (match);
//const obj = JSON.parse(hits[0])
//record_log(obj["bitrates"]); // Prints [ '#with', '#hashtags' ]
//return false
// 意见反馈
if (window.location.href.endsWith("from=script")) {
//let log = GM_getValue("log")
document.querySelector("#e_textarea").value = GM_getValue("log")
return
}
// 基础div
const node = _xO("//div[@class='t_fsz']/table/tbody", document);
if (node == null || !menu_value("menu_showGallery")) {
return;
}
// 封面
let cover = document.querySelector("td[id^=postmessage] img").src
if (!cover.match(/(pics.dmm.co.jp|www.hxmmdd.com)/)) {
return
}
// 预览容器
const tr = document.createElement("tr");
const td = document.createElement("td");
const gallery_div = document.createElement("div")
td.appendChild(gallery_div)
tr.appendChild(td)
gallery_div.setAttribute("class", "x1080x-gallery");
const ga_inner = document.createElement('span');
gallery_div.appendChild(ga_inner)
node.appendChild(tr)
// 播放容器
const play_box = document.createElement("a");
play_box.setAttribute("class", "x1080x-ga-box x1080x-play-box");
play_box.setAttribute("data-fancybox", "");
gallery_div.insertBefore(play_box, gallery_div.firstChild);
// 视频封面
const poster = document.createElement("img");
poster.setAttribute("class", "x1080x-auto-img");
poster.src = cover
const span = document.createElement("span");
span.setAttribute("class", "x1080x-preview");
span.innerHTML = '預告片'
const outer_span = document.createElement("span");
outer_span.setAttribute("class", "x1080x-outer");
outer_span.innerHTML = '外链'
play_box.appendChild(span);
play_box.appendChild(outer_span);
play_box.appendChild(poster);
// 播放器
const video_player = document.createElement("video");
video_player.setAttribute("id", "x1080x-player");
video_player.setAttribute("class", "video-js vjs-default-skin");
play_box.append(video_player)
const options = {
controls: true,
responsive: true,
plugins: {
videoJsResolutionSwitcher: {
default: menu_value('menu_quality') ? `high`: `low`, // Default resolution [{Number}, 'low', 'high'],
dynamicLabel: true
}
},
};
let player = videojs("x1080x-player", options, function(){});
// 加载fancybox样式
const fancybox_css = GM_getResourceText("fancybox_css");
GM_addStyle(fancybox_css);
// 加载video-js样式
const videojs_css = GM_getResourceText("videojs_css");
GM_addStyle(videojs_css);
// 加载videojs-resolution-switcher样式
const videojs_resolution_switcher_css = GM_getResourceText("videojs_resolution_switcher_css");
GM_addStyle(videojs_resolution_switcher_css);
// 自定义样式
let btn_img = `PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNTEycHgiIGhlaWdodD0iNTEycHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPCEtLSBHZW5lcmF0b3I6IFNrZXRjaCA1Mi4xICg2NzA0OCkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+YnRuLXBsYXk8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0iYnRuLXBsYXkiIGZpbGwtcnVsZT0ibm9uemVybyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yNTYsMCBDMTE0Ljg0MzU0OSwwIDAsMTE0Ljg0MzU0OSAwLDI1NiBDMCwzOTcuMTU2NDUxIDExNC44NDM1NDksNTEyIDI1Niw1MTIgQzM5Ny4xNTY0NTEsNTEyIDUxMiwzOTcuMTU2NDUxIDUxMiwyNTYgQzUxMiwxMTQuODQzNTQ5IDM5Ny4xNTY0NTEsMCAyNTYsMCBaIiBpZD0iU2hhcGUiIGZpbGw9IiMwQTVFRTAiPjwvcGF0aD4KICAgICAgICAgICAgPHBvbHlnb24gaWQ9IlBhdGgiIGZpbGw9IiNGRkZGRkYiIHBvaW50cz0iMTkyIDM4My45OTcyODUgMTkyIDEyNy45OTkwOTUgMzg0IDI1NS45OTcyODUiPjwvcG9seWdvbj4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==`
GM_addStyle(`
.x1080x-gallery {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-top: 10px;
max-width: 95%;
}
.x1080x-ga-box {
display: inline-block;
width: 250px;
height: auto;
text-align: center;
vertical-align: middle;
overflow-x: hidden;
text-overflow: ellipsis;
font-size: .9rem;
background-color: black;
margin: 5px 5px 0px 0px;
cursor: pointer;
}
.x1080x-ga-box .x1080x-auto-img {
position: relative;
height: 120px;
}
.x1080x-play-box {
display: none;
position: relative;
}
.x1080x-play-box span.x1080x-preview {
font-size: .8rem;
color: #fff;
background-color: #fc8300;
position: absolute;
top: 4px;
left: 4px;
text-align: center;
padding: 1px 2px;
border-radius: 3px;
z-index: 999;
}
.x1080x-play-box span.x1080x-outer {
font-size: .8rem;
color: #fff;
background-color: #fc8300;
position: absolute;
top: 4px;
right: 4px;
text-align: center;
padding: 1px 2px;
border-radius: 3px;
z-index: 999;
display: none;
}
.x1080x-play-box:after {
background: url("data:image/svg+xml;base64,${btn_img}") 50% no-repeat;
background-color: rgba(0,0,0,.2);
background-size: 40px 40px;
bottom: 0;
content: "";
display: block;
left: 0;
position: absolute;
right: 0;
top: 0;
height: 100%;
}
.x1080x-play-box:hover::after {
background-color: rgba(33,156,239,0);;
}
#x1080x-player {
display:none;
position: absolute;
width: 50%;
height: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
}
`);
GM_setValue("log", "");
let title_pattern = /\)([^\(\)].*)</g;
let subject = document.querySelector("#thread_subject").innerText
let video_type;
if (subject.match(/\(SOD\)|\(SODVR\)/)) {
video_type = "sod"
} else if (subject.indexOf("(Prestige)") !== -1) {
video_type = "mgs"
} else {
video_type = "dmm"
}
let is_vr = subject.indexOf("【VR】") !== -1 ? true: false
let pid = cover.replace("pl.jpg", ".jpg").split("/").slice(-1)[0].split(".")[0]
record_log(`浏览器: ${navigator.sayswho}`)
record_log(`插件版本: ${GM_info.script.version}`)
record_log(`标题: ${subject}`)
record_log(`地址: ${window.location.href}`)
record_log(`番号: ${pid}`)
let dmm = async() => {
if (video_type !== "dmm") {
record_log(`DMM Search: 跳过`)
throw new Error('DMM Search: 跳过');
}
record_log(`DMM Search: ${pid}`)
let dmm_headers = {"accept-language": "ja-JP,ja;q=0.9"}
let dmm_cookie = "age_check_done=1"
let search_request = {url: `https://www.dmm.co.jp/search/=/searchstr=${pid}`, headers: dmm_headers}
let search_res = await gmFetch(search_request).catch(err => {record_log(err); return;})
let search_html = parseResponse(search_res.responseText)
let ele_detail = search_html.querySelector(`.tmb a[href*="${pid}"]`)
if (!ele_detail) {
record_log(`DMM Search: 未找到`);
throw new Error('DMM Search: 未找到');
}
let detail_url = ele_detail.getAttribute("href")
record_log(`DMM Search: 详情页 ${detail_url}`)
let detail_request = {url: detail_url, headers: dmm_headers, cookie: dmm_cookie}
let detail_res = await gmFetch(detail_request).catch(err => {record_log(err); return;})
let detail_html = parseResponse(detail_res.responseText)
// 预览图
let imgs = [...detail_html.querySelectorAll("#sample-image-block img")].map( item => item.getAttribute("src")).map( item => preview_src(item))
// 预览视频
let video = []
if (is_vr) {
let video_request = {url: `https://www.dmm.co.jp/digital/-/vr-sample-player/=/cid=${pid}/`, headers: dmm_headers, cookie: dmm_cookie}
let video_res = await gmFetch(video_request).catch(err => {record_log(err); return;});
let video_pattern = /var sampleUrl = "(.*)";/g;
let video_url = video_pattern.exec(video_res.responseText)[1]
if (video_url !== '') {
video.push({
src: video_url,
type: 'video/mp4',
label: `VR`,
res: `100`
})
}
} else {
let video_request = {url: `https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=${pid}/mtype=AhRVShI_/service=litevideo/mode=/width=560/height=360/`, headers: dmm_headers, cookie: dmm_cookie};
const video_label = {300: "流畅", 1000: "清晰", 1500: "高清", 3000: "HD"}
let video_res = await gmFetch(video_request).catch(err => {record_log(err); return;});
let video_pattern = /(const args = |const params = )({.+});$/gm;
let bitrates = JSON.parse(video_pattern.exec(video_res.responseText)[2]).bitrates
video = bitrates.map( function(item) {
return {
src: item.src,
type: 'video/mp4',
label: video_label[item.bitrate],
res: item.bitrate
}
})
}
return {imgs: imgs, video: video}
}
let mgstage = async() => {
if (video_type !== "mgs") {
record_log(`MGSTAGE Search: 跳过`)
throw new Error('MGSTAGE Search: 跳过');
}
record_log(`MGSTAGE Search: ${pid}`)
let cookie = `adc=1`;
let detail_request = {url: `https://www.mgstage.com/product/product_detail/${pid}/`, cookie: cookie}
let detail_res = await gmFetch(detail_request).catch(err => {record_log(err); return;})
let detail_html = parseResponse(detail_res.responseText)
// 预览图
let imgs = [...detail_html.querySelectorAll(".sample_image")].map( item => item.getAttribute("href"))
// 预览视频
let video = []
let ele = detail_html.querySelector('div.detail_photo p.sample_movie_btn a:not([disabled])');
if (ele) {
let href = ele.getAttribute('href');
let pid = href.split('/').pop();
record_log(`MGSTAGE Search: 视频ID ${pid}`);
let video_request = {url: `https://www.mgstage.com/sampleplayer/sampleRespons.php?pid=${pid}`, cookie: cookie}
let video_res = await gmFetch(video_request).catch(err => {record_log(err); return;})
let re = /https.*?ism/
let json_obj = JSON.parse(video_res.responseText);
let video_url = json_obj.url;
video_url = re.exec(video_url)[0].replace('ism', 'mp4');
video.push({
src: video_url,
type: 'video/mp4',
label: `MGS`,
res: `100`
})
}
return {imgs: imgs, video: video}
}
function getBase64FromImage(url, onSuccess, onError) {
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("GET", url);
xhr.onload = function () {
var base64, binary, bytes, mediaType;
bytes = new Uint8Array(xhr.response);
//NOTE String.fromCharCode.apply(String, ...
//may cause "Maximum call stack size exceeded"
binary = [].map.call(bytes, function (byte) {
return String.fromCharCode(byte);
}).join('');
mediaType = xhr.getResponseHeader('content-type');
base64 = [
'data:',
mediaType ? mediaType + ';':'',
'base64,',
btoa(binary)
].join('');
onSuccess(base64);
};
xhr.onerror = onError;
xhr.send();
}
let sod = async() => {
if (video_type !== "sod") {
record_log(`SOD Search: 跳过`)
throw new Error('SOD Search: 跳过');
}
record_log(`SOD Search: ${pid}`)
let detail_request = {url: `https://ec.sod.co.jp/prime/videos/?id=${pid}`}
let detail_res = await gmFetch(detail_request).catch(err => {record_log(err); return;})
let detail_html = parseResponse(detail_res.responseText)
let age_check = detail_html.querySelector(".pkg_age")
if (age_check) {
await gmFetch({url: `https://ec.sod.co.jp/prime/_ontime.php`}).catch(err => {record_log(err); return;})
detail_res = await gmFetch(detail_request).catch(err => {record_log(err); return;})
detail_html = parseResponse(detail_res.responseText)
}
// 预览图
let imgs = [...detail_html.querySelectorAll(".img-gallery a")].map( item => item.getAttribute("href"))
let imgs_blob = []
await asyncForEach(imgs, async (img) => {
const response = await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "get",
url: img,
headers: {"referer": `https://ec.sod.co.jp/prime/videos/?id=${pid}`},
responseType: "blob",
onload: response => {resolve(response); console.log("onload");},
onerror: response => {reject(response); console.log("onerror");},
});
});
console.log("response:", response);
const {response: blob} = response;
imgs_blob.push(blob)
//let img_request = {url: img, headers: {"referer": `https://ec.sod.co.jp/prime/videos/?id=${pid}`}, nocache: true}
//let img_res = await gmFetch(img_request).catch(err => {record_log(err); return;});
//let base = window.btoa(img_res.responseText)
//console.log(base)
})
imgs = imgs_blob
//await accessSODImages(imgs, {"referer": "https://ec.sod.co.jp/prime/videos/?id=" + pid})
// 预览视频
let video = []
let ele = detail_html.querySelector(".videos_sampb a");
if (ele) {
let video_url = `https://ec.sod.co.jp/prime/videos/${ele.getAttribute('href')}`;
video.push({
src: video_url,
type: 'video/mp4',
label: `SOD`,
res: `100`
})
}
return {imgs: imgs, video: video}
}
ga_inner.innerHTML = "正在搜索预览图..."
Promise.allSettled([dmm(),mgstage(),sod()]).then(results=>{
ga_inner.innerHTML = ""
let p = results.find(result => result.status==="fulfilled")
if (p) {
let imgs = p.value.imgs
let video = p.value.video
if (imgs.length !== 0) {
imgs.forEach(insertImages)
}
if (video.length !==0) {
play_box.setAttribute("style", "display:inline-block");
if (video_type === "sod") {
outer_span.setAttribute("style", "display:block");
} else {
player.updateSrc(video)
}
// 点击弹出播放器
play_box.onclick = function (e) {
e.preventDefault();
if (video_type === "sod") {
GM_openInTab(video[0].src, {active : true})
} else {
video_player.setAttribute("style", "display:block");
$.fancybox.open({
src : '#x1080x-player',
type : 'inline',
opts : {
smallBtn: false,
touch: false,
afterShow : function( instance, current ) {
player.play();
},
afterClose : function( instance, current ) {
player.pause();
}
}
});
}
}
}
if (imgs.length === 0 && video.length === 0 ){
gallery_div.style.display = "none"
}
}
})
//$.fancybox.defaults.loop = "true";
})();