suragch / flutter_audio_service_demo

Companion project for Flutter audio_service tutorial
https://suragch.medium.com/background-audio-in-flutter-with-audio-service-and-just-audio-3cce17b4a7d?sk=0837a1b1773e27a4f879ff3072e90305
MIT License
57 stars 28 forks source link

Shuffle like VLC App #6

Open gOzaru opened 3 years ago

gOzaru commented 3 years ago

Hello, I found out that just_audio shuffle method only made a random indexes of current playlist for once only. Meanwhile, in VLC app, it doesn't work that way. If we press Shuffle inside the app, and press Next, then the next song will jump into another index. It doesn't change the order of playlist.

Is there anyone who knows how to implement shuffle to work like VLC app? Any tips and guidance will be a great help. Thanks.

suragch commented 2 years ago

I recently saw this in the docs for ConcatenatingAudioSorce:

  /// Creates a [ConcatenatingAudioSorce] with the specified [children]. If
  /// [useLazyPreparation] is `true`, children will be loaded/buffered as late
  /// as possible before needed for playback (currently supported on Android
  /// only). When [AudioPlayer.shuffleModeEnabled] is `true`, [shuffleOrder]
  /// will be used to determine the playback order (defaulting to
  /// [DefaultShuffleOrder]).

Can you try setting shuffleOrder to see if that makes a difference?

gOzaru commented 2 years ago

@suragch I didn't know how to put variable Random inside the ConcatenatingAudioSource since it gave me an error.

gOzaru commented 2 years ago

@suragch I think the Shuffle method from just_audio works the same way VLC works. I think maybe the main problem is located in how to implement this and combine it with audio_service. You can view my comment here.

https://github.com/ryanheise/audio_service/issues/774

I am gonna close this for now. If I found the way, I will let you know.

suragch commented 2 years ago

I'm reopening this until I can fix the tutorial. Thank you for your comments.

gOzaru commented 2 years ago

@suragch If you find out a way to implement it in the latest audio_service, please let me know. Thank you.

gOzaru commented 2 years ago

@suragch Actually, ryanheise just updated the example_playlist.dart in audio_service 0.18.0 and he added Shuffle function with working Loop All. I wonder if you can implement it in your tutorial?

https://github.com/ryanheise/audio_service/issues/774

gOzaru commented 2 years ago

@suragch If you want to learn the complete fixed of shuffle playlist with loop all are active based on above example, you can visit my repository below: link

gOzaru commented 2 years ago

@suragch Do you know how to convert these lines of code into PlaylistRepository like yours in the tutorial:

class MediaLibrary {
  static const albumsRootId = 'albums';

  final items = <String, List<MediaItem>>{
    AudioService.browsableRootId: const [MediaItem(id: albumsRootId, title: "Albums", playable: false)],
    albumsRootId: [
      MediaItem(    // <--- I need to include these MediaItem using a function like in PlaylistRepository
        id: 'https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3',
        album: "Science Monday",
        title: "I can do it",
        artist: "Science Friday and WNYC Studios",
        duration: const Duration(milliseconds: 5739820),
        artUri: Uri.parse('https://media.wnyc.org/i/1400/1400/l/80/1/ScienceFriday_WNYCStudios_1400.jpg'),
      ),
    ],
  };
}
gOzaru commented 2 years ago

No need. I found this as the best solution:

class MediaLibrary {
  static const albumsRootId = 'albums';
  final audioHandler = getIt<AudioHandler>();
  int status = -1;
  late final Map<String, List<MediaItem>> items; // <-- I declared it here as late variable
  List<MediaItem> mediaItems = [];

  void init() async {
    await loadPlaylist();
  }

  Future<List<MediaItem>> loadPlaylist() async {
    final songRepository = getIt<PlaylistRepository>();
    final playlistData = await songRepository.fetchInitialPlaylist();

    audioHandler.queue.listen((playlist) async {
      int lengthX = playlist.length;
      if (lengthX > 0) {
        status = 1;
      } else if (lengthX == 0) {
        status = 0;
      }
    });

    if (status == 0) {
      mediaItems = playlistData
          .map((song) => MediaItem(
                id: song['id'],
                album: song['album'],
                title: song['title'],
                artist: song['artist'],
                extras: {'url': song['url']},
              ))
          .toList();

      items = {
        AudioService.browsableRootId: const [
          MediaItem(
            id: albumsRootId,
            title: "Albums",
            playable: false,
          ),
        ],
        albumsRootId: mediaItems,  //I added here the variable of List<MediaItem>, problem solved. 
      };

      audioHandler.updateQueue(mediaItems);

      log("List of all indexes in first mediaItems");
      for (int i = 0; i < mediaItems.length; i++) {
        log("[$i] ${mediaItems[i].title}");
      }
    } else if (status == 1) {
      mediaItems = playlistData
          .map((song) => MediaItem(
                id: song['id'],
                album: song['album'],
                title: song['title'],
                artist: song['artist'],
                extras: {'url': song['url']},
              ))
          .toList();

      items = {
        AudioService.browsableRootId: const [
          MediaItem(
            id: albumsRootId,
            title: "Albums",
            playable: false,
          ),
        ],
        albumsRootId: mediaItems,
      };

      audioHandler.updateQueue(mediaItems);

      log("List of all indexes in first mediaItems");
      for (int i = 0; i < mediaItems.length; i++) {
        log("[$i] ${mediaItems[i].title}");
      }
    }

    return mediaItems;
  }
}
suragch commented 2 years ago

Thanks for all your comments. I'm still planning to update the tutorial but haven't gotten around to it.