Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.3.0 #10

Merged
merged 18 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## v1.3.0

### Changelog

* Add [FVP](https://github.com/wang-bin/fvp) player backend (Experimental, with unknown bugs)
* Adding volume adjust
* Add file sort
* Add hotkeys: Volume up ( `Arrow Up` ), Volume down ( `Arrow Down` ), Volume mute ( `Ctrl + M` ), Toggle always on top ( `F10` ), Close currently media file ( `Ctrl + C` ), Exit application ( `Alt + X` )
* Improved some visual effects

### 更新日志
* 添加 [FVP](https://github.com/wang-bin/fvp) 播放器后端(实验性,有未知bug)
* 添加音量调整
* 添加文件排序
* 添加快捷键:提升音量( `Arrow Up` )、降低音量( `Arrow Down` )、静音(`Ctrl + M`)、切换窗口置顶( `F10` )、关闭当前媒体文件( `Ctrl + C` )、退出应用( `Alt + X` )
* 改进了部分视觉效果


## v1.2.1

### Changelog
Expand Down
52 changes: 29 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ English | [中文](./README_CN.md)

## Features

- [x] Base on [media-kit](https://github.com/media-kit/media-kit) supports multiple video formats
- [x] Base on [Media Kit](https://github.com/media-kit/media-kit) | [FVP](https://github.com/wang-bin/fvp), supports multiple video formats
- [x] Local storage and WebDAV support
- [x] Switchable subtitle and audio track
- [x] Playback queue support for random and repeat
Expand All @@ -33,37 +33,43 @@ English | [中文](./README_CN.md)
### Keyboard Controls
| Key | Description |
|----------------------|------------------------------------------|
| `Space` | Play / Pause / Select File |
| `Enter` | Enter Full Screen / Exit Full Screen / Select File |
| `F11` | Enter Full Screen / Exit Full Screen |
| `Space` | Play / Pause / Select file |
| `Arrow Left` | Fast backward 10 seconds |
| `Arrow Right` | Fast forward 10 seconds |
| `Arrow Up` | Volume up |
| `Arrow Down` | Volume down |
| `Ctrl + Arrow Left` | Previous |
| `Ctrl + Arrow Right` | Next |
| `Ctrl + X` | Shuffle |
| `Ctrl + R` | Repeat |
| `Ctrl + V` | Video Zoom |
| `F` | Save |
| `P` | Play Queue |
| `S` | Subtitles and Audio Tracks |
| `Ctrl + O` | Open File |
| `Ctrl + L` | Open Link |
| `Ctrl + H` | Play History |
| `Ctrl + V` | Video zoom |
| `Ctrl + M` | Volume mute |
| `S` | Subtitles and audio tracks |
| `P` | Play queue |
| `F` | Storages |
| `Ctrl + O` | Open file |
| `Ctrl + L` | Open link |
| `Ctrl + C` | Close currently media file |
| `Ctrl + H` | Play history |
| `Ctrl + P` | Settings |
| `Esc` | Exit Current Menu / Go Back / Close Full Screen |
| `Enter` | Enter full screen / Exit full screen / Select file |
| `F11` | Enter full screen / Exit full screen |
| `Esc` | Exit current Menu / Go back / Exit full screen |
| `F10` | Toggle always on top |
| `Alt + X` | Exit application |

### Gesture Controls
| Gesture | Description |
|----------------------|------------------------------------------|
| Tap | Select an item or open a menu |
| Double Tap Center | Play / Pause |
| Double Tap Left Side | Fast backward 10 seconds |
| Double Tap Right Side | Fast forward 10 seconds |
| Swipe Left / Right | Adjust playback progress |
| Swipe Up / Down on Left Side | Adjust screen brightness |
| Swipe Up / Down on Right Side | Adjust device volume |
| Long Press | Start Speed Playback |
| Long Press and Swipe Left/Right | Adjust Speed Playback Speed |
| Gesture | Description |
|---------------------------------|------------------------------------------|
| Tap | Select an item or open a menu |
| Double tap center | Play / Pause |
| Double tap left side | Fast backward 10 seconds |
| Double tap right side | Fast forward 10 seconds |
| Swipe left / right | Adjust playback progress |
| Swipe up / down on left side | Adjust screen brightness |
| Swipe up / down on right side | Adjust device volume |
| Long press | Start speed playback |
| Long press and swipe left / right | Adjust speed playback speed |

## Contribution

Expand Down
16 changes: 11 additions & 5 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

## 特性

- [x] 基于 [media-kit](https://github.com/media-kit/media-kit) 可播放多种视频格式
- [x] 基于 [Media Kit](https://github.com/media-kit/media-kit) | [FVP](https://github.com/wang-bin/fvp),可播放多种视频格式
- [x] 支持本地存储、WebDAV
- [x] 可切换字幕和音轨
- [x] 播放队列支持随机和重复
Expand All @@ -34,23 +34,29 @@
| 键位 | 描述 |
|----------------------|----------------------------------------|
| `Space` | 播放 / 暂停 / 选择文件 |
| `Enter` | 进入全屏 / 退出全屏 / 选择文件 |
| `F11` | 进入全屏 / 退出全屏 |
| `Arrow Left` | 快退 10 秒 |
| `Arrow Right` | 快进 10 秒 |
| `Arrow Up` | 提升音量 |
| `Arrow Down` | 降低音量 |
| `Ctrl + Arrow Left` | 上一个 |
| `Ctrl + Arrow Right` | 下一个 |
| `Ctrl + X` | 随机 |
| `Ctrl + R` | 重复 |
| `Ctrl + V` | 视频缩放 |
| `F` | 存储 |
| `P` | 播放队列 |
| `Ctrl + M` | 静音 |
| `S` | 字幕和音轨 |
| `P` | 播放队列 |
| `F` | 存储 |
| `Ctrl + O` | 打开文件 |
| `Ctrl + L` | 打开链接 |
| `Ctrl + C` | 关闭当前媒体文件 |
| `Ctrl + H` | 播放历史 |
| `Ctrl + P` | 设置 |
| `Enter` | 进入全屏 / 退出全屏 / 选择文件 |
| `F11` | 进入全屏 / 退出全屏 |
| `Esc` | 退出当前菜单 / 返回上一级 / 关闭全屏 |
| `F10` | 切换窗口置顶 |
| `Alt + X` | 退出应用 |

### 手势操作
| 手势 | 描述 |
Expand Down
2 changes: 2 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ GeneratedPluginRegistrant.java
key.properties
**/*.keystore
**/*.jks

/app/src/main/assets/flutter_assets
43 changes: 43 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import java.io.File
import java.nio.file.Files
import java.security.MessageDigest

plugins {
id "com.android.application"
id "kotlin-android"
Expand Down Expand Up @@ -57,3 +61,42 @@ android {
flutter {
source = "../.."
}


task downloadFiles(type: Exec) {
def filesToDownload = [
[
"url": "https://github.com/notofonts/noto-cjk/raw/refs/heads/main/Sans/OTF/SimplifiedChinese/NotoSansCJKsc-Medium.otf",
"md5": "58c83279d990b2cf88d40a0a34832e31",
"destination": file("./src/main/assets/flutter_assets/assets/fonts/NotoSansCJKsc-Medium.otf")
]
]

filesToDownload.each { fileInfo ->
def destFile = fileInfo.destination

if (destFile.exists()) {
def calculatedMD5 = MessageDigest.getInstance("MD5").digest(Files.readAllBytes(destFile.toPath())).encodeHex().toString()

if (calculatedMD5 != fileInfo.md5) {
destFile.delete()
println "MD5 mismatch. File deleted: ${destFile}"
}
}

if (!destFile.exists()) {
destFile.parentFile.mkdirs()
println "Downloading file from: ${fileInfo.url}"
destFile.withOutputStream { os ->
os << new URL(fileInfo.url).openStream()
}

def calculatedMD5 = MessageDigest.getInstance("MD5").digest(Files.readAllBytes(destFile.toPath())).encodeHex().toString()
if (calculatedMD5 != fileInfo.md5) {
throw new GradleException("MD5 verification failed for ${destFile}")
}
}
}
}

assemble.dependsOn(downloadFiles)
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
Expand Down
21 changes: 21 additions & 0 deletions lib/hooks/use_app_lifecycle.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'dart:ui';

import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:iris/models/player.dart';
import 'package:iris/utils/logger.dart';

void useAppLifecycle(MediaPlayer player) {
AppLifecycleState? appLifecycleState = useAppLifecycleState();

useEffect(() {
try {
if (appLifecycleState == AppLifecycleState.paused) {
logger('App lifecycle state: paused');
player.saveProgress();
}
} catch (e) {
logger('App lifecycle state error: $e');
}
return;
}, [appLifecycleState]);
}
62 changes: 62 additions & 0 deletions lib/hooks/use_cover.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_zustand/flutter_zustand.dart';
import 'package:iris/models/file.dart';
import 'package:iris/models/storages/storage.dart';
import 'package:iris/store/use_play_queue_store.dart';
import 'package:iris/store/use_storage_store.dart';
import 'package:iris/utils/files_filter.dart';

FileItem? useCover(BuildContext context) {
final playQueue =
usePlayQueueStore().select(context, (state) => state.playQueue);
final currentIndex =
usePlayQueueStore().select(context, (state) => state.currentIndex);

final int currentPlayIndex = useMemoized(
() => playQueue.indexWhere((element) => element.index == currentIndex),
[playQueue, currentIndex]);

final PlayQueueItem? currentPlay = useMemoized(
() => playQueue.isEmpty || currentPlayIndex < 0
? null
: playQueue[currentPlayIndex],
[playQueue, currentPlayIndex]);

final localStorages =
useStorageStore().select(context, (state) => state.localStorages);
final storages = useStorageStore().select(context, (state) => state.storages);

final List<String> dir = useMemoized(
() => currentPlay?.file == null || currentPlay!.file.path.isEmpty
? []
: ([...currentPlay.file.path]..removeLast()),
[currentPlay?.file],
);

final Storage? storage = useMemoized(
() => currentPlay?.file == null
? null
: [...localStorages, ...storages].firstWhereOrNull(
(storage) => storage.id == currentPlay?.file.storageId),
[currentPlay?.file, localStorages, storages]);

final getCover = useMemoized(() async {
if (currentPlay?.file.type != ContentType.audio) return null;

final files = await storage?.getFiles(dir);

if (files == null) return null;

final images = filesFilter(files, [ContentType.image]);

return images.firstWhereOrNull(
(image) => image.name.split('.').first.toLowerCase() == 'cover') ??
images.firstOrNull;
}, [currentPlay?.file, dir]);

final cover = useFuture(getCover).data;

return cover;
}
Loading