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

Releases/v1.4.0 #22

Merged
merged 4 commits into from
Jan 15, 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
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:

- run: flutter pub get

- run: |
sed -i '882a\rect = rect.inflate(96);' ${{ env.FLUTTER_ROOT }}/packages/flutter/lib/src/rendering/viewport.dart

- name: Decode Keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
Expand Down
41 changes: 26 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

[下载](https://github.com/GhostenEditor/Ghosten-Player/releases/latest)

一款同时适配Android TV和Android Phone的视频播放器,同时支持云播放(阿里云盘、夸克网盘和Webdav)和本地播放,支持刮削影视的元信息,界面简洁纯净,操作简单
一款同时适配Android TV和Android Phone的视频播放器,同时支持云播放(阿里云盘、夸克网盘和Webdav)和本地播放,支持刮削影视元信息,管理网盘文件,多线程加速等功能。
界面简洁纯净,操作简单。

[^1]: 开发中

Expand All @@ -18,20 +19,20 @@

<table>
<tr>
<td><img src="https://github.com/user-attachments/assets/d08bacb8-d660-4ad6-8fbc-e71681f339d9" alt="TV Screenshot 1" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/53e0e529-df2a-4b76-ba7c-31d29c2bb6a4" alt="TV Screenshot 2" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/11e2e8c6-ee09-479d-97ce-55b8c328a69d" alt="TV Screenshot 1" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/06126725-a87c-468a-8b4e-61fe91f3b5b6" alt="TV Screenshot 2" width="700"/></td>
</tr>
<tr>
<td><img src="https://github.com/user-attachments/assets/9f677129-8183-44aa-b714-42b8a9ef2df8" alt="TV Screenshot 3" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/09f6e0e3-11b1-4db5-8c76-cfaf45be1249" alt="TV Screenshot 4" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/d39b9e8c-b630-4861-b325-c38c3e8a404c" alt="TV Screenshot 3" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/c061c773-1f89-496c-86cf-04caca4a7503" alt="TV Screenshot 4" width="700"/></td>
</tr>
<tr>
<td><img src="https://github.com/user-attachments/assets/967731bc-a13c-485b-a360-b71f53da3f53" alt="TV Screenshot 5" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/f7559fa5-2294-4bde-bd73-f112ba841c06" alt="TV Screenshot 6" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/45cb240a-a921-46c2-a2ce-c31e5709656a" alt="TV Screenshot 6" width="700"/></td>
</tr>
<tr>
<td><img src="https://github.com/user-attachments/assets/e448ac52-81c6-4c2b-acf0-412b05f3dad6" alt="TV Screenshot 7" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/b4e523ff-f4ce-408c-a11f-41df1d54954d" alt="TV Screenshot 8" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/9a34cfa9-27b7-457e-b2ab-18b014dd57c9" alt="TV Screenshot 7" width="700"/></td>
<td><img src="https://github.com/user-attachments/assets/a43ec774-3ad1-4387-bb04-68a040bca288" alt="TV Screenshot 8" width="700"/></td>
</tr>
</table>

Expand All @@ -45,7 +46,7 @@
<tr>
<td><img src="https://github.com/user-attachments/assets/2191a341-e9ac-43e4-a79f-17ba6f979d86" alt="Mobile Screenshot 1" width="315"/></td>
<td><img src="https://github.com/user-attachments/assets/28ee59ee-0846-49f1-8ead-b16bb67be54c" alt="Mobile Screenshot 2" width="315"/></td>
<td><img src="https://github.com/user-attachments/assets/92828f5b-5a99-40ff-8f72-4fedbad0aacb" alt="Mobile Screenshot 3" width="315"/></td>
<td><img src="https://github.com/user-attachments/assets/92828f5b-5a99-40ff-8f72-4fedbad0aacb" alt="Mobile Screenshot 3" width="315"/></td>
<td><img src="https://github.com/user-attachments/assets/a292ac1c-3e7a-44a9-a0a8-d4426422431f" alt="Mobile Screenshot 4" width="315"/></td>
</tr>
<tr>
Expand Down Expand Up @@ -118,6 +119,10 @@ _**[Media3文档](https://developer.android.google.cn/media/media3/exoplayer/sup

手机端至 [**Releases页**](https://github.com/GhostenEditor/Ghosten-Player/releases) 自行下载安装,TV端可以使用U盘或当贝市场进行安装

### TV端操作方式

TV端主要通过遥控器进行界面交互(也可外接鼠标),主要使用到上下左右四个方向键进行焦点切换,选择键选择内容,以及菜单键呼出侧边菜单栏。若你的遥控器缺少某个按键导致功能使用受限,可以提issue。

### 添加账号

进入设置 → 账号管理,点击加号按钮,进入登录页面。
Expand All @@ -139,7 +144,7 @@ _**[Media3文档](https://developer.android.google.cn/media/media3/exoplayer/sup

#### 夸克网盘

通过网页登录夸克后,点击右上角确认按钮后完成登录
通过网页登录夸克后,点击右上角确认按钮后完成登录(TV端无需点击完成按钮)

<img alt="Quark Login Page" src="https://github.com/user-attachments/assets/7a5671b5-82f6-444a-ae4c-d16f85ce7a5a" width="315"/>

Expand Down Expand Up @@ -233,12 +238,13 @@ _**[Media3文档](https://developer.android.google.cn/media/media3/exoplayer/sup

### TV端辅助输入

由于TV端使用遥控器输入链接、账号密码等信息不便,可在TV端点击辅助输入按钮,然后使用手机(需在用以局域网下)
扫描二维码进入网页,手机端编辑的文本,会推送到TV端聚焦的文本框内
由于TV端使用遥控器输入链接、账号密码等信息不便。部分页面支持TV端辅助输入,在同一个局域网下,扫描页面上的二维码进入网页,手机端编辑的文本,会推送到TV端聚焦的文本框内

<img src="https://github.com/user-attachments/assets/28ee59ee-0846-49f1-8ead-b16bb67be54c" alt="Mobile Screenshot 2" width="315"/>

### 文件下载

Todo
目前仅支持单个文件的下载(后续会添加批量下载功能),在电影页面,剧集页面以及播放器会有下载按钮。可在设置中的下载管理页面管理下载任务。若播放已下载或正在下载的内容,会优先使用已下载的部分,以节约网络带宽。下载中的文件存放在下载目录,下载成功后文件会按照剧集的结构存放在电影目录下。

### 多线程播放和下载

Expand Down Expand Up @@ -323,13 +329,18 @@ Android 6+

## Todos

- [ ] 音乐播放器
- [ ] 增加ftp和smb协议的支持
- [ ] 保存媒体信息至文件(nfo)
- [ ] 桌面端(Developing)
- [ ] 应用串联
- [ ] 使用mpv作为视频解码器以兼容更多的视频格式
- [ ] TV端增加搜索功能
- [ ] 完善播放器的缩放功能(交互逻辑和兼容性)
- [ ] DLNA投屏的兼容问题

## 声明

本项目仅作为个人学习使用

本项目不提供任何的内容资源,若出现任何内容侵权行为皆与本项目开发人员无关

在使用本程序之前,你应了解并承担相应的风险,包括但不限于账号被ban,下载限速等,与本程序无关
3 changes: 0 additions & 3 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@
<data android:host="player"/>
</intent-filter>
</activity>
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="true"/>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class MainActivity : FragmentActivity() {
mainFragment = ensureFlutterFragmentCreated(
PLAYER_FRAGMENT, "player", listOf(androidDeviceType().toString(), intent.data?.toString())
)
} else if (androidDeviceType() == DEVICE_TYPE_TV) {
mainFragment = ensureFlutterFragmentCreated(PLAYER_FRAGMENT, "tv", listOf())
} else {
mainFragment = ensureFlutterFragmentCreated(MAIN_FRAGMENT, "main", listOf(androidDeviceType().toString()))
}
Expand Down
3 changes: 3 additions & 0 deletions android/app/src/main/res/values-television/colors.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<resources>
<color name="background">#FF000000</color>
</resources>
Binary file added assets/images/bg-pixel.webp
Binary file not shown.
Binary file added assets/images/bg-stripe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/bg-wheat.webp
Binary file not shown.
Binary file removed fonts/Roboto-Regular.ttf
Binary file not shown.
Binary file added fonts/RobotoCondensed-Regular.ttf
Binary file not shown.
15 changes: 9 additions & 6 deletions lib/components/async_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class AsyncImage extends StatelessWidget {
final bool needLoading;
final double errorIconSize;
final EdgeInsets padding;
final Map<String, String>? httpHeaders;

const AsyncImage(
this.src, {
Expand All @@ -27,6 +28,7 @@ class AsyncImage extends StatelessWidget {
this.needLoading = true,
this.errorIconSize = 36,
this.padding = EdgeInsets.zero,
this.httpHeaders = const {headerUserAgent: ua},
});

@override
Expand All @@ -43,7 +45,7 @@ class AsyncImage extends StatelessWidget {
filterQuality: FilterQuality.medium,
width: width,
height: height,
httpHeaders: const {headerUserAgent: ua},
httpHeaders: httpHeaders,
errorWidget: (context, url, error) => Center(child: Icon(Icons.broken_image, size: errorIconSize)),
placeholder: (context, _) => needLoading ? const _AnimatedLoading() : const SizedBox(),
imageBuilder: ink
Expand All @@ -54,12 +56,13 @@ class AsyncImage extends StatelessWidget {
width: width,
height: height,
decoration: BoxDecoration(
borderRadius: radius,
image: DecorationImage(
image: imageProvider,
fit: fit,
alignment: alignment,
filterQuality: FilterQuality.medium,
)),
image: imageProvider,
fit: fit,
alignment: alignment,
filterQuality: FilterQuality.medium,
)),
),
);
}
Expand Down
111 changes: 0 additions & 111 deletions lib/components/connect_button.dart

This file was deleted.

19 changes: 1 addition & 18 deletions lib/components/focus_card.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import 'package:flutter/material.dart';

import '../platform_api.dart';

class FocusCard<T> extends StatefulWidget {
final Widget child;

final GestureTapCallback? onTap;
final ValueChanged<bool>? onFocusChange;
final PopupMenuItemBuilder<T>? itemBuilder;
final PopupMenuItemBuilder<T>? itemLongPressBuilder;
final double? scale;
final double? width;
final double? height;

Expand All @@ -19,9 +15,7 @@ class FocusCard<T> extends StatefulWidget {
super.key,
required this.child,
this.onTap,
this.scale,
this.autofocus = false,
this.onFocusChange,
this.width,
this.height,
this.itemBuilder,
Expand Down Expand Up @@ -56,22 +50,11 @@ class _FocusCardState<T> extends State<FocusCard<T>> {
autofocus: widget.autofocus,
focusColor: Colors.transparent,
customBorder: Theme.of(context).cardTheme.shape,
onFocusChange: (focused) {
setState(() {});
if (widget.onFocusChange != null) widget.onFocusChange!(focused);
},
child: widget.child,
),
),
);
return PlatformApi.isAndroidTV() && widget.scale != null
? AnimatedScale(
scale: _focusNode.hasFocus ? widget.scale! : 1,
duration: const Duration(milliseconds: 400),
curve: Curves.easeOutBack,
child: child,
)
: child;
return child;
}

onTap(BuildContext context, PopupMenuItemBuilder<T> builder) {
Expand Down
3 changes: 0 additions & 3 deletions lib/components/image_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'focus_card.dart';
class ImageCard extends StatelessWidget {
final Widget child;
final GestureTapCallback? onTap;
final ValueChanged<bool>? onFocusChange;
final double? scale;
final bool autofocus;
final String? image;
Expand All @@ -18,7 +17,6 @@ class ImageCard extends StatelessWidget {
super.key,
required this.child,
this.onTap,
this.onFocusChange,
this.scale,
this.autofocus = false,
required this.image,
Expand All @@ -30,7 +28,6 @@ class ImageCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FocusCard(
scale: scale,
autofocus: autofocus,
onTap: onTap,
width: width,
Expand Down
Loading