Greasy Fork is available in English.

get_douban_info

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

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/425243/958866/get_douban_info.js

// ==UserScript==
// @name         get_douban_info
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  辅助auto-feed脚本获取豆瓣信息
// @author       tomorrow505
// @match        https://passthepopcorn.me/torrents.php?id=238092&torrentid=869948
// @icon         https://www.google.com/s2/favicons?domain=passthepopcorn.me
// @grant        none
// ==/UserScript==

const TIMEOUT = 6000;
function getPoster(doc) {
    try {
        return $('#mainpic img', doc)[0].src.replace(
            /^.+(p\d+).+$/,
            (_, p1) => `https://img9.doubanio.com/view/photo/l_ratio_poster/public/${p1}.jpg`
        );
    } catch (e) {
        return null;
    }
}
 
function getTitles(doc) {
    let isChinese = false;
    const chineseTitle = doc.title.replace(/\(豆瓣\)$/, '').trim();
    const originalTitle = $('#content h1>span[property]', doc).text().replace(chineseTitle, '').trim() || ((isChinese = true), chineseTitle);
    try {
        let akaTitles = $('#info span.pl:contains("又名")', doc)[0].nextSibling.textContent.trim().split(' / ');
        const transTitle = isChinese ? akaTitles.find(e => {return e.match(/[a-z]/i);}) || chineseTitle: chineseTitle;
        const priority = e => {
            if (e === transTitle) {
                return 0;
            }
            if (e.match(/\(港.?台\)/)) {
                return 1;
            }
            if (e.match(/\([港台]\)/)) {
                return 2;
            }
            return 3;
        };
        akaTitles = akaTitles.sort((a, b) => priority(a) - priority(b)).filter(e => e !== transTitle);
        return [{
            chineseTitle: chineseTitle,
            originalTitle: originalTitle,
            translatedTitle: transTitle,
            alsoKnownAsTitles: akaTitles
            }, 
            isChinese
        ];
    } catch (e) {
        return [{
            chineseTitle: chineseTitle,
            originalTitle: originalTitle,
            translatedTitle: chineseTitle,
            alsoKnownAsTitles: []
            },
            isChinese
        ];
    }
}
 
function getYear(doc) {
    return parseInt($('#content>h1>span.year', doc).text().slice(1, -1));
}
 
function getRegions(doc) {
    try {
        return $('#info span.pl:contains("制片国家/地区")', doc)[0].nextSibling.textContent.trim().split(' / ');
    } catch (e) {
        return [];
    }
}
 
function getGenres(doc) {
    try {
        return $('#info span[property="v:genre"]', doc).toArray().map(e => e.innerText.trim());
    } catch (e) {
        return [];
    }
}
 
function getLanguages(doc) {
    try {
        return $('#info span.pl:contains("语言")', doc)[0].nextSibling.textContent.trim().split(' / ');
    } catch (e) {
        return [];
    }
}
 
function getReleaseDates(doc) {
    try {
        return $('#info span[property="v:initialReleaseDate"]', doc).toArray().map(e => e.innerText.trim()).sort((a, b) => new Date(a) - new Date(b));
    } catch (e) {
        return [];
    }
}
 
function getDurations(doc) {
    try {
        return $('span[property="v:runtime"]', doc).text();
    } catch (e) {
        return [];
    }
}
 
function getEpisodeDuration(doc) {
    try {
        return $('#info span.pl:contains("单集片长")', doc)[0].nextSibling.textContent.trim();
    } catch (e) {
        return null;
    }
}
 
function getEpisodeCount(doc) {
    try {
        return parseInt($('#info span.pl:contains("集数")', doc)[0].nextSibling.textContent.trim());
    } catch (e) {
        return null;
    }
}
 
function getTags(doc) {
    return $('div.tags-body>a', doc).toArray().map(e => e.textContent);
}
 
function getDoubanScore(doc) {
    const $interest = $('#interest_sectl', doc);
    const ratingAverage = parseFloat(
      $interest.find('[property="v:average"]').text()
    );
    const ratingVotes = parseInt($interest.find('[property="v:votes"]').text());
    return {
        rating: ratingAverage,
        ratingCount: ratingVotes,
        ratingHistograms: {
            'Douban Users': {
            aggregateRating: ratingAverage,
            demographic: 'Douban Users',
            totalRatings: ratingVotes
        }
      }
    };
}
 
