get_douban_info

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

Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta // @require https://update.greasyfork.org/scripts/425243/958866/get_douban_info.js

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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();
});