Skip to content

Commit b9621eb

Browse files
committed
Closed #116
1 parent e36ffdd commit b9621eb

27 files changed

+331
-277
lines changed

Diff for: .vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
"typescript.tsdk": "node_modules/typescript/lib",
88
"eslint.validate": ["javascript", "typescript", "typescriptreact"],
99
"editor.codeActionsOnSave": {
10-
"source.fixAll.eslint": true
10+
"source.fixAll.eslint": "explicit"
1111
}
1212
}

Diff for: package.json

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
"webpack": "^4.43.0",
5555
"webpack-cli": "^3.3.12"
5656
},
57+
"engines": {
58+
"node": "^14.20.0"
59+
},
5760
"husky": {
5861
"hooks": {
5962
"pre-commit": "lint-staged"

Diff for: public/manifest.json

+9
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@
5454
"default_popup": "popup.html",
5555
"default_icon": "icons/48.png"
5656
},
57+
"commands": {
58+
"toggle": {
59+
"suggested_key": {
60+
"default": "Ctrl+Shift+L",
61+
"mac": "Command+Shift+L"
62+
},
63+
"description": "Toggle lyrics"
64+
}
65+
},
5766
"options_ui": {
5867
"page": "options.html"
5968
},

Diff for: src/background.ts

+58-47
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { browser } from 'webextension-polyfill-ts';
22
import * as Sentry from '@sentry/browser';
33

4-
import { Message, Event, ContextItems, isProd, VERSION } from './common/consts';
4+
import { Message, Event, ContextItems, isProd, VERSION } from './common/constants';
5+
import { sendMessage } from './common/bg';
56
import { getOptions } from './options/store';
67
import { i18n, i18nMap } from './i18n';
78
import type { Req, Res } from './page/request';
9+
810
declare global {
911
interface Window {
1012
Sentry?: typeof Sentry;
@@ -36,55 +38,64 @@ disableBrowserAction();
3638

3739
browser.runtime.onMessage.addListener(async (msg: Message, sender) => {
3840
const { type, data } = msg || {};
39-
if (type === Event.GET_OPTIONS) {
40-
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage#Parameters
41-
return getOptions().then((options) => ({
42-
...options,
43-
i18nMap,
44-
}));
45-
}
46-
if (type === Event.POPUP_ACTIVE) {
47-
if (data === true) {
48-
enableBrowserAction();
49-
} else {
50-
disableBrowserAction();
41+
switch (type) {
42+
case Event.GET_OPTIONS: {
43+
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage#Parameters
44+
return getOptions().then((options) => ({
45+
...options,
46+
i18nMap,
47+
}));
5148
}
52-
}
53-
// breadcrumb and exception are cumulative
54-
if (type === Event.CAPTURE_EXCEPTION) {
55-
const err = new Error(data.message);
56-
err.name = data.name;
57-
err.stack = data.stack;
58-
window.Sentry?.captureException(err, {
59-
extra: data.extra,
60-
});
61-
}
62-
63-
if (type === Event.SEND_REQUEST) {
64-
const { reqId, uri, options } = data as Req;
65-
const tabId = sender.tab?.id;
66-
if (!tabId) return;
67-
68-
const sendRes = (data: Omit<Res, 'reqId'>) => {
69-
browser.tabs.sendMessage(tabId, {
70-
type: Event.SEND_RESPONSE,
71-
data: { reqId, ...data },
72-
} as Message<Res>);
73-
};
74-
try {
75-
const res = await fetch(uri, options);
76-
if (res.status === 0) throw 'Request fail';
77-
if (res.status >= 400) throw res.statusText;
78-
const res2 = res.clone();
79-
let result: any;
49+
case Event.POPUP_ACTIVE: {
50+
if (data === true) {
51+
enableBrowserAction();
52+
} else {
53+
disableBrowserAction();
54+
}
55+
return;
56+
}
57+
// breadcrumb and exception are cumulative
58+
case Event.CAPTURE_EXCEPTION: {
59+
const err = new Error(data.message);
60+
err.name = data.name;
61+
err.stack = data.stack;
62+
window.Sentry?.captureException(err, {
63+
extra: data.extra,
64+
});
65+
return;
66+
}
67+
case Event.SEND_REQUEST: {
68+
const { reqId, uri, options } = data as Req;
69+
const tabId = sender.tab?.id;
70+
if (!tabId) return;
71+
72+
const sendRes = (data: Omit<Res, 'reqId'>) => {
73+
sendMessage<Res>(tabId, { type: Event.SEND_RESPONSE, data: { reqId, ...data } });
74+
};
8075
try {
81-
result = await res.json();
82-
} catch {
83-
result = await res2.text();
76+
const res = await fetch(uri, options);
77+
if (res.status === 0) throw 'Request fail';
78+
if (res.status >= 400) throw res.statusText;
79+
const res2 = res.clone();
80+
let result: any;
81+
try {
82+
result = await res.json();
83+
} catch {
84+
result = await res2.text();
85+
}
86+
sendRes({ ok: true, data: result });
87+
} catch (err) {
88+
sendRes({ ok: false, data: String(err) });
8489
}
85-
sendRes({ ok: true, data: result });
86-
} catch (err) {
87-
sendRes({ ok: false, data: String(err) });
90+
return;
91+
}
92+
}
93+
});
94+
95+
browser.commands.onCommand.addListener((command) => {
96+
switch (command) {
97+
case 'toggle': {
98+
return sendMessage({ type: Event.TOGGLE });
8899
}
89100
}
90101
});

Diff for: src/common/bg.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { browser } from 'webextension-polyfill-ts';
2+
3+
import type { Message } from '../common/constants';
4+
5+
export function sendMessage<T>(tabId: number, msg: Message<T>): void;
6+
export function sendMessage<T>(msg: Message<T>): void;
7+
export function sendMessage<T>(tabIdOrMsg: number | Message<T>, msg?: Message<T>) {
8+
if (typeof tabIdOrMsg === 'number') {
9+
browser.tabs.sendMessage(tabIdOrMsg, msg);
10+
} else {
11+
const manifest = browser.runtime.getManifest() as typeof import('../../public/manifest.json');
12+
browser.tabs.query({ url: manifest.content_scripts[0].matches }).then((tabs) => {
13+
tabs.forEach((tab) => {
14+
// Only the tab that open the lyrics will response
15+
if (tab?.id) browser.tabs.sendMessage(tab.id, tabIdOrMsg);
16+
});
17+
});
18+
}
19+
}

Diff for: src/common/consts.ts renamed to src/common/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export enum Event {
2323
CAPTURE_EXCEPTION = 'capture-exception',
2424
SEND_REQUEST = 'send-request',
2525
SEND_RESPONSE = 'send-response',
26+
TOGGLE = 'toggle',
2627
}
2728

2829
export const ContextItems = {

Diff for: src/common/ga.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import type { Req } from '../page/request';
66

7-
import { isProd, isWebApp, VERSION, Event } from './consts';
7+
import { isProd, isWebApp, VERSION, Event } from './constants';
88

99
const postReq = (params: Record<string, string>) => {
1010
const uri = 'https://www.google-analytics.com/collect';

Diff for: src/content.ts

+18-18
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
import { browser } from 'webextension-polyfill-ts';
22

3-
import { Message, Event, isProd } from './common/consts';
3+
import { Message, Event, isProd } from './common/constants';
44

55
browser.runtime.onMessage.addListener((msg: Message) => {
66
window.postMessage(msg, '*');
77
});
88

99
window.addEventListener('message', ({ data }) => {
1010
const { type } = data || {};
11-
if (type === Event.GET_OPTIONS) {
12-
browser.runtime
13-
.sendMessage(data)
14-
.then((options) => {
15-
window.postMessage({ type: Event.SEND_OPTIONS, data: options }, '*');
16-
})
17-
.catch(() => {
11+
switch (type) {
12+
case Event.GET_OPTIONS: {
13+
return browser.runtime
14+
.sendMessage(data)
15+
.then((options) => {
16+
window.postMessage({ type: Event.SEND_OPTIONS, data: options }, '*');
17+
})
18+
.catch(() => {
19+
//
20+
});
21+
}
22+
case Event.SEND_REQUEST:
23+
case Event.POPUP_ACTIVE:
24+
case Event.CAPTURE_EXCEPTION:
25+
case Event.SEND_SONGS: {
26+
return browser.runtime.sendMessage(data).catch(() => {
1827
//
1928
});
20-
}
21-
if (
22-
type === Event.SEND_REQUEST ||
23-
type === Event.POPUP_ACTIVE ||
24-
type === Event.CAPTURE_EXCEPTION ||
25-
type === Event.SEND_SONGS
26-
) {
27-
browser.runtime.sendMessage(data).catch(() => {
28-
//
29-
});
29+
}
3030
}
3131
});
3232

Diff for: src/options/app.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { customElement, refobject, RefObject } from '@mantou/gem/lib/decorators';
22
import { GemElement, html } from '@mantou/gem/lib/element';
33

4-
import { Options, LyricsPositions, LyricsAlign, LyricsFontFamily } from '../common/consts';
4+
import { Options, LyricsPositions, LyricsAlign, LyricsFontFamily } from '../common/constants';
55
import { sendEvent, events } from '../common/ga';
66
import { theme } from '../common/theme';
77

Diff for: src/options/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import '@webcomponents/webcomponentsjs';
33
import { browser } from 'webextension-polyfill-ts';
44
import { render, html } from '@mantou/gem/lib/element';
55

6-
import { isWebApp } from '../common/consts';
6+
import { isWebApp } from '../common/constants';
77
import { fontStyle } from '../common/font';
88

99
import './app';

Diff for: src/options/modal.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1656732
22
import { customElement } from '@mantou/gem/lib/decorators';
33

4-
import { Event } from '../common/consts';
4+
import { Event } from '../common/constants';
55

66
import { Modal } from '../common/elements/modal-base';
77

Diff for: src/options/store.ts

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { browser } from 'webextension-polyfill-ts';
22

3-
import { Message, Event, Options, isWebApp, LyricsFontFamily } from '../common/consts';
3+
import { sendMessage } from '../common/bg';
4+
import { Event, Options, isWebApp, LyricsFontFamily } from '../common/constants';
45

56
const uiLanguage = browser.i18n.getUILanguage();
67

@@ -30,18 +31,9 @@ export async function updateOptions(value: Partial<Options>) {
3031
await browser.storage.sync.set(value);
3132
const options = await getOptions();
3233
if (isWebApp) {
33-
window.postMessage({ type: Event.SEND_OPTIONS, data: await getOptions() }, '*');
34+
window.postMessage({ type: Event.SEND_OPTIONS, data: options }, '*');
3435
} else {
35-
const manifest = browser.runtime.getManifest() as typeof import('../../public/manifest.json');
36-
const tabs = await browser.tabs.query({ url: manifest.content_scripts[0].matches });
37-
tabs.forEach((tab) => {
38-
if (tab.id) {
39-
browser.tabs.sendMessage(tab.id, {
40-
type: Event.SEND_OPTIONS,
41-
data: options,
42-
} as Message);
43-
}
44-
});
36+
sendMessage({ type: Event.SEND_OPTIONS, data: options });
4537
}
4638
return options;
4739
}

Diff for: src/page/btn.ts

+24-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { sendEvent, events } from '../common/ga';
2-
import { Event, Message } from '../common/consts';
2+
import { Event, isProd, Message } from '../common/constants';
33

4-
import config, { localConfig } from './config';
4+
import { configPromise, localConfig } from './config';
55
import { lyricVideo, audioPromise, lyricVideoIsOpen } from './element';
66
import { appendStyle, css, captureException, documentQueryHasSelector } from './utils';
77
import { sharedData } from './share-data';
@@ -13,7 +13,7 @@ import { openLyrics, closeLyrics } from './pip';
1313
// In spotify is the pip button
1414
// In deezer is the native lyrics button, and many lyrics buttons
1515
// Note that the css selector needs to support multiple languages
16-
config.then(({ PIP_BTN_SELECTOR }) => {
16+
configPromise.then(({ PIP_BTN_SELECTOR }) => {
1717
appendStyle(css`
1818
${PIP_BTN_SELECTOR} {
1919
display: none;
@@ -22,7 +22,7 @@ config.then(({ PIP_BTN_SELECTOR }) => {
2222
});
2323

2424
export async function getLyricsBtn() {
25-
const { BTN_WRAPPER_SELECTOR } = await config;
25+
const { BTN_WRAPPER_SELECTOR } = await configPromise;
2626
const btnWrapper = document.querySelector(BTN_WRAPPER_SELECTOR);
2727
return btnWrapper?.getElementsByClassName(
2828
localConfig.LYRICS_CLASSNAME,
@@ -59,7 +59,26 @@ export const insetLyricsBtn = async () => {
5959
await audioPromise;
6060

6161
const options = await optionsPromise;
62-
const { BTN_WRAPPER_SELECTOR, BTN_LIKE_SELECTOR } = await config;
62+
const { BTN_WRAPPER_SELECTOR, BTN_LIKE_SELECTOR } = await configPromise;
63+
64+
// test selector
65+
if (!isProd) {
66+
console.log('===============================');
67+
Object.entries(await configPromise).forEach(([k, v]) => {
68+
if (k.includes('SELECTOR')) {
69+
console.log(k, document.querySelector(`${v}`));
70+
}
71+
});
72+
Object.entries(localConfig).forEach(([k, v]) => {
73+
if (k.includes('STYLE')) {
74+
const styleSheet = new CSSStyleSheet();
75+
styleSheet.replaceSync(v);
76+
[...styleSheet.cssRules].forEach((rule: CSSStyleRule) => {
77+
console.log(rule.selectorText, document.querySelectorAll(rule.selectorText));
78+
});
79+
}
80+
});
81+
}
6382

6483
const btnWrapper = document.querySelector(BTN_WRAPPER_SELECTOR) as HTMLDivElement;
6584
const likeBtn = documentQueryHasSelector(BTN_LIKE_SELECTOR) as HTMLButtonElement;

Diff for: src/page/canvas-renderer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { LyricsAlign } from '../common/consts';
1+
import { LyricsAlign } from '../common/constants';
22

33
import { Lyric } from './lyrics';
44

0 commit comments

Comments
 (0)