// ==UserScript==
// @name 豆瓣资源下载大师:1秒搞定豆瓣电影|图书|音乐下载(精简重构版)
// @namespace http://tampermonkey.net/
// @version 4.1.1
// @description 合并自「豆瓣电影网盘资源自动搜索」与「在豆瓣读书显示 Z-Library 书籍」,剔除原版海量失效死链与 jQuery 依赖。新增豆瓣音乐全网下载试听与无感复制,并修复了 IMDb 评分展示等体验。
// @author Tim (Fixed by AI)
// @match https://movie.douban.com/subject/*
// @match https://book.douban.com/subject/*
// @match https://music.douban.com/subject/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_setClipboard
// @connect *
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// ==========================================
// 通用辅助函数
// ==========================================
function getDoc(url, callback, errorCallback) {
GM_xmlhttpRequest({
method: 'GET', url: url, withCredentials: true,
onload: function (responseDetail) {
let resText = responseDetail.responseText;
if (responseDetail.status === 503 || responseDetail.status === 403 || resText.includes("Checking your browser") || resText.includes("Just a moment")) {
if (errorCallback) errorCallback("captcha"); return;
}
if (responseDetail.status === 200 || responseDetail.status === 404) {
callback((new DOMParser()).parseFromString(resText, 'text/html'), responseDetail);
} else {
if (errorCallback) errorCallback("error");
}
},
onerror: function () { if (errorCallback) errorCallback("error"); }
});
}
// ==========================================
// 第一模块:豆瓣电影(网盘搜索 + IMDb评分)
// ==========================================
function initMovieScript() {
// 样式注入
GM_addStyle(`
.douban-pan-search { margin-bottom: 30px; padding: 15px; background: #f8fcf8; border-radius: 4px; border: 1px solid #e2ece2; }
.douban-pan-search h2 { color: #007722; margin: 0 0 10px 0; font-size: 15px; border-bottom: 1px dashed #dddddd; padding-bottom: 5px; }
.pan-search-loading { color: #666; font-size: 13px; }
.pan-item { margin: 8px 0; font-size: 13px; display: flex; align-items: center; }
.pan-item a { color: #3377aa; text-decoration: none; max-width: 170px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-right: 5px; }
.pan-item a:hover { color: #ffffff; background-color: #3377aa; }
.pan-tag { display: inline-block; padding: 2px 5px; border-radius: 2px; font-size: 11px; margin-right: 5px; color: #fff; flex-shrink: 0; }
.tag-ali { background-color: #ff6a00; }
.tag-baidu { background-color: #06a7ff; }
.tag-quark { background-color: #00b4ff; }
.tag-other { background-color: #999; }
.pan-pwd { margin-left: 5px; color: #e74c3c; font-family: monospace; cursor: pointer; flex-shrink: 0; }
/* 评分增强区域样式 */
.imdb-badge { color: #e5a826; font-weight: bold; margin-left: 5px; text-decoration: none; font-size: 13px; }
.imdb-badge:hover { color: #d19720; }
.imdb-votes { color: #999; font-size: 11px; margin-left: 4px; }
`);
// 提取豆瓣电影信息
let titleNode = document.querySelector('h1 span[property="v:itemreviewed"]');
if (!titleNode) return;
let rawTitle = titleNode.innerText.trim();
let mainTitle = rawTitle.split(' ')[0]; // 取冒号或空格前的主标题
// 构建侧边栏面板
let aside = document.querySelector('.aside');
if (!aside) return;
let panel = document.createElement('div');
panel.className = 'douban-pan-search';
panel.innerHTML = `
☁️ 网盘资源检索
🔄 正在拦截全网《${mainTitle}》的分享链接...
`;
aside.insertBefore(panel, aside.firstChild);
// 请求搜索数据
let container = document.getElementById('pan-results');
let keyword = encodeURIComponent(mainTitle);
let apiUrl = `https://so.252035.xyz/api/search?kw=${keyword}`;
GM_xmlhttpRequest({
method: "GET",
url: apiUrl,
onload: function (response) {
if (response.status === 200) {
try {
let res = JSON.parse(response.responseText);
if (res.code === 0 && res.data && res.data.merged_by_type) {
let results = [];
let merged = res.data.merged_by_type;
let typesToExtract = [
{ key: 'ali', label: 'ali' },
{ key: 'quark', label: 'quark' },
{ key: 'baidu', label: 'baidu' },
{ key: 'xunlei', label: 'other' }
];
typesToExtract.forEach(t => {
let list = merged[t.key] || [];
list.slice(0, 3).forEach(item => {
results.push({ name: item.note || '未命名资源', url: item.url, type: t.label, pwd: item.password || '' });
});
});
renderPanResults(results, container);
} else {
renderPanResults([], container);
}
} catch (e) {
container.innerHTML = '⚠️ 数据解析失败,接口可能变更。 ';
}
} else {
container.innerHTML = `⚠️ 请求聚合服务器失败 (${response.status})。 `;
}
},
onerror: function () {
container.innerHTML = '⚠️ 网络请求异常,请检查跨域配置。 ';
}
});
// 附加:解析 IMDb 评分展示(原版豆瓣下载大师核心亮点)
let infoDiv = document.getElementById('info');
if (infoDiv) {
let imdbMatch = infoDiv.innerText.match(/IMDb:?\s*(tt\d+)/);
if (imdbMatch && imdbMatch[1]) {
fetchImdbRating(imdbMatch[1]);
}
}
}
function renderPanResults(results, container) {
if (!results || results.length === 0) {
container.innerHTML = '⚠️ 抱歉,未找到直接匹配的高清网盘资源。 ';
return;
}
let html = '';
results.forEach(res => {
let tagClass = 'tag-other', tagText = '其他';
if (res.type === 'ali') { tagClass = 'tag-ali'; tagText = '阿里'; }
else if (res.type === 'baidu') { tagClass = 'tag-baidu'; tagText = '百度'; }
else if (res.type === 'quark') { tagClass = 'tag-quark'; tagText = '夸克'; }
let pwdHtml = res.pwd ? `🔑 ${res.pwd} ` : '';
html += `
`;
});
container.innerHTML = html;
}
function fetchImdbRating(imdbId) {
let infoDiv = document.getElementById('info');
if (!infoDiv) return;
let imdbUrl = 'https://www.imdb.com/title/' + imdbId + '/';
getDoc(imdbUrl, function (doc) {
try {
let rating = '', votes = '';
// 解析方法 1: 新一代 IMDb Next.js JSON 数据
let nextData = doc.querySelector('script#__NEXT_DATA__');
if (nextData) {
try {
let data = JSON.parse(nextData.innerHTML);
let aboveTheFold = data.props.pageProps.aboveTheFoldData;
rating = aboveTheFold.ratingsSummary.aggregateRating;
votes = aboveTheFold.ratingsSummary.voteCount;
} catch (e) { }
}
// 解析方法 2: 传统的 ld+json
if (!rating) {
let ldJson = doc.querySelector('script[type="application/ld+json"]');
if (ldJson) {
try {
let data = JSON.parse(ldJson.innerText);
if (data.aggregateRating) {
rating = data.aggregateRating.ratingValue;
votes = data.aggregateRating.ratingCount;
}
} catch (e) { }
}
}
// 解析方法 3: 直接查找 DOM
if (!rating) {
let ratingEl = doc.querySelector('[data-testid="hero-rating-bar__aggregate-rating__score"] span');
if (ratingEl) { rating = ratingEl.innerText; }
let voteEl = doc.querySelector('.kn-1x1-stars span.bYitIg, div[data-testid="hero-rating-bar__aggregate-rating__score"] ~ div:last-child');
if (voteEl) { votes = voteEl.innerText; }
}
if (rating) {
let badge = document.createElement('span');
badge.innerHTML = ` ⭐ ${rating} (${votes}人评价) `;
let imdbSpan = Array.from(infoDiv.querySelectorAll('span.pl')).find(el => el.innerText.includes('IMDb'));
if (imdbSpan && imdbSpan.nextSibling) {
imdbSpan.parentNode.insertBefore(badge, imdbSpan.nextSibling.nextSibling);
} else {
infoDiv.appendChild(badge);
}
}
} catch (e) {
console.warn("解析 IMDb 失败", e);
}
});
}
// ==========================================
// 第二模块:豆瓣读书 (Z-Library 搜索)
// ==========================================
const ZLIB_DOMAIN = "https://zlib.im";
function initBookScript() {
GM_addStyle(`
/* Z-lib 样式 */
.zlib-status-btn { display: inline-block; margin-top: 5px; color: #42bd56 !important; background: #f0f9f2; padding: 4px 8px; border-radius: 4px; font-size: 12px; text-decoration: none !important; }
.zlib-status-btn:hover { background: #e2f4e5; }
.zlib-dl-btn { margin-left: 8px; padding: 2px 10px; background: #e8ecef; color: #37a !important; border-radius: 2px; font-size: 12px; text-decoration: none !important; transition: all 0.2s; }
.zlib-dl-btn:hover { background: #37a !important; color: #fff !important; }
`);
// 清理原有广告
let ad = document.getElementById('dale_book_subject_top_right');
if (ad && ad.parentNode) ad.parentNode.removeChild(ad);
let wrapper = document.getElementById('wrapper');
if (!wrapper) return;
let subTitleSpan = wrapper.querySelector('h1 span');
if (!subTitleSpan) return;
// 提取检索关键字(优先 ISBN)
let isbn = '';
let infoDiv = document.getElementById('info');
if (infoDiv) {
let isbnMatch = infoDiv.innerText.match(/ISBN[::\s]*(\d[\d-]{9,}[\dXx])/);
if (isbnMatch) isbn = isbnMatch[1].replace(/-/g, '');
}
let rawTitle = subTitleSpan.innerHTML.trim();
let cleanTitle = rawTitle.replace(/[\((【\[].*?[\]】)\)]/g, '').trim() || rawTitle;
let searchTerm = isbn || cleanTitle;
let searchLabel = isbn ? `ISBN: ${isbn}` : cleanTitle;
// 挂载侧边栏容器
let aside = document.getElementsByClassName('aside')[0];
if (aside) {
let doc = new DOMParser().parseFromString(`Z-Library 电子书 · · · · · · 正在获取资源 (${searchLabel})...
`, "text/html");
aside.prepend(doc.body.firstChild);
}
let url = `${ZLIB_DOMAIN}/s/${encodeURIComponent(searchTerm)}`;
loadZlibData(url, url); // url twice for reference logic
}
function loadZlibData(url, currentSearchUrl) {
getDoc(url, function (doc) {
let zlibContainer = document.getElementById('zlib');
if (!zlibContainer) return;
zlibContainer.innerHTML = '';
let ele = doc.getElementById('searchResultBox');
if (!ele) {
zlibContainer.innerHTML = `Z-Library · · · · · · `;
return;
}
let items = ele.querySelectorAll('.resItemBox, .resItemBoxBooks, .book-item');
let totalCounterEl = doc.querySelector('.totalCounter, z-bookterms');
let totalCounter = '0';
if (totalCounterEl) {
let match = (totalCounterEl.innerText || totalCounterEl.innerHTML || '').match(/\d+/);
if (match) totalCounter = match[0];
}
if (totalCounter === '0' && items.length > 0) totalCounter = items.length.toString();
zlibContainer.innerHTML = `
`;
let filterItemsNum = 0;
// 解析 Z-Library 数据(兼容旧版 DOM 和 新版 Z-BookCard WebComponent)
for (let i = 0; i < items.length && filterItemsNum < 5; i++) {
try {
let currentItem = items[i];
if (currentItem.classList.contains('booklist')) continue;
let bookName = '', link = '', publisher = '', author = '', year = '', file = '', img = '', dlLink = '';
let zCard = currentItem.querySelector('z-bookcard');
if (zCard) { // 新版 DOM
link = zCard.getAttribute('href') || '';
if (!link) continue;
let titleSlot = zCard.querySelector('[slot="title"]');
bookName = titleSlot ? titleSlot.innerText.trim() : '';
let authorSlot = zCard.querySelector('[slot="author"]');
author = authorSlot ? authorSlot.innerText.trim() : '';
publisher = zCard.getAttribute('publisher') || '';
year = zCard.getAttribute('year') || '';
let ext = zCard.getAttribute('extension') || '';
let size = zCard.getAttribute('filesize') || '';
file = (ext && size) ? `${ext.toUpperCase()}, ${size}` : (ext || size);
let dlAttr = zCard.getAttribute('download');
if (dlAttr) dlLink = ZLIB_DOMAIN + dlAttr;
let imgEl = zCard.querySelector('img');
img = imgEl ? imgEl.outerHTML.replace('data-src', 'src') : '';
} else { // 旧版 DOM
let titleLink = currentItem.querySelector('h3 a[itemprop="url"]') || currentItem.querySelector('a[style*="text-decoration: underline"]');
if (!titleLink) {
let trs = currentItem.getElementsByTagName('td');
if (trs.length > 2) titleLink = trs[2].querySelector('a');
}
if (!titleLink) continue;
bookName = titleLink.innerText.trim();
link = titleLink.getAttribute("href");
let authorArr = [];
currentItem.querySelectorAll('td a').forEach(aTag => {
let text = aTag.innerText.trim();
if (aTag.getAttribute('title') === 'Publisher') publisher = text;
else if (aTag.getAttribute('itemprop') === 'author') authorArr.push(text);
});
author = authorArr.join(', ');
let imgEl = currentItem.querySelector('img.cover') || currentItem.querySelector('img.itemCover');
img = imgEl ? imgEl.outerHTML.replace('data-src', 'src') : '';
let yearEl = currentItem.querySelector('.property_year .property_value');
if (yearEl) year = yearEl.innerText.trim();
let fileEl = currentItem.querySelector('.property__file .property_value');
if (fileEl) file = fileEl.innerText.trim();
let dlNode = currentItem.querySelector('a[href^="/dl/"]');
if (dlNode) dlLink = ZLIB_DOMAIN + dlNode.getAttribute('href');
}
let infos = [publisher, author, file].filter(Boolean);
let downloadBtnHtml = dlLink ? `⬇ 下载 ` : '';
let itemHtml = `
${img}
${bookName} ${year ? '(' + year + ')' : ''}
${infos.join(' ')}
${downloadBtnHtml}
`;
zlibContainer.insertAdjacentHTML('beforeend', itemHtml);
filterItemsNum++;
} catch (innerErr) { console.warn("解析跳过异常项", innerErr); }
}
let filterNumEl = document.getElementById('filterItemsNum');
if (filterNumEl) filterNumEl.innerHTML = filterItemsNum;
if (filterItemsNum === 0) {
zlibContainer.innerHTML = `Z-Library (0) · · · · · · (去原站确认 ) 未提取到有效单本书籍(结果可能都是文章片段或书单聚合),请手动查询。
`;
} else {
let images = zlibContainer.getElementsByTagName('img');
for (let i = 0; i < images.length; i++) {
images[i].setAttribute('width', '50px');
images[i].setAttribute('referrerpolicy', 'no-referrer');
}
if (items.length > 5) {
zlibContainer.insertAdjacentHTML('beforeend', ``);
}
}
}, function (err) {
let zlibStatus = document.getElementById('zlib-status');
if (!zlibStatus) return;
if (err === "captcha") {
zlibStatus.innerHTML = `提示:Z-Library 开启了防机器人保护。
为正常显示电子书,请按照以下步骤证明您是真人:
↗ 1. 点击去 Z-lib 验证一下
↻ 2. 验证后点我重新加载 `;
document.getElementById('zlib-btn-retry').onclick = () => {
zlibStatus.innerHTML = "正在重新获取资源...";
loadZlibData(url, currentSearchUrl);
};
document.getElementById('zlib-btn-gocheck').onclick = () => {
let focusHandler = () => {
let st = document.getElementById('zlib-status');
if (st && st.innerHTML.includes('拦截')) {
st.innerHTML = "检测到您已返回,正在自动重试...";
loadZlibData(url, currentSearchUrl);
}
window.removeEventListener('focus', focusHandler);
};
setTimeout(() => { window.addEventListener('focus', focusHandler); }, 2000);
};
} else {
zlibStatus.innerHTML = `网络失败。该镜像域名可能被阻断。 ↗ 尝试手动打开新窗口搜索 `;
}
});
}
// ==========================================
// 第三模块:豆瓣音乐 (聚合搜索跳转)
// ==========================================
function initMusicScript() {
GM_addStyle(`
.douban-music-search { margin-bottom: 20px; padding: 15px; background: #f4f8fb; border-radius: 4px; border: 1px solid #e1eaf2; }
.douban-music-search h2 { color: #1f6b9c; margin: 0 0 12px 0; font-size: 15px; border-bottom: 1px dashed #d0dcea; padding-bottom: 6px; }
.music-category { margin-bottom: 8px; font-weight: bold; color: #555; font-size: 13px; }
.music-btn-group { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.music-btn { padding: 4px 10px; font-size: 12px; border-radius: 3px; text-decoration: none !important; transition: all 0.2s; color: #fff !important; }
.music-btn:hover { opacity: 0.85; }
.btn-mp3 { background-color: #ff6a00; }
.btn-listen { background-color: #00b4ff; }
.btn-app { background-color: #607d8b; }
.btn-tg { background-color: #2ca5e0; }
`);
// 获取页面上的专辑标题和歌手名称
let wrapper = document.getElementById('wrapper');
if (!wrapper) return;
let titleSpan = wrapper.querySelector('h1 span');
if (!titleSpan) return;
let rawTitle = titleSpan.innerText.trim();
// 提取前缀作为主标题(过滤掉 'EP', 'Remastered' 等括号内容)
let cleanTitle = rawTitle.replace(/[\((【\[].*?[\]】)\)]/g, '').trim();
// 尝试从 info 区域提取歌手名字
let artist = '';
let infoDiv = document.getElementById('info');
if (infoDiv) {
let artistSpan = infoDiv.querySelector('span.pl a');
if (artistSpan) {
artist = artistSpan.innerText.trim();
} else {
let artistMatch = infoDiv.innerText.match(/(表演者|歌手)[\s::]*([^\n]*)/);
if (artistMatch) artist = artistMatch[2].trim().split('/')[0].trim();
}
}
// 组成搜索关键词,如果是非常长的标题,通常只搜歌手+前几个字最精准
let keyword = cleanTitle;
if (artist && !cleanTitle.includes(artist)) {
keyword = artist + ' ' + cleanTitle;
}
let encodeKw = encodeURIComponent(keyword);
let safeKeyword = keyword; // addEventListener中直接使用变量,无需转义
// 构建侧边栏面板
let aside = document.querySelector('.aside');
if (!aside) return;
let panel = document.createElement('div');
panel.className = 'douban-music-search';
panel.innerHTML = `
🎵 音乐下载 · 在线试听
⚡ MP3 极速下载站
🎧 无损源 / 试听引擎
⚙️ 全网聚合网页版 (需手搜)
* 💡 提示: 点击带 (需手搜) 的按钮,将为您自动复制歌曲名!
`;
aside.insertBefore(panel, aside.firstChild);
// 为需要手动搜索的按钮绑定自动复制事件(必须在JS上下文中绑定,不能用内联onclick避免跨沙箱权限不足)
let copyBtns = panel.querySelectorAll('.btn-copy-kw');
copyBtns.forEach(btn => {
btn.addEventListener('click', function () {
GM_setClipboard(safeKeyword, 'text');
});
});
// 增加内嵌极简播放器功能: 尝试通过网易云接口搜索并获取第一首歌曲的ID
GM_xmlhttpRequest({
method: 'POST',
url: 'https://music.163.com/api/search/get/web',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': 'https://music.163.com/'
},
data: 's=' + encodeKw + '&type=1&offset=0&total=true&limit=1',
onload: function (response) {
try {
let res = JSON.parse(response.responseText);
if (res.code === 200 && res.result && res.result.songs && res.result.songs.length > 0) {
let songId = res.result.songs[0].id;
let playerContainer = document.getElementById('douban-music-player-container');
if (playerContainer) {
playerContainer.style.display = 'block';
// 改用原生 audio 标签结合外链直达接口,并增加 onerror 容错防盗链及无版权提示
playerContainer.innerHTML =
' ' +
'⚠️ 该首歌曲受版权保护,暂无法提供直接试听。请使用下方按钮跳转收听。
';
}
}
} catch (e) {
console.log('Douban Master: Failed to load netease music iframe', e);
}
}
});
}
// ==========================================
// 主入口
// ==========================================
if (location.host === 'movie.douban.com') {
setTimeout(initMovieScript, 500);
} else if (location.host === 'book.douban.com') {
setTimeout(initBookScript, 500);
} else if (location.host === 'music.douban.com') {
setTimeout(initMusicScript, 500);
}
})();