Skip to content

Commit

Permalink
feat: 完善文档,新增搜索历史,修复单曲循环时偶现暂停的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
lyy committed Sep 14, 2024
1 parent 52d756d commit 8d148be
Show file tree
Hide file tree
Showing 19 changed files with 593 additions and 248 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## 0.0.5

- [feat] 完善文档
- [feat] 新增搜索历史
- [fix] 修复单曲循环时偶现暂停的问题
51 changes: 42 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
# 哔哔音乐

A new Flutter project.
使用 B 站作为歌曲源开发的音乐播放器

## Getting Started
## 实现思路

This project is a starting point for a Flutter application.
1. B 站上有很多的音乐视频,相当于一种超级全的音乐聚合曲库(索尼直接将 B 站当做网盘,传了 15w 个视频)
2. 对这些视频进行收集制作成歌单
3. 无需登录即可完整播放,无广告
4. 使用 [SocialSisterYi](https://github.com/SocialSisterYi/bilibili-API-collect) 整理的 B 站接口文档,直接就可以获取和搜索 B 站视频数据

A few resources to get you started if this is your first Flutter project:
## 功能

- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
- [x] 播放器
- [x] 基础功能(播放,暂停,上一首,下一首)
- [x] 播放列表
- [x] 单曲循环,列表循环,随机播放
- [x] 进度拖动
- [ ] 计时播放
- [x] 搜索
- [x] 名称关键字搜索
- [x] 歌单
- [x] 歌单同步
- [x] 歌单广场(由用户贡献分享自己的歌单)

For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
## 技术栈

1. Flutter

## 缺陷

1. 因为没有用户认证,歌曲的质量并不是很高(听个响儿)
2. 没有 IOS 版本(上架太贵了)

## UI

![](./doc/imgs/1.png)
![](./doc/imgs/2.png)
![](./doc/imgs/3.png)
![](./doc/imgs/4.png)

## 警告

此项目仅供个人学习使用,请勿用于商业用途,否则后果自负。

## 鸣谢致敬

1. [SocialSisterYi](https://github.com/SocialSisterYi/bilibili-API-collect) 感谢这个库的作者和相关贡献者
2. 感谢广大 B 站网友们提供的视频资源
Binary file added assets/not_cover.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 doc/imgs/1.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 doc/imgs/2.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 doc/imgs/3.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 doc/imgs/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions lib/constants/cache_key.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class CacheKey {
// 歌单广场
static String openMusicOrderUrls = 'open_music_order_urls';
// 搜索历史
static String searchHistory = 'search_history';

// 当前播放的歌曲
static String playerCurrent = 'player_current';
Expand Down
62 changes: 51 additions & 11 deletions lib/modules/music_order/detail.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'package:bbmusic/components/music_list_tile/music_list_tile.dart';
import 'package:bbmusic/modules/download/model.dart';
import 'package:bbmusic/modules/music_order/edit_music.dart';
import 'package:bbmusic/modules/music_order/utils.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:bbmusic/components/sheet/bottom_sheet.dart';
import 'package:bbmusic/modules/music_order/list.dart';
import 'package:bbmusic/modules/music_order/model.dart';
import 'package:bbmusic/modules/player/player.dart';
import 'package:bbmusic/modules/player/model.dart';
Expand Down Expand Up @@ -30,6 +32,38 @@ class _MusicOrderDetailState extends State<MusicOrderDetail> {
musicOrder = widget.data;
}

_formItemHandler(MusicItem data) {
if (widget.umoService == null) {
return;
}
if (!widget.umoService!.canUse()) {
BotToast.showSimpleNotification(
title: "歌单源目前无法使用,请先完善配置",
);
return;
}
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return EditMusic(
musicOrderId: widget.data.id,
service: widget.umoService!,
data: data,
onOk: (music) {
setState(() {
final ind = musicOrder.musicList
.indexWhere((item) => item.id == data.id);
if (ind != -1) {
musicOrder.musicList[ind] = music;
}
});
},
);
},
),
);
}

