前言前面我发了一篇文章,向大家推荐了一个听歌软件:Listen(原文链接),我一般是在Edge浏览器里安装插件使用的,但是由于我是用的iPhone手机,然后Listen的源码我又一直编译不过去(吐槽下ReactNative)所以想自己撸一个听歌软件自己用.
技术选型本人原本是做ios开发的,但是奈何objective-C比较难用,swift又一言难尽,swiftUI坑又比较多.在加上最近flutter比较火,而我之前也在demo上试了写了一下,感觉还不错,所以就打算使用flutter来写app了.
而且flutter还是跨平台的,还可以把android windows的一起给搞定了,嘿嘿~ 美滋滋
api接口巧妇难为无米之炊,没有接口也没法进行下去啊. 我第一时间想到的是抓Listen1的包. 但是咪咕渠道的有个sid字段的值不知道是什么规则生成的,每次都不一样.导致我咪咕渠道的api迟迟搞不定.
文章插图
不过我在github上找到了其它可用的api(链接地址),谢谢这位大哥了嘿嘿.
开始撸代码先撸一个公共类,作为解析各平台的解析协议
class SongModel {Map<String, dynamic> originMap = {}; //原始数据String channel = ""; //渠道//资源idString resourceId() {return "";}//歌曲名String songName() {return "";}//歌曲图片Future<String> songImg() {return Future.value("");}//歌手名String singer() {return '';}//专辑名String album() {return "";}//播放地址Future<String> playUrl() async {return "";}//获取歌词Future<String> lyric() async {return "";}}
特定平台的api实现import 'package:dio/dio.dart';import 'package:listen_flutter/api/migu/model/models/migu_models.dart';class MiguApi {//搜索歌曲static Future<MiguPageListModel> search(String? text) async {var searchText = "jay";if (text?.isNotEmpty == true) {searchText = text!;}var path = 'http://iecoxe.top:5000/v1/migu/search?key=$searchText';var response = await Dio().get(path);return MiguPageListModel(response.data);}//获取播放地址static Future<String> getPlayUrl(MiguSongModel song) async {var copyrightId = song.originMap['copyrightId'];var path = 'http://iecoxe.top:5000/v1/migu/song?cid=$copyrightId';var response = await Dio().get(path);var map = response.data as Map;return map['lyric'];}//获取播放地址static Future<String> getLyric(MiguSongModel song) async {var copyrightId = song.originMap['copyrightId'];var path = 'http://iecoxe.top:5000/v1/migu/lyric?cid=$copyrightId';var response = await Dio().get(path);var map = response.data as Map;return map['lyric'];}}
model类做好解析import 'package:hive/hive.dart';import 'package:listen_flutter/api/migu/apis/migu_api.dart';import 'package:listen_flutter/models/page_response.dart';import 'package:listen_flutter/models/song_model.dart';part 'migu_models.g.dart';@HiveType(typeId: 0)class MiguSongModel extends HiveObject implements SongModel {@override@HiveField(1)Map<String, dynamic> originMap; //原始数据@override@HiveField(2)String channel = "migu";MiguSongModel(this.originMap);//资源id@overrideString resourceId() {return "migu" + originMap['id'];}//歌曲名@overrideString songName() {return originMap['songName'];}//歌曲图片@overrideFuture<String> songImg() {return Future.value(originMap['cover']);}//歌手名@overrideString singer() {return originMap['singerName'];}//专辑名@overrideString album() {return originMap['albumName'];}@overrideFuture<String> playUrl() {return Future.value(originMap['mp3']);}@overrideFuture<String> lyric() {return MiguApi.getLyric(this);}}class MiguPageListModel implements PageResponse {late Map<String, dynamic> originMap; //原始数据MiguPageListModel(this.originMap);@overrideList<MiguSongModel> list() {var list = originMap["musics"] as List;return list.map((e) => MiguSongModel(e)).toList();}@overridebool hasNextPage() {return true;}@overrideint nextPage() {return 1;}}
最后就是构建UI,解析歌词啥的了// import 'package:just_audio/just_audio.dart';import 'dart:math';import 'package:audio_service/audio_service.dart';import 'package:audioplayers/audioplayers.dart';import 'package:get/get.dart';import 'package:get_storage/get_storage.dart';// import 'package:just_audio/just_audio.dart';import 'package:listen_flutter/models/song_model.dart';import 'package:listen_flutter/songlist/songlist.dart';import 'audio_handle.dart';class PlayerManager {var currentSong = Rx<SongModel?>(null); //当前播放歌曲var playerState = Rx<PlayerState>(PlayerState.PAUSED); //当前播放状态var position = Duration.zero.obs;var duration = Duration.zero.obs;var isInit = false.obs;var queueState = 0.obs; //0 顺序播放 1:随机播放 2:单曲循环AudioPlayer audioPlayer = AudioPlayer(); //播放器var audioHandler = Get.find<MyAudioHandler>();factory PlayerManager() => _getInstance();static PlayerManager get instance => _getInstance();static PlayerManager? _instance;PlayerManager._internal() {audioPlayer.onPlayerStateChanged.listen((event) {playerState.value = https://www.goobye.net/event;audioHandler.playbackState.add(audioHandler.playbackState.value.copyWith(playing: event == PlayerState.PLAYING));});audioPlayer.onAudioPositionChanged.listen((event) {position.value = event;audioHandler.playbackState.add(audioHandler.playbackState.value.copyWith(updatePosition: event));});audioPlayer.onDurationChanged.listen((event) {duration.value = event;});audioPlayer.onPlayerCompletion.listen((event) {next();});queueState.listen((value) {GetStorage().write("queueState", value);});queueState.value = https://www.goobye.net/GetStorage().read
- 连续蒸了20多天鸡蛋羹 蒸蛋羹一个鸡蛋蒸多久
- 华为鸿蒙OS真的好用吗 鸿蒙os和emui
- 跑好滴滴的第一个技巧方法 跑滴滴有啥技巧接好单
- 【历史故事】《山河月明》建文帝朱允炆四大坑友:三驾马车,外加一个大将军
- 法令纹看健康
- 【爱历史】志愿军神炮手一人独操一门榴炮,美军:对面增援了一个炮兵营?
- 曾经的邮政EMS投递员 中国邮政投递员
- 投资葡萄酒专卖店需要多少钱 投资一个酒庄需要多少钱
- 【历史故事】从一个街头小混混逆袭成为殿帅府太尉,高俅是如何做到的?
- 【历史故事】李煜这首词,4句无一不是千古名句,最后9个字只有他写得出来