function getDescription(doc) {
    try {
        return Array.from($('#link-report>[property="v:summary"],#link-report>span.all.hidden', doc)[0].childNodes)
            .filter(e => e.nodeType === 3)
            .map(e => e.textContent.trim())
            .join('\n');
    } catch (e) {
        return null;
    }
}
 
function addComma(x) {
    var parts = x.toString().split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return parts.join(".");
}
 
function getDirector(doc) {
    try{
        return $('#info span.pl:contains("导演")', doc)[0].nextSibling.nextSibling.textContent.trim().split(' / ');
    } catch (err) {
        return [];
    }
}
 
function getWriters(doc) {
    try{
        return $('#info span.pl:contains("编剧")', doc)[0].nextSibling.nextSibling.textContent.trim().split(' / ');
    } catch (err) {
        return [];
    }
}
 
function getCasts(doc) {
    try{
        return $('#info span.pl:contains("主演")', doc)[0].nextSibling.nextSibling.textContent.trim().split(' / ');
    } catch (err) {
        return [];
    }
}
 
async function getIMDbScore(ID, timeout = TIMEOUT) {
    if (ID) {
        return new Promise(resolve => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `http://p.media-imdb.com/static-content/documents/v1/title/tt${ID}/ratings%3Fjsonp=imdb.rating.run:imdb.api.title.ratings/data.json`,
                headers: {
                    referrer: 'http://p.media-imdb.com/'
                },
                timout: timeout,
                onload: x => {
                    try {
                        const e = JSON.parse(x.responseText.slice(16, -1));
                        resolve(e.resource);
                    } catch (e) {
                        console.warn(e);
                        resolve(null);
                    }
                },
                ontimeout: e => {
                    console.warn(e);
                    resolve(null);
                },
                onerror: e => {
                    console.warn(e);
                    resolve(null);
                }
            });
        });
    } else {
        return null;
    }
}
 
async function getIMDbID(doc) {
    try {
        return $('#info span.pl:contains("IMDb:")', doc).parent().text().match(/tt(\d+)/)[1];
    } catch (e) {
      return null;
    }
}
 
