Skip to content

Commit

Permalink
Merge pull request #13 from 2jun0/dev
Browse files Browse the repository at this point in the history
Dev: 1.3.4
  • Loading branch information
2jun0 authored Dec 1, 2021
2 parents 3456cfd + 441a4f2 commit 5c6a087
Show file tree
Hide file tree
Showing 23 changed files with 266 additions and 244 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ Add a subtitle tag language that you want on the video thumbnail in the YouTube.

## Showcase

![Showcase Videos](chrome/asset/showcase/showcase_videos.jpg)
![Showcase Videos](showcase/showcase_videos.jpg)

![Showcase In Video](chrome/asset/showcase/showcase_invideo.jpg)
![Showcase In Video](showcase/showcase_invideo.jpg)

---

## Customize

<img src="chrome/asset/showcase/showcase_popup.jpg" align="right" width="200">
<img src="showcase/showcase_popup.jpg" align="right" width="200">

- You can customize tag color in popup menu (background and text color)

Expand Down
6 changes: 3 additions & 3 deletions README_KO.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ README 페이지를 영문로 보시려면 아래를 참고하세요.

## 예시화면

![동영상 목록 예시화면](chrome/asset/showcase/showcase_videos.jpg)
![동영상 목록 예시화면](showcase/showcase_videos.jpg)

![동영상 실행 중 예시화면](chrome/asset/showcase/showcase_invideo.jpg)
![동영상 실행 중 예시화면](showcase/showcase_invideo.jpg)

---

## 사용자 설정

<img src="chrome/asset/showcase/showcase_popup.jpg" align="right" width="200">
<img src="showcase/showcase_popup.jpg" align="right" width="200">

- 팝업 메뉴에서 태그의 색상을 선택할 수 있습니다. (배경색상, 글자색상)

Expand Down
66 changes: 38 additions & 28 deletions chrome/js/background/ytVideo.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import {
FIELD_VIDEO_LANG_LIST_URL,
loadDataAsync,
saveData,
saveDataAsync,
} from '../storage.js';

