JavDB 跳转 JavTrailers; From JavDB jump to JavTrailers.
// ==UserScript==
// @name JavDB to JavTrailers
// @namespace http://tampermonkey.net/
// @version 1.5
// @description JavDB 跳转 JavTrailers; From JavDB jump to JavTrailers.
// @author Phoebe
// @match https://javdb.com/*
// @match https://javtrailers.com/video/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// --- JavTrailers 自动重定向逻辑---
// 如 SNOS-001,依次尝试 snos00001, 1snos00001, 118snos00001,如果都不行则进入搜索页
if (location.hostname === 'javtrailers.com') {
if (document.title.includes('Page not found') || document.title.includes('404')) {
const currentUrl = location.href;
const pathParts = location.pathname.split('/');
let vid = pathParts[pathParts.length - 1];
if (!vid) return;
console.log('JavTrailers 404 detected for:', vid);
const retryKey = 'javtrailers_retry_chain';
const retryChain = JSON.parse(sessionStorage.getItem(retryKey) || '[]');
if (!retryChain.includes(vid)) {
retryChain.push(vid);
sessionStorage.setItem(retryKey, JSON.stringify(retryChain));
}
let newVid = null;
let attempt = 0;
// 判断当前是第几次尝试
if (vid.match(/^[a-z]+\d{5}$/i)) {
attempt = 1; // snos00001
newVid = '1' + vid;
}
else if (vid.startsWith('1') && vid.match(/^1[a-z]+\d{5}$/i)) {
attempt = 2; // 1snos00001
const withoutOne = vid.substring(1);
newVid = '118' + withoutOne; // 118snos00001
}
else if (vid.startsWith('118') && vid.match(/^118[a-z]+\d{5}$/i)) {
attempt = 3; // 118snos00001
}
if (newVid && attempt < 3 && !retryChain.includes(newVid)) {
// 第1、2、3次重试
const newUrl = currentUrl.replace('/' + vid, '/' + newVid);
console.log(`Retry ${attempt}/3: ${vid} → ${newVid}`);
location.replace(newUrl);
}
else {
// 三次都失败 → 跳转搜索页
const searchMatch = vid.replace(/^\d+/, '').match(/^([a-z]+)0*(\d+)$/i);
let searchId = searchMatch
? `${searchMatch[1].toLowerCase()}-${searchMatch[2].padStart(3, '0')}`
: vid.replace(/^\d+/, '').replace(/(\d+)$/, '-$1');
const searchUrl = `https://javtrailers.com/search/${searchId}`;
console.log(`All 3 attempts failed. Jumping to search: ${searchUrl}`);
sessionStorage.removeItem(retryKey);
location.replace(searchUrl);
}
} else {
sessionStorage.removeItem('javtrailers_retry_chain');
}
return;
}
// --- JavDB 页面按钮插入逻辑---
function formatId(rawId) {
const match = rawId.match(/^([A-Za-z]+)-?(\d+)$/);
if (match) {
const prefix = match[1].toLowerCase();
const number = match[2].padStart(5, '0');
return prefix + number;
}
return rawId.replace('-', '').toLowerCase().trim();
}
function createJumpButton(id, isMini = false) {
const formattedId = formatId(id);
const url = `https://javtrailers.com/video/${formattedId}`;
let btn;
if (isMini) {
btn = document.createElement('span');
btn.innerHTML = '🎬 预告片';
btn.style.cssText = 'margin-left:8px; padding:0 4px; font-size:11px; background-color:#3e8ed0; color:#fff; border-radius:3px; cursor:pointer; display:inline-block; vertical-align:middle;';
btn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
window.open(url, '_blank');
});
} else {
btn = document.createElement('a');
btn.href = url;
btn.target = '_blank';
btn.className = 'button is-info is-outlined is-small';
btn.innerHTML = `<span class="icon is-small"><i class="icon-play-circle"></i></span><span>預告片</span>`;
btn.style.marginLeft = '5px';
btn.style.height = '2.25em';
}
return btn;
}
function handlePage() {
// 详情页
if (window.location.pathname.startsWith('/v/')) {
const labels = document.querySelectorAll('strong');
for (const label of labels) {
if ((label.innerText.includes('番號') || label.innerText.includes('ID'))&& !label.dataset.jumpAdded) {
const parent = label.parentElement;
const valueSpan = parent.querySelector('.value');
const copyBtn = parent.querySelector('.copy-to-clipboard');
if (valueSpan) {
const id = valueSpan.innerText.trim();
(copyBtn || valueSpan).after(createJumpButton(id, false));
label.dataset.jumpAdded = "true";
}
break;
}
}
}
// 列表页
const items = document.querySelectorAll('.item');
items.forEach(item => {
const scoreEl = item.querySelector('.score');
const idEl = item.querySelector('.video-title strong');
if (scoreEl && idEl && !scoreEl.dataset.jumpAdded) {
const id = idEl.innerText.trim();
scoreEl.appendChild(createJumpButton(id, true));
scoreEl.dataset.jumpAdded = "true";
}
});
}
handlePage();
const observer = new MutationObserver(() => handlePage());
observer.observe(document.body, { childList: true, subtree: true });
})();