get_douban_info

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

Ce script ne doit pas être installé directement. C'est une librairie destinée à être incluse dans d'autres scripts avec la méta-directive // @require https://update.greasyfork.org/scripts/425243/958866/get_douban_info.js

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

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