let TabId;
Expand Down Expand Up @@ -48,65 +48,75 @@ async function createWattingIntervalAsync(videoId) {
return new Promise(resolve => {
let count = 0;
waittingIntervals[videoId] = {
id: setInterval(() => {
// during 1 sec, wait web request
if (count >= 60) {
id: setInterval(async () => {
// during 30 sec, wait web request
if (count >= 300) {
resolve();
return;
}

// when find timedtext url, save url and return
if (waittingIntervals[videoId].langListUrl) {
saveData(vLangListUrlField, waittingIntervals[videoId].langListUrl);
await saveDataAsync(
vLangListUrlField,
waittingIntervals[videoId].langListUrl,
);
resolve(waittingIntervals[videoId].langListUrl);
return;
}
count++;
}, 1000),
}, 100),
};
}).then(langListUrl => {
// remove yt player and interval
document.getElementById(`player-${videoId}`).remove();
clearInterval(waittingIntervals[videoId].id);
delete waittingIntervals[videoId];

return langListUrl;
});
}

async function getLangListUrlAsync(videoId) {
async function getLangListUrlByStorageAsync(videoId) {
const vLangListUrlField = `${FIELD_VIDEO_LANG_LIST_URL}_${videoId}`;

return loadDataAsync(vLangListUrlField).then(items => {
let langListUrl = items[vLangListUrlField];

if (langListUrl) {
// already saved
return langListUrl;
} else {
// load Youtube Player (wait until the "onReady" event occurs)
return loadYtPlayerAsync(videoId).then(() => {
return createWattingIntervalAsync(videoId);
});
}
// Test if url is vaild
if (!items[vLangListUrlField]) return null;

return requestAysnc('GET', items[vLangListUrlField]).then(res => {
return res ? items[vLangListUrlField] : null;
});
});
}

async function getLangListUrlByIframeUrlAsync(videoId) {
// load Youtube Player (wait until the "onReady" event occurs)
return loadYtPlayerAsync(videoId).then(() => {
return createWattingIntervalAsync(videoId);
});
}

async function hasSubtitlesAsync(videoId, langs) {
const langCodeCheck = RegExp(`lang_code="(${langs.join('|')})"`);

return getLangListUrlAsync(videoId).then(langListUrl => {
if (!langListUrl) {
return false;
} else {
return requestAysnc('GET', langListUrl).then(res => {
return langCodeCheck.test(res);
});
}
let langListUrl = await getLangListUrlByStorageAsync(videoId);

if (!langListUrl) langListUrl = await getLangListUrlByIframeUrlAsync(videoId);

if (!langListUrl) return false;

return requestAysnc('GET', langListUrl).then(res => {
return res ? langCodeCheck.test(res) : false;
});
}

// Get web Request
chrome.webRequest.onBeforeRequest.addListener(
details => {
// Avoid self check
if (details.url.includes('type=list')) return;

let videoId = getYTVideoId(details.url);
let langListUrl = getLangListUrl(details.url);

Expand All @@ -120,8 +130,8 @@ chrome.webRequest.onBeforeRequest.addListener(
// Get content script message
chrome.runtime.onMessage.addListener(({ type, value }, sender, sendRes) => {
if (type === 'has-subtitles') {
let langs = value.langs;
let videoId = value.videoId;
const langs = value.langs;
const videoId = value.videoId;

hasSubtitlesAsync(videoId, langs).then(sendRes);
}
Expand Down
7 changes: 4 additions & 3 deletions chrome/js/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ export function requestAysnc(method, url, msg = null) {
return new Promise(resolve => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState == this.DONE) {
if (this.status == 200) {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.responseText);
} else if (this.status === 404) {
resolve(null);
}
}
};

xhr.open(method, url);
console.log(method, url, msg);
xhr.send(msg);
});
}
166 changes: 79 additions & 87 deletions chrome/js/content_script/subtitleFilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,117 +59,115 @@
setCCLang(ccLang.split('-')[0]);
}

function waitOverlayLoaded(e, callback) {
async function waitOverlayLoadedAsnyc(e) {
const overlays = e.querySelector('#overlays');
if (overlays.childElementCount >= 2) callback(overlays);

let intervalId = setInterval(() => {
if (overlays.childElementCount < 2) return;
return new Promise(resolve => {
let intervalId = setInterval(() => {
if (overlays.childElementCount > 0) {
resolve(overlays);
clearInterval(intervalId);
}
}, 100);
});
}

callback(overlays);
function createLoadingTag() {
let ccLoading = document.createElement('div');
ccLoading.id = 'cc-loading';
ccLoading.style.color = ccColorTxt;

clearInterval(intervalId);
}, 100);
return ccLoading;
}

function showTagLoading(e) {
// To avoid deleting the ccLoading,
// Wait loading video overlays
waitOverlayLoaded(e, overlays => {
if (
overlays.querySelector('#cc-loading') ||
overlays.querySelector('#cc-status')
)
return;

let ccLoading = document.createElement('div');
ccLoading.id = 'cc-loading';
ccLoading.style.color = ccColorTxt;

overlays.insertBefore(ccLoading, overlays.lastChild);
function createSubtitleTag() {
let ccStatus = document.createElement('div');
Object.assign(ccStatus, {
id: 'cc-status',
overlayStyle: 'DEFAULT',
className: 'style-scope ytd-thumbnail',
lang: ccLang,
});
Object.assign(ccStatus.style, {
backgroundColor: ccColorBg,
color: ccColorTxt,
fontSize: ccFontSize,
});

let span = document.createElement('span');
Object.assign(span, {
className: 'style-scope ytd-thumbnail-overlay-time-status-renderer',
ariaLabel: ccLang.toUpperCase() + ' CC',
textContent: ccLang.toUpperCase() + ' CC',
});

ccStatus.appendChild(span);

return ccStatus;
}

function tagVideo(e, lang) {
let url = e.href;
async function tagVideo(e, lang) {
const url = e.href;
if (!url) return;

let ccStatus = e.querySelector('#cc-status');
const langs = ccCombineRegion ? getRelatedLangCodes(ccLang) : [lang];

// if already tagged remove it
let ccStatus = e.querySelector('#cc-status');
if (ccStatus) ccStatus.remove();

// Show tag loading
showTagLoading(e);
// To avoid deleting the ccStatus and ccLoading
// Wait loading video overlays
const overlays = await waitOverlayLoadedAsnyc(e);

let callback = hasSubtitle => {
// To avoid deleting the ccStatus,
// Wait loading video overlays
waitOverlayLoaded(e, overlays => {
function removeTagLoading() {
let ccLoading = overlays.querySelector('#cc-loading');
if (ccLoading) ccLoading.remove();
}
// Show the loading tag
let ccLoading = e.querySelector('#cc-loading') || createLoadingTag();
overlays.insertBefore(ccLoading, overlays.lastChild);

if (!hasSubtitle) {
removeTagLoading();
return;
}
// Once load overlays, insert ccStatus
ccStatus = document.createElement('div');
ccStatus.id = 'cc-status';
ccStatus.overlayStyle = 'DEFAULT';
ccStatus.className = 'style-scope ytd-thumbnail';
ccStatus.style.backgroundColor = ccColorBg;
ccStatus.style.color = ccColorTxt;
ccStatus.style.fontSize = ccFontSize;
ccStatus.lang = ccLang;

let span = document.createElement('span');
span.className =
'style-scope ytd-thumbnail-overlay-time-status-renderer';
span.ariaLabel = ccLang.toUpperCase() + ' CC';
span.textContent = ccLang.toUpperCase() + ' CC';
ccStatus.appendChild(span);

// if user change langauge or url in processing,
// Remove ccStatus
if (e.href != url || ccStatus.lang != ccLang) ccStatus.remove();
removeTagLoading();
overlays.insertBefore(ccStatus, overlays.lastChild);
});
};
// Check if video has subtitles
const hasSubtitles = await hasSubtitlesAsync(url, langs);

if (hasSubtitles) {
// Once load overlays, insert ccStatus

if (ccCombineRegion) {
let langs = getRelatedLangCodes(ccLang);
hasSubtitles(url, langs, callback);
} else {
hasSubtitles(url, [lang], callback);
ccStatus = createSubtitleTag();

// if user change langauge or url in processing,
// Remove ccStatus and ccLoading
if (e.href != url || ccStatus.lang != ccLang) {
ccStatus.remove();
} else {
overlays.insertBefore(ccStatus, overlays.lastChild);
}
}

ccLoading.remove();
let a = e.querySelector('#cc-loading');
}

function hasSubtitles(videoUrl, langs, callback) {
async function hasSubtitlesAsync(videoUrl, langs) {
// URL example : /watch?v=[video_id]
const videoId = getYTVideoId(videoUrl);

function sendMsg() {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
{
type: 'has-subtitles',
value: { langs, videoId },
},
res => {
hasSubtitle => {
let lastError = chrome.runtime.lastError;
if (lastError) {
console.error(lastError.message);
return;
reject(lastError);
} else {
resolve(hasSubtitle);
}

callback(res);
},
);
}

sendMsg();
}).catch(e => {
console.error(videoId, e.message);
return hasSubtitlesAsync(videoUrl, langs);
});
}

function checkNodes(nodes) {
Expand All @@ -184,17 +182,11 @@
}

function checkNode(node) {
if (node.tagName != 'A' || node.id != 'thumbnail') {
// if (node.id == 'video-title') console.log(node);
return;
}
// except thumbnail
if (node.tagName != 'A' || node.id != 'thumbnail') return;
// except play list
if (node.parentElement.tagName == 'YTD-PLAYLIST-THUMBNAIL') return;
addVideo(node);
}

function addVideo(video) {
tagVideo(video, ccLang);
tagVideo(node);
}

function checkAllNode() {
Expand Down
Loading

0 comments on commit 5c6a087

Please sign in to comment.