Skip to content

Commit 8ef4252

Browse files
authored
Fix deezer(multiple audio)
1 parent 179014f commit 8ef4252

File tree

6 files changed

+69
-45
lines changed

6 files changed

+69
-45
lines changed

Diff for: src/page/btn.ts

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

44
import { configPromise, localConfig } from './config';
5-
import { lyricVideo, audioPromise, lyricVideoIsOpen } from './element';
5+
import { lyricVideo, getCurrentAudio, lyricVideoIsOpen } from './element';
66
import {
77
appendStyle,
88
css,
@@ -63,7 +63,7 @@ window.addEventListener(
6363
);
6464

6565
export const insetLyricsBtn = async () => {
66-
await audioPromise;
66+
await getCurrentAudio();
6767

6868
const options = await optionsPromise;
6969
const { BTN_WRAPPER_SELECTOR, BTN_LIKE_SELECTOR } = await configPromise;

Diff for: src/page/config.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@ export const localConfig: LocalConfig = (() => {
9999
return {
100100
SERVICE_WORKER: '',
101101
STATIC_STYLE: css`
102-
.page-topbar + div [data-testid='conversionBanner'] {
103-
display: none;
102+
.page-topbar + div [data-testid='conversionBanner'],
103+
[data-testid='alert-StreamingNotAllowed'],
104+
.ads {
105+
display: none !important;
104106
}
105107
.${LYRICS_CLASSNAME} {
106108
order: 100;

Diff for: src/page/editor/app.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { customElement, emitter, Emitter, refobject, RefObject } from '@mantou/g
33

44
import { theme } from '../../common/theme';
55
import { events, sendEvent } from '../../common/ga';
6-
import { audioPromise, lyricVideoIsOpen } from '../element';
6+
import { getCurrentAudio, lyricVideoIsOpen } from '../element';
77
import { sharedData } from '../share-data';
88
import { parseLyrics, Lyric } from '../lyrics';
99
import { setSong } from '../store';
@@ -88,7 +88,7 @@ export class EditorApp extends GemElement<State> {
8888
const options = await optionsPromise;
8989
sendEvent(options.cid, events.openEditor);
9090

91-
const audio = await audioPromise;
91+
const audio = await getCurrentAudio();
9292
this.originLoop = audio.loop;
9393
audio.loop = true;
9494
this.originPlaybackRate = audio.playbackRate;
@@ -97,7 +97,7 @@ export class EditorApp extends GemElement<State> {
9797
}
9898

9999
async unmounted() {
100-
const audio = await audioPromise;
100+
const audio = await getCurrentAudio();
101101
audio.loop = this.originLoop;
102102
audio.playbackRate = this.originPlaybackRate;
103103
document.removeEventListener('paste', this.pasteHandler);
@@ -107,7 +107,7 @@ export class EditorApp extends GemElement<State> {
107107
changePlaybackRate = async () => {
108108
const { element } = this.playbackRateInput;
109109
if (!element) return;
110-
const audio = await audioPromise;
110+
const audio = await getCurrentAudio();
111111
audio.playbackRate = Number(element.value);
112112
};
113113

@@ -132,7 +132,7 @@ export class EditorApp extends GemElement<State> {
132132
};
133133

134134
mark = async () => {
135-
const audio = await audioPromise;
135+
const audio = await getCurrentAudio();
136136
const { lyrics, currentIndex } = this.state;
137137
this.scrollInto();
138138
lyrics[currentIndex + 1].startTime = audio.currentTime;
@@ -141,7 +141,7 @@ export class EditorApp extends GemElement<State> {
141141
};
142142

143143
insertLine = async () => {
144-
const audio = await audioPromise;
144+
const audio = await getCurrentAudio();
145145
const { lyrics, currentIndex } = this.state;
146146
this.scrollInto();
147147
lyrics.splice(currentIndex + 1, 0, { startTime: audio.currentTime, text: '' });
@@ -177,7 +177,7 @@ export class EditorApp extends GemElement<State> {
177177
};
178178

179179
resetLocal = async (state?: Partial<State>) => {
180-
const audio = await audioPromise;
180+
const audio = await getCurrentAudio();
181181
audio.currentTime = 0;
182182
this.setState({ ...state, currentIndex: -1 });
183183
setTimeout(this.scrollInto);
@@ -220,7 +220,7 @@ export class EditorApp extends GemElement<State> {
220220

221221
jump = async (t: number | null, index: number) => {
222222
if (typeof t !== 'number') return;
223-
const audio = await audioPromise;
223+
const audio = await getCurrentAudio();
224224
audio.currentTime = t;
225225
this.setState({ currentIndex: index });
226226
};

Diff for: src/page/element.ts

+51-29
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ window.addEventListener('beforeunload', () => {
5454
if (lyricVideoIsOpen) setPopupState(false);
5555
});
5656

57-
export const audioPromise = new Promise<HTMLAudioElement>((resolveAudio) => {
58-
let audio: HTMLAudioElement | null = null;
57+
let audio: HTMLAudioElement | null = null;
5958

59+
const firstAudioPromise = new Promise<HTMLAudioElement>((resolveAudio) => {
6060
const createElement: typeof document.createElement = document.createElement.bind(document);
6161

6262
const elementCountOverrideBefore = document.querySelectorAll('*').length;
@@ -70,11 +70,11 @@ export const audioPromise = new Promise<HTMLAudioElement>((resolveAudio) => {
7070
) {
7171
const element = createElement(tagName, options);
7272
// Spotify: <video>
73-
// Deezer: <audio>
7473
if ((tagName === 'video' || tagName === 'audio') && !audio) {
75-
if (!isProd) console.log('capture_audio_element', audio);
74+
if (!isProd) console.log('capture_audio_element', element);
7675
performance.measure('capture_audio_element');
7776
audio = element as HTMLAudioElement;
77+
handleAudio(audio);
7878
resolveAudio(audio);
7979
}
8080
return element;
@@ -88,13 +88,29 @@ export const audioPromise = new Promise<HTMLAudioElement>((resolveAudio) => {
8888
const element = querySelector(AUDIO_SELECTOR);
8989
if (element) {
9090
audio = element as HTMLAudioElement;
91+
handleAudio(audio);
9192
resolveAudio(audio);
9293
} else {
9394
setTimeout(queryAudio, 100);
9495
}
9596
};
9697
queryAudio();
9798

99+
if (currentPlatform === 'DEEZER') {
100+
const A = Audio;
101+
(window as any).Audio = class {
102+
constructor(src?: string) {
103+
const element = new A(src);
104+
element.addEventListener('play', () => {
105+
audio = element;
106+
handleAudio(audio);
107+
resolveAudio(audio);
108+
});
109+
return element;
110+
}
111+
};
112+
}
113+
98114
// Apple music does not insert audio elements by default
99115
if (currentPlatform !== 'APPLE') {
100116
// Check if audio is found normally
@@ -118,8 +134,15 @@ export const audioPromise = new Promise<HTMLAudioElement>((resolveAudio) => {
118134
}
119135
});
120136

121-
audioPromise.then((audio) => {
122-
let reported = false;
137+
/**
138+
* Some platforms (such as Deezer) keep changing Audio
139+
*/
140+
export async function getCurrentAudio() {
141+
return audio || firstAudioPromise;
142+
}
143+
144+
let reported = false;
145+
function handleAudio(audio: HTMLAudioElement) {
123146
audio.addEventListener('playing', async () => {
124147
const isMusic = audio.duration && audio.duration > 2.6 * 60 && audio.duration < 4 * 60;
125148
if (!reported && isMusic && !(await getLyricsBtn())) {
@@ -134,30 +157,29 @@ audioPromise.then((audio) => {
134157
}
135158
});
136159

137-
// safari not support media session, pip contorl video
138-
// safari turning off pip will also cause the video to pause
139-
let time = performance.now();
140-
lyricVideo.addEventListener('pause', () => {
141-
const now = performance.now();
142-
if (now - time > 300) {
143-
time = now;
144-
audio.pause();
145-
}
146-
});
147-
lyricVideo.addEventListener('play', () => {
148-
// video need't seek, because it is stream
149-
audio.play();
160+
audio.addEventListener('play', () => {
161+
lyricVideo.play();
162+
navigator.mediaSession.playbackState = 'playing';
150163
});
151164

152-
if (navigator.mediaSession) {
153-
const mediaSession = navigator.mediaSession;
154-
audio.addEventListener('play', () => {
155-
lyricVideo.play();
156-
mediaSession.playbackState = 'playing';
157-
});
158-
audio.addEventListener('pause', () => {
159-
lyricVideo.pause();
160-
mediaSession.playbackState = 'paused';
161-
});
165+
audio.addEventListener('pause', () => {
166+
lyricVideo.pause();
167+
navigator.mediaSession.playbackState = 'paused';
168+
});
169+
}
170+
171+
// safari not support media session, pip control video
172+
// safari turning off pip will also cause the video to pause
173+
let time = performance.now();
174+
lyricVideo.addEventListener('pause', () => {
175+
const now = performance.now();
176+
if (now - time > 300) {
177+
time = now;
178+
audio?.pause();
162179
}
163180
});
181+
182+
lyricVideo.addEventListener('play', () => {
183+
// video need't seek, because it is stream
184+
audio?.play();
185+
});

Diff for: src/page/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
RenderLyricsOptions,
1010
RenderTextOptions,
1111
} from './canvas-renderer';
12-
import { coverCanvas, coverHDCanvas, lyricCtx, audioPromise, lyricVideoIsOpen } from './element';
12+
import { coverCanvas, coverHDCanvas, lyricCtx, lyricVideoIsOpen, getCurrentAudio } from './element';
1313
import { sharedData } from './share-data';
1414
import { optionsPromise, OptionsAndI18n } from './options';
1515
import { appendStyle } from './utils';
@@ -20,7 +20,7 @@ import { getLyricsBtn } from './btn';
2020
import './observer';
2121

2222
const tick = async (options: OptionsAndI18n) => {
23-
const audio = await audioPromise;
23+
const audio = await getCurrentAudio();
2424
const i18nMap = options.i18nMap;
2525

2626
const isOnlyCover = options['only-cover'] === 'on';

Diff for: src/page/share-data.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { fetchSongList, fetchGeniusLyrics } from './genius';
1414
import { setSong, getSong } from './store';
1515
import { optionsPromise } from './options';
1616
import { captureException, querySelector } from './utils';
17-
import { audioPromise } from './element';
17+
import { getCurrentAudio } from './element';
1818
import { configPromise } from './config';
1919
import { fetchNetEaseSongList } from './netease';
2020
import { fetchLRCLIBSongList } from './lrclib';
@@ -182,7 +182,7 @@ export class SharedData {
182182

183183
// can only modify `lyrics`/`id`/`aId`/`list`
184184
private async _matching(fetchOptions: RequestInit) {
185-
const audio = await audioPromise;
185+
const audio = await getCurrentAudio();
186186
const startTime = audio.currentSrc ? performance.now() : null;
187187
const options = await optionsPromise;
188188
const parseLyricsOptions = await this._getParseLyricsOptions();

0 commit comments

Comments
 (0)