_moreHandler(BuildContext context, MusicItem item) {
openBottomSheet(context, [
SheetItem(
Expand All @@ -51,12 +85,14 @@ class _MusicOrderDetailState extends State<MusicOrderDetail> {
SheetItem(
title: const Text('添加到歌单'),
onPressed: () {
collectToMusicOrder(context, [item]);
collectToMusicOrder(context, [item], musicOrder: musicOrder);
},
),
SheetItem(
title: const Text('编辑'),
onPressed: () {},
onPressed: () {
_formItemHandler(item);
},
hidden: widget.umoService == null,
),
SheetItem(
Expand Down Expand Up @@ -113,16 +149,20 @@ class _MusicOrderDetailState extends State<MusicOrderDetail> {
title: const Text('加入歌单'),
hidden: widget.umoService != null,
onPressed: () {
collectToMusicOrder(context, musicOrder.musicList);
collectToMusicOrder(
context,
musicOrder.musicList,
musicOrder: musicOrder,
);
},
),
SheetItem(
title: const Text('下载全部'),
hidden: widget.umoService != null,
onPressed: () {
collectToMusicOrder(context, musicOrder.musicList);
},
)
// SheetItem(
// title: const Text('下载全部'),
// onPressed: () {
// Provider.of<DownloadModel>(context, listen: false)
// .download(musicOrder.musicList);
// },
// )
]);
},
)
Expand Down
100 changes: 100 additions & 0 deletions lib/modules/music_order/edit_music.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:bbmusic/modules/music_order/model.dart';
import 'package:bbmusic/modules/user_music_order/common.dart';
import 'package:bbmusic/origin_sdk/origin_types.dart';
import 'package:provider/provider.dart';

// 编辑歌单内的歌曲信息
class EditMusic extends StatefulWidget {
final String musicOrderId; // 歌单 ID
final MusicItem data;
final UserMusicOrderOrigin service;
final Function(MusicItem music) onOk;

const EditMusic({
super.key,
required this.musicOrderId,
required this.data,
required this.service,
required this.onOk,
});

@override
State<EditMusic> createState() => _EditMusicState();
}

class _EditMusicState extends State<EditMusic> {
final TextEditingController _nameController = TextEditingController();
final TextEditingController _authorController = TextEditingController();

@override
void initState() {
super.initState();
setState(() {
_nameController.text = widget.data.name;
_authorController.text = widget.data.author;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('修改歌曲'),
),
body: Container(
padding: const EdgeInsets.all(15),
child: Column(
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("歌曲名称"),
),
),
const SizedBox(height: 20),
TextField(
controller: _authorController,
maxLines: 3,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("歌曲作者"),
),
),
const SizedBox(height: 40),
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: () async {
final cancel = BotToast.showLoading();
final music = MusicItem(
id: widget.data.id,
origin: widget.data.origin,
duration: widget.data.duration,
cover: widget.data.cover,
name: _nameController.text,
author: _authorController.text,
);
await widget.service.updateMusic(
widget.musicOrderId,
[music],
);
cancel();
if (context.mounted) {
Provider.of<UserMusicOrderModel>(context, listen: false)
.load(widget.service.name);
Navigator.of(context).pop();
}
widget.onOk(music);
},
child: const Text('确 认'),
),
),
],
),
),
);
}
}
114 changes: 114 additions & 0 deletions lib/modules/music_order/edit_order.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:bbmusic/modules/music_order/model.dart';
import 'package:bbmusic/modules/user_music_order/common.dart';
import 'package:bbmusic/origin_sdk/origin_types.dart';
import 'package:provider/provider.dart';

// 编辑/创建歌单
class EditMusicOrder extends StatefulWidget {
final MusicOrderItem? data;
final UserMusicOrderOrigin service;

const EditMusicOrder({super.key, this.data, required this.service});

@override
State<EditMusicOrder> createState() => _EditMusicOrderState();
}

class _EditMusicOrderState extends State<EditMusicOrder> {
final TextEditingController _nameController = TextEditingController();
final TextEditingController _coverController = TextEditingController();
final TextEditingController _descController = TextEditingController();

bool get _isCreate => widget.data?.id == "";

@override
void initState() {
super.initState();
setState(() {
_nameController.text = widget.data?.name ?? '';
_descController.text = widget.data?.desc ?? '';
_coverController.text = widget.data?.cover ?? '';
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: _isCreate ? const Text('创建歌单') : const Text('修改歌单'),
),
body: Container(
padding: const EdgeInsets.all(15),
child: Column(
children: [
TextField(
controller: _coverController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("歌单封面"),
),
),
const SizedBox(height: 20),
TextField(
controller: _nameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("歌单名称"),
),
),
const SizedBox(height: 20),
TextField(
controller: _descController,
maxLines: 3,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("歌单描述"),
),
),
const SizedBox(height: 40),
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: () async {
final cancel = BotToast.showLoading();
if (_isCreate) {
await widget.service.create(
MusicOrderItem(
id: '',
author: '',
name: _nameController.text,
desc: _descController.text,
cover: _coverController.text,
musicList: [],
),
);
} else {
await widget.service.update(
MusicOrderItem(
id: widget.data!.id,
name: _nameController.text,
desc: _descController.text,
cover: _coverController.text,
author: widget.data!.author,
musicList: widget.data!.musicList,
),
);
}
cancel();
if (context.mounted) {
Provider.of<UserMusicOrderModel>(context, listen: false)
.load(widget.service.name);
Navigator.of(context).pop();
}
},
child: const Text('确 认'),
),
),
],
),
),
);
}
}
Loading

0 comments on commit 8d148be

Please sign in to comment.