tft每日頭條

 > 科技

 > 有啥聽歌的好軟件

有啥聽歌的好軟件

科技 更新时间:2024-07-19 00:14:18
前言

前面我發了一篇文章,向大家推薦了一個聽歌軟件:Listen(原文鍊接),我一般是在Edge浏覽器裡安裝插件使用的,但是由于我是用的iPhone手機,然後Listen的源碼我又一直編譯不過去(吐槽下ReactNative)所以想自己撸一個聽歌軟件自己用.

技術選型

本人原本是做ios開發的,但是奈何objective-C比較難用,swift又一言難盡,swiftUI坑又比較多.在加上最近flutter比較火,而我之前也在demo上試了寫了一下,感覺還不錯,所以就打算使用flutter來寫app了.

而且flutter還是跨平台的,還可以把android windows的一起給搞定了,嘿嘿~ 美滋滋

api接口

巧婦難為無米之炊,沒有接口也沒法進行下去啊. 我第一時間想到的是抓Listen1的包. 但是咪咕渠道的有個sid字段的值不知道是什麼規則生成的,每次都不一樣.導緻我咪咕渠道的api遲遲搞不定.

有啥聽歌的好軟件(寫一個想聽啥聽啥的聽歌軟件)1

不過我在github上找到了其它可用的api(鍊接地址),謝謝這位大哥了嘿嘿.

開始撸代碼先撸一個公共類,作為解析各平台的解析協議

class SongModel { Map<String, dynamic> originMap = {}; //原始數據 String channel = ""; //渠道 //資源id String 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 @override String resourceId() { return "migu" originMap['id']; } //歌曲名 @override String songName() { return originMap['songName']; } //歌曲圖片 @override Future<String> songImg() { return Future.value(originMap['cover']); } //歌手名 @override String singer() { return originMap['singerName']; } //專輯名 @override String album() { return originMap['albumName']; } @override Future<String> playUrl() { return Future.value(originMap['mp3']); } @override Future<String> lyric() { return MiguApi.getLyric(this); } } class MiguPageListModel implements PageResponse { late Map<String, dynamic> originMap; //原始數據 MiguPageListModel(this.originMap); @override List<MiguSongModel> list() { var list = originMap["musics"] as List; return list.map((e) => MiguSongModel(e)).toList(); } @override bool hasNextPage() { return true; } @override int 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 = 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 = GetStorage().read<int>("queueState") ?? 0; var resourceId = GetStorage().read<String>("currentSong"); if (resourceId == null) { SongListManager.playList() .then((value) => currentSong.value = value.first); } else { SongListManager.getSong(resourceId) .then((value) => currentSong.value = value); } } static PlayerManager _getInstance() { _instance = _instance ?? PlayerManager._internal(); return _instance!; } play(SongModel songModel) async { SongListManager.addSong(songModel); try { var url = await songModel.playUrl(); int state = await audioPlayer.play(url); audioPlayer.getDuration(); currentSong.value = songModel; GetStorage().write("currentSong", currentSong.value!.resourceId()); addSong(); isInit.value = true; } catch (e) { next(); } } pause() { if (currentSong.value == null) { return; } audioPlayer.pause(); } resume() async { if (currentSong.value == null) { return; } if (isInit.value) { audioPlayer.resume(); } else { play(currentSong.value!); } } next() async { if (currentSong.value == null) { return; } var list = await SongListManager.playList(); if (queueState.value == 0) { var index = list.indexOf(currentSong.value!); var i = index 1; if (index >= list.length - 1) { i = 0; } var song = list.elementAt(i); currentSong.value = song; play(song); } else if (queueState.value == 1) { var random = Random(); var index = random.nextInt(list.length); var song = list.elementAt(index); currentSong.value = song; play(song); } else { play(currentSong.value!); } } previous() async { if (currentSong.value == null) { return; } var list = await SongListManager.playList(); if (queueState.value == 0) { var index = list.indexOf(currentSong.value!); var i = index - 1; if (index <= 0) { i = list.length - 1; } var song = list.elementAt(i); currentSong.value = song; play(song); } else if (queueState.value == 1) { var random = Random(); var index = random.nextInt(list.length); var song = list.elementAt(index); currentSong.value = song; play(song); } else { play(currentSong.value!); } } seek(Duration duration) async { if (currentSong.value == null) { return; } await audioPlayer.seek(duration); } addSong() async { var songModel = currentSong.value; if (songModel == null) { return; } var img = await songModel.songImg(); var album = songModel.album(); var title = songModel.songName(); // var duration = await audioPlayer.getDuration(); var duration = 200000; var item = MediaItem( id: songModel.resourceId(), album: album, title: title, artist: '', duration: Duration(milliseconds: duration), artUri: Uri.parse(img), ); // audioHandler.playMediaItem(item); audioHandler.mediaItem.add(item); var playbackState = PlaybackState( // Which buttons should appear in the notification now controls: [ MediaControl.skipToPrevious, MediaControl.play, MediaControl.pause, MediaControl.stop, MediaControl.skipToNext, ], // Which other actions should be enabled in the notification systemActions: const { MediaAction.seek, MediaAction.seekForward, MediaAction.seekBackward, }, // Which controls to show in Android's compact view. androidCompactActionIndices: const [0, 1, 3], // Whether audio is ready, buffering, ... processingState: AudioProcessingState.ready, // Whether audio is playing speed: 1.0, // The current queue position queueIndex: 0, playing: true, ); audioHandler.playbackState.add(playbackState); } }

哎,我為啥要在頭條上發這種東西呢?這種東西真的有人看嗎?

不管了,發幾張成品圖:

有啥聽歌的好軟件(寫一個想聽啥聽啥的聽歌軟件)2

有啥聽歌的好軟件(寫一個想聽啥聽啥的聽歌軟件)3

有啥聽歌的好軟件(寫一個想聽啥聽啥的聽歌軟件)4

順便搞了個mac版的,上班好好用 嘿嘿

有啥聽歌的好軟件(寫一個想聽啥聽啥的聽歌軟件)5

雖然界面比較簡陋,但是聽歌的搞這麼花裡胡哨的幹啥呢,是吧?

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved