Skip to content

Commit 4cfef5e

Browse files
authored
Merge pull request #100 from solidSpoon/调整音频
改善播放音频、查询单词的体验
2 parents f85b891 + 5021931 commit 4cfef5e

20 files changed

+445
-293
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "dash-player",
33
"productName": "DashPlayer",
4-
"version": "5.0.2",
4+
"version": "5.1.0",
55
"description": "My Electron application description",
66
"main": ".vite/build/main.js",
77
"scripts": {

src/app.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import useSetting from '@/fronted/hooks/useSetting';
44
import { HashRouter, Route, Routes } from 'react-router-dom';
55
import HomePage from '@/fronted/pages/HomePage';
66
import TitleBarLayout from '@/fronted/pages/TieleBarLayout';
7-
import PlayerP from '@/fronted/pages/PlayerP';
7+
import PlayerWithControlsPage from '@/fronted/pages/PlayerWithControlsPage';
88
import Layout from '@/fronted/pages/Layout';
99
import About from '@/fronted/pages/About';
1010
import SettingLayout from '@/fronted/pages/setting/SettingLayout';
@@ -48,7 +48,7 @@ const App = () => {
4848
<Route element={<TitleBarLayout />}>
4949
<Route
5050
path="player/:videoId"
51-
element={<PlayerP />}
51+
element={<PlayerWithControlsPage />}
5252
/>
5353
<Route path="*" element={<Layout />}>
5454
<Route

src/backend/services/impl/WatchHistoryServiceImpl.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export default class WatchHistoryServiceImpl implements WatchHistoryService {
126126
}
127127
const videos = existFiles
128128
.filter(file => fs.statSync(file).isFile())
129-
.filter(file => MediaUtil.isVideo(file));
129+
.filter(file => MediaUtil.isMedia(file));
130130
for (const video of videos) {
131131
const sids = await this.tryCreate(video);
132132
ids.push(...sids);
@@ -243,7 +243,7 @@ export default class WatchHistoryServiceImpl implements WatchHistoryService {
243243
return ids;
244244
}
245245
const files = fs.readdirSync(folder);
246-
const videoFiles = files.filter(file => MediaUtil.isVideo(file))
246+
const videoFiles = files.filter(file => MediaUtil.isMedia(file))
247247
.map(file => path.join(folder, file));
248248
for (const video of videoFiles) {
249249
const sids = await this.tryCreate(video, WatchHistoryType.DIRECTORY);
@@ -354,7 +354,7 @@ export default class WatchHistoryServiceImpl implements WatchHistoryService {
354354
return;
355355
}
356356
const files = await FileUtil.listFiles(libraryPath);
357-
const videoFiles = files.filter(file => MediaUtil.isVideo(file))
357+
const videoFiles = files.filter(file => MediaUtil.isMedia(file))
358358
.map(file => path.join(libraryPath, file));
359359
for (const video of videoFiles) {
360360
await this.tryCreate(video);

src/fronted/components/MainSubtitle.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { ReactElement } from 'react';
2-
import TranslatableLine from './TranslatableLine';
2+
import TranslatableLine from './srt-cops/translatable-line';
33
import NormalLine from './NormalLine';
44
import usePlayerController from '../hooks/usePlayerController';
55

src/fronted/components/PlayerPPlayer.tsx renamed to src/fronted/components/PlayerSrtLayout.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {cn} from "@/fronted/lib/utils";
22
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/fronted/components/ui/resizable';
33
import { darkColor, lightColor } from '@/fronted/styles/style';
44
import Player from '@/fronted/components/Player';
5-
import SubtitleViewer from '@/fronted/components/subtitle-viewer/subtitle-viewer';
5+
import PodcastViewer from '@/fronted/components/srt-cops/podcast-viewer';
66
import MainSubtitle from '@/fronted/components/MainSubtitle';
77
import Subtitle from '@/fronted/components/Subtitle';
88
import React from 'react';
@@ -11,7 +11,7 @@ import useLayout from '@/fronted/hooks/useLayout';
1111
import { useLocalStorage } from '@uidotdev/usehooks';
1212
import StrUtil from '@/common/utils/str-util';
1313

14-
const PlayerPPlayer = () => {
14+
const PlayerSrtLayout = () => {
1515
const hasSubTitle = useFile((s) => StrUtil.isNotBlank(s.subtitlePath));
1616
const showSideBar = useLayout((state) => state.showSideBar);
1717
const fullScreen = useLayout((s) => s.fullScreen);
@@ -60,7 +60,7 @@ const PlayerPPlayer = () => {
6060
<div
6161
className={cn('w-full h-full grid grid-cols-1 grid-rows-1')}>
6262
<Player className={cn('row-start-1 row-end-2 col-start-1 col-end-2')} />
63-
{podcastMode && <SubtitleViewer
63+
{podcastMode && <PodcastViewer
6464
className={cn('row-start-1 row-end-2 col-start-1 col-end-2 z-0')}
6565
/>}
6666
</div>
@@ -92,7 +92,6 @@ const PlayerPPlayer = () => {
9292
if (fullScreen) {
9393
return;
9494
}
95-
console.log('eeeeeea', e);
9695
setSizeOb(e);
9796
}}
9897
>
@@ -104,4 +103,4 @@ const PlayerPPlayer = () => {
104103
)
105104
}
106105

107-
export default PlayerPPlayer;
106+
export default PlayerSrtLayout;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { cn } from '@/fronted/lib/utils';
2+
import { Music } from 'lucide-react';
3+
import React from 'react';
4+
5+
// 预定义一些渐变色组合
6+
const gradientCombinations = [
7+
['#ea580c', '#fb923c', '#fed7aa'], // 橙色系
8+
['#2563eb', '#60a5fa', '#bfdbfe'], // 蓝色系
9+
['#16a34a', '#4ade80', '#bbf7d0'], // 绿色系
10+
['#9333ea', '#a855f7', '#e9d5ff'], // 紫色系
11+
['#dc2626', '#ef4444', '#fca5a5'], // 红色系
12+
['#0d9488', '#2dd4bf', '#99f6e4'], // 青色系
13+
['#db2777', '#ec4899', '#fbcfe8'], // 粉色系
14+
['#854d0e', '#ca8a04', '#fef08a'], // 黄色系
15+
];
16+
17+
interface MusicCardProps {
18+
fileName: string;
19+
}
20+
21+
const MusicCard: React.FC<MusicCardProps> = ({ fileName }) => {
22+
// 使用文件名生成一个简单的哈希值
23+
const hashCode = (str: string) => {
24+
let hash = 0;
25+
for (let i = 0; i < str.length; i++) {
26+
const char = str.charCodeAt(i);
27+
hash = ((hash << 5) - hash) + char;
28+
hash = hash & hash;
29+
}
30+
return Math.abs(hash);
31+
};
32+
33+
// 基于文件名选择一个渐变色组合
34+
const colorIndex = hashCode(fileName) % gradientCombinations.length;
35+
const [from, via, to] = gradientCombinations[colorIndex];
36+
37+
return (
38+
<div
39+
style={{
40+
aspectRatio: '16/9',
41+
background: `radial-gradient(ellipse at bottom, ${from}, ${via}, ${to})`
42+
}}
43+
className={cn(
44+
'w-full relative flex items-center justify-center',
45+
'transition-all duration-300',
46+
)}
47+
>
48+
<div className="absolute inset-0 bg-gradient-to-t from-background/30 to-transparent" />
49+
<Music className="w-12 h-12 text-primary-foreground drop-shadow-lg z-10" />
50+
</div>
51+
);
52+
};
53+
54+
export default MusicCard;

src/fronted/components/fileBowser/project-list-card.tsx

Lines changed: 88 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import useSWR from 'swr';
22
import { cn } from '@/fronted/lib/utils';
33
import React from 'react';
4-
import { SWR_KEY, swrApiMutate, swrMutate } from '@/fronted/lib/swr-util';
5-
import { Film, ListVideo, Trash2 } from 'lucide-react';
4+
import { SWR_KEY, swrApiMutate } from '@/fronted/lib/swr-util';
5+
import { Film, ListVideo, Trash2, Music } from 'lucide-react'; // 注意这里导入了 Music 图标
66
import { Button } from '@/fronted/components/ui/button';
77
import TimeUtil from '@/common/utils/TimeUtil';
88
import { Progress } from '@/fronted/components/ui/progress';
@@ -15,22 +15,41 @@ import {
1515
import UrlUtil from '@/common/utils/UrlUtil';
1616
import WatchHistoryVO from '@/common/types/WatchHistoryVO';
1717
import PathUtil from '@/common/utils/PathUtil';
18+
import FileUtil from '@/backend/utils/FileUtil';
19+
import MediaUtil from '@/common/utils/MediaUtil';
20+
import MusicCard from '@/fronted/components/fileBowser/music-card';
1821

1922
const api = window.electron;
2023

21-
const ProjectListCard = ({ video, onSelected }: {
22-
video: WatchHistoryVO,
23-
className?: string
24+
const ProjectListCard = ({
25+
video,
26+
onSelected
27+
}: {
28+
video: WatchHistoryVO;
29+
className?: string;
2430
onSelected: () => void;
2531
}) => {
26-
const { data: url } = useSWR([SWR_KEY.SPLIT_VIDEO_THUMBNAIL, video.basePath, video.fileName, video.current_position] ,
32+
// 1. 检测是否是 mp3
33+
const isAudio = MediaUtil.isAudio(video.fileName);
34+
35+
// 2. 如果是 mp3,就不调用生成缩略图的接口,把 key 设为 null
36+
const { data: url } = useSWR(
37+
!isAudio
38+
? [SWR_KEY.SPLIT_VIDEO_THUMBNAIL, video.basePath, video.fileName, video.current_position]
39+
: null,
2740
async ([_key, path, file, time]) => {
28-
return await api.call('split-video/thumbnail', { filePath: PathUtil.join(path, file), time });
41+
return await api.call('split-video/thumbnail', {
42+
filePath: PathUtil.join(path, file),
43+
time
44+
});
2945
}
3046
);
47+
3148
console.log('video', video);
49+
3250
const [hover, setHover] = React.useState(false);
3351
const [contextMenu, setContextMenu] = React.useState(false);
52+
3453
return (
3554
<ContextMenu
3655
onOpenChange={(open) => {
@@ -44,71 +63,102 @@ const ProjectListCard = ({ video, onSelected }: {
4463
className={cn('')}
4564
onClick={onSelected}
4665
>
47-
<div className={cn('relative w-full rounded-lg overflow-hidden border-none')}>
48-
{url ? <img
49-
src={UrlUtil.file(url)}
50-
style={{
51-
aspectRatio: '16/9'
52-
}}
53-
className={cn('w-full object-cover', (hover || contextMenu) && 'filter brightness-75')}
54-
alt={video.fileName}
55-
/> : <div
56-
style={{
57-
aspectRatio: '16/9'
58-
}}
59-
className={'w-full bg-gray-500 flex items-center justify-center'}>
60-
<Film className={'w-8 h-8'} />
61-
</div>}
66+
<div
67+
className={cn('relative w-full rounded-lg overflow-hidden border-none')}
68+
>
69+
{/* 3. 判断如果是 mp3,优先展示 Music 图标,否则还是原先逻辑 */}
70+
{isAudio ? (
71+
<MusicCard fileName={video.fileName}/>
72+
) : url ? (
73+
<img
74+
src={UrlUtil.file(url)}
75+
style={{
76+
aspectRatio: '16/9'
77+
}}
78+
className={cn(
79+
'w-full object-cover',
80+
(hover || contextMenu) && 'filter brightness-75'
81+
)}
82+
alt={video.fileName}
83+
/>
84+
) : (
85+
<div
86+
style={{
87+
aspectRatio: '16/9'
88+
}}
89+
className="w-full bg-gray-500 flex items-center justify-center"
90+
>
91+
<Film className="w-8 h-8" />
92+
</div>
93+
)}
94+
6295
<div
63-
className={cn('absolute bottom-2 right-2 text-white bg-black bg-opacity-80 rounded-md p-1 py-0.5 text-xs flex')}>
64-
{!video.isFolder ? TimeUtil.secondToTimeStrCompact(video?.duration) : <>
65-
<ListVideo className={'w-4 h-4'} /></>}
96+
className={cn(
97+
'absolute bottom-2 right-2 text-white bg-black bg-opacity-80 rounded-md p-1 py-0.5 text-xs flex'
98+
)}
99+
>
100+
{/* 如果是文件夹,就用 ListVideo 图标;如果不是文件夹,就展示时长 */}
101+
{!video.isFolder ? (
102+
TimeUtil.secondToTimeStrCompact(video?.duration)
103+
) : (
104+
<ListVideo className="w-4 h-4" />
105+
)}
66106
</div>
107+
108+
{/* 进度条 */}
67109
<Progress
68110
className={cn('absolute bottom-0 left-0 w-full rounded-none h-1 bg-gray-500')}
69-
value={Math.floor((video?.current_position || 0) / (video?.duration || 1) * 100)}
111+
value={Math.floor(
112+
((video?.current_position || 0) / (video?.duration || 1)) * 100
113+
)}
70114
/>
71115

72-
116+
{/* 悬浮时展示删除按钮 */}
73117
{hover && (
74118
<Button
75-
className={'absolute top-2 right-2 w-6 h-6 bg-background'}
76-
size={'icon'}
77-
variant={'ghost'}
119+
className="absolute top-2 right-2 w-6 h-6 bg-background"
120+
size="icon"
121+
variant="ghost"
78122
onClick={async (e) => {
79123
e.stopPropagation();
80124
console.log('swrdelete', video.id);
81125
await api.call('watch-history/group-delete', video.id);
82126
await swrApiMutate('watch-history/list');
83127
}}
84128
>
85-
<Trash2
86-
className={'w-3 h-3'}
87-
/>
129+
<Trash2 className="w-3 h-3" />
88130
</Button>
89131
)}
90132
</div>
91133

92134
<div
93-
className={cn('w-full line-clamp-2 break-words', (hover || contextMenu) && 'underline')}
94-
>{video.fileName}</div>
135+
className={cn(
136+
'w-full line-clamp-2 break-words',
137+
(hover || contextMenu) && 'underline'
138+
)}
139+
>
140+
{video.fileName}
141+
</div>
95142
</div>
96143
</ContextMenuTrigger>
97144
<ContextMenuContent>
98145
<ContextMenuItem
99146
onClick={async () => {
100147
await api.call('system/open-folder', video.basePath);
101148
}}
102-
>Show In Explorer</ContextMenuItem>
149+
>
150+
Show In Explorer
151+
</ContextMenuItem>
103152
<ContextMenuItem
104153
onClick={async () => {
105154
await api.call('watch-history/group-delete', video.id);
106155
await swrApiMutate('watch-history/list');
107156
}}
108-
>Delete</ContextMenuItem>
157+
>
158+
Delete
159+
</ContextMenuItem>
109160
</ContextMenuContent>
110161
</ContextMenu>
111-
112162
);
113163
};
114164

0 commit comments

Comments
 (0)