Greasy Fork is available in English.
Letterboxd全局TMDB中文标题搜索 / 查询bt、字幕源是否存在 / 电影详情页增加显示:电影中文标题|导演中文名|中文简介|演员头像列表(中日韩演员显示中文名)|豆瓣ID图标|IMDB电影宽高比、底片格式
当前为
// ==UserScript==
// @name Letterboxd Enhancer 中文增强显示与搜索:集合啦!数字难民
// @namespace http://tampermonkey.net/
// @version 0.4
// @connect *
// @description Letterboxd全局TMDB中文标题搜索 / 查询bt、字幕源是否存在 / 电影详情页增加显示:电影中文标题|导演中文名|中文简介|演员头像列表(中日韩演员显示中文名)|豆瓣ID图标|IMDB电影宽高比、底片格式
// @thanks Catspinner bimzcy Rhilip LeLobster
// @author estost
// @match https://letterboxd.com/film/*
// @match https://letterboxd.com/*
// @match https://letterboxd.com*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @icon https://letterboxd.com/favicon.ico
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js
// ==/UserScript==
// 设置横向滚动条的样式
GM_addStyle(`
/* 滚动条整体样式 */
::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: #14181c;
}
/* 滑道样式 */
::-webkit-scrollbar-track:horizontal {
background-color: #14181c;
}
/* 滑块样式 */
::-webkit-scrollbar-thumb:horizontal:hover {
background-color: #242c34;
border-radius: 5px;
\`);
`);
// 设置竖向滚动条的样式
GM_addStyle(`
/* 滚动条整体样式 */
::-webkit-scrollbar {
width: 6px;
height: 8px;
background-color: #202830;
}
/* 滑道样式 */
::-webkit-scrollbar-track:vertical {
background-color: #202830;
}
/* 滑块样式 */
::-webkit-scrollbar-thumb:vertical {
background-color: #14181c;
border-radius: 5px;
}
`);
// 默认显示details菜单
var currentUrl = window.location.href;
if (currentUrl.startsWith('https://letterboxd.com/film/') && currentUrl.indexOf('/details') === -1 && currentUrl.indexOf('/lists/') === -1 && currentUrl.indexOf('/members/') === -1) {
window.location.replace(currentUrl + 'details/');
}
var tmdb_api = '你的api'
var tmdb_api = GM_getValue('tmdb_api', '');
if (tmdb_api.length <= 15) {
var api = prompt('请输入 TMDB API:');
if (api !== null && api.length > 0) {
GM_setValue('tmdb_api', api);
alert('TMDB API设置成功!');
}
}
$(document).ready(function () {
// 获取imdb/tmdb id/原始标题/电影年份
var imdb_nb = '';
try {
imdb_nb = [...document.querySelectorAll(".micro-button")].find(a => a.href.includes("imdb")).href.split("/tt")[1].split("/")[0];
} catch (error) {
imdb_nb = null;
}
var imdb_id = 'tt' + imdb_nb
var tmdb_id = [...document.querySelectorAll(".micro-button")].find(a => a.href.includes("themoviedb")).href.split(/\/(movie|tv)\//)[2].split("/")[0].split("/")[0];
var imdb_link = `https://www.imdb.com/title/${imdb_id}/`
var has_imdb_button = imdb_id.length > 0;
// 从 Letterboxd 中已有的数组 filmData 中获取电影的标题和年份
// var filmTitle01 = filmData['name']
// filmTitle01 = filmTitle01.replace(/[\/\\#,+()$~%.":*?<>{}!&]/g, '');
// var filmYear01 = filmData['releaseYear']
var film_title = $('#featured-film-header').find('h1').text().replace(/[\/\\#,+()$~%.":*?<>{}!&]/g, '').replace(/\xa0/g, ' ');
var film_year = $('#featured-film-header a[href*="films/year/"]').text();
var originalTitle = $('#featured-film-header').not('#chi_title').find('em').text().replace(/[\/\\#,+()$~%.":*?<>{}!&]/g, '');
var film_language_a = $('div#tab-details span:contains("Language")').parent('h3').next('div').find('a');
console.log(`IMDB ID: ${imdb_id}`)
console.log(`TMDB ID: ${tmdb_id}`)
console.log(`英文标题: ${film_title}`)
console.log(`原始标题: ${originalTitle}`)
console.log(`电影年份: ${film_year}`)
function hasJapanese(str) {
var regExp = /[\u3040-\u309F\u30A0-\u30FF\u31F0-\u31FF\uFF65-\uFF9F]/g;
return regExp.test(str);
}
function getZhName(also_known_as) {
// 判断是不是简体中文字符
function isSimpChinese(char) {
return /^[\u4E00-\u9FA5]+$/.test(char);
}
// 判断是不是繁体中文字符
function isTradChinese(char) {
return /^[\u4E00-\u9FFF]+$/.test(char);
}
// 判断是不是日文汉字
function isJapaneseKanji(char) {
return /^[\u4E00-\u9FFF\u3400-\u4DBF]+$/.test(char);
}
// 判断是不是日文平假名
function isHiragana(char) {
return /^[\u3040-\u309F]+$/.test(char);
}
// 判断是不是日文片假名
function isKatakana(char) {
return /^[\u30A0-\u30FF]+$/.test(char);
}
function isHangul(char) {
const unicode = char.charCodeAt(0);
return unicode >= 0xAC00 && unicode <= 0xD7AF;
}
const weights = {
"汉": {"simp": 10, "trad": 8, "jap": 7},
"ひらがな": {"jap": 2},
"カタカナ": {"jap": -2},
"kor": {"kor": -3}
};
let maxWeight = 0;
let zhjaName = "";
let minStrokeNames = []; // 记录权重相同且笔画最少的名字
let minStrokeCount = Number.MAX_SAFE_INTEGER; // 记录当前权重相同名字中笔画最少的名字的笔画数
let isAllNonChineseJapanese = true; // 新增变量,记录是否所有名字都不含汉字和平假名
for (let i = 0; i < also_known_as.length; i++) {
const name = also_known_as[i];
let weight = 0;
if (/(豆瓣)$/.test(name))
return name.replace('(豆瓣)', '');
let isNonChineseJapanese = true; // 新增变量,记录当前名字是否不含汉字和平假名
for (let j = 0; j < name.length; j++) {
let char = name[j];
if (isSimpChinese(char)) {
weight += weights["汉"]["simp"] || 0;
isNonChineseJapanese = false;
} else if (isTradChinese(char)) {
weight += weights["汉"]["trad"] || 0;
isNonChineseJapanese = false;
} else if (isJapaneseKanji(char)) {
weight += weights["汉"]["jap"] || 0;
isNonChineseJapanese = false;
} else if (isHiragana(char)) {
weight += weights["ひらがな"]["jap"] || 0;
isNonChineseJapanese = false;
} else if (isKatakana(char)) {
weight += weights["カタカナ"]["jap"] || 0;
isNonChineseJapanese = false;
} else if (isHangul(char)) {
weight += weights["kor"]["kor"] || 0;
}
}
if (isNonChineseJapanese) {
continue; // 如果当前名字不含汉字和平假名,则继续循环下一个名字
} else {
isAllNonChineseJapanese = false; // 反之,记录当前名字为包含汉字和平假名的名字
}
if (weight > maxWeight) {
maxWeight = weight;
zhjaName = name;
}
}
if (isAllNonChineseJapanese) {
return ""; // 如果所有名字都不含汉字和平假名,则返回 null
}
let return_name = zhjaName || '';
return return_name.replace('(dorama.info)', '').replace('(旧芸名)', '').replace('(本名)', '');
}
$(document).ready(function () {
$('#userpanel').css('margin-top', '-30px');
});
// 获取导演中文名
function getDirectorAndAKA(tmdb_id) {
return new Promise((resolve, reject) => {
$.getJSON(`https://api.themoviedb.org/3/movie/${tmdb_id}/credits?api_key=${tmdb_api}`, function (data) {
const crew = data.crew;
let director = null;
// 找到第一位导演信息
for (let i = 0; i < crew.length; i++) {
if (crew[i].job === 'Director') {
director = crew[i];
break;
}
}
if (director !== null) {
// 获取导演的 AKA 信息
$.getJSON(`https://api.themoviedb.org/3/person/${director.id}?api_key=${tmdb_api}`,
function (data) {
console.log(`导演aka: ${data.also_known_as}`)
resolve(data.also_known_as);
// resolve(`${director.name} (${data.also_known_as.join(', ')})`);
});
} else {
reject('未找到导演信息!');
}
});
});
};
async function printDirectorAndAKA(tmdb_id) {
try {
const director_aka = await getDirectorAndAKA(tmdb_id);
console.log(director_aka);
var dir_zh_txt = getZhName(director_aka).replace(' ', '');
var dir_en = $('#featured-film-header p').children('a:first').find('.prettify');
dir_en.css({'font-weight': '300'});
var dir_en_txt = dir_en.text();
dir_en.text(`${dir_zh_txt} ${dir_en_txt}`);
} catch (error) {
console.error(error);
}
};
printDirectorAndAKA(tmdb_id);
// 定义获取tmdb电影信息的函数
var tmdb_zh_overview = '';
$.getJSON(
"https://api.themoviedb.org/3/movie/" + tmdb_id + "?api_key=" + tmdb_api + "&language=zh-CN",
function (tmdb_zh_data) {
console.log(tmdb_zh_data);
tmdb_zh_overview = tmdb_zh_data.overview;
console.log(tmdb_zh_overview);
createTmdbZhOverview(tmdb_zh_overview); // 在回调函数中执行封装函数
}
);
GM_addStyle(`
#overview-content header {
border-bottom: 1px solid #456;
margin-bottom: 15px;
}
#overview-content header ul {
margin-bottom: -1px;
overflow: hidden;
}
#overview-content header ul li {
float: left;
font-size: 1rem;
letter-spacing: .075em;
line-height: 1;
margin: 0 15px 0 0;
text-transform: uppercase;
}
#overview-content header ul li a {
cursor: pointer;
color: #00e054;
display: block;
padding: 0 0 5px;
}
#overview-content header ul li.selected a {
border-bottom: 1px solid #fff;
color: #fff;
}
`);
// 创建tmdb中文简介栏
function createTmdbZhOverview(tmdb_zh_overview) {
var en_condenseable = $('div.review.body-text.-prose.-hero.prettify').find('div.condenseable');
var tmdb_en_overview = '';
var tmdb_en_overview_300 = '';
var tmdb_zh_overview_140 = tmdb_zh_overview.substring(0, 140);
console.log(tmdb_zh_overview_140);
// 判断页面原英文简介是否折叠
if (en_condenseable.length) {
tmdb_en_overview = $('.truncate.condenseable').find('p').text().replace('×', '');
console.log(tmdb_en_overview);
tmdb_en_overview_300 = tmdb_en_overview.substring(0, 300);
console.log(`原英文简介折叠了:${tmdb_en_overview_300}`);
} else {
const en_truncate = $('.review.body-text.-prose.-hero.prettify .truncate p');
tmdb_en_overview_300 = en_truncate.text();
console.log(`原英文简介没有折叠:${tmdb_en_overview_300}`)
}
// 创建选项卡和内容的HTML
const tabbedContentHtml = `
<div id="overview-content">
<header>
<ul class="tabs">
<li class="view-tab active selected" data-tab="tab-overview-en"><a>Overview</a></li>
<li class="view-tab" data-tab="tab-overview-zh"><a>剧情简介</a></li>
</ul>
</header>
<div class="tab-content review body-text -prose -hero prettify" id="tab-overview-en" >
<div class="ov-en-seable" style="display: none; width: 390px; opacity: 1;">
<p id="en_overview_fulltxt">${tmdb_en_overview}<span class="ov-en-condense-less" style="cursor:pointer;color: #def;white-space: nowrap;">×</span>
</p>
</div>
<div class="ov-en-sed" style="">
<p id="en_overview_truntxt">${tmdb_en_overview_300}</p>
</div>
</div>
<div class="tab-content review body-text -prose -hero prettify" id="tab-overview-zh" style="display: none;">
<div class="ov-zh-seable" style="display: none; width: 390px; opacity: 1;">
<p id="zh_overview_fulltxt">${tmdb_zh_overview}<span class="ov-zh-condense-less" style="cursor:pointer;color: #def;white-space: nowrap;">×</span>
</p>
</div>
<div class="ov-zh-sed" style="">
<p id="zh_overview_truntxt">${tmdb_zh_overview_140}</p>
</div>
</div>
</div>
`;
$('.section.col-10.col-main section').hide();
// 在#tabbed-content div之前插入选项卡内容
$('#tabbed-content').before(tabbedContentHtml);
// 判断原英文简介是否折叠 并创建…more 按键
if (en_condenseable.length) {
$('#en_overview_truntxt').append(`<span class="ov-en-condense-more"
style="cursor:pointer; color: #def;white-space: nowrap;">…more</span>`);
}
// 判断tmdb中文简介长度是否大于140 并创建 …more 按键
if ((tmdb_zh_overview.length > 140)) {
$('#zh_overview_truntxt').append(`<span class="ov-zh-condense-more"
style="cursor:pointer; color: #def;white-space: nowrap;">…更多</span>`);
}
// 判断tagline是否存在 并新建
const en_tagline = $('.review.body-text.-prose.-hero.prettify h4.tagline');
if (en_tagline.length) {
$('.ov-en-seable').prepend(en_tagline);
$('.ov-en-sed').prepend(en_tagline);
}
function overviewPanelInteraction() {
// 处理标签页点击
$('.view-tab').click(function () {
// 获取要显示的内容的ID
const tabId = $(this).data('tab');
// 隐藏所有内容块
$('.tab-content').hide();
// 显示所选的内容块
$('#' + tabId).show();
// 更新活动选项卡的样式
$('.view-tab').removeClass('selected');
$(this).addClass('selected');
});
// 显示更多英文简介
$('.ov-en-condense-more').click(function () {
$('.ov-en-sed').hide();
$('.ov-en-seable').show();
});
// 隐藏更多英文简介
$('.ov-en-condense-less').click(function () {
$('.ov-en-seable').hide();
$('.ov-en-sed').show();
});
// 显示更多中文简介
$('.ov-zh-condense-more').click(function () {
$('.ov-zh-sed').hide();
$('.ov-zh-seable').show();
});
// 隐藏更多中文简介
$('.ov-zh-condense-less').click(function () {
$('.ov-zh-seable').hide();
$('.ov-zh-sed').show();
});
};
overviewPanelInteraction();
}
// 折叠aka title
function akaTtitleFold() {
const aka_title = $('#tab-details .text-indentedlist');
const alternative_title = aka_title.find('p').text().replace(/\s{2,}/g, '');
console.log(`aka标题:${alternative_title}`)
const alternative_title_30 = alternative_title.substring(0, 60);
const alternativeTitleFold = `
<div>
<div class="aka-title-seable" style="display: none;">
<p>${alternative_title}<span class="aka-title-less" style="cursor:pointer;color: #def;white-space: nowrap;">×</span></p>
</div>
<div class="aka-title-sed" style="">
<p>${alternative_title_30}<span class="aka-title-more" style="cursor:pointer; color: #def;white-space: nowrap;">…</span></p>
</div>
</div>
`;
// 判断页面原英文简介是否折叠
if (alternative_title.length > 60) {
aka_title.find('p').hide();
aka_title.append(alternativeTitleFold);
$('.aka-title-more').click(function () {
$('.aka-title-sed').hide();
$('.aka-title-seable').show();
});
$('.aka-title-less').click(function () {
$('.aka-title-seable').hide();
$('.aka-title-sed').show();
});
}
}
akaTtitleFold();
// 重构tmdb/imdb ID 图标
$(document).ready(function refactorTmdbImdbIcons() {
// 给 时长 db 元素设置ID
$('div#tabbed-content').next().attr('id', 'runtime_url');
// 移除简介底部留白
$('.truncate').children('p').css('margin-bottom', '0');
// 将 时长 db 元素移动到电影标题下面
let runtime_bd_url = $('p#runtime_url');
let year_title_dir = $('section#featured-film-header');
$('section#featured-film-header').css('margin-bottom', '0');
$('span.block-flag-wrapper').css('top', '-2px').css('margin-left', '-8px');
runtime_bd_url.insertAfter(year_title_dir);
// 删除tmdb按钮边框
$('#runtime_url').find('[data-track-action="TMDb"]').attr('id', 'tmdb_button').css('border',
'none').text(tmdb_id);
// 创建tmdb图标
$(document).ready(function () {
const brandSpan = $('<span class="brand"><svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" style="margin: 0 4px -4.5px 4px;">' +
'<defs><clipPath id="maskID1655656042540"><path d="M12,24 C2.372583,24 0,21.627417 0,12 C0,2.372583 2.372583,0 12,0 C21.627417,0 24,2.372583 24,12 C24,21.627417 21.627417,24 12,24 Z"></path></clipPath></defs><title></title><desc>Amazon</desc>' +
'<image clip-path="url(#maskID1655656042540)" width="24" height="24" xlink:href="data:image/webp;base64,UklGRhwCAABXRUJQVlA4TBACAAAvH8AHAN/kKpJsV9k598VfCgdowL8EvOR479hwG0lW7MwC+7B+IsrfUSIKQvbN9dwGYNs2AGmnJ1M9pu75/4TkhE4C8x8n3UYQQTAylCACgRLkhF' +
'mDQBFEEAwgBYIJBJtamGpqSgWZlEM55IEcCCEJHelbOuWoo4IotJ+FVVNzTrXb09LT9fXy/JWBmHZ+3h3q1uLUAmgNC5Y0wYIbIbRGCG5YaI0u1vLTz3rJ1kfrd4M1GCP5D87kSP6TMzmCIzmTMziSIzhTX1DvuY25voik3VNFwI0KcRMTC5YDztSuAjQkrZkysRYWbGBTmJhYhYhVCXEBGin0BoSIaMFGWvWGCChREIw0oiF' +
'ARBSgnlK9ASFKFLFS0H8lQqBLFQLQRaAKATz2i2nMwfP/d3k87PeTlSkDJAEAy0hTj20ba9u2d8dY27Zt67nVdY5NRP8ngEiTQ7hSISfLpBIxAEAEMIRZ5m9tTXVVZUV5WWlJcVFhQX5ejpsJlPHz8nh3fX56uL+1ubo8Nz0xFo0MemAaVF3/8XR/e3lxfLS7s762tDA7NZ5Ihf4cMBUv++uVXTwVHHYiNFmfb+ySqeCIiwbS' +
'NLyzS6RC/3aYCkCB7+eHm6uzk4O97Y2VxfmZydFYeMgHE/R8f11jU3NLa1t7R2dXd09vX/9ArldAMIVUWp2e4wzAaALAzFmsNiFCsIRoYVoibQw="></image><path d="M12,23.5 C21.2262746,23.5 23.5,21.2262746 23.5,12 C23.5,2.77372538 21.2262746,0.5 12,0.5 C2.77372538,0.5 0.5,2' +
'.77372538 0.5,12 C0.5,21.2262746 2.77372538,23.5 12,23.5 Z" class="overlay" stroke-opacity="0.35" stroke="#000000" fill="rgba(0,0,0,0)"></path></svg></span>');
$('#tmdb_button').before(brandSpan);
});
// 删除imdb按钮边框
$('#runtime_url').find('[data-track-action="IMDb"]').attr('id', 'imdb_button').css('text-transform',
'none').css('border', 'none').text(imdb_id);
// 移动imdb按钮
$(document).ready(function () {
// 获取 #imdb_button 元素
const imdbButton = $('#imdb_button');
// 从父元素中删除 #imdb_button 元素
imdbButton.detach();
// 将 #imdb_button 元素插入到 #tmdb_button 元素的后面
imdbButton.insertAfter('#tmdb_button');
});
// 创建imdb图标
$(document).ready(function () {
const brandSpan = $('<span class="brand"><svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" style="margin: 0 4px -4.5px 4px;">' +
'<defs><clipPath id="maskID1655656042540"><path d="M12,24 C2.372583,24 0,21.627417 0,12 C0,2.372583 2.372583,0 12,0 C21.627417,0 24,2.372583 24,12 C24,21.627417 21.627417,24 12,24 Z"></path></clipPath></defs><title></title><desc>Amazon</desc>' +
'<image clip-path="url(#maskID1655656042540)" width="24" height="24" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAahJREFUWMNj+HpU4v9AYoZRB4w6YNQBow4YdQC6wKIm/v+u5mz/w1w5/h+aIwxmg3CiH+f' +
'/pzvE4HwQvrJaBIXvZsH2vyqJ5//nw+L/c8K5wGLdBbykOaAxg+c/AwPDfwlhpv9ruwXBbBDmZGf4f2SuMJwPwicWIviCvIxw9vI2gf9mOqxgdhLQ4VRxAAh35vHidMD2yYL/WZgh7AnFfHAHgEJudacAGH85Ik6eA9hYIQaDghQUEtgcsGuq0H8uDkYMB7CzIdQ3Z/KQ5wB1eWYwzQE0TEuRhSgHmGpDHBDjxfnf34EdzPa1' +
'YyfPAYYaLP8lRZjAbG9bdpJCIMmfE4xBbB9bMh1gBHSArSEbmA1K3bgcAIsemjgAlJhA7L4iXqwOqE3lgbMnliCiIBYYBaEuHJRFAcgBrdkQi9f3CmJ1AAwzMTH8PzpfGB4CrCwIucpEbsIOOLlI+P/0Kr7/Cxv5/99aLwpmr+4S+H9llQiY/Xi7GJgG4SfbReFsEJ4BxCD9IHPWdAuAxQ4DC7OpFXz/p5Tz/f9wUHy0Lhh1w' +
'KgDRh0w6oDB5wAAnyEaXz1l5ZIAAAAASUVORK5CYII="></image><path d="M12,23.5 C21.2262746,23.5 23.5,21.2262746 23.5,12 C23.5,2.77372538 21.2262746,0.5 12,0.5 C2.77372538,0.5 0.5,2.77372538 0.5,12 C0.5,21.2262746 2.77372538,23.5 12,23.5 Z" class="ov' +
'erlay" stroke-opacity="0.35" stroke="#000000" fill="rgba(0,0,0,0)"></path></svg></span>');
$('#imdb_button').before(brandSpan);
});
});
//构建 imdb Technical 表格
// 对使用GM_xmlhttpRequest返回的html文本进行处理并返回DOM树
function page_parser(responseText) {
// 替换一些信息防止图片和页面脚本的加载,同时可能加快页面解析速度
// responseText = responseText.replace(/s+src=/ig, ' data-src='); // 图片,部分外源脚本
// responseText = responseText.replace(/<script[^>]*?>[\S\s]*?<\/script>/ig, ''); //页面脚本
return (new DOMParser()).parseFromString(responseText, 'text/html');
}
function getDoc(url, meta, callback) {
GM_xmlhttpRequest({
method: 'GET',
url: url,
onload: function (responseDetail) {
if (responseDetail.status === 200) {
let doc = page_parser(responseDetail.responseText);
callback(doc, responseDetail, meta);
}
}
});
}
function createTechnicalTable(imdb_link) {
// 在tabbed-content上创建 technical_sp div
$('div#tabbed-content').prepend(`
<section id='loading_technical' style="border: none">Loading Technical...</section>
<div class="tabbed-content-block column-block" style="display: inline-flex;margin: -15px 0 -5px 0;"
id="technical_sp"></div>
`);
// 构建要添加的元素
let technical_multi_data = [ /** {name, link || `${imdb_link}`, text} */];
// 创建imdb technical 标签
function technical_specifications(data) {
technical_multi_data.push(data);
let technical_sp = $('#technical_sp');
let technical_html = '';
for (let i = 0; i < technical_multi_data.length; i++) {
let technical_data = technical_multi_data[i];
// 将 technical_data['data'] 字符串按照竖线分隔,并去重生成字符串数组
let links = [...new Set(technical_data['data'].split('|'))]
.map((str, index) => {
// 如果字符串长度大于 14,且包含 8mm、16mm、35mm、65mm,则将其替换为其中的一个子串
if (str.length > 14 && /(8 mm|16 mm|35 mm|65 mm)/.test(str)) {
str = str.replace(/.*(8 mm|16 mm|35 mm|65 mm).*/, '$1');
}
// 生成链接 HTML 元素
let style = '';
if (index === 0) {
style = 'margin-left: 7.5em';
}
return `<a href="${technical_data['link']}" class="text-slug tooltip" style="margin: 0 0 6px 4.5px;${style}">${str.trim()}</a>`;
});
technical_html += `
<div style="padding-right: 3em;position: relative;">
<h3 style="width: 8em;position: absolute;">
<span>${technical_data['name']}</span>
</h3>
<div class="text-sluglist" style="margin-left: 0;width: 14.5em;float: left;">
<p style="display: flex;flex-wrap: wrap;flex-direction: row-reverse;padding-left: 2em;">${links.join('')}</p>
</div>
<div style="content: '';display: block;clear: both;"></div>
</div>
`;
}
technical_sp.html(technical_html);
technical_sp.show();
$("#loading_technical").hide();
}
let technical_link = `${imdb_link}technical/?ref_=tt_spec_sm`
if (has_imdb_button) {
getDoc(technical_link, null, function (doc) {
// 判断是不是新版界面
let new_another = $('script#__NEXT_DATA__', doc);
let is_new = new_another.length > 0;
try {
// 从网页中获取的部分信息,要区分是否新版页面
if (is_new) {
if ($("li.ipc-metadata-list__item:contains('Aspect ratio')", doc).length > 0) {
technical_specifications({
name: 'Aspect',
link: imdb_link + 'technical/?ref_=tt_spec_sm',
data: $("li.ipc-metadata-list__item:contains('Aspect ratio')", doc).text().replace(/^Aspect ratio/, '')
.replace(/\([^)]*\)/g, '').replace(/:\s*1/g, ': 1|').replace(/\|([^|]*)$/, '$1')
});
}
if ($("li.ipc-metadata-list__item:contains('Negative Format')", doc).length > 0) {
technical_specifications({
name: 'Negative',
link: imdb_link + 'technical/?ref_=tt_spec_sm',
data: $("li.ipc-metadata-list__item:contains('Negative Format')", doc).text().replace(/^Negative Format/, '')
.replace(/\([^)]*\)/g, '').replace(/ mm/g, " mm|").replace("Codex", "Codex|").replace("Video", "Video|")
.replace("Redcode RAW", "Redcode RAW|").replace("HDCAM", "HDCAM|").replace(/\|([^|]*)$/, '$1')
});
}
} else { // 旧版代码
if ($("div.txt-block:contains('Aspect Ratio:')", doc).text().length > 0) {
technical_specifications({
name: 'Aspect',
link: imdb_link + 'technical?ref_=tt_dt_spec',
data: $("div.txt-block:contains('Aspect Ratio:')", doc).text().trim().replace(/\n/g, '').replace(/^Aspect Ratio:/, '')
.replace(/\([^)]*\)/g, '').replace(/:\s*1/g, ': 1|').replace(/\|([^|]*)$/, '$1')
});
}
if ($("div.txt-block:contains('Negative Format:')", doc).text().length > 0) {
technical_specifications({
name: 'Negative',
link: imdb_link + 'technical?ref_=tt_dt_spec',
data: $("div.txt-block:contains('Negative Format:')", doc).text().trim().replace(/\n/g, '').replace(/^Negative Format:/, '')
.replace(/\([^)]*\)/g, '').replace(/ mm/g, " mm|").replace("Codex", "Codex|").replace("Video", "Video|")
.replace("Redcode RAW", "Redcode RAW|").replace("HDCAM", "HDCAM|").replace(/\|([^|]*)$/, '$1')
});
}
}
} catch (e) {
// throw e;
}
;
});
}
// 超时隐藏 loading technical
setTimeout(function () {
// 检查 #technical_sp 元素下是否有 a 标签
if (!document.querySelector("#technical_sp a")) {
$("#loading_technical").hide();
}
}, 5000);
};
createTechnicalTable(imdb_link)
///// 从tmdb获取演员列表 /////
window.onload = function () {
// 获取页面原本的演员链接
let actorLinks = $('.cast-list').find('a').filter(function () {
return this.hasAttribute('href') && $(this).attr('href').indexOf('actor') !== -1;
});
let actorArray = actorLinks.map(function () {
return $(this).attr('href');
}).get();
console.log(`tmdb演员列表: ${actorArray}`)
// 构造演员列表
GM_xmlhttpRequest({
method: 'GET',
url: `https://api.themoviedb.org/3/movie/${tmdb_id}/credits?api_key=${tmdb_api}`,
onload: response => {
const data = JSON.parse(response.responseText);
// 生成演职人员表格
const table = $('<table>').css({
'display': 'inline-block',
'white-space': 'nowrap'
});
const tbody = $('<tbody>').css({
'display': 'flex',
'flex-wrap': 'nowrap',
'padding': '0',
'margin': '0',
'justify-content': 'center',
'align-items': 'center',
'height': '120px',
'overflow-x': 'auto',
'scroll-behavior': 'smooth'
});
async function getZhJaName(cast_order, cast_id) {
return new Promise((resolve, reject) => {
var zhja_name = '';
if (film_language_a.attr('href').indexOf('chinese') !== -1 || film_language_a.attr('href').indexOf('cantonese') !== -1 || film_language_a.attr('href').indexOf('korean') !== -1 || film_language_a.attr('href').indexOf('japanese') !== -1) {
console.log('电影是中日韩电影');
if (cast_order < 10) {
$.getJSON("https://api.themoviedb.org/3/person/" + cast_id + "?api_key=" + tmdb_api + "&language=en-US", function (data) {
console.log(data);
var also_known_as = data.also_known_as;
var zhja_name = getZhName(also_known_as);
resolve(zhja_name);
});
} else {
resolve(zhja_name);
}
} else {
resolve(zhja_name);
}
});
};
data.cast.forEach(async item => {
const td = $('<td>').css({
'padding': '5px',
'width': '90px',
'text-align': 'center'
});
tbody.append(td);
console.log(JSON.stringify(item));
const cast_id = item.id;
const cast_order = item.order;
const cast_character = item.character;
let zhja_re = await getZhJaName(cast_order, cast_id);
let zhja_name = zhja_re.replace(' ', '');
console.log(`第 ${cast_order} 位演员的名字为:${zhja_name}`);
var castShowName = zhja_name ? zhja_name : item.name;
console.log(`castShowName: ${castShowName}`)
const name = $('<p class="tooltip">').text(castShowName).attr('title', cast_character).css({
'cursor': 'pointer',
'text-align': 'center',
'margin-top': '8px',
'font-size': '10px',
'text-overflow': 'ellipsis',
'white-space': 'nowrap',
'overflow': 'hidden',
'max-width': '100px'
});
const actorName = item.name
.normalize('NFD') // 将字符串中的带变音符号的字符转换为等效的基本字符和单独的变音符号
.replace(/\p{Diacritic}/gu, '') // 删除所有的单独变音符号
.replace(/\s+/g, '-') // 将剩余空格替换成短横线
.toLowerCase(); // 全部小写
// 在原本的演员url数组中查找匹配的url
const actorUrl = actorArray.filter(function (item) {
return item.includes(actorName);
});
// 如果item.profile_path不存在,则根据gender判断应该使用什么图片链接
// 如果gender为1,使用female图片链接,否则使用默认值
// 如果gender为2,使用male图片链接,否则使用默认值
const gender = item.gender;
const imageUrl = (item.profile_path)
? `https://image.tmdb.org/t/p/w185${item.profile_path}`
: (gender === 1)
? 'https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-36-user-female-grey-d9222f16ec16a33ed5e2c9bbdca07a4c48db14008bbebbabced8f8ed1fa2ad59.svg'
: (gender === 2)
? 'https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-4-user-grey-d8fe957375e70239d6abdd549fd7568c89281b2179b5f4470e2e12895792dfa5.svg'
: 'https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-4-user-grey-d8fe957375e70239d6abdd549fd7568c89281b2179b5f4470e2e12895792dfa5.svg';
const image = imageUrl
? $('<a>').attr({
'href': actorUrl,
'target': '_blank'
}).append(
$('<img>').attr('src', imageUrl).css({
'overflow': 'hidden',
'width': '70px',
'margin-top': '-5px',
'filter': 'grayscale(100%)'
}))
: '';
const circleWrapper = $('<div>').css({
'width': '70px',
'height': '70px',
'border-radius': '50%',
'overflow': 'hidden',
'position': 'relative',
'margin': '0 10px',
'transition': 'transform 0.2s' // 添加动画效果
}).hover( // 鼠标悬停时放大circleWrapper和字标签
function () {
$(this).css({
'transform': 'scale(1.1)'
}).find('p').css({
'transform': 'scale(1.1)'
});
},
function () {
$(this).css({
'transform': 'scale(1.0)'
}).find('p').css({
'transform': 'scale(1.0)'
});
}
);
const imgWrapper = $('<div>').css({
'position': 'relative'
});
circleWrapper.append(image);
imgWrapper.append(circleWrapper).append(name);
td.append(imgWrapper);
});
table.append(tbody);
// 将表格插入到页面
let activityFriends = $('.activity-from-friends').find('.section-heading');
let activityMore = $('.activity-from-friends').find('.all-link');
let popularReview = $('#popular-reviews').find('.section-heading');
let reviewMore = $('#popular-reviews').find('.all-link');
let popularLists = $('#film-popular-lists').find('.section-heading');
let ListMore = $('#film-popular-lists').find('.all-link');
GM_addStyle(".moreytxtCss { position: static; float: right; color: #678 !important; }")
const castTableDiv = $('<div>').attr('id', 'cast-list-table').css('margin', '0 0 20px 0');
if (activityFriends.length > 0) {
activityFriends.before(castTableDiv);
activityMore.addClass("moreytxtCss").appendTo(activityFriends);
console.log('activityFriends 存在')
} else if (popularReview.length > 0) {
popularReview.before(castTableDiv);
reviewMore.addClass("moreytxtCss").appendTo(popularReview);
console.log('popularReview 存在')
} else if (popularLists.length > 0) {
popularLists.before(castTableDiv);
ListMore.addClass("moreytxtCss").appendTo(popularLists);
console.log('popularLists 存在')
}
castTableDiv.append($('<h3>').addClass('section-heading').text('Cast List'), $('<div>').css({'overflow-x': 'auto'}).append(table));
},
onerror: error => {
console.error(`构造演员列表失败 ${tmdb_id}: ${error}`);
}
});
};
////// 豆瓣相关操作 豆瓣ID图标 豆瓣中文标题 bt/字幕 搜索栏 /////
$(document).ready(function createDoubanASO() {
// 查找豆瓣id方法
function getDoubanID0(movie_id) {
return new Promise(resolve => {
GM.xmlHttpRequest({
method: "GET",
timeout: 6000,
url: "https://movie.douban.com/j/subject_suggest?q=tt" + movie_id,
headers: {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0"},
onload: function (response) {
const data = JSON.parse(response.responseText)[0];
if (String(response.responseText).match(movie_id)) {
const douban_id = data.id;
resolve(data);
} else {
const douban_id = "00000000";
resolve("00000000");
}
},
onerror: function () {
GM.notification("Request Error.", "IMDb Scout Mod (getDoubanID0)");
console.log("IMDb Scout Mod (getDoubanID0): Request Error.");
resolve("00000000");
},
onabort: function () {
console.log("IMDb Scout Mod (getDoubanID0): Request Aborted.");
resolve("00000000");
},
ontimeout: function () {
console.log("IMDb Scout Mod (getDoubanID0): Request Timeout.");
resolve("00000000");
}
});
});
}
function getDoubanID1(movie_id) {
console.log("IMDb Scout Mod (getDoubanID1): Started.");
return new Promise(resolve => {
GM.xmlHttpRequest({
method: "GET",
timeout: 8000,
url: "https://www.douban.com/search?cat=1002&q=tt" + movie_id,
headers: {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0"},
onload: function (response) {
const parser = new DOMParser();
const result = parser.parseFromString(response.responseText, "text/html");
if ($(result).find('[onclick*=' + movie_id + ']').length) {
// 获取 href 属性值
const x = $(result).find('[onclick*=' + movie_id + ']').attr('href');
// 获取 a 标签的文本内容
const a = $(result).find('[onclick*=' + movie_id + ']').text();
if (x.match(/subject%2F(\d+)/)) {
const y = x.match(/subject%2F(\d+)/)[1];
const z = a + '|' + y
console.log(z)
resolve(z);
} else {
resolve("00000000");
}
} else {
resolve("00000000");
}
},
onerror: function () {
GM.notification("Request Error.", "IMDb Scout Mod (getDoubanID1)");
console.log("IMDb Scout Mod (getDoubanID1): Request Error.");
resolve("00000000");
},
onabort: function () {
console.log("IMDb Scout Mod (getDoubanID1): Request Aborted.");
resolve("00000000");
},
ontimeout: function () {
console.log("IMDb Scout Mod (getDoubanID1): Request Timeout.");
resolve("00000000");
}
});
});
}
function getDoubanID2(movie_id) {
console.log("IMDb Scout Mod (getDoubanID2): Started.");
return new Promise(resolve => {
GM.xmlHttpRequest({
method: "GET",
timeout: 8000,
url: 'https://query.wikidata.org/sparql?format=json&query=SELECT * WHERE {?s wdt:P345 "tt' + movie_id + '". OPTIONAL { ?s wdt:P4529 ?Douban_film_ID. }}',
headers: {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0"},
onload: function (response) {
const result = JSON.parse(response.responseText);
if (result.results.bindings[0] != undefined) {
if (result.results.bindings[0].Douban_film_ID != undefined) {
const douban_id = result.results.bindings[0].Douban_film_ID.value;
resolve(douban_id);
} else {
resolve("00000000");
}
} else {
const douban_id = "00000000";
resolve(douban_id);
}
},
onerror: function () {
GM.notification("Request Error.", "IMDb Scout Mod (getDoubanID2)");
console.log("IMDb Scout Mod (getDoubanID2): Request Error.");
resolve("00000000");
},
onabort: function () {
console.log("IMDb Scout Mod (getDoubanID2): Request Aborted.");
resolve("00000000");
},
ontimeout: function () {
console.log("IMDb Scout Mod (getDoubanID2): Request Timeout.");
resolve("00000000");
}
});
});
}
function getDoubanID3(movie_id) {
console.log("IMDb Scout Mod (getDoubanID3): Started.");
let searchTitle = originalTitle || film_title;
console.log(`搜索标题:${searchTitle}`)
return new Promise(resolve => {
GM.xmlHttpRequest({
method: "GET",
timeout: 10000,
url: 'https://www.google.com/search?q="' + searchTitle + '" site:https://movie.douban.com/subject/',
//url: 'https://search.douban.com/movie/subject_search?search_text=' + searchTitle + '+' + film_year + '&cat=1002',
headers: {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"},
onload: function (response) {
const result = String(response.responseText);
console.log(`Google搜索豆瓣条目: ${result}`)
//movie.douban.com/subject/
//m.douban.com/movie/subject/
if (result.match("movie.douban.com/subject/")) {
const regex = /<a\s+[^>]*href="(https:\/\/movie.douban.com\/subject\/[^"]+)"/;
const match = result.match(regex);
const href = match ? match[1] : null; // 获取匹配到的 href 属性值
const x = href.split("movie.douban.com/subject/")[1];
const y = x.split("/")[0];
const douban_id = y;
resolve({douban_id, result});
} else {
const douban_id = "00000000";
resolve(douban_id);
}
},
onerror: function () {
GM.notification("Request Error.", "IMDb Scout Mod (getDoubanID3)");
console.log("IMDb Scout Mod (getDoubanID3): Request Error.");
resolve("00000000");
},
onabort: function () {
console.log("IMDb Scout Mod (getDoubanID3): Request Aborted.");
resolve("00000000");
},
ontimeout: function () {
console.log("IMDb Scout Mod (getDoubanID3): Request Timeout.");
resolve("00000000");
}
});
});
}
function getDoubanID4(movie_id) {
console.log("IMDb Scout Mod (getDoubanID4): Started.");
let searchTitle = originalTitle || film_title;
console.log(`搜索标题:${searchTitle}`)
return new Promise(resolve => {
GM.xmlHttpRequest({
method: "GET",
timeout: 10000,
url: 'https://www.google.com/search?q="' + searchTitle + '" site:https://m.douban.com/movie/subject/',
//url: 'https://search.douban.com/movie/subject_search?search_text=' + searchTitle + '+' + film_year + '&cat=1002',
headers: {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"},
onload: function (response) {
const result = String(response.responseText);
console.log(`Google搜索豆瓣条目: ${result}`)
//movie.douban.com/subject/
//m.douban.com/movie/subject/
if (result.match("m.douban.com/movie/subject/")) {
const regex = /<a\s+[^>]*href="(https:\/\/m.douban.com\/movie\/subject\/[^"]+)"/;
const match = result.match(regex);
const href = match ? match[1] : null; // 获取匹配到的 href 属性值
const x = href.split("m.douban.com/movie/subject/")[1];
const y = x.split("/")[0];
const douban_id = y;
resolve({douban_id, result});
} else {
const douban_id = "00000000";
resolve(douban_id);
}
},
onerror: function () {
GM.notification("Request Error.", "IMDb Scout Mod (getDoubanID4)");
console.log("IMDb Scout Mod (getDoubanID4): Request Error.");
resolve("00000000");
},
onabort: function () {
console.log("IMDb Scout Mod (getDoubanID4): Request Aborted.");
resolve("00000000");
},
ontimeout: function () {
console.log("IMDb Scout Mod (getDoubanID4): Request Timeout.");
resolve("00000000");
}
});
});
}
// 创建豆瓣按钮
function createDoubanButton(douban_url, douban_id) {
// 创建豆瓣id按钮
const doubanButton = $(`<a href="${douban_url}" class="micro-button track-event" style="border: none" data-track-action="Douban" id="douban_button">${douban_id}</a>`);
if ($('#imdb_button').length > 0) { // 如果存在#imdb_button,则在它后面插入doubanButton
$('#imdb_button').after(doubanButton);
} else { // 否则在#tmdb_button后面插入doubanButton
$('#tmdb_button').after(doubanButton);
}
// 创建豆瓣图标
const brandSpan = $('<span class="brand"><svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" style="margin: 0 4px -4.5px 4px;">' +
'<defs><clipPath id="maskID1655656042540"><path d="M12,24 C2.372583,24 0,21.627417 0,12 C0,2.372583 2.372583,0 12,0 C21.627417,0 24,2.372583 24,12 C24,21.627417 21.627417,24 12,24 Z"></path></clipPath></defs><title></title><desc>Amazon</desc>' +
'<image clip-path="url(#maskID1655656042540)" width="24" height="24" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAABhElEQVRYhe2Wv0tCURTHPz600EVe8AYTKUHUodDZQSGMksYamrOhrfG15ZhjW0v' +
'NDTY0RAbW4F+QGJLiUPjrgVD4F9ik+St9mnUd/E7v3nvO+X645zzeM6DKEeASsPG/qgFRA6pcFWDehpAEmgPYJIHmABh7N97UDCuy40/M3j9LrMZ9XXvCb0A4gAFVbooEEH4DfUPY0vNxGp9tbSommdoL/vPgwLPZvYFO5etFrjM3YxXe9+3iUVzTAXitF4il4mMB+JfXdQEIb8EcQNcMeBU3sbA6VmGv4p4egEdxcTomgF4J' +
'b8HIb0HyIMGWewOAUqNC8GJnaMH00R0Oqx2Ah8IT21d7Q+NHtiCRvW0DOKx2Fo0L5OvFgbEexdU2b+WO0sgWJAuPXeuIZ/PH2N6z3tyJAMqNKlkt12ESHgLwfZbVcpQb1d8DANznU+3nkDOAxWTui7GYzIScgYE5w9Q3hM2zD12Jk8pwstS1Fv4aCgeY/xPOBEBNoL8mIXEIaALMK0hEvwAFElrDSCjZkwAAAABJRU5ErkJgg' +
'g=="></image><path d="M12,23.5 C21.2262746,23.5 23.5,21.2262746 23.5,12 C23.5,2.77372538 21.2262746,0.5 12,0.5 C2.77372538,0.5 0.5,2.77372538 0.5,12 C0.5,21.2262746 2.77372538,23.5 12,23.5 Z" class="overlay" stroke-opacity="0.35" stroke="#00' +
'0000" fill="rgba(0,0,0,0)"></path></svg></span>');
$('#douban_button').before(brandSpan);
}
// 判断是否华语电影并添加标题
function addDoubanTitle(douban_title) {
// 如果 a 元素的 href 属性不包含 'chinese',则执行指定步骤
if (film_language_a.attr('href').indexOf('chinese') === -1 && film_language_a.attr('href').indexOf('cantonese') === -1) {
if (film_language_a.attr('href').indexOf('japanese') === -1) {
$('section#featured-film-header').find("small").after(`<em id="chi_title" style="margin-left: 4px"></em>`);
$("#chi_title").text(douban_title)
console.log('电影不是华语/日语电影 添加中文标题')
} else if (hasJapanese(originalTitle)) {
$('section#featured-film-header').find("small").after(`<em id="chi_title" style="margin-left: 4px"></em>`);
$("#chi_title").text(douban_title)
console.log('电影含假名 添加中文标题')
} else if (!originalTitle) {
$('section#featured-film-header').find("small").after(`<em id="chi_title" style="margin-left: 4px"></em>`);
$("#chi_title").text(douban_title)
console.log('电影含英文 添加中文标题')
} else {
console.log('电影是汉字标题 不添加中文标题')
}
} else {
console.log('电影是华语电影 不添加中文标题')
}
}
// 创建 bt 字幕 搜索栏
function searchBars(imdb_nb, douban_id, film_title, film_year) {
// 判断imdb豆瓣id是否存在
if (!imdb_nb) {
imdb_nb = film_title;
let notimdbnb = 'imdb_id 不存在';
console.log(notimdbnb)
}
if (!douban_id) {
douban_id = film_title;
let notdoubanid = 'douban_id 不存在';
console.log(notdoubanid)
}
GM_addStyle(`
.search-bar-btsub > .service.missing > .atag-btsub > .site-img {
filter: grayscale(100%) brightness(50%);
}
.search-bar-btsub > .service.error > .atag-btsub> .site-img {
filter: grayscale(100%) brightness(50%);
}
.search-bar-btsub > .service.logged_out > .atag-btsub> .site-img {
filter: grayscale(100%) brightness(50%);
}
`);
// 内部使用的状态值
const valid_states = [
'found',
'missing',
'logged_out',
'error'
];
// 替换搜索URL中的占位符
function replaceSearchUrlParams(site, imdb_nb, douban_id, film_title, film_year) {
var search_url = site['searchUrl'];
var s = search_url.replace(/%tt%/g, 'tt' + imdb_nb)
.replace(/%nott%/g, imdb_nb)
.replace(/%doubanId%/g, douban_id)
.replace(/%s_title%/g, film_title)
.replace(/%s_year%/g, film_year)
.replace(/---/g, '-');
console.log(`替换后的搜索url:${s}`)
return s;
}
// 检查是否添加链接到某个站点
async function maybeAddLink(elem, site_name, search_url, site, movie_id) {
console.log('Testing... ', site_name)
// 对每个站点进行连接速率限制
var set_rate = ('rateLimit' in site) ? site['rateLimit'] : 200;
var rate = set_rate
var domain = search_url.split('/')[2];
var now = (new Date()) * 1;
var lastLoaded = window.localStorage[domain + '_lastLoaded'];
if (!lastLoaded) {
lastLoaded = now - 50000;
} else {
lastLoaded = parseInt(lastLoaded);
}
// 如果在限制之内,则延迟请求
if (now - lastLoaded < rate) {
window.setTimeout(maybeAddLink.bind(undefined, elem, site['name'], search_url, site, movie_id), rate);
return;
} else {
window.localStorage[domain + '_lastLoaded'] = (new Date()) * 1;
}
var success_match = ('positiveMatch' in site) ? site['positiveMatch'] : false;
var target = search_url;
if ('goToUrl' in site) {
target = await replaceSearchUrlParams({
'searchUrl': site['goToUrl'],
'spaceEncode': ('spaceEncode' in site) ? site['spaceEncode'] : '+'
}, movie_id);
}
// 检查tmdb/tvdb转换
if (search_url.indexOf('=00000000') > -1 || search_url.indexOf('=undefined') > -1) {
addLink(elem, site_name, target, site, 'error');
return;
}
// 请求头
let reqHeader = {};
// 使用GET方法检查结果
GM.xmlHttpRequest({
method: 'GET',
headers: reqHeader,
timeout: 30000,
url: search_url,
onload: function (response) {
// 判断是否登出、404或空白响应等情况,并按照不同状态添加链接
if (response.responseHeaders.indexOf('efresh: 0; url') > -1 || response.status > 499 || (response.status > 399 && !site.ignore404) || (response.responseText == "" && !site.ignoreEmpty)) {
addLink(elem, site_name, target, site, 'logged_out');
} else if (site['positiveMatch'] && site['loggedOutRegex'] && String(response.responseText).match(site['loggedOutRegex'])) {
addLink(elem, site_name, target, site, 'logged_out');
} else if (String(response.responseText).match(site['matchRegex']) ? !(success_match) : success_match) {
addLink(elem, site_name, target, site, 'missing');
} else if (site['loggedOutRegex'] && String(response.responseText).match(site['loggedOutRegex'])) {
addLink(elem, site_name, target, site, 'logged_out');
} else {
addLink(elem, site_name, target, site, 'found');
}
},
onerror: function () {
addLink(elem, site_name, target, site, 'error');
console.log("Letterboxd Scout Mod (GET-Request Error. Site): " + site_name);
},
onabort: function () {
addLink(elem, site_name, target, site, 'error');
console.log("Letterboxd Scout Mod (GET-Request aborted. Site): " + site_name);
},
ontimeout: function () {
addLink(elem, site_name, target, site, 'error');
console.log("Letterboxd Scout Mod (GET-Request timed out. Site): " + site_name);
}
});
return elem
}
// 添加链接到DOM中
function addLink(elem, site_name, target, site, state) {
// 状态值应该是valid_states数组中定义的值
if (!valid_states.includes(state)) {
console.log("Unknown state: " + state);
}
elem.classList.add(state)
}
// 站点列表
const sites = [
{
'name': 'BT4G',
'icon': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAGFBMVEX////ExMRGRkYaGhqqqqqYmJiIiIhvb2/FncXiAAAAU0lEQVQI12NgTGCAAFZzAQiD2UwFwioKFQkAM5RUWCBSxQGMEIZwIpTBpAZlsJkJQPUbqUAZzkpQOVZjRQcIK9hIxDERzAoyUjZWB7MYBQUY4AAAUfkIESxqP9YAAAAASUVORK5CYII=',
'searchUrl': 'https://bt4g.org/search/%s_title% %s_year%/bysize/1',
'loggedOutRegex': /Cloudflare|Ray ID/,
'ignore404': true,
'spaceEncode': ' ',
'matchRegex': /did not match any/
},
{
'name': 'RARBG',
'icon': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAADMUExURQAAADhgu/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////7+/zhgu1d5xlt8x2GByWiGzHCNz3aS0XqV0oCa1Iig1o+l2Zar25yw3qK14Ky947DA5LXE5rnH6MbS7MvW7tDa79ff8tzj8+Pp9uzw+fT2+/7+/////0INwLoAAAAodFJOUwAAAAMIDRQZHSIqMzpAR09dY251foaPl6CmrbO7wMfQ19re5Orx9/zZOpCWAAAB3ElEQVRIx5XVWVvaQBSA4ZlhsewoBapVlqFZKqKtiFAkZfn+/3/yIhAmkJDxXOQiOe8zmeXMEUopJYQolOsNM+q1armYE/FQSqnwUah1B65nhOs4o/5dp1X/lgxqmuRw7m/KCeDqjvTo1c9Bw70AGDULp6AF8D6LxXyxXHuhcFv5E9AG8BNi8s8DcJpSSivg+79XAKOKNfD9BcB9zh74S8CpfAH4W6Arw3wr8Ab0ZJifBObz+Wz2OjYmDuh8Knjc79dH7J+cciZgGYEAaGSDXQQ+gGY24OnwamU3whEE4FYsgDnpUTEbrCMADKTKAt7k8OYV+JkJ1lG+/x+863TgT6fTvy/GRv8BdFGlg9OK2AJtZQ/WgC5Zg/EGcJvSFrx5gNuW1mAD0JP24GkHjKqXQRAE41i10S/nLoDH2KnwVwC3VxmARXwaTjcL8HK8/XYAmWB7HGJmBcw7IDBF+vGexm+ybOAd1/bZGMKq4vx3YHMJuD2AedI0ksEw7JLP8aK4BOS1B2yMsjuIZDCQYWNdGt3LBC3z2pqEB7oyOFlbE5y13Y4QouGcNeAIlB7iH35VhRD57+lA1Aax/BshhBClH855/h6IUvthqLXWWg97neq+8eert319DGPjvhKfLLE8ejIzVGgAAAAASUVORK5CYII=',
'searchUrl': 'https://rarbgweb.org/torrents.php?imdb=%tt%&order=size',
'loggedOutRegex': /something wrong|Please wait|enter the captcha|too many requests/,
'matchRegex': /imdb_thumb.gif/,
'positiveMatch': true,
'rateLimit': 4000,
'both': true
},
{
'name': '1337x',
'icon': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTI4cHgiIGhlaWdodD0iMTI4cHgiIHZpZXdCb3g9IjAgMCAxMjggMTI4IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3' +
'd3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPHRpdGxlPjEzMzd4PC90aXRsZT4KICAgIDxkZWZzPgogICAgICAgIDxwb2x5Z29uIGlkPSJwYXRoLTEiIHBvaW50cz0iMCAwIDEyOCAwIDEy' +
'OCAxMjggMCAxMjgiPjwvcG9seWdvbj4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSLpobXpnaItMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IjEzMzd4Ij4KICAgIC' +
'AgICAgICAgPG1hc2sgaWQ9Im1hc2stMiIgZmlsbD0id2hpdGUiPgogICAgICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICA8ZyBpZD0iMTAyNOW5s+a7keWchuinkuefqeW9' +
'ouiSmeeJiCI+PC9nPgogICAgICAgICAgICA8ZyBpZD0ibG9nbyIgbWFzaz0idXJsKCNtYXNrLTIpIiBmaWxsLXJ1bGU9Im5vbnplcm8iPgogICAgICAgICAgICAgICAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4yODcwMDAsIC0wLjEyMDAwMCkiIGlkPSLot6' +
'/lvoQiPgogICAgICAgICAgICAgICAgICAgIDxwb2x5Z29uIGZpbGw9IiNGRjkwMTAiIHBvaW50cz0iNS4zMzM1MDMzNiAwLjE5ODA0NTIwOSA0NS44MDYxMDIgMC4xOTgwNDUyMDkgNjUuMTg5NTMwNCAzOC44NDEwMTI5IDg1LjkyNzc1ODUgMC4xOTgwNDUyMDkg' +
'MTI1LjAzNzM5NiAwLjE5ODA0NTIwOSA5NC4wODkyMDIgNjIuNTg3MTE2NSAxMjggMTI3Ljk0MjAzNiA4NC45MDc1NzggMTI4IDY0Ljc1Njk3MzkgODkuNTgxNjQ0NiA0NS40NjMzMjEzIDEyOCAwIDEyNy44ODY0ODYgMzcuOTc5Mjc3NiA2Mi41MDAxNjk4Ij48L3' +
'BvbHlnb24+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTI2LjUwMDIwNzIsODIuMjE1MzI4OSBDMjYuNTAwMjA3Miw4Mi4yMTUzMjg5IDY0LjY1NDk1NTgsNzguODk0NDQ4OCAxMDAuNTI4NTgxLDQ5LjYxMDMyNDkgTDEyNS4wNDU1NTcsMC4yMDUyOTA3' +
'NjYgTDg1LjkyNzc1ODUsMC4yMDA0NjAzOTUgTDY1LjIwNTg1MzMsMzguMjI3NTU1OCBMNDUuODg3NzE2NCwwIEw1LjI3MjI5MjU0LDAgTDM3Ljc5MTU2NDQsNjIuMTkxMDI2MSBMMjYuNTAwMjA3Miw4Mi4yMTUzMjg5IFoiIGZpbGw9IiNGRjlEMkIiPjwvcGF0aD' +
'4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+',
'searchUrl': 'https://1337x.to/category-search/%s_title%+%s_year%/Movies/1/',
'matchRegex': /No results were returned/
},
{
'name': 'Blu-ray',
'icon': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAADeUExURVO29Vq59Vu59Vy59V269WC79W6/9W+/9XDA9XDB9nDC93HC9' +
'3PC9nXE93bG9njF93vF9n3I94DH9oHG9oLH9oTI9oXJ9orK9orN+IvK94zM94zO+I3L943O+JDN95HP+JHQ+JPP95XQ+JbQ95jU+ZnR+JzR+JzS95zT+J3S+J3T+J3U+J7S+J/T+J/U+KDT+KPV+KTX+anX+K7Z+q/a+bHc+bbf+rrf+cTk+sXk+8jk+svl+svm+8zn+9vt/Nvu/Nzu/Nzv' +
'/N3v/ODv/OHw/Ojz/Onz/er0/er1/f///532i+4AAAC+SURBVDjLtdNFDsNADEDRFFxmZmZmZs79L9TUo1ZZOGOpamdlK0/K6EdRgDnK74CqO9cRA7RT54DapMFpf3wLEvTsNkdmKkCBAi5chzhXKODH0ceBEs55CrhfU/yBc4gCk1qnvxB3LJulHbYRMElBCsAqL3lgU58DFPACWJJzIZY' +
'GHbRXd/UfgwKw5sAYl7RhatjgkjVKDQ1xhwQBquForD0Tzy8eqsPt/glRZEIN5CV3OVnqVSvo/Mev9zV4Aq22bvwYC8iHAAAAAElFTkSuQmCC',
'searchUrl': 'https://www.blu-ray.com/search/?quicksearch=1&quicksearch_country=all&quicksearch_keyword=%tt%§ion=theatrical',
'matchRegex': /return any results/,
'inSecondSearchBar': true,
'both': true
},
{
'name': 'Caps-A-Holic',
'icon': 'data:image/webp;base64,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',
'searchUrl': 'https://caps-a-holic.com/index.php?s=%s_title%',
'matchRegex': /No results for/,
'showByDefault': false
},
{
'name': 'Zimuku',
'icon': 'data:image/webp;base64,UklGRlwAAABXRUJQVlA4TE8AAAAvH8AHAA9wt/9z/N/zf/7jAY5q23aaR5eBlC+NJgBJDLGROCDzrL/Ti4OI/k+ADSt6pKyLON7tXN4NEd6x4MxwkK6krIo4vZOyP1SZ7slLAA==',
'searchUrl': 'https://so.zimuku.org/search?q=%tt%',
'loggedOutRegex': /Cloudflare|Ray ID/,
'matchRegex': /搜索不到相关字幕/,
'inSecondSearchBar': true,
'both': true
},
{
'name': 'SubHD',
'icon': 'data:image/webp;base64,UklGRuACAABXRUJQVlA4TNMCAAAvH8AHEK8lIZJt16p6P6IFTOFfRoYf7tljw0EbSY7kCxCe+lO9tDPTcBtJciRFHRPPpvPfFCq+9LcJR5IkRZI3LEus79P3XywzHl9XQCmEgrCNIDQESUEQthFqGv7fEcJ1RShsUdMgnDfXh9AgkAah4SwqgiCUGNpo' +
'ELYQGuoUmO3UNJwvwlnsoomwxXWzKzXXS6GK8P9hK9dFSY1t6tTU7LAfkoaGsB9N/t9U7EobDZqzUpjQ0BAENAT+ESnQnU3CNz7QmCFTpF/6bBMs4z0Bn2iUx1I2dngHwtYzftFY3Pi9wJGGNEpijBzBqaHD/kdR+kLcYVmzd7sUaTQeEl3TX6r3+2nEOU5tedOK/8bP4cjVHC3mVDoEP2f' +
'b4e6TbpayOi5/z+vY8vXtVv46gr8Pno2HF9Lb791//d8fkChJsmlb01fPtm3bNq5tzLVt28azbX7hWr3Ovn8Q0f8JEPu/V487++urSlQLq+qHuiZefhfnj+256nNu2yf2ezxLPc0b/235M6aej/w2nuksPhWRr3mzkfdZpFV5+oPze7bsOH493kFb5XsuC10D+4KLaazg21ulwfPguD2F6N' +
'sJkrwSwNzNh3YuBYALbLKD3AawMU5Vk88CWJJKuobJOQDBamasBRBKemvJKQAPLXrr5MmT4aS2mVwCsOp+uuHeWE5CYS7bezUi3a2hlOgBw1yy62aqQ1kRSz0TaAOwIsShkqnGXtm20IZF0aSiyUVV08Ku/l8IAEdJc50PZtIJAMtJbR/Zvm7dhmSLps4BFpKhbrIBwB1bQgCwnHRPkfMAV' +
'kQYifsAHCGTH0jsYgD+6w8e3rQQQFAkefEzx6Z358Mx4Ibac37KKNGorX5k9T2lz0W+ZBLVmGun9+8+djkkQ2nmFxGZdvBwRkTkV693A38N+Tud703+zF+hb1qyfctueS3OP9496hmsqS5WLa6uGex+8v6H2AEA',
'searchUrl': 'https://subhd.tv/d/%doubanId%',
'loggedOutRegex': /Cloudflare|Ray ID/,
'matchRegex': /上线时间表/,
'inSecondSearchBar': true,
'both': true
},
{
'name': 'R3SUB',
'icon': 'data:image/webp;base64,UklGRooCAABXRUJQVlA4TH4CAAAvH8AHEDfloG0jQUoys6d//oCHBsS2jSTJOdHVu/dAbNtIkiS6+t78811WkWQ1aoIgjGAA/x8ISJcvKNRPvdRPHVSnCgyLEEIQiIVNpY1gU9Mi2vx+f8175k5os+/xoKkA8d5zqLAJFhC6E26z0DgswPL//xfA3KNY' +
'3Ox72gQw73FYDIx9zHsq7XTTe6Zg5iYzd4Tjfb7Mzrwzd/bOSQ1iAXPH4p29Y9nPl8MEcFiIhmBT2fcYyuHdOeymO3tf9AGE4Xjv2fccBnNHHCrA0h03bSwG8n2/CdHG4gZ87xHAAoLmfb8EMe8JQhBKGyGkUo3KkLBt2/G2sr+rtvt9aWrb9mzbtu2t+2Z1Rq07yQ9do7cR/Vfktm0jIT3' +
'uOo+wLMsXiI+LJaKxcfEBn/XfBD8G+hMsy6jAb/kw1BcwJRBvSnycKXExphgXkObxOI7HTrOd3MRwm0m3nUyCrH3guu7ru22nXzy6vLUAgMIdF1efHLuzqxggb6Mk/Wvs+CLpcSXQ5eplZ8M76cNAEtAsST9qOC9Ju4FL0tx2jkp64wVaQzgnSfuBnROzf1ZxQNJ4SRiquCBpvAvIaeqvJv' +
'uqNLM3Iwzda78ufrvSQoi996dnnw1BGNZdm1/4frMnNQTvps9znw6Xh+FXTf49SZPDQFlfUxock/S2KAz1nJWkQ7Dm9+zUiRSOSFoaDJooaOCiJF0frTgj6WFW0EQ/a8DeJkkz63M3TErSx7qaV4sTW5Ib3kt/92RA8xN3+WFvl+aM3Bh7eqoRvJtPH8w5/vzWvvYkIHP5XzgeJwVSHZtgc' +
'5NsO5OVMda4zP+1eS7Mc2WeS/Ncr0BfCOor0cQvJrivWA==',
'searchUrl': 'https://r3sub.com/search.php?s=%tt%',
'loggedOutRegex': /Cloudflare|Ray ID/,
'matchRegex': /查無資料/,
'inSecondSearchBar': true,
'both': true
},
{
'name': 'OpenSubtitles',
'icon': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAAD///8TExOI954UAAAAk0lEQVQoz62SQQ7DMAgEcSXfe/F/+gQf4D99egeCjJtTpITIG4agtYMsX1nxkr/os56r8EB0+6ANJcxmqEWJV6oMFTq6ynAgm64N8J6j7EksW0CaE' +
'L7Z1h0GBjvoBt20oHGoBXyyAmgDTliAe26avk3PoAnxCwVh8nYD1oTJmklsbZTQY1QapVlDZDz34/492K/YD8ElL5+2GoYbAAAAAElFTkSuQmCC',
'searchUrl': 'https://www.opensubtitles.org/zh/search/sublanguageid-chi,zht,zhe,eng/imdbid-%nott%/sort-5/asc-0',
'loggedOutRegex': /Guru Meditation/,
'matchRegex': /div itemscope/,
'positiveMatch': true,
'inSecondSearchBar': true,
'both': true
}
]
// 创建一个用于显示站点链接的元素
const PTSectionFactory = async (name, link, icon, site) => {
const section = $('<p style="margin:0;padding: 8px;"></p>').addClass('service');
const img = $('<img class="site-img"/>').css({'height': '18px', 'width': '18px'});
const linkElem = $('<a class="atag-btsub"></a>').attr({
'target': '_blank',
'rel': 'nofollow noopener noreferrer'
});
linkElem.append(img);
linkElem.attr({'href': link, 'title': name});
img.attr('src', icon);
section.append(linkElem);
// 检查是否添加链接到该站点
await maybeAddLink(section[0], name, link, site, imdb_nb);
return section[0];
};
// 构建搜索栏
$('ul.js-actions-panel').append(`<li style="padding: 0;"><div class="search-bar-btsub"
id="search_bar01" style="display: flex;flex-wrap: wrap;justify-content: center;padding: 0 25px;">
<tr id="search_bar01"></tr></div></li>`)
// 添加站点链接到页面中
sites.forEach(async (site) => {
const link = replaceSearchUrlParams(site, imdb_nb, douban_id, film_title, film_year)
const toAppend = await PTSectionFactory(site.name, link, site.icon, site)
$('#search_bar01').append(toAppend)
})
}
// 查找豆瓣信息 构成相关标签
async function processScanResult(scanResult) {
const imdbID = imdb_nb
// 调用 getDoubanID0 获取豆瓣 ID
let douban_data = await getDoubanID0(imdbID);
const douban_data_str = JSON.stringify(douban_data);
// 判断豆瓣api是否找到条目
if (douban_data_str.length > 12) {
// 豆瓣api找到找到条目
// 构造豆瓣相关标签
let douban_title = douban_data.title;
let douban_id = douban_data.id;
let douban_url = `https://movie.douban.com/subject/${douban_id}/`
console.log(`豆瓣信息: ${douban_data_str}`);
console.log(`豆瓣标题: ${douban_title}`);
console.log(`豆瓣id: ${douban_id}`);
console.log(`豆瓣链接: ${douban_url}`);
// 创建豆瓣按钮
createDoubanButton(douban_url, douban_id);
// 添加中文标题
addDoubanTitle(douban_title);
// 创建搜索栏
searchBars(imdb_nb, douban_id, film_title, film_year);
} else {
// 豆瓣api没找到找到条目
// 如果 getDoubanID0 返回默认值,则继续调用 getDoubanID1 获取豆瓣 ID
if (douban_data === '00000000') {
douban_data = await getDoubanID1(imdbID);
}
// 如果 getDoubanID1 返回默认值,则继续调用 getDoubanID2 获取豆瓣 ID
if (douban_data === '00000000') {
douban_data = await getDoubanID2(imdbID);
} else {
function getDoubanID1_getinfo() {
const douban_id = douban_data.split('|')[1].trim();
console.log(`getDoubanID2找到的豆瓣id: ${douban_id}`)
let douban_url = `https://movie.douban.com/subject/${douban_id}/`;
// 创建豆瓣按钮
createDoubanButton(douban_url, douban_id);
// 创建搜索栏
searchBars(imdb_nb, douban_id, film_title, film_year);
// 添加中文标题
addDoubanTitle(douban_title);
};
let douban_title = douban_data.split('|')[0].trim();
console.log(douban_title)
if (douban_title.length > 14 && douban_title.indexOf(' ') > -1) {
douban_title = douban_title.substr(0, douban_title.indexOf(' ')).trim();
console.log(douban_title)
getDoubanID1_getinfo();
} else {
getDoubanID1_getinfo();
}
}
// 如果 getDoubanID2 返回默认值,则继续调用 getDoubanID3 获取豆瓣 ID
if (douban_data === '00000000') {
douban_data = await getDoubanID3(imdbID);
// 构造豆瓣相关标签
let douban_id = douban_data.douban_id;
let serch_douban_html = douban_data.result;
// 如果 getDoubanID3 未找到符合 ,则继续调用 getDoubanID4 获取豆瓣 ID
if (serch_douban_html.match("未找到符合")) {
douban_data4 = await getDoubanID4(imdbID);
douban_id = douban_data4.douban_id;
serch_douban_html = douban_data4.result;
}
const regex = /<h3\s+class="LC20lb MBeuO DKV0Md"[^>]*>(.*?)<\/h3>/i;
const match = serch_douban_html && serch_douban_html.match(regex);
let douban_title = '';
if (match) {
// .replace('- 电影- 豆瓣', '').replace('- 电视剧- 豆瓣', '')
let titleWithSuffix = match[1];
titleWithSuffix = titleWithSuffix.split("- ")[0];
if (titleWithSuffix.match(/[\u4e00-\u9fa5]/)) { // 判断是否含有中文字符
douban_title = titleWithSuffix;
}
}
const douban_url = `https://movie.douban.com/subject/${douban_id}/`
console.log(`豆瓣 ID: ${douban_id}`);
console.log(`豆瓣 ID: ${douban_url}`);
// 创建豆瓣按钮
if (douban_id !== undefined) {
createDoubanButton(douban_url, douban_id);
}
// 添加中文标题
addDoubanTitle(douban_title);
// 创建搜索栏
searchBars(imdb_nb, douban_id, film_title, film_year);
}
}
}
processScanResult(imdb_nb);
});
});
$(document).ready(function createTMDBChiSearchBOX() {
GM_addStyle(`
.search-box-radius {
border-radius: 20px !important;
}
.search-box {
border-radius: 30px;
position: fixed;
top: 72px;
right: 72px;
width: 300px;
padding: 5px;
background-color: #202830;
border: none;
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
z-index: 999;
opacity: 0;
visibility: hidden;
transition: border-radius 0.3s ease-out; opacity 0.3s ease-out, visibility 0s linear 0.3s, filter 0.3s ease-out;
filter: blur(10px);
}
.search-box.show {
opacity: 1;
visibility: visible;
transition: opacity 0.3s ease-in, visibility 0s linear 0s, filter 0.3s ease-in;
filter: blur(0);
}
.search-box.hide {
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease-out, visibility 0s linear 0.3s, filter 0.3s ease-out;
filter: blur(10px);
}
.search-results-fold {
overflow-y: auto;
height: 0px;
transition: height 0.5s ease-out;
}
.search-results-unfold {
margin-bottom: 5px;
height: 400px;
}
#tmdb-search-container input[type='text'] {
display: block;
height: 18px;
line-height: 1.30769231;
font-size: 1em;
background-color: #456;
padding: 6px 30px 6px 15px;
border-radius: 15px;
border: none;
box-shadow: none;
width: -webkit-fill-available;
margin: 10px;
}
.chi-search-info {
color: #678;
}
.chi-search-info:hover {
color: #99AABB;
}
@media (max-width: 768px) {
#tmdb-search-box {
position: fixed;
left: 50%;
transform: translateX(-50%);
width: calc(80vw);
height: 80vh;
}
`);
// tmdb中文搜索 按键图标
function createChiSearchIcno() {
let imgChinese = 'data:image/webp;base64,UklGRjICAABXRUJQVlA4TCYCAAAvH8AHEGfDtm0jSZzZja7/Hi+8/BtH14PjRpIUKbpn+e78d+c' +
'8wh+Ww7ZtJInObgl7d/1Xdy38sdvYtlXl7/vdQzdogJRCKYcGiMktdne4VYCRFABccV6eTs/DbOvPfzXOMqF6vZGYUBFWIepAYmzx0LSIR9+qvp' +
'8/hiUvg4gMPnVwFC+SA4QFAwLcKu5Kq/hwYQEAgQ9+BwcCYAIIAEB54iRxcMYzKuKDX6Vf3ZAUZJRUk6o+0oqCefrXp13/LaYzN804nXs6s+7Q3' +
'1f51F7W+Gz2dDK39e79c7/fHz3GNS2urOKRSlLE9Z+37uJNTmrX1+sxAQRJkk1b/fy+n23r2779bdv2/jdw5t57/g4i+j8BAFyx95EF2l4YeY+5' +
'oB5+UvvnIYC7af7j1B2cLf5ryxmh5a3ei9CMNV4WLS3tAwjYKG5b2gIAj43tNZKv57fivoIu+Sg8SHJmhWy7oPlxlVwxyBS0l0iDZF5fk+Jcj66' +
'IIXHx49t6Ugh+UXtC+Zug9iGnEqd9o5LfILncBwDOXQ0B4DlHpqEGab8DAM5c2aE8D2t4UeD0Qv2hxoVbRb6k1tE7s4M1PayaJWnVMBuLOs1wum' +
'lmrJgU3LD8lDOZn5aGHbB5PyVNdaQ6xOtC9U7Ap7TTkMaeAbjOJsm9XzeAmzkpeyzx/e5hYJvicP9D9wvlK7xJpEGdb4Bv3UTruA+Av6av5od4k' +
'mmtT+3NWt6bWm9lTgAA';
let engSearch = $('nav.main-nav').find('li.js-nav-search-toggle');
let chiSearch = $(`<li class="navitem"><a id="chi-search" href="#" class="chi-replace" style="background:none">
<img src="${imgChinese}" style="height: 20px;margin-top: 4px;}"> </a></li>`);
engSearch.after(chiSearch);
};
createChiSearchIcno();
// tmdb中文搜索框
function tmdbChiSearch() {
// 获取指定<a>标签和整个页面
const searchAnchor = $('a#chi-search');
const page = $('body');
// 创建TMDB搜索框,并设置样式
const searchBox = $(
'<div id="tmdb-search-box" class="search-box">' +
'<div id="tmdb-search-container" style="height: 100%;">' +
'<input type="text" style="color: #9ab;" placeholder="按回车搜索...">' +
'<div id="tmdb-results" class="search-results-fold"></div>' +
'</div>' +
'</div>'
).appendTo(page);
// 点击<a>标签显示/隐藏搜索框
searchAnchor.click(function () {
searchBox.toggleClass('show');
if (searchBox.hasClass('show')) {
searchBox.removeClass('hide');
searchBox.css('opacity', '0');
searchBox.css('visibility', 'hidden');
setTimeout(function () {
searchBox.css('opacity', '');
searchBox.css('visibility', '');
}, 0);
} else {
searchBox.addClass('hide');
setTimeout(function () {
searchBox.removeClass('show');
searchBox.removeClass('hide');
searchBox.css('opacity', '');
searchBox.css('visibility', '');
}, 300);
}
});
// 监听输入框的回车事件;调用TMDB API搜索电影/电视剧
searchBox.find('input').keydown(function (event) {
if (event.keyCode === 13) { // 当用户按下回车键
event.preventDefault();
const keywords = $(this).val();
searchBox.addClass('search-box-radius');
$('#tmdb-results').addClass('search-results-unfold');
// 匹配电影标题和年份的正则表达式
var titlePattern = /^(.+?)(?:\s(\d{4}))?$/;
// 格式化输入的搜索关键词
var match = keywords.match(titlePattern);
var kw_title = match[1];
var kw_year = match[2] || "";
// 输出结果
console.log("tmdb搜索电影标题:" + kw_title);
console.log("tmdb搜索发行年份:" + kw_year);
searchTMDB(kw_title, kw_year);
}
});
// 利用TMDB API搜索电影/电视剧
function searchTMDB(kw_title, kw_year) {
// 用输入的关键词调用TMDB API搜索电影/电视剧
//https://api.themoviedb.org/3/search/movie?api_key=<YOUR_API_KEY>&query=<MOVIE_NAME>&year=<YEAR>
//https://api.themoviedb.org/3/search/multi?api_key=${tmdb_api}&language=zh-CN&query=${encodeURIComponent(kw_title)}
const tmdbApiUrl = `https://api.themoviedb.org/3/search/movie?api_key=${tmdb_api}&language=zh-CN&query=${encodeURIComponent(kw_title)}&primary_release_year=${kw_year}`;
GM_xmlhttpRequest({
method: 'GET',
url: tmdbApiUrl,
onload: function (response) {
const searchResults = JSON.parse(response.responseText).results;
const chiSearchResultList = $('#tmdb-results').empty();
// 显示搜索结果
searchResults.forEach(function (result) {
console.log(result)
const tmdbId = result.id; // TMDB ID
const zhTitle = result.title || result.name; // 中文标题
const orTitle = result.original_title || result.original_name; // 英文标题
const releaseYear = result.release_date.slice(0, 4); //发行年份
const orLanguage = result.original_language // 原始语言
const posterUrl = 'https://image.tmdb.org/t/p/w92' + result.poster_path; // 海报缩略图
const genre_dict = {
28: '动作',
12: '冒险',
16: '动画',
35: '喜剧',
80: '犯罪',
99: '纪录',
18: '剧情',
10751: '家庭',
14: '奇幻',
36: '历史',
27: '恐怖',
10402: '音乐',
9648: '悬疑',
10749: '爱情',
878: '科幻',
10770: '电视电影',
53: '惊悚',
10752: '战争',
37: '西部'
}; // 类型id字典
// 取前三个类型id转换成中文类型
const movie_genre_ids = result.genre_ids.slice(0, 3);
const chiGenres = movie_genre_ids.map(genre_id => {
if (genre_dict[genre_id]) {
return genre_dict[genre_id];
}
}).join('/');
const moreChiInfo = releaseYear + "/" + chiGenres // 整合年份/国家/类型 信息
const chiSearchlistItem = $(`<div data-tmdb-id="${tmdbId}">`).css({
'height': '125px',
'border-bottom': '1px solid #303840',
'overflow': 'hidden',
'position': 'relative',
});
const chiSearchPoster = $(`<img src="${posterUrl}">`).css({
'display': 'inline-block',
'height': '105px',
'width': '70px',
'border-radius': '6px',
'transition': 'transform 0.2s'
}).hover( // 鼠标悬停时放大和阴影
function () {
$(this).css({
'transform': 'scale(1.05)',
'box-shadow': '0 0 5px rgba(0, 0, 0, 0.3)'
}).find('p').css({
'transform': 'scale(1.05)',
'box-shadow': '0 0 5px rgba(0, 0, 0, 0.3)'
});
},
function () {
$(this).css({
'transform': 'scale(1.0)',
'box-shadow': 'none'
}).find('p').css({
'transform': 'scale(1.0)',
'box-shadow': 'none'
});
}
);
const chiSearchLink = $(`<a href="https://letterboxd.com/tmdb/${tmdbId}/"></a>`).css({
'display': 'flex',
'height': '105px',
'margin': '10px',
'width': '280px',
});
const chiSearchZhTitle = $(`<div>${zhTitle}</div>`).css({
"font-size": "1.2em",
"color": "#99AABB",
"margin": "4px 5px",
'display': '-webkit-box',
'-webkit-box-orient': 'vertical',
'-webkit-line-clamp': '2',
'overflow': 'hidden',
'text-overflow': 'ellipsis'
});
const chiSearchOrTitle = $(`<div>${orTitle}</div>`).css({
'font-size': '13px',
'margin': '2.5px 5px',
'overflow': 'hidden',
'display': '-webkit-box',
'-webkit-box-orient': 'vertical',
'-webkit-line-clamp': '2',
'overflow': 'hidden',
'text-overflow': 'ellipsis'
});
const chiSearchMoreChiInfo = $(`<div>${moreChiInfo}</div>`).css({
'font-size': '13px',
'margin': '2.5px 5px',
"overflow": "hidden",
"text-overflow": "ellipsis",
"display": "-webkit-box",
"-webkit-line-clamp": 2,
"-webkit-box-orient": "vertical"
});
const chiSearchInfo = $(`<div class="chi-search-info"></div>`).css({
'display': 'inline-block',
'display': 'flex',
'justify-content': 'center',
'flex-direction': 'center',
'flex-direction': 'column',
'align-items': 'flex-start',
'height': '105px',
'margin': '5px'
});
chiSearchResultList.append(chiSearchlistItem);
chiSearchlistItem.append(chiSearchLink);
chiSearchLink.append(chiSearchPoster).append(chiSearchInfo);
if (orLanguage === 'zh') {
chiSearchInfo.append(chiSearchZhTitle).append(chiSearchMoreChiInfo);
} else {
chiSearchInfo.append(chiSearchZhTitle).append(chiSearchOrTitle).append(chiSearchMoreChiInfo);
}
});
},
});
}
};
tmdbChiSearch();
});