Skip to content

Commit

Permalink
Merge pull request #6 from anandnet/fix_issues_related_to_network
Browse files Browse the repository at this point in the history
Bug fixes
  • Loading branch information
anandnet authored Jun 4, 2023
2 parents f799ac8 + ebacfed commit b604811
Show file tree
Hide file tree
Showing 16 changed files with 372 additions and 145 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## 1.0.1

* Some Network Exceptions handled
* Ignore battery enable option for notification issues
* Some Minor changes & bug fixes

## 1.0.0

* initial release.
110 changes: 77 additions & 33 deletions lib/services/audio_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
final _player = AudioPlayer();
// ignore: prefer_typing_uninitialized_variables
var currentIndex;
late String currentSongUrl;
late String? currentSongUrl;
bool isPlayingUsingLockCachingSource = false;
bool loopModeEnabled = false;
var networkErrorPause = false;

final _playList = ConcatenatingAudioSource(
children: [],
Expand Down Expand Up @@ -112,13 +113,22 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
printERROR('Error message: ${e.message}');
} else {
printERROR('An error occurred: $e');
final box = Hive.box("songsUrlCache");
if (box.containsKey(mediaItem.value!.id)) {
if (isExpired(url: box.get(mediaItem.value!.id)[1])) {
await customAction("playByIndex", {'index': currentIndex});
return;
}
}
if (isPlayingUsingLockCachingSource &&
e.toString().contains("Connection closed while receiving data")) {
Duration curPos = _player.position;
await _player.stop();
await _player.seek(curPos, index: 0);
await _player.play();
}
await _player.stop();
await customAction("setSourceNPlay",
{'mediaItem': queue.value[currentIndex], 'retry': true});
// Duration curPos = _player.position;
// await _player.stop();
// await _player.seek(curPos,index:0);
// await _player.play();
networkErrorPause = true;
}
});
}
Expand Down Expand Up @@ -219,16 +229,33 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
final currentQueue = queue.value;
final currentSong = mediaItem.value;
final itemIndex = currentQueue.indexOf(mediaItem_);
if(currentIndex>itemIndex){
currentIndex -=1;
if (currentIndex > itemIndex) {
currentIndex -= 1;
}
currentQueue.remove(mediaItem_);
queue.add(currentQueue);
mediaItem.add(currentSong);
}

@override
Future<void> play() => _player.play();
Future<void> play() async {
if (currentSongUrl == null) {
await customAction("playByIndex", {'index': currentIndex});
return;
}
// Workaround for network error pause in case of PlayingUsingLockCachingSource
if (isPlayingUsingLockCachingSource && networkErrorPause) {
await _player.play();
Future.delayed(const Duration(seconds: 2)).then((value) {
if (_player.playing) {
networkErrorPause = false;
}
});
await _player.play();
return;
}
await _player.play();
}

@override
Future<void> pause() => _player.pause();
Expand All @@ -250,7 +277,7 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
if (queue.value.length > currentIndex + 1) {
_player.seek(Duration.zero);
await customAction("playByIndex", {'index': currentIndex + 1});
}else{
} else {
_player.seek(Duration.zero);
_player.pause();
}
Expand Down Expand Up @@ -283,8 +310,12 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
currentIndex = extras!['index'];
final currentSong = queue.value[currentIndex];
mediaItem.add(currentSong);
currentSong.extras!['url'] = await checkNGetUrl(currentSong.id);
currentSongUrl = currentSong.extras!['url'];
final url = await checkNGetUrl(currentSong.id);
currentSongUrl = url;
if (url == null) {
return;
}
currentSong.extras!['url'] = url;
playbackState.add(playbackState.value.copyWith(queueIndex: currentIndex));

