get_douban_info

辅助auto-feed脚本获取豆瓣信息

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/425243/958866/get_douban_info.js

  1. // ==UserScript==
  2. // @name get_douban_info
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description 辅助auto-feed脚本获取豆瓣信息
  6. // @author tomorrow505
  7. // @match https://passthepopcorn.me/torrents.php?id=238092&torrentid=869948
  8. // @icon https://www.google.com/s2/favicons?domain=passthepopcorn.me
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. const TIMEOUT = 6000;
  13. function getPoster(doc) {
  14. try {
  15. return $('#mainpic img', doc)[0].src.replace(
  16. /^.+(p\d+).+$/,
  17. (_, p1) => `https://img9.doubanio.com/view/photo/l_ratio_poster/public/${p1}.jpg`
  18. );
  19. } catch (e) {
  20. return null;
  21. }
  22. }
  23. function getTitles(doc) {
  24. let isChinese = false;
  25. const chineseTitle = doc.title.replace(/\(豆瓣\)$/, '').trim();
  26. const originalTitle = $('#content h1>span[property]', doc).text().replace(chineseTitle, '').trim() || ((isChinese = true), chineseTitle);
  27. try {
  28. let akaTitles = $('#info span.pl:contains("又名")', doc)[0].nextSibling.textContent.trim().split(' / ');
  29. const transTitle = isChinese ? akaTitles.find(e => {return e.match(/[a-z]/i);}) || chineseTitle: chineseTitle;
  30. const priority = e => {
  31. if (e === transTitle) {
  32. return 0;
  33. }
  34. if (e.match(/\(港.?台\)/)) {
  35. return 1;
  36. }
  37. if (e.match(/\([港台]\)/)) {
  38. return 2;
  39. }
  40. return 3;
  41. };
  42. akaTitles = akaTitles.sort((a, b) => priority(a) - priority(b)).filter(e => e !== transTitle);
  43. return [{
  44. chineseTitle: chineseTitle,
  45. originalTitle: originalTitle,
  46. translatedTitle: transTitle,
  47. alsoKnownAsTitles: akaTitles
  48. },
  49. isChinese
  50. ];
  51. } catch (e) {
  52. return [{
  53. chineseTitle: chineseTitle,
  54. originalTitle: originalTitle,
  55. translatedTitle: chineseTitle,
  56. alsoKnownAsTitles: []
  57. },
  58. isChinese
  59. ];
  60. }
  61. }
  62. function getYear(doc) {
  63. return parseInt($('#content>h1>span.year', doc).text().slice(1, -1));
  64. }
  65. function getRegions(doc) {
  66. try {
  67. return $('#info span.pl:contains("制片国家/地区")', doc)[0].nextSibling.textContent.trim().split(' / ');
  68. } catch (e) {
  69. return [];
  70. }
  71. }
  72. function getGenres(doc) {
  73. try {
  74. return $('#info span[property="v:genre"]', doc).toArray().map(e => e.innerText.trim());
  75. } catch (e) {
  76. return [];
  77. }
  78. }
  79. function getLanguages(doc) {
  80. try {
  81. return $('#info span.pl:contains("语言")', doc)[0].nextSibling.textContent.trim().split(' / ');
  82. } catch (e) {
  83. return [];
  84. }
  85. }
  86. function getReleaseDates(doc) {
  87. try {
  88. return $('#info span[property="v:initialReleaseDate"]', doc).toArray().map(e => e.innerText.trim()).sort((a, b) => new Date(a) - new Date(b));
  89. } catch (e) {
  90. return [];
  91. }
  92. }
  93. function getDurations(doc) {
  94. try {
  95. return $('span[property="v:runtime"]', doc).text();
  96. } catch (e) {
  97. return [];
  98. }
  99. }
  100. function getEpisodeDuration(doc) {
  101. try {
  102. return $('#info span.pl:contains("单集片长")', doc)[0].nextSibling.textContent.trim();
  103. } catch (e) {
  104. return null;
  105. }
  106. }
  107. function getEpisodeCount(doc) {
  108. try {
  109. return parseInt($('#info span.pl:contains("集数")', doc)[0].nextSibling.textContent.trim());
  110. } catch (e) {
  111. return null;
  112. }
  113. }
  114. function getTags(doc) {
  115. return $('div.tags-body>a', doc).toArray().map(e => e.textContent);
  116. }
  117. function getDoubanScore(doc) {
  118. const $interest = $('#interest_sectl', doc);
  119. const ratingAverage = parseFloat(
  120. $interest.find('[property="v:average"]').text()
  121. );
  122. const ratingVotes = parseInt($interest.find('[property="v:votes"]').text());
  123. return {
  124. rating: ratingAverage,
  125. ratingCount: ratingVotes,
  126. ratingHistograms: {
  127. 'Douban Users': {
  128. aggregateRating: ratingAverage,
  129. demographic: 'Douban Users',
  130. totalRatings: ratingVotes
  131. }
  132. }
  133. };
  134. }
  135. function getDescription(doc) {
  136. try {
  137. return Array.from($('#link-report>[property="v:summary"],#link-report>span.all.hidden', doc)[0].childNodes)
  138. .filter(e => e.nodeType === 3)
  139. .map(e => e.textContent.trim())
  140. .join('\n');
  141. } catch (e) {
  142. return null;
  143. }
  144. }
  145. function addComma(x) {
  146. var parts = x.toString().split(".");
  147. parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  148. return parts.join(".");
  149. }
  150. function getDirector(doc) {
  151. try{
  152. return $('#info span.pl:contains("导演")', doc)[0].nextSibling.nextSibling.textContent.trim().split(' / ');
  153. } catch (err) {
  154. return [];
  155. }
  156. }
  157. function getWriters(doc) {
  158. try{
  159. return $('#info span.pl:contains("编剧")', doc)[0].nextSibling.nextSibling.textContent.trim().split(' / ');
  160. } catch (err) {
  161. return [];
  162. }
  163. }
  164. function getCasts(doc) {
  165. try{
  166. return $('#info span.pl:contains("主演")', doc)[0].nextSibling.nextSibling.textContent.trim().split(' / ');
  167. } catch (err) {
  168. return [];
  169. }
  170. }
  171. async function getIMDbScore(ID, timeout = TIMEOUT) {
  172. if (ID) {
  173. return new Promise(resolve => {
  174. GM_xmlhttpRequest({
  175. method: 'GET',
  176. url: `http://p.media-imdb.com/static-content/documents/v1/title/tt${ID}/ratings%3Fjsonp=imdb.rating.run:imdb.api.title.ratings/data.json`,
  177. headers: {
  178. referrer: 'http://p.media-imdb.com/'
  179. },
  180. timout: timeout,
  181. onload: x => {
  182. try {
  183. const e = JSON.parse(x.responseText.slice(16, -1));
  184. resolve(e.resource);
  185. } catch (e) {
  186. console.warn(e);
  187. resolve(null);
  188. }
  189. },
  190. ontimeout: e => {
  191. console.warn(e);
  192. resolve(null);
  193. },
  194. onerror: e => {
  195. console.warn(e);
  196. resolve(null);
  197. }
  198. });
  199. });
  200. } else {
  201. return null;
  202. }
  203. }
  204. async function getIMDbID(doc) {
  205. try {
  206. return $('#info span.pl:contains("IMDb:")', doc).parent().text().match(/tt(\d+)/)[1];
  207. } catch (e) {
  208. return null;
  209. }
  210. }
  211. async function getCelebrities(doubanid, timeout = TIMEOUT) {
  212. var awardurl = 'https://movie.douban.com/subject/{a}/celebrities/'.format({'a': doubanid});
  213. return new Promise(resolve => {
  214. getDoc(awardurl, null, function(doc){
  215. const entries = $('#celebrities>div.list-wrapper', doc).toArray().map(e => {
  216. const [positionChinese, positionForeign] = $(e).find('h2').text().match(/([^ ]*)(?:$| )(.*)/).slice(1, 3);
  217. const people = $(e).find('li.celebrity').toArray().map(e => {
  218. let [nameChinese, nameForeign] = $(e).find('.info>.name').text().match(/([^ ]*)(?:$| )(.*)/).slice(1, 3);
  219. if (!nameChinese.match(/[\u4E00-\u9FCC]/)) {
  220. nameForeign = nameChinese + ' ' + nameForeign;
  221. nameChinese = null;
  222. }
  223. const [roleChinese, roleForeign, character] = $(e).find('.info>.role').text().match(/([^ ]*)(?:$| )([^(]*)(?:$| )(.*)/).slice(1, 4);
  224. return {
  225. name: {
  226. chs: nameChinese,
  227. for: nameForeign
  228. },
  229. role: {
  230. chs: roleChinese,
  231. for: roleForeign
  232. },
  233. character: character.replace(/[()]/g, '')
  234. };
  235. });
  236. return [
  237. positionForeign.toLowerCase(),
  238. {
  239. position: positionChinese,
  240. people: people
  241. }
  242. ];
  243. });
  244. console.log(typeof(entries))
  245. console.log(entries)
  246. if (entries.length) {
  247. // jsonCeleb = Object.fromEntries(entries);
  248. // console.log(jsonCeleb)
  249. jsonCeleb = entries;
  250. } else {
  251. jsonCeleb = null;
  252. }
  253. resolve(jsonCeleb);
  254. });
  255. });
  256. }
  257. async function getAwards(doubanid, timeout = TIMEOUT) {
  258. var awardurl = 'https://movie.douban.com/subject/{a}/awards/'.format({'a': doubanid});
  259. return new Promise(resolve => {
  260. getDoc(awardurl, null, function(doc){
  261. resolve($('div.awards', doc).toArray().map(function(e){
  262. const $title = $(e).find('.hd>h2');
  263. const $awards = $(e).find('.award');
  264. return {
  265. name: $title.find('a').text().trim(),
  266. year: parseInt($title.find('.year').text().match(/\d+/)[0]),
  267. awards: $awards.toArray().map(e => ({
  268. name: $(e).find('li:first-of-type').text().trim(),
  269. people: $(e).find('li:nth-of-type(2)').text().split('/').map(e => e.trim())
  270. }))
  271. };
  272. }));
  273. });
  274. })
  275. }
  276. async function getInfo(doc) {
  277. const [titles, isChinese] = getTitles(doc),
  278. year = getYear(doc),
  279. regions = getRegions(doc),
  280. genres = getGenres(doc),
  281. languages = getLanguages(doc),
  282. releaseDates = getReleaseDates(doc),
  283. durations = getDurations(doc),
  284. episodeDuration = getEpisodeDuration(doc),
  285. episodeCount = getEpisodeCount(doc),
  286. tags = getTags(doc),
  287. DoubanID = raw_info.dburl.match(/subject\/(\d+)/)[1],
  288. DoubanScore = getDoubanScore(doc),
  289. poster = getPoster(doc),
  290. description = getDescription(doc);
  291. directors = getDirector(doc);
  292. writers = getWriters(doc);
  293. casts = getCasts(doc);
  294. let IMDbID, IMDbScore, awards, celebrities;
  295. const concurrentFetches = [];
  296. concurrentFetches.push(
  297. // IMDb Fetch
  298. getIMDbID(doc)
  299. .then(e => {
  300. IMDbID = e;
  301. return getIMDbScore(IMDbID);
  302. })
  303. .then(e => {
  304. IMDbScore = e;
  305. return getAwards(DoubanID);
  306. })
  307. .then(e => {
  308. awards = e;
  309. return getCelebrities(DoubanID);
  310. })
  311. .then(e => {
  312. celebrities = e;
  313. })
  314. );
  315. await Promise.all(concurrentFetches);
  316. if (IMDbScore && IMDbScore.title) {
  317. if (isChinese) {
  318. if (!titles.translatedTitle.includes(IMDbScore.title)) {
  319. titles.alsoKnownAsTitles.push(titles.translatedTitle);
  320. const index = titles.alsoKnownAsTitles.indexOf(IMDbScore.title);
  321. if (index >= 0) {
  322. titles.alsoKnownAsTitles.splice(index, 1);
  323. }
  324. titles.translatedTitle = IMDbScore.title;
  325. }
  326. } else {
  327. if (!titles.originalTitle.includes(IMDbScore.title) &&titles.alsoKnownAsTitles.indexOf(IMDbScore.title) === -1) {
  328. titles.alsoKnownAsTitles.push(IMDbScore.title);
  329. }
  330. }
  331. }
  332. return {
  333. poster: poster,
  334. titles: titles,
  335. year: year,
  336. regions: regions,
  337. genres: genres,
  338. languages: languages,
  339. releaseDates: releaseDates,
  340. durations: durations,
  341. episodeDuration: episodeDuration,
  342. episodeCount: episodeCount,
  343. tags: tags,
  344. DoubanID: DoubanID,
  345. DoubanScore: DoubanScore,
  346. IMDbID: IMDbID,
  347. IMDbScore: IMDbScore,
  348. description: description,
  349. directors: directors,
  350. writers: writers,
  351. casts: casts,
  352. awards: awards,
  353. celebrities: celebrities
  354. };
  355. }
  356. function formatInfo(info) {
  357. let temp;
  358. const infoText = (
  359. (info.poster ? `[img]${info.poster}[/img]\n\n` : '') +
  360. '◎译  名 ' + [info.titles.translatedTitle].concat(info.titles.alsoKnownAsTitles).join(' / ') + '\n' +
  361. '◎片  名 ' + info.titles.originalTitle + '\n' +
  362. '◎年  代 ' + info.year + '\n' +
  363. (info.regions.length ? '◎产  地 ' + info.regions.join(' / ') + '\n' : '') +
  364. (info.genres.length ? '◎类  别 ' + info.genres.join(' / ') + '\n' : '') +
  365. (info.languages.length ? '◎语  言 ' + info.languages.join(' / ') + '\n' : '') +
  366. (info.releaseDates.length ? '◎上映日期 ' + info.releaseDates.join(' / ') + '\n' : '') +
  367. ((info.IMDbScore && info.IMDbScore.rating) ? `◎IMDb评分  ${Number(info.IMDbScore.rating).toFixed(1)}/10 from ${addComma(info.IMDbScore.ratingCount)} users\n` : '') +
  368. (info.IMDbID ? `◎IMDb链接  https://www.imdb.com/title/tt${info.IMDbID}/\n` : '') +
  369. ((info.DoubanScore && info.DoubanScore.rating) ? `◎豆瓣评分 ${info.DoubanScore.rating}/10 from ${addComma(info.DoubanScore.ratingCount)} users\n` : '') +
  370. (info.DoubanID ? `◎豆瓣链接 https://movie.douban.com/subject/${info.DoubanID}/\n` : '') +
  371. ((info.durations && info.durations.length) ? '◎片  长 ' + info.durations + '\n' : '') +
  372. (info.episodeDuration ? '◎单集片长 ' + info.episodeDuration + '\n' : '') +
  373. (info.episodeCount ? '◎集  数 ' + info.episodeCount + '\n' : '') +
  374. (info.celebrities ? info.celebrities.map(e => {
  375. const position = e[1].position;
  376. let title = '◎';
  377. switch (position.length) {
  378. case 1:
  379. title += '   ' + position + '    ';
  380. break;
  381. case 2:
  382. title += position.split('').join('  ') + ' ';
  383. break;
  384. case 3:
  385. title += position.split('').join('  ') + ' ';
  386. break;
  387. case 4:
  388. title += position + ' ';
  389. break;
  390. default:
  391. title += position + '\n      ';
  392. }
  393. const people = e[1].people.map((f, i) => {
  394. const name = f.name.chs ? (f.name.for ? f.name.chs + ' / ' + f.name.for : f.name.chs) : f.name.for;
  395. return (i > 0 ? '      ' : '') + name + (f.character ? ` (${f.character})` : '');
  396. }).join('\n');
  397. return title + people;
  398. }).join('\n') + '\n\n' : '') +
  399. (info.tags.length ? '◎标  签 ' + info.tags.join(' | ') + '\n\n' : '') +
  400. (info.description ? '◎简  介 \n' + info.description.replace(/^|\n/g, '\n  ') + '\n\n' : '◎简  介 \n\n  暂无相关剧情介绍') +
  401. (info.awards.length ? '◎获奖情况 \n\n' + info.awards.map(e => {
  402. const awardName = '  ' + e.name + ' (' + e.year + ')\n';
  403. const awardItems = e.awards.map(e => '  ' + e.name + (e.people ? ' ' + e.people : '')).join('\n');
  404. return awardName + awardItems;
  405. }).join('\n\n') + '\n\n' : '')
  406. ).trim();
  407. return infoText;
  408. }
  409. getDoc(raw_info.dburl, null, function(doc) {
  410. const infoGenClickEvent = async e => {
  411. var data = formatInfo(await getInfo(doc));
  412. raw_info.descr = data + '\n\n' + raw_info.descr;
  413.  
  414. if (!location.href.match(/usercp.php\?action=persona/)){
  415. if (is_douban_needed && raw_info.descr.match(/http(s*):\/\/www.imdb.com\/title\/tt(\d+)/i)){
  416. raw_info.url = raw_info.descr.match(/http(s*):\/\/www.imdb.com\/title\/tt(\d+)/i)[0] + '/';
  417. }
  418. if (raw_info.descr.match(/类[\s\S]{0,5}别[\s\S]{0,30}纪录片/i)) {
  419. raw_info.type = '纪录';
  420. } else if (raw_info.descr.match(/类[\s\S]{0,5}别[\s\S]{0,30}动画/i)) {
  421. raw_info.type = '动漫';
  422. }
  423. set_jump_href(raw_info, 1);
  424. jump_str = dictToString(raw_info);
  425. douban_button.value = '获取成功';
  426. $('#textarea').val(data);
  427. GM_setClipboard(douban_info);
  428. tag_aa = forward_r.getElementsByClassName('forward_a');
  429. for (i = 0; i < tag_aa.length; i++) {
  430. if (['常用站点', 'PTgen', 'BUG反馈', '简化MI', '脚本设置', '单图转存', '转存PTP'].indexOf(tag_aa[i].textContent) < 0){
  431. tag_aa[i].href = decodeURI(tag_aa[i]).split(seperator)[0] + seperator + encodeURI(jump_str);
  432. }
  433. }
  434. } else {
  435. $('textarea[name="douban_info"]').val(raw_info.descr);
  436. $('#go_ptgen').prop('value', '获取成功');
  437. };
  438. }
  439. infoGenClickEvent();
  440. });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址