此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/438042/1005207/Douban%20Info%20Class.js
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name Douban Info Class
// @description parse douban info
// @version 0.0.8
// @author Secant(TYT@NexusHD)
// @icon https://movie.douban.com/favicon.ico
// @contributionURL https://i.loli.net/2020/02/28/JPGgHc3UMwXedhv.jpg
// @contributionAmount 10
// @namespace https://greasyfork.org/users/152136
// @grant GM_xmlhttpRequest
// @connect movie.douban.com
class DoubanInfo {
static origin = "https://movie.douban.com";
static subjectPathName = "/subject/";
static timeout = 6000;
constructor(id) {
this.id = (async () => id)();
this.pathname = (async () => DoubanInfo.subjectPathName + id + "/")();
}
get subjectDoc() {
return (async () => {
const currentURL = new URL(window.location.href);
let doc;
if (
currentURL.origin === DoubanInfo.origin &&
currentURL.pathname === (await this.pathname)
) {
doc = document;
} else {
doc = new Promise(async (resolve) => {
GM_xmlhttpRequest({
method: "GET",
url: new URL(await this.pathname, DoubanInfo.origin).toString(),
headers: {
referrer: DoubanInfo.origin,
},
timout: DoubanInfo.timeout,
onload: (resp) => {
try {
resolve(
new DOMParser().parseFromString(
resp.responseText,
"text/html"
)
);
} catch (err) {
console.warn(err);
resolve(null);
}
},
ontimeout: (e) => {
console.warn(e);
resolve(null);
},
onerror: (e) => {
console.warn(e);
resolve(null);
},
});
});
}
Object.defineProperty(this, "subjectDoc", {
value: (async () => doc)(),
writable: false,
});
return this.subjectDoc;
})();
}
get linkingData() {
return (async () => {
const doc = await this.subjectDoc;
const ldJSON =
dJSON.parse(
heDecode(
doc?.querySelector("head>script[type='application/ld+json']")
?.textContent
)
) || null;
Object.defineProperty(this, "linkingData", {
value: (async () => ldJSON)(),
writable: false,
});
return this.linkingData;
})();
}
get title() {
return (async () => {
const doc = await this.subjectDoc;
const ld = await this.linkingData;
const titleFromPage =
doc?.querySelector("body #content h1>span[property]")?.textContent ||
null;
const titleFromMeta =
doc?.querySelector("head>meta[property='og:title']")?.content || null;
const titleFromLD = ld?.name || null;
const title = titleFromPage || titleFromMeta || titleFromLD;
Object.defineProperty(this, "title", {
value: (async () => title)(),
writable: false,
});
return this.title;
})();
}
get type() {
return (async () => {
const ld = await this.linkingData;
const type = ld?.["@type"]?.toLowerCase() || null;
Object.defineProperty(this, "type", {
value: (async () => type)(),
writable: false,
});
return this.type;
})();
}
get poster() {
return (async () => {
const doc = await this.subjectDoc;
const poster =
doc
?.querySelector("head>meta[property='og:image']")
?.content.replace("s_ratio_poster", "l_ratio_poster") || null;
Object.defineProperty(this, "poster", {
value: (async () => poster)(),
writable: false,
});
return this.poster;
})();
}
get duration() {
return (async () => {
const doc = await this.subjectDoc;
const ld = await this.linkingData;
const durationFromMeta =
parseInt(
doc?.querySelector("head>meta[property='video:duration']")?.content,
10
) || null;
const durationFromLD =
ld?.duration.replace(
/^PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/,
(_, p1, p2, p3) => {
return (
parseInt(p1, 10) * 3600 +
parseInt(p2, 10) * 60 +
parseInt(p3, 10)
).toString();
}
) || null;
/*const durationFromPage =*/
const duration = durationFromMeta || durationFromLD;
Object.defineProperty(this, "duration", {
value: (async () => duration)(),
writable: false,
});
return this.duration;
})();
}
}