mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-02-21 09:14:42 +08:00
feat: implement airplay
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
"framer-motion": "^12.18.1",
|
||||
"hls.js": "^1.6.5",
|
||||
"lucide-react": "^0.438.0",
|
||||
"media-icons": "^1.1.5",
|
||||
"next": "^14.2.23",
|
||||
"next-pwa": "^5.6.0",
|
||||
"react": "^18.2.0",
|
||||
|
||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -29,6 +29,9 @@ importers:
|
||||
lucide-react:
|
||||
specifier: ^0.438.0
|
||||
version: 0.438.0(react@18.3.1)
|
||||
media-icons:
|
||||
specifier: ^1.1.5
|
||||
version: 1.1.5
|
||||
next:
|
||||
specifier: ^14.2.23
|
||||
version: 14.2.30(@babel/core@7.27.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -3543,6 +3546,10 @@ packages:
|
||||
resolution: {integrity: sha512-cyDNmuZvvO4H27rcBq2Eudxo9IZRDCOX/I7VEyqbxsEiD2Ei7UYUhG/Sc5fvMZjmathgz3fEK7iAKqvpY+Ux1w==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
media-icons@1.1.5:
|
||||
resolution: {integrity: sha512-zu3CjKRs63ybLLWPomRRgTDyYiSrk2bRRgw97ZmN3FGXuo9qUUhBSfYwnjmvSdLG2JOJfAwzDz99bPATSY81DQ==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
meow@8.1.2:
|
||||
resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -9192,6 +9199,8 @@ snapshots:
|
||||
|
||||
media-captions@1.0.4: {}
|
||||
|
||||
media-icons@1.1.5: {}
|
||||
|
||||
meow@8.1.2:
|
||||
dependencies:
|
||||
'@types/minimist': 1.2.5
|
||||
|
||||
@@ -2,11 +2,19 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import { MediaPlayer, MediaProvider } from '@vidstack/react';
|
||||
import {
|
||||
type MediaProviderAdapter,
|
||||
AirPlayButton,
|
||||
isHLSProvider,
|
||||
MediaPlayer,
|
||||
MediaProvider,
|
||||
} from '@vidstack/react';
|
||||
import { AirPlayIcon } from '@vidstack/react/icons';
|
||||
import {
|
||||
defaultLayoutIcons,
|
||||
DefaultVideoLayout,
|
||||
} from '@vidstack/react/player/layouts/default';
|
||||
import Hls from 'hls.js';
|
||||
import { Heart } from 'lucide-react';
|
||||
import Head from 'next/head';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
@@ -1125,6 +1133,20 @@ function PlayPageClient() {
|
||||
);
|
||||
};
|
||||
|
||||
const onProviderChange = (provider: MediaProviderAdapter | null) => {
|
||||
class extendedHls extends Hls {
|
||||
attachMedia(media: HTMLMediaElement): void {
|
||||
super.attachMedia(media);
|
||||
|
||||
media.disableRemotePlayback = false;
|
||||
media.autoplay = true;
|
||||
}
|
||||
}
|
||||
if (isHLSProvider(provider)) {
|
||||
provider.library = extendedHls;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@@ -1204,6 +1226,7 @@ function PlayPageClient() {
|
||||
onTimeUpdate={onTimeUpdate}
|
||||
onPause={saveCurrentPlayProgress}
|
||||
onError={handlePlayerError}
|
||||
onProviderChange={onProviderChange}
|
||||
>
|
||||
<MediaProvider />
|
||||
<PlayerUITopbar
|
||||
@@ -1220,11 +1243,11 @@ function PlayPageClient() {
|
||||
icons={defaultLayoutIcons}
|
||||
slots={{
|
||||
googleCastButton: null,
|
||||
airPlayButton: null,
|
||||
pipButton: null,
|
||||
settingsMenu: null,
|
||||
muteButton: null, // 隐藏静音按钮
|
||||
volumeSlider: null, // 隐藏音量条
|
||||
airPlayButton: null, // 隐藏默认 AirPlay 按钮
|
||||
beforeCurrentTime:
|
||||
totalEpisodes > 1 ? (
|
||||
// 下一集按钮放在时间显示前
|
||||
@@ -1259,6 +1282,10 @@ function PlayPageClient() {
|
||||
</button>
|
||||
)}
|
||||
<PlaybackRateButton playerRef={playerRef} />
|
||||
{/* 自定义 AirPlay 按钮 */}
|
||||
<AirPlayButton className='vds-button'>
|
||||
<AirPlayIcon className='vds-icon' />
|
||||
</AirPlayButton>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
@@ -1623,7 +1650,7 @@ const PlaybackRateButton = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<button className='vds-button' onClick={cycleRate}>
|
||||
<button className='vds-button mr-2' onClick={cycleRate}>
|
||||
{rate === 1 ? '倍速' : `${rate.toFixed(2)}x`}
|
||||
</button>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user