// ==UserScript== // @name TMDB 한국 지원 강화 // @namespace http://tampermonkey.net/ // @version 1.3.7 // @description TMDB 영화/TV 시리즈 페이지에 한국어, 영어, 원어 제목 추가, 개별 클립보드 복사 기능, 한국 시청등급 및 제작국 표시 // @match https://www.themoviedb.org/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @author DongHaerang // @downloadURL none // ==/UserScript== // 주의사항: 아래 YOUR_API_KEY 부분을 실제 TMDB API 키로 교체하는 것을 잊지 마세요. const apiKey = "YOUR_API_KEY"; (function() { 'use strict'; GM_addStyle(` .additional-titles { font-size: 1.1em; line-height: 1.4; margin-bottom: 10px; } .additional-title { cursor: pointer; transition: color 0.3s; } .additional-title:hover { color: blue !important; } #additional-info { margin-top: 10px; clear: both; display: flex; align-items: center; width: 100%; } #production-countries { font-size: inherit; margin-right: 20px; } #external-links { font-size: inherit; } #external-links a { margin-right: 10px; text-decoration: none; color: inherit; transition: color 0.3s; } #external-links a:hover { color: blue; } .original-title-label { cursor: pointer; transition: color 0.3s; } .original-title-label:hover { color: blue !important; } .title-label { cursor: pointer; transition: color 0.3s; } .title-label:hover { color: blue !important; } .ko-title-text { cursor: pointer; text-decoration: none; transition: color 0.3s; } .ko-title-text:hover { color: blue !important; } .main-link { cursor: pointer; text-decoration: none; transition: color 0.3s; } .main-link:hover { color: blue !important; } .en-original-link { cursor: pointer; text-decoration: none; transition: color 0.3s; } .en-original-link:hover { color: blue !important; } .type-link { cursor: pointer; text-decoration: none; transition: color 0.3s; margin: 0 5px; } .type-link:hover { color: blue !important; } .language-link { cursor: pointer; text-decoration: none; transition: color 0.3s; margin: 0 5px; } .language-link:hover { color: blue !important; } .plus-en-link, .plus-original-link, .plus-tmdb-link { cursor: pointer; text-decoration: none; transition: color 0.3s; margin: 0 5px; } .plus-en-link:hover, .plus-original-link:hover, .plus-tmdb-link:hover { color: blue !important; } .year-link { cursor: pointer; text-decoration: none; transition: color 0.3s; margin: 0 5px; } .year-link:hover { color: blue !important; } `); const copyToClipboard = text => { navigator.clipboard.writeText(text).then(() => { showTemporaryMessage(`${text} 클립보드에 복사됨`); }); }; const showTemporaryMessage = message => { const messageElement = document.createElement('div'); Object.assign(messageElement.style, { position: 'fixed', top: '10px', left: '50%', transform: 'translateX(-50%)', backgroundColor: 'rgba(0, 0, 0, 0.7)', color: 'white', padding: '10px', borderRadius: '5px', zIndex: '9999' }); messageElement.textContent = message; document.body.appendChild(messageElement); setTimeout(() => document.body.removeChild(messageElement), 1000); }; // 국가 코드를 한글로 변환하는 함수 const translateCountry = (countryCode) => { const countryMap = { 'US': '미국', 'GB': '영국', 'KR': '한국', 'JP': '일본', 'CN': '중국', 'FR': '프랑스', 'DE': '독일', 'IT': '이탈리아', 'ES': '스페인', 'CA': '캐나다', 'AU': '호주', 'RU': '러시아', 'IN': '인도', 'BR': '브라질', 'MX': '멕시코', 'NL': '네덜란드', 'BE': '벨기에', 'SE': '스웨덴', 'DK': '덴마크', 'NO': '노르웨이', 'FI': '핀란드', 'PL': '폴란드', 'TR': '터키', 'TH': '태국', 'VN': '베트남', 'ID': '인도네시아', 'MY': '말레이시아', 'SG': '싱가포르', 'PH': '필리핀', 'TW': '대만', 'HK': '홍콩', 'NZ': '뉴질랜드', 'CO': '콜롬비아', 'AR': '아르헨티나', 'ZA': '남아프리카', // 국가 전체 이름도 매핑 'United States of America': '미국', 'United Kingdom': '영국', 'South Korea': '한국', 'Japan': '일본', 'China': '중국', 'France': '프랑스', 'Germany': '독일', 'Italy': '이탈리아', 'Spain': '스페인', 'Canada': '캐나다', 'Australia': '호주', 'Russia': '러시아', 'India': '인도', 'Brazil': '브라질', 'Mexico': '멕시코', 'Netherlands': '네덜란드', 'Belgium': '벨기에', 'Sweden': '스웨덴', 'Denmark': '덴마크', 'Norway': '노르웨이', 'Finland': '핀란드', 'Poland': '폴란드', 'Turkey': '터키', 'Thailand': '태국', 'Vietnam': '베트남', 'Indonesia': '인도네시아', 'Malaysia': '말레이시아', 'Singapore': '싱가포르', 'Philippines': '필리핀', 'Taiwan': '대만', 'Hong Kong': '홍콩', 'New Zealand': '뉴질랜드', 'Colombia': '콜롬비아', 'Argentina': '아르헨티나', 'South Africa': '남아프리카' }; return countryMap[countryCode] || '미기재'; }; const getIdAndType = () => { const [, type, id] = window.location.pathname.split('/'); return { id: id?.split('-')[0], type }; }; const goToMainPage = () => { const currentUrl = window.location.href; let mainUrl; if (currentUrl.startsWith('https://www.themoviedb.org/tv/')) { const match = currentUrl.match(/\/tv\/(\d+)/); if (match) { mainUrl = `https://www.themoviedb.org/tv/${match[1]}`; } } else if (currentUrl.startsWith('https://www.themoviedb.org/movie/')) { const match = currentUrl.match(/\/movie\/(\d+)/); if (match) { mainUrl = `https://www.themoviedb.org/movie/${match[1]}`; } } if (mainUrl) { window.location.href = mainUrl; } }; const changeLanguage = (lang) => { const currentUrl = new URL(window.location.href); currentUrl.searchParams.set('language', lang); window.location.href = currentUrl.toString(); }; const getCountryPrefix = (originCountry, productionCountry) => { const country = originCountry || productionCountry; const countryName = translateCountry(country); if (['뉴질랜드', '남아프리카', '미국', '캐나다', '호주'].includes(countryName)) return '영'; if (['대만', '홍콩'].includes(countryName)) return '중'; if (['멕시코', '아르헨티나', '콜롬비아'].includes(countryName)) return '스'; if (countryName === '벨기에') return '프'; if (countryName === '브라질') return '포'; if (countryName === '스웨덴') return '웨'; if (countryName === '인도') return '힌'; return countryName.charAt(0); }; const displayTitles = (koTitle, enTitle, originalTitle, type, id, koreanRating, originCountry, productionCountry, year) => { const titleElement = document.querySelector('.title h2') || document.querySelector('.header .title h2'); if (!titleElement) return; // 변수 정의 const KoTitle = koTitle; const EnTitle = enTitle; const OriginalTitle = originalTitle; const ChangedKoTitle = koTitle.replace(/:/g, ';').replace(/\?/g, '?'); const ChangedEnTitle = enTitle.replace(/:/g, ';').replace(/\?/g, '?'); const ChangedOriginalTitle = originalTitle.replace(/:/g, ';').replace(/\?/g, '?'); const titleContainer = document.createElement('div'); titleContainer.className = 'additional-titles'; const titleColor = window.getComputedStyle(titleElement).color; const typeText = type === 'tv' ? 'TV' : 'MOVIE'; titleContainer.innerHTML = ` 메인 / ${typeText} ${type === 'movie' ? `+TMDB +영 +원` : `+TMDB +영 +원` } / 한제: ${KoTitle} (${year}) / 영제: ${EnTitle} (${year}) / 원제: ${OriginalTitle} (${year}) `; titleElement.parentNode.insertBefore(titleContainer, titleElement); titleContainer.querySelector('.main-link').addEventListener('click', goToMainPage); // MOVIE/TV 클릭 이벤트 titleContainer.querySelector('.type-link').addEventListener('click', function() { const countryPrefix = getCountryPrefix(originCountry, productionCountry); let copyText = ''; if (type === 'movie') { copyText = `${ChangedKoTitle} (${year}) {tmdb-${id}} ${countryPrefix}A !${koreanRating} $${translateCountry(originCountry || productionCountry)}`; } else { copyText = `${ChangedKoTitle} (${year}) ${countryPrefix}A !${koreanRating} $${translateCountry(originCountry || productionCountry)}`; } copyToClipboard(copyText); }); // +TMDB 링크 이벤트 titleContainer.querySelector('.plus-tmdb-link').addEventListener('click', function() { const countryPrefix = getCountryPrefix(originCountry, productionCountry); let copyText = `${ChangedKoTitle} (${year}) {tmdb-${id}} !${koreanRating} $${translateCountry(originCountry || productionCountry)}`; copyToClipboard(copyText); }); // +영 링크 이벤트 titleContainer.querySelector('.plus-en-link').addEventListener('click', function() { let copyText = `${ChangedKoTitle} (${year}) [${ChangedEnTitle}] {tmdb-${id}} !${koreanRating} $${translateCountry(originCountry || productionCountry)}`; copyToClipboard(copyText); }); // +원 링크 이벤트 titleContainer.querySelector('.plus-original-link').addEventListener('click', function() { let copyText = `${ChangedKoTitle} (${year}) [${ChangedEnTitle}] [${ChangedOriginalTitle}] {tmdb-${id}} !${koreanRating} $${translateCountry(originCountry || productionCountry)}`; copyToClipboard(copyText); }); // 연도 클릭 이벤트 titleContainer.querySelector('.ko-year').addEventListener('click', function() { copyToClipboard(`${KoTitle} ${year}`); }); titleContainer.querySelector('.en-year').addEventListener('click', function() { copyToClipboard(`${EnTitle} ${year}`); }); titleContainer.querySelector('.original-year').addEventListener('click', function() { copyToClipboard(`${OriginalTitle} ${year}`); }); // 타이틀 클릭 이벤트 titleContainer.querySelector('.ko-title-text').addEventListener('click', function() { copyToClipboard(`${KoTitle} (${year})`); }); titleContainer.querySelector('.ko-title').addEventListener('click', function() { copyToClipboard(KoTitle); }); titleContainer.querySelector('.en-original-link').addEventListener('click', function() { copyToClipboard(`[${EnTitle}]`); }); titleContainer.querySelector('.en-title').addEventListener('click', function() { copyToClipboard(EnTitle); }); titleContainer.querySelector('.original-title-label').addEventListener('click', function() { copyToClipboard(`[${OriginalTitle}]`); }); titleContainer.querySelector('.original-title').addEventListener('click', function() { copyToClipboard(OriginalTitle); }); // 언어 변경 이벤트 리스너 추가 titleContainer.querySelectorAll('.language-link').forEach(link => { link.addEventListener('click', function() { const lang = this.getAttribute('onclick').match(/'([^']+)'/)[1]; changeLanguage(lang); }); }); }; const getKoreanCertification = (data, type) => { const ratings = type === 'movie' ? data.release_dates?.results : data.content_ratings?.results; const koreanRating = ratings?.find(r => r.iso_3166_1 === 'KR')?.release_dates?.[0]?.certification || ratings?.find(r => r.iso_3166_1 === 'KR')?.rating; return koreanRating || '등급미정'; }; const getOriginCountry = (data) => { return data.origin_country?.[0] || data.production_countries?.[0]?.iso_3166_1 || null; }; const getProductionCountry = (data) => { return data.production_countries?.[0]?.iso_3166_1 || null; }; const displayKoreanRating = rating => { if (!rating) return; const factsElement = document.querySelector('.facts'); if (!factsElement) return; let koreanRatingElement = document.getElementById('korean-rating'); if (!koreanRatingElement) { koreanRatingElement = Object.assign(document.createElement('span'), { id: 'korean-rating', style: 'font-size: 1em; margin-right: 10px; font-weight: bold;' }); factsElement.insertBefore(koreanRatingElement, factsElement.firstChild); } koreanRatingElement.textContent = rating; }; const displayAdditionalInfo = (originCountry, productionCountry, koTitle, enTitle, imdbId, wikidataId, tvdbId, year) => { const factsElement = document.querySelector('.facts'); let additionalInfoContainer = document.getElementById('additional-info'); if (!additionalInfoContainer) { additionalInfoContainer = document.createElement('div'); additionalInfoContainer.id = "additional-info"; factsElement.parentNode.insertBefore(additionalInfoContainer, factsElement.nextSibling); const originCountryText = translateCountry(originCountry); const productionCountryText = translateCountry(productionCountry); let searchLinks = ''; if (imdbId) { const imdbIdNum = imdbId.replace('tt', ''); searchLinks = ` OS(IMDB) SUBDL 씨네(한) 씨네(영) 씨드(한) 씨드(영) `; } else { searchLinks = ` OS(Title) SUBDL 씨네(한) 씨네(영) 씨드(한) 씨드(영) `; } additionalInfoContainer.innerHTML = `