修复视频长预览图

This commit is contained in:
lzyme.dev@gmail.com
2026-08-30 03:49:06 +08:00
parent 06e9f4e8b4
commit b0fe131a03
6 changed files with 1764 additions and 333 deletions
+1189 -215
View File
File diff suppressed because it is too large Load Diff
+118
View File
@@ -451,6 +451,124 @@ const mainCss = `
background: rgba(0, 0, 0, 0.3);
z-index: 999998;
}
.jhs-preview-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.85);
z-index: 2147483647;
display: flex;
overflow: auto;
cursor: zoom-out;
backdrop-filter: blur(5px);
}
.jhs-preview-img {
border-radius: 4px;
margin: auto;
cursor: zoom-in;
max-width: 95vw;
max-height: 95vh;
object-fit: contain;
display: block;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
}
.jhs-preview-img.zoomed {
max-width: none;
max-height: none;
cursor: zoom-out;
}
.jhs-preview-toolbar {
position: fixed;
top: 20px;
right: 20px;
display: flex;
gap: 8px;
z-index: 2147483648;
background: #fff;
padding: 8px 12px;
border-radius: 8px;
border: 1px solid #e5e7eb;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.jhs-preview-btn {
padding: 7px 16px;
background: #f3f4f6;
color: #374151;
border: 1px solid #d1d5db;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 4px;
white-space: nowrap;
}
.jhs-preview-btn:hover {
background: #e5e7eb;
border-color: #9ca3af;
}
.jhs-preview-btn.active {
color: #fff;
background: #2ecc71;
border-color: #2ecc71;
}
.jhs-loading-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.7);
z-index: 2147483649;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 18px;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
.jhs-loading-spinner {
text-align: center;
}
.jhs-loading-spinner .spinner {
width: 40px;
height: 40px;
margin: 0 auto 12px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-top-color: #fff;
border-radius: 50%;
animation: jhs-spin 0.6s linear infinite;
}
@keyframes jhs-spin {
to { transform: rotate(360deg); }
}
.jhs-preview-toast {
position: fixed;
top: 80px;
left: 50%;
transform: translate(-50%, -20px);
z-index: 2147483650;
padding: 10px 24px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
color: #fff;
opacity: 0;
transition: opacity 0.3s ease, transform 0.3s ease;
pointer-events: none;
}
.jhs-preview-toast.show {
opacity: 1;
transform: translate(-50%, 0);
}
.jhs-preview-toast-error {
background: rgba(220, 38, 38, 0.9);
box-shadow: 0 4px 16px rgba(220, 38, 38, 0.4);
}
.jhs-preview-toast-info {
background: rgba(59, 130, 246, 0.9);
box-shadow: 0 4px 16px rgba(59, 130, 246, 0.4);
}
</style>
`;
+1 -1
View File
@@ -101,7 +101,7 @@ class CoverButtonPlugin extends BasePlugin {
carNum2 = carNum2.replace("FC2-", "");
const imgUrl = await this.getBean("ScreenShotPlugin").getScreenshot(carNum2);
loadObj.close();
showImageViewer(imgUrl);
showPreviewOverlay(imgUrl, carNum2);
} catch (error) {
console.error("图片预览出错:", error);
show.error("图片预览出错:" + error);
+1 -1
View File
@@ -269,7 +269,7 @@ class Fc2By123AvPlugin extends BasePlugin {
$(".screen-container").on("click", (event => {
event.stopPropagation();
event.preventDefault();
showImageViewer(event.currentTarget);
showPreviewOverlay(imgUrl, carNum2);
}));
}
}));
+1 -1
View File
@@ -151,7 +151,7 @@ class Fc2Plugin extends BasePlugin {
utils.loopDetector((() => $(".movie-gallery .image-list").length > 0), (async () => {
$(".movie-gallery .image-list").prepend(' <a class="tile-item screen-container" style="overflow:hidden;max-height: 150px;max-width:150px; text-align:center;"><div style="margin-top: 50px;color: #000;cursor: auto">正在加载缩略图</div></a> ');
const screenShotPlugin = this.getBean("ScreenShotPlugin"), imgUrl = await screenShotPlugin.getScreenshot(carNum2);
imgUrl && await screenShotPlugin.addImg("缩略图", imgUrl);
imgUrl && await screenShotPlugin.addImg("缩略图", imgUrl, carNum2);
}));
}
handleMagnets(movieId) {
+454 -115
View File
@@ -1,153 +1,492 @@
import { BasePlugin } from '../core/base-plugin.js';
import { __publicField, isJavBus, isJavDb } from '../core/constants.js';
import { searchFiles } from './wangpan-115-task.js';
const Thumbnail = {
sources: ['javfree', 'projectjav', 'javstore'],
cacheKey(code) {
return `thumb_cache_v3_${code}`;
},
lookupCode(code) {
const text = String(code || '').trim();
const fc2 = text.match(/^(?:FC2[-_\s]?(?:PPV[-_\s]?)?)?(\d{6,9})$/i);
return fc2 ? fc2[1] : text;
},
sourceOrder() {
const savedOrder = ['javfree', 'projectjav', 'javstore'];
const seen = new Set();
return [...savedOrder, ...this.sources].filter(src => {
if (seen.has(src) || typeof this[src] !== 'function') return false;
seen.add(src);
return true;
});
},
async fetchFromSource(source, code) {
try {
return await this[source](this.lookupCode(code));
} catch (e) {
clog.debug(`Thumbnail[${source}] 异常:`, e.message);
return null;
}
},
normalizeForCompare(text) {
return String(text || '').toLowerCase().replace(/[^a-z0-9]/g, '');
},
isCodeMatched(text, code) {
const normalizedText = this.normalizeForCompare(text);
const normalizedCode = this.normalizeForCompare(code);
return !!normalizedCode && normalizedText.includes(normalizedCode);
},
isDetailMatched(doc, url, code) {
const title = doc?.querySelector('title')?.textContent || '';
const headings = [...(doc?.querySelectorAll('h1,h2,h3,.entry-title,.movie-title,.post-title') || [])]
.map(el => el.textContent || '').join(' ');
const bodyText = (doc?.body?.textContent || '').slice(0, 5000);
return this.isCodeMatched([url, title, headings, bodyText].join(' '), code);
},
normalizePreviewUrl(url, baseUrl = '') {
if (!url) return '';
const absolute = /^https?:\/\//i.test(url)
? url : (baseUrl ? new URL(url, baseUrl).href : url);
return absolute.replace(/^http:/, 'https:');
},
isJavfreePreviewImage(url, code) {
const cleanUrl = String(url || '').split('?')[0];
const lookupCode = this.lookupCode(code);
const isFc2Numeric = /^\d{6,9}$/.test(lookupCode);
const fc2ShotPattern = isFc2Numeric
? new RegExp(`${lookupCode}_\\d+\\.(?:jpe?g|png|webp)$`, 'i')
: null;
return this.isCodeMatched(cleanUrl, code) && (
/-(?:1080p|demosaic)\.(?:jpe?g|png|webp)$/i.test(cleanUrl) ||
(isFc2Numeric && fc2ShotPattern.test(cleanUrl))
);
},
selectJavfreePreviewUrl(doc, detailUrl, code) {
const urls = [...doc.querySelectorAll('p > img[src]')]
.map(img => this.normalizePreviewUrl(img.getAttribute('src') || img.src || '', detailUrl))
.filter(url => this.isJavfreePreviewImage(url, code));
return urls.find(url => /-1080p\./i.test(url)) ||
urls.find(url => /-demosaic\./i.test(url)) ||
urls.find(url => /_1\.(?:jpe?g|png|webp)$/i.test(url)) || '';
},
async javfree(code) {
code = this.lookupCode(code);
const cacheKey = this.cacheKey(code);
const cached = sessionStorage.getItem(cacheKey);
if (cached) return cached;
try {
const html = await gmHttp.get(`https://javfree.me/search/${code}`);
const doc = new DOMParser().parseFromString(html, 'text/html');
const link = [...doc.querySelectorAll('.entry-title>a')]
.find(a => this.isCodeMatched([a.href, a.textContent].join(' '), code))?.href;
if (!link) return null;
const dHtml = await gmHttp.get(link);
const dDoc = new DOMParser().parseFromString(dHtml, 'text/html');
if (!this.isDetailMatched(dDoc, link, code)) return null;
const url = this.selectJavfreePreviewUrl(dDoc, link, code);
if (url) {
sessionStorage.setItem(cacheKey, url);
return url;
}
return null;
} catch {
return null;
}
},
async javstore(code) {
code = this.lookupCode(code);
try {
const normalizedCode = code.replace(/^fc2-?/i, '').replace(/-/g, '').toLowerCase();
const searchUrl = `https://javstore.net/search?q=${encodeURIComponent(code)}`;
const searchHtml = await gmHttp.get(searchUrl);
const searchDoc = new DOMParser().parseFromString(searchHtml, 'text/html');
const candidateLinks = searchDoc.querySelectorAll('a[href*="/"]');
const detailUrls = [];
for (const link of candidateLinks) {
const href = link.getAttribute('href');
if (!href) continue;
if (href.startsWith('http') && !href.includes('javstore.net')) continue;
const urlObj = new URL(href, searchUrl);
if (!/javstore\.net$/i.test(urlObj.hostname)) continue;
if (/^\/search(?:[/?#]|$)/i.test(urlObj.pathname)) continue;
const fullUrl = urlObj.href;
const pathLastPart = decodeURIComponent(urlObj.pathname.split('/').pop() || '');
const normalizedPath = pathLastPart.toLowerCase().replace(/-/g, '');
const looksLikeDetail = /\.html$/i.test(urlObj.pathname) || /^\/\d+[-/]/.test(urlObj.pathname);
if (looksLikeDetail && normalizedPath.includes(normalizedCode) && !detailUrls.includes(fullUrl)) {
detailUrls.push(fullUrl);
}
}
if (detailUrls.length === 0) return null;
for (const detailUrl of detailUrls) {
const imgUrl = await this._extractImgFromDetail(detailUrl, code);
if (imgUrl) return imgUrl;
}
return null;
} catch (e) {
clog.debug('javstore 获取失败', e);
return null;
}
},
async _extractImgFromDetail(detailUrl, code) {
try {
const detailHtml = await gmHttp.get(detailUrl);
const detailDoc = new DOMParser().parseFromString(detailHtml, 'text/html');
if (!this.isDetailMatched(detailDoc, detailUrl, code)) return null;
for (const link of detailDoc.querySelectorAll('a')) {
if (link.textContent.includes('CLICK HERE')) {
const imgUrl = link.href || link.getAttribute('href') || '';
if (imgUrl) return this.normalizePreviewUrl(imgUrl, detailUrl);
}
}
const img = detailDoc.querySelector('img[src*="_s.jpg"]');
if (img) {
let src = img.getAttribute('src') || '';
if (!src.startsWith('http')) src = new URL(src, detailUrl).href;
return this.normalizePreviewUrl(src.replace(/_s\.jpg$/, '_l.jpg'), detailUrl);
}
return null;
} catch (e) {
clog.debug('javstore: 详情页请求失败', detailUrl, e.message);
return null;
}
},
async projectjav(code) {
code = this.lookupCode(code);
try {
const request = (url) => gmHttp.get(url, {}, {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
});
const searchUrl = `https://projectjav.com/?searchTerm=${encodeURIComponent(code)}`;
const searchHtml = await request(searchUrl);
const searchDoc = new DOMParser().parseFromString(searchHtml, 'text/html');
let detailUrl = '';
const allMovieLinks = [...searchDoc.querySelectorAll('a[href*="/movie/"]')];
const firstLink = allMovieLinks[0]?.getAttribute('href') || '';
if (firstLink) {
detailUrl = firstLink.startsWith('http') ? firstLink : `https://projectjav.com${firstLink}`;
}
if (!detailUrl) return null;
const detailHtml = await request(detailUrl);
const detailDoc = new DOMParser().parseFromString(detailHtml, 'text/html');
const screenshotLink = [...detailDoc.querySelectorAll('.col-md-12.thumbnail a[data-featherlight="image"], .thumbnail a[data-featherlight="image"]')]
.find(a => this.isCodeMatched([a.outerHTML, a.closest('.thumbnail')?.outerHTML, detailUrl].join(' '), code));
if (screenshotLink) {
const thumbImg = screenshotLink.querySelector('img');
const href = screenshotLink.getAttribute('href') || '';
if (href) return this.normalizePreviewUrl(href, detailUrl);
if (thumbImg) {
const src = (thumbImg.getAttribute('src') || '').replace(/\?.*$/, '');
if (src) return this.normalizePreviewUrl(src, detailUrl);
}
}
return null;
} catch (e) {
clog.debug('[projectjav] 异常:', e.message);
return null;
}
},
async get(code) {
const cacheKey = this.cacheKey(code);
const cached = sessionStorage.getItem(cacheKey);
if (cached) return {url: cached, source: null};
let url = null, source = null;
for (const src of this.sourceOrder()) {
url = await this.fetchFromSource(src, code);
if (url) {
source = src;
break;
}
}
if (url) sessionStorage.setItem(cacheKey, url);
return {url, source};
}
};
let previewOverlay = null;
function showPreviewOverlay(imgUrl, code, source = null) {
if (previewOverlay) {
previewOverlay.close();
}
let currentBlobUrl = null;
const originalHtmlOverflow = document.documentElement.style.overflow;
const originalBodyOverflow = document.body.style.overflow;
document.documentElement.style.overflow = 'hidden';
document.body.style.overflow = 'hidden';
const container = document.createElement('div');
container.className = 'jhs-preview-overlay';
const img = document.createElement('img');
img.src = imgUrl;
img.className = 'jhs-preview-img';
img.onclick = (e) => {
e.stopPropagation();
img.classList.toggle('zoomed');
};
img.onerror = () => {
img.src = imgUrl;
};
const toolbar = document.createElement('div');
toolbar.className = 'jhs-preview-toolbar';
const createButton = (text, className, onClick) => {
const btn = document.createElement('button');
btn.className = `jhs-preview-btn ${className}`;
btn.textContent = text;
btn.onclick = onClick;
return btn;
};
const setActiveSource = (activeSource) => {
toolbar.querySelectorAll('.jhs-preview-btn').forEach(b => b.classList.remove('active'));
const activeBtn = toolbar.querySelector(`.jhs-preview-btn-${activeSource}`);
if (activeBtn) activeBtn.classList.add('active');
};
const changeSource = async (src, srcName) => {
const loadingOverlay = document.createElement('div');
loadingOverlay.className = 'jhs-loading-overlay';
loadingOverlay.innerHTML = '<div class="jhs-loading-spinner"><div class="spinner"></div><div>正在加载预览图...</div></div>';
document.body.appendChild(loadingOverlay);
try {
const newUrl = src === 'javfree' ? await Thumbnail.javfree(code)
: src === 'projectjav' ? await Thumbnail.projectjav(code)
: await Thumbnail.javstore(code);
if (newUrl) {
if (currentBlobUrl) {
URL.revokeObjectURL(currentBlobUrl);
currentBlobUrl = null;
}
img.src = newUrl;
setActiveSource(src);
} else {
showToast(`${srcName} 未找到预览图`, 'error');
}
} catch (err) {
showToast(`${srcName} 加载失败: ${err.message}`, 'error');
} finally {
loadingOverlay.remove();
}
};
let toastTimer = null;
const showToast = (msg, type = 'info') => {
const existing = container.querySelector('.jhs-preview-toast');
if (existing) existing.remove();
if (toastTimer) clearTimeout(toastTimer);
const toast = document.createElement('div');
toast.className = `jhs-preview-toast jhs-preview-toast-${type}`;
toast.textContent = msg;
container.appendChild(toast);
requestAnimationFrame(() => toast.classList.add('show'));
toastTimer = setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 3000);
};
const javfreeBtn = createButton('javfree', 'jhs-preview-btn-javfree javfree', (e) => {
e.stopPropagation();
changeSource('javfree', 'javfree');
});
const projectjavBtn = createButton('projectjav', 'jhs-preview-btn-projectjav projectjav', (e) => {
e.stopPropagation();
changeSource('projectjav', 'projectjav');
});
const javstoreBtn = createButton('javstore', 'jhs-preview-btn-javstore javstore', (e) => {
e.stopPropagation();
changeSource('javstore', 'javstore');
});
const newWindowBtn = createButton('新窗口打开', 'jhs-preview-btn-action action', (e) => {
e.stopPropagation();
window.open(img.src);
});
const downloadBtn = createButton('下载', 'jhs-preview-btn-action action', (e) => {
e.stopPropagation();
const a = document.createElement('a');
a.href = img.src;
a.download = `${code}.jpg`;
a.click();
});
toolbar.appendChild(javfreeBtn);
toolbar.appendChild(projectjavBtn);
toolbar.appendChild(javstoreBtn);
toolbar.appendChild(newWindowBtn);
toolbar.appendChild(downloadBtn);
if (source === 'javfree') setActiveSource('javfree');
else if (source === 'projectjav') setActiveSource('projectjav');
else if (source === 'javstore') setActiveSource('javstore');
else setActiveSource('javfree');
container.appendChild(img);
const closeOverlay = () => {
if (container.parentNode) {
container.remove();
toolbar.remove();
document.documentElement.style.overflow = originalHtmlOverflow;
document.body.style.overflow = originalBodyOverflow;
if (currentBlobUrl) {
URL.revokeObjectURL(currentBlobUrl);
currentBlobUrl = null;
}
}
};
container.onclick = closeOverlay;
const escHandler = (e) => {
if (e.key === 'Escape') {
closeOverlay();
document.removeEventListener('keydown', escHandler);
}
};
document.addEventListener('keydown', escHandler);
document.body.appendChild(container);
document.body.appendChild(toolbar);
previewOverlay = {container, toolbar, close: closeOverlay};
}
class ScreenShotPlugin extends BasePlugin {
getName() {
return "ScreenShotPlugin";
}
async handle() {
this.loadScreenShot().then();
}
async loadScreenShot() {
if (!window.isDetailPage) return;
if ("yes" !== await storageManager.getSetting("enableLoadScreenShot", "yes")) return;
let carNum2 = this.getPageInfo().carNum;
isJavDb && $(".preview-images .tile-item").first().before(' <a class="tile-item screen-container" style="overflow:hidden;max-height: 215px;text-align:center;"><div style="margin-top: 50px;color: #000;cursor: auto">正在加载缩略图</div></a> ');
isJavBus && $("#sample-waterfall .sample-box:first").after(' <a class="sample-box screen-container" style="overflow:hidden; height: 110px; text-align:center;"><div style="margin-top: 30px;color: #000;cursor: auto">正在加载缩略图</div></a> ');
isJavDb && $(".preview-images .tile-item").first().before(
'<a class="tile-item screen-container" style="overflow:hidden;max-height:215px;text-align:center;">' +
'<div style="margin-top:50px;color:#000;cursor:auto">正在加载缩略图</div></a>'
);
isJavBus && $("#sample-waterfall .sample-box:first").after(
'<a class="sample-box screen-container" style="overflow:hidden;height:110px;text-align:center;">' +
'<div style="margin-top:30px;color:#000;cursor:auto">正在加载缩略图</div></a>'
);
try {
const imgUrl = await this.getScreenshot(carNum2);
this.addImg("缩略图", imgUrl);
clog.log("加载缩略图:", imgUrl);
const result = await Thumbnail.get(carNum2);
if (result.url) {
this.addImg("缩略图", result.url, carNum2, result.source);
clog.log("加载缩略图:", result.url, result.source);
} else {
this.showErrorFallback(carNum2, new Error("所有来源均未找到预览图"));
}
} catch (e) {
this.showErrorFallback(carNum2, e);
}
}
async getScreenshot(carNum2) {
const cacheData = localStorage.getItem("jhs_screenShot") ? JSON.parse(localStorage.getItem("jhs_screenShot")) : {};
if (cacheData[carNum2]) {
clog.debug("缓存中存在缩略图:", carNum2, cacheData[carNum2]);
return cacheData[carNum2];
}
let imgUrl;
try {
imgUrl = await Promise.any([ this.getJavStoreScreenShot(carNum2) ]);
} catch (e) {
clog.error("获取缩略图资源失败:", imgUrl, e);
throw e;
}
if (!imgUrl) {
this.showErrorFallback(carNum2, null);
return null;
}
const httpsIndex = imgUrl.indexOf("https://");
-1 !== httpsIndex && (imgUrl = imgUrl.substring(httpsIndex));
cacheData[carNum2] = imgUrl;
clog.log("缩略图获取成功:", imgUrl);
localStorage.setItem("jhs_screenShot", JSON.stringify(cacheData));
return imgUrl;
const result = await Thumbnail.get(carNum2);
if (result.url) return result.url;
throw new Error("未找到预览图");
}
async getJavStoreScreenShot(carNum2) {
let url = `https://javstore.net/search/${carNum2}.html`;
clog.log("正在解析缩略图:", url);
let html = await gmHttp.get(url);
const $dom = utils.htmlTo$dom(html);
let detailPageUrl = null;
$dom.find("#content_news h3 span a").each((function() {
if ($(this).attr("title").toLowerCase().includes(carNum2.toLowerCase())) {
detailPageUrl = $(this).attr("href");
return !1;
}
}));
if (!detailPageUrl) {
clog.error("JavStore, 查询番号失败:", url);
return null;
}
let detailPageHtml = await gmHttp.get(detailPageUrl);
const $detailPageDom = utils.htmlTo$dom(detailPageHtml);
let imgUrl = $detailPageDom.find("a:contains('CLICK HERE')").attr("href") || $detailPageDom.find("img[src*='_s.jpg']").attr("src");
if (!imgUrl) {
clog.error("JavStore, 解析预览图失败:", url);
return null;
}
return imgUrl.replace(".th", "");
}
async getJavBestScreenShot(carNum2) {
let url = `https://javbest.net/?s=${carNum2}`;
clog.log("正在解析缩略图:", url);
let html = await gmHttp.get(url);
const $dom = utils.htmlTo$dom(html), href = $dom.find(".app_loop_thumb a").first().attr("href");
if (!href) {
clog.error("解析JavBest搜索页失败:", url);
throw new Error("解析JavBest搜索页失败");
}
const title = $dom.find(".app_loop_thumb a").first().attr("title");
if (!title.toLowerCase().includes(carNum2.toLowerCase())) {
clog.error("解析JavBest搜索页失败:", title);
throw new Error("解析JavBest搜索页失败");
}
const detailPageHtml = await gmHttp.get(href);
let imgUrl = $(detailPageHtml).find('#content a img[src*="_t.jpg"]').attr("src");
if (!imgUrl) {
clog.error("解析JavBest缩略图失败:", url);
throw new Error("解析JavBest缩略图失败");
}
imgUrl = imgUrl.replace("_t", "").replace("http:", "https:");
return imgUrl;
return await Thumbnail.javstore(carNum2);
}
async getJavFreeScreenShot(carNum2) {
let url = `https://javfree.me/search/${carNum2}/`, html = await gmHttp.get(url);
const $itemList = utils.htmlTo$dom(html).find("article h2.entry-title a");
if (!$itemList || 0 === $itemList.length) {
clog.error("解析JavFree搜索页失败:", url);
throw new Error("解析JavFree搜索页失败");
}
let detailPageUrl = $($itemList[0]).attr("href"), detailPageHtml = await gmHttp.get(detailPageUrl);
const $imgList = utils.htmlTo$dom(detailPageHtml).find("#main > article > .entry-content > p img");
if (!$imgList || 0 === $imgList.length) {
clog.error("解析JavFree详情页失败:", detailPageUrl);
throw new Error("解析JavFree详情页失败");
}
const srcList = $imgList.filter((function() {
const src = $(this).attr("src");
return src && src.toLowerCase().endsWith(".jpeg");
})).map((function() {
return $(this).attr("src");
})).get();
console.log(srcList);
return srcList.at(-1);
return await Thumbnail.javfree(carNum2);
}
addImg(title, imgUrl) {
if (imgUrl) {
isJavDb && $(".screen-container").html(`<img src="${imgUrl}" alt="${title}" loading="lazy" style="width: 100%;">`);
isJavBus && $(".screen-container").html(`<div class="photo-frame"><img src="${imgUrl}" style="height: inherit;width: 100%;" title="${title}" alt="${title}"></div>`);
$(".screen-container").on("click", (event => {
event.stopPropagation();
event.preventDefault();
showImageViewer(event.currentTarget);
}));
}
addImg(title, imgUrl, code, source) {
if (!imgUrl) return;
isJavDb && $(".screen-container").html(
`<img src="${imgUrl}" alt="${title}" loading="lazy" style="width:100%;">`
);
isJavBus && $(".screen-container").html(
`<div class="photo-frame"><img src="${imgUrl}" style="height:inherit;width:100%;" title="${title}" alt="${title}"></div>`
);
$(".screen-container").on("click", (event) => {
event.stopPropagation();
event.preventDefault();
showPreviewOverlay(imgUrl, code || title, source);
});
}
showErrorFallback(carNum2, error) {
var _a2;
console.error("获取缩略图失败:", null == (_a2 = null == error ? void 0 : error.message) ? void 0 : _a2.substring(0, 100));
let differentCss = isJavBus ? "margin-top: 30px" : "margin-top: 50px";
$(".screen-container").html(`<div style="${differentCss}; cursor:auto;color:#000;">获取缩略图失败</div><br/><a href='#' class='retry-link'>点击重试</a> 或 <a class="check-link" href='https://javstore.net/search/${carNum2}.html' target='_blank'>前往确认</a>`).off("click", ".retry-link").off("click", ".check-link").on("click", ".retry-link", (async e => {
console.error("获取缩略图失败:", error?.message?.substring?.(0, 100) || error);
let differentCss = isJavBus ? "margin-top:30px" : "margin-top:50px";
$(".screen-container").html(
`<div style="${differentCss};cursor:auto;color:#000;">获取缩略图失败</div>` +
`<br/><a href='#' class='retry-link'>点击重试</a> 或 ` +
`<a class="check-link" href='https://javstore.net/search?q=${encodeURIComponent(carNum2)}' target='_blank'>前往确认</a>`
).off("click", ".retry-link").off("click", ".check-link")
.on("click", ".retry-link", async (e) => {
e.stopPropagation();
e.preventDefault();
$(".screen-container").html(`<div style="${differentCss};cursor:auto;color:#000;">正在重新加载...</div>`);
$(".screen-container").html(
`<div style="${differentCss};cursor:auto;color:#000;">正在重新加载...</div>`
);
try {
const imgUrl = await this.getScreenshot(carNum2);
this.addImg("缩略图", imgUrl);
const result = await Thumbnail.get(carNum2);
if (result.url) {
this.addImg("缩略图", result.url, carNum2, result.source);
} else {
this.showErrorFallback(carNum2, new Error("所有来源均未找到预览图"));
}
} catch (err) {
this.showErrorFallback(carNum2, err);
}
})).on("click", ".check-link", (async e => {
}).on("click", ".check-link", (e) => {
e.stopPropagation();
e.preventDefault();
window.open(`https://javstore.net/search/${carNum2}.html`, "_blank");
}));
window.open(`https://javstore.net/search?q=${encodeURIComponent(carNum2)}`, "_blank");
});
}
}
export { ScreenShotPlugin };
export {ScreenShotPlugin, Thumbnail, showPreviewOverlay};
window.showPreviewOverlay = showPreviewOverlay;