await _playList.add(_createAudioSource(currentSong));
Expand All @@ -306,14 +337,16 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
} else if (name == 'setSourceNPlay') {
await _playList.clear();
final currMed = (extras!['mediaItem'] as MediaItem);
if (!extras['retry']) {
currentIndex = 0;
mediaItem.add(currMed);
queue.add([currMed]);
currentIndex = 0;
mediaItem.add(currMed);
queue.add([currMed]);
final url = (await checkNGetUrl(currMed.id,useNewInstanceOfExplode: true));
currentSongUrl = url;
if (url == null) {
return;
}
currentSongUrl =
(await checkNGetUrl(currMed.id, generateNewUrl: extras['retry']))!;
currMed.extras!['url'] = currentSongUrl;
currentSongUrl = url;
currMed.extras!['url'] = url;
await _playList.add(_createAudioSource(currMed));
await _player.play();
cacheNextSongUrl();
Expand All @@ -330,15 +363,15 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
mediaItem.add(currentItem);
currentIndex = 0;
cacheNextSongUrl();
}else if(name == "reorderQueue"){
} else if (name == "reorderQueue") {
printINFO("Reorder queue");
final oldIndex = extras!['oldIndex'];
int newIndex = extras['newIndex'];

if (oldIndex < newIndex) {
newIndex--;
}

final currentQueue = queue.value;
final currentItem = currentQueue[currentIndex];
final item = currentQueue.removeAt(
Expand All @@ -359,36 +392,47 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {

Future<void> cacheNextSongUrl() async {
if (queue.value.length > currentIndex + 1) {
await checkNGetUrl((queue.value[currentIndex+1]).id);
await checkNGetUrl((queue.value[currentIndex + 1]).id);
printINFO("Next Song Url Cached");
}
}

// Work around used [useNewInstanceOfExplode = false] to Fix Connection closed before full header was received issue
Future<String?> checkNGetUrl(String songId,
{bool generateNewUrl = false}) async {
{bool useNewInstanceOfExplode = false}) async {
final songsCacheBox = Hive.box("SongsCache");
if (songsCacheBox.containsKey(songId) && !generateNewUrl) {
if (songsCacheBox.containsKey(songId)) {
printINFO("Got Song from cachedbox ($songId)");
return "file://$_cacheDir/cachedSongs/$songId.mp3";
} else {
//check if song stream url is cached and allocate url accordingly
final songsUrlCacheBox = Hive.box("SongsUrlCache");
final qualityIndex = Hive.box('AppPrefs').get('streamingQuality');
final musicServices = Get.find<MusicServices>();
List<String> url = [];
if (songsUrlCacheBox.containsKey(songId) && !generateNewUrl) {
dynamic url;
if (songsUrlCacheBox.containsKey(songId)) {
if (isExpired(url: songsUrlCacheBox.get(songId)[qualityIndex])) {
url = (await musicServices.getSongUri(songId))!;
songsUrlCacheBox.put(songId, url);
url = useNewInstanceOfExplode
? await MusicServices(false).getSongUri(songId)
: (await musicServices.getSongUri(songId));
if (url != null) songsUrlCacheBox.put(songId, url);
} else {
url = songsUrlCacheBox.get(songId);
}
} else {
url = (await musicServices.getSongUri(songId))!;
songsUrlCacheBox.put(songId, url);
printINFO("Url cached in Box for songId $songId");
url = useNewInstanceOfExplode
? await MusicServices(false).getSongUri(songId)
: (await musicServices.getSongUri(songId));
if (url != null) {
songsUrlCacheBox.put(songId, url);
printINFO("Url cached in Box for songId $songId");
}
}
return url[qualityIndex];
return url != null ? url[qualityIndex] : null;
}
}
}

class UrlError extends Error {
String message() => 'Unable to fetch url';
}
8 changes: 8 additions & 0 deletions lib/services/music_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class MusicServices extends getx.GetxService {
Future<Response> _sendRequest(String action, Map<dynamic, dynamic> data,
{additionalParams = ""}) async {
//print("$baseUrl$action$fixedParms$additionalParams data:$data");
try{
final response =
await dio.post("$baseUrl$action$fixedParms$additionalParams",
options: Options(
Expand All @@ -118,6 +119,9 @@ class MusicServices extends getx.GetxService {
} else {
return _sendRequest(action, data, additionalParams: additionalParams);
}
}on DioError{
throw NetworkError();
}
}

// Future<List<Map<String, dynamic>>>
Expand Down Expand Up @@ -620,3 +624,7 @@ class MusicServices extends getx.GetxService {
return artist;
}
}

class NetworkError extends Error{
final message = "Network Error !";
}
2 changes: 1 addition & 1 deletion lib/services/nav_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ List<dynamic> parseSearchResults(List<dynamic> results,

dynamic parseSearchResult(Map<String, dynamic> data,
List<String> searchResultTypes, String? resultType, String category) {
if (resultType != null && resultType.contains("playlist")) {
if ((resultType != null && resultType.contains("playlist"))|| category.contains("playlists")) {
resultType = 'playlist';
}
int defaultOffset = (resultType == null) ? 2 : 0;
Expand Down
15 changes: 12 additions & 3 deletions lib/ui/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,15 @@ class Home extends StatelessWidget {
SizedBox(
width: 40,
child: InkWell(
onTap: playerController.next,
onTap: (playerController
.currentQueue.isEmpty || (playerController
.currentQueue
.last
.id ==
playerController
.currentSong.value!.id))
? null
: playerController.next,
child: Icon(
Icons.skip_next_rounded,
color: Theme.of(context)
Expand Down Expand Up @@ -179,7 +187,8 @@ class Home extends StatelessWidget {
iconSize: 35.0,
onPressed: controller.play,
);
} else if (buttonState == PlayButtonState.playing) {
} else if (buttonState == PlayButtonState.playing ||
buttonState == PlayButtonState.loading) {
return IconButton(
icon: Icon(
Icons.pause_rounded,
Expand All @@ -195,7 +204,7 @@ class Home extends StatelessWidget {
color: Theme.of(context).textTheme.titleMedium!.color,
),
iconSize: 35.0,
onPressed: (){},
onPressed: () {},
);
}
});
Expand Down
25 changes: 14 additions & 11 deletions lib/ui/player/Player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,8 @@ class Player extends StatelessWidget {
iconSize: 40.0,
onPressed: controller.play,
);
} else if (buttonState == PlayButtonState.playing) {
} else if (buttonState == PlayButtonState.playing ||
buttonState == PlayButtonState.loading) {
return IconButton(
icon: const Icon(Icons.pause_rounded),
iconSize: 40.0,
Expand Down Expand Up @@ -386,14 +387,16 @@ class Player extends StatelessWidget {
}

Widget _nextButton(PlayerController playerController, BuildContext context) {
return IconButton(
icon: Icon(
Icons.skip_next_rounded,
color: Theme.of(context).textTheme.titleMedium!.color,
),
iconSize: 30,
onPressed: () async {
await playerController.next();
},
);
return Obx(() {
final isLastSong = playerController.currentQueue.isEmpty ||
(playerController.currentQueue.last.id ==
playerController.currentSong.value!.id);
return IconButton(
icon: Icon(
Icons.skip_next_rounded,
color: Theme.of(context).textTheme.titleMedium!.color,
),
iconSize: 30,
onPressed: isLastSong ? null : playerController.next);
});
}
10 changes: 7 additions & 3 deletions lib/ui/player/player_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,22 @@ class PlayerController extends GetxController {
currentSong.value = mediaItem;
_playerPanelCheck();
await _audioHandler.customAction(
"setSourceNPlay", {'mediaItem': mediaItem, 'retry': false});
"setSourceNPlay", {'mediaItem': mediaItem});
}

///enqueueSong append a song to current queue
///if current queue is empty, push the song into Queue and play that song
Future<void> enqueueSong(MediaItem mediaItem) async {
//check if song is available in cache and allocate
await _audioHandler.addQueueItem(mediaItem);
await enqueueSongList([mediaItem]);
}

///enqueueSongList method add song List to current queue
Future<void> enqueueSongList(List<MediaItem> mediaItems) async {
if(currentQueue.isEmpty){
await playPlayListSong(mediaItems, 0);
return;
}
for(MediaItem item in mediaItems){
if(!currentQueue.contains(item)){
_audioHandler.addQueueItem(item);
Expand All @@ -200,7 +204,7 @@ class PlayerController extends GetxController {
currentSong.value = mediaItem;
_playerPanelCheck();
await _audioHandler.customAction(
"setSourceNPlay", {'mediaItem': mediaItem, 'retry': false});
"setSourceNPlay", {'mediaItem': mediaItem});
}

Future<void> playPlayListSong(List<MediaItem> mediaItems, int index) async {
Expand Down
Loading

0 comments on commit b604811

Please sign in to comment.