async function getCelebrities(doubanid, timeout = TIMEOUT) {
    var awardurl = 'https://movie.douban.com/subject/{a}/celebrities/'.format({'a': doubanid});
    return new Promise(resolve => {
        getDoc(awardurl, null, function(doc){
            const entries = $('#celebrities>div.list-wrapper', doc).toArray().map(e => {
                const [positionChinese, positionForeign] = $(e).find('h2').text().match(/([^ ]*)(?:$| )(.*)/).slice(1, 3);
                const people = $(e).find('li.celebrity').toArray().map(e => {
                    let [nameChinese, nameForeign] = $(e).find('.info>.name').text().match(/([^ ]*)(?:$| )(.*)/).slice(1, 3);
                    if (!nameChinese.match(/[\u4E00-\u9FCC]/)) {
                        nameForeign = nameChinese + ' ' + nameForeign;
                        nameChinese = null;
                    }
                    const [roleChinese, roleForeign, character] = $(e).find('.info>.role').text().match(/([^ ]*)(?:$| )([^(]*)(?:$| )(.*)/).slice(1, 4);
                    return {
                        name: {
                            chs: nameChinese,
                            for: nameForeign
                        },
                        role: {
                            chs: roleChinese,
                            for: roleForeign
                        },
                        character: character.replace(/[()]/g, '')
                    };
                });
                return [
                    positionForeign.toLowerCase(),
                    {
                        position: positionChinese,
                        people: people
                    }
                ];
            });
            console.log(typeof(entries))
            console.log(entries)
            if (entries.length) {
                // jsonCeleb = Object.fromEntries(entries);
                // console.log(jsonCeleb)
                jsonCeleb = entries;
            } else {
                jsonCeleb = null;
            }
            resolve(jsonCeleb);
        });
    });
}
 
async function getAwards(doubanid, timeout = TIMEOUT) {
    var awardurl = 'https://movie.douban.com/subject/{a}/awards/'.format({'a': doubanid});
    return new Promise(resolve => {
        getDoc(awardurl, null, function(doc){
            resolve($('div.awards', doc).toArray().map(function(e){
                const $title = $(e).find('.hd>h2');
                const $awards = $(e).find('.award');
                return {
                    name: $title.find('a').text().trim(),
                    year: parseInt($title.find('.year').text().match(/\d+/)[0]),
                    awards: $awards.toArray().map(e => ({
                        name: $(e).find('li:first-of-type').text().trim(),
                        people: $(e).find('li:nth-of-type(2)').text().split('/').map(e => e.trim())
                    }))
                };
            }));
        });
    })
}
 
async function getInfo(doc) {
    const [titles, isChinese] = getTitles(doc),
        year = getYear(doc),
        regions = getRegions(doc),
        genres = getGenres(doc),
        languages = getLanguages(doc),
        releaseDates = getReleaseDates(doc),
        durations = getDurations(doc),
        episodeDuration = getEpisodeDuration(doc),
        episodeCount = getEpisodeCount(doc),
        tags = getTags(doc),
        DoubanID = raw_info.dburl.match(/subject\/(\d+)/)[1],
        DoubanScore = getDoubanScore(doc),
        poster = getPoster(doc),
        description = getDescription(doc);
        directors = getDirector(doc);
        writers = getWriters(doc);
        casts = getCasts(doc);
 
    let IMDbID, IMDbScore, awards, celebrities;
 
    const concurrentFetches = [];
 
    concurrentFetches.push(
        // IMDb Fetch
        getIMDbID(doc)
        .then(e => {
            IMDbID = e;
            return getIMDbScore(IMDbID);
        })
        .then(e => {
            IMDbScore = e;
            return getAwards(DoubanID);
        })
        .then(e => {
            awards = e;
            return getCelebrities(DoubanID);
        })
        .then(e => {
            celebrities = e;
        })
 
    );
    await Promise.all(concurrentFetches);
    if (IMDbScore && IMDbScore.title) {
        if (isChinese) {
            if (!titles.translatedTitle.includes(IMDbScore.title)) {
                titles.alsoKnownAsTitles.push(titles.translatedTitle);
                const index = titles.alsoKnownAsTitles.indexOf(IMDbScore.title);
                if (index >= 0) {
                    titles.alsoKnownAsTitles.splice(index, 1);
                }
                titles.translatedTitle = IMDbScore.title;
            }
        } else {
            if (!titles.originalTitle.includes(IMDbScore.title) &&titles.alsoKnownAsTitles.indexOf(IMDbScore.title) === -1) {
              titles.alsoKnownAsTitles.push(IMDbScore.title);
            }
        } 
    }
    return {
        poster: poster,
        titles: titles,
        year: year,
        regions: regions,
        genres: genres,
        languages: languages,
        releaseDates: releaseDates,
        durations: durations,
        episodeDuration: episodeDuration,
        episodeCount: episodeCount,
        tags: tags,
        DoubanID: DoubanID,
        DoubanScore: DoubanScore,
        IMDbID: IMDbID,
        IMDbScore: IMDbScore,
        description: description,
        directors: directors,
        writers: writers,
        casts: casts,
        awards: awards,
        celebrities: celebrities
    };
}
 
function formatInfo(info) {
    let temp;
    const infoText = (
        (info.poster ? `[img]${info.poster}[/img]\n\n` : '') +
        '◎译  名 ' + [info.titles.translatedTitle].concat(info.titles.alsoKnownAsTitles).join(' / ') + '\n' +
        '◎片  名 ' + info.titles.originalTitle + '\n' +
        '◎年  代 ' + info.year + '\n' +
        (info.regions.length ? '◎产  地 ' + info.regions.join(' / ') + '\n' : '') +
        (info.genres.length ? '◎类  别 ' + info.genres.join(' / ') + '\n' : '') +
        (info.languages.length ? '◎语  言 ' + info.languages.join(' / ') + '\n' : '') +
        (info.releaseDates.length ? '◎上映日期 ' + info.releaseDates.join(' / ') + '\n' : '') +
        ((info.IMDbScore && info.IMDbScore.rating) ? `◎IMDb评分  ${Number(info.IMDbScore.rating).toFixed(1)}/10 from ${addComma(info.IMDbScore.ratingCount)} users\n` : '') +
        (info.IMDbID ? `◎IMDb链接  https://www.imdb.com/title/tt${info.IMDbID}/\n` : '') +
        ((info.DoubanScore && info.DoubanScore.rating) ? `◎豆瓣评分 ${info.DoubanScore.rating}/10 from ${addComma(info.DoubanScore.ratingCount)} users\n` : '') +
        (info.DoubanID ? `◎豆瓣链接 https://movie.douban.com/subject/${info.DoubanID}/\n` : '') +
        ((info.durations && info.durations.length) ? '◎片  长 ' + info.durations + '\n' : '') +
        (info.episodeDuration ? '◎单集片长 ' + info.episodeDuration + '\n' : '') +
        (info.episodeCount ? '◎集  数 ' + info.episodeCount + '\n' : '') +
        (info.celebrities ? info.celebrities.map(e => {
            const position = e[1].position;
            let title = '◎';
            switch (position.length) {
                case 1:
                    title += '   ' + position + '    ';
                    break;
                case 2:
                    title += position.split('').join('  ') + ' ';
                    break;
                case 3:
                    title += position.split('').join('  ') + ' ';
                    break;
                case 4:
                    title += position + ' ';
                    break;
                default:
                    title += position + '\n      ';
            }
            const people = e[1].people.map((f, i) => {
                const name = f.name.chs ? (f.name.for ? f.name.chs + ' / ' + f.name.for : f.name.chs) : f.name.for;
                return (i > 0 ? '      ' : '') + name + (f.character ? ` (${f.character})` : '');
            }).join('\n');
            return title + people;
        }).join('\n') + '\n\n' : '') +
        (info.tags.length ? '◎标  签 ' + info.tags.join(' | ') + '\n\n' : '') +
        (info.description ? '◎简  介 \n' + info.description.replace(/^|\n/g, '\n  ') + '\n\n' : '◎简  介 \n\n  暂无相关剧情介绍') +
        (info.awards.length ? '◎获奖情况 \n\n' + info.awards.map(e => {
            const awardName = '  ' + e.name + ' (' + e.year + ')\n';
            const awardItems = e.awards.map(e => '  ' + e.name + (e.people ? ' ' + e.people : '')).join('\n');
            return awardName + awardItems;
        }).join('\n\n') + '\n\n' : '')
        ).trim();
    return infoText;
}
 
getDoc(raw_info.dburl, null, function(doc) {
    const infoGenClickEvent = async e => {
        var data = formatInfo(await getInfo(doc));
        raw_info.descr = data + '\n\n' + raw_info.descr;

        if (!location.href.match(/usercp.php\?action=persona/)){
            if (is_douban_needed && raw_info.descr.match(/http(s*):\/\/www.imdb.com\/title\/tt(\d+)/i)){
                raw_info.url = raw_info.descr.match(/http(s*):\/\/www.imdb.com\/title\/tt(\d+)/i)[0] + '/';
            }
            if (raw_info.descr.match(/类[\s\S]{0,5}别[\s\S]{0,30}纪录片/i)) {
                raw_info.type = '纪录';
            } else if (raw_info.descr.match(/类[\s\S]{0,5}别[\s\S]{0,30}动画/i)) {
                raw_info.type = '动漫';
            }
            set_jump_href(raw_info, 1);
            jump_str = dictToString(raw_info);
            douban_button.value = '获取成功';
            $('#textarea').val(data);
            GM_setClipboard(douban_info);
 
            tag_aa = forward_r.getElementsByClassName('forward_a');
            for (i = 0; i < tag_aa.length; i++) {
                if (['常用站点', 'PTgen', 'BUG反馈', '简化MI', '脚本设置', '单图转存', '转存PTP'].indexOf(tag_aa[i].textContent) < 0){
                    tag_aa[i].href = decodeURI(tag_aa[i]).split(seperator)[0] + seperator + encodeURI(jump_str);
                }
            }
        } else {
            $('textarea[name="douban_info"]').val(raw_info.descr);
            $('#go_ptgen').prop('value', '获取成功');
        };
    }
    infoGenClickEvent();
});