Code Monkey home page Code Monkey logo

flutter_audio_query's Introduction

Flutter Audio Query

A Flutter plugin, Android only at this moment, that allows you query for audio metadata info about artists, albums, songs audio files and genres available on device storage. All work is made using Android native MediaStore API with ContentResolver API and query methods run in background thread. AndroidX support it's OK!

Note: This plugin is under development, Works in Android devices only and some APIs are not available yet. Feedback, pull request, bug reports and suggestions are all welcome!

Feel free to help!

Example app included

| | | |

Features

  • Android permissions READ_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE built-in
  • Get all artists audio info available on device storage
  • Get artists available from a specific genre
  • Search for artists matching a name
  • Artist comes with some album Artwork cover if available
  • Get all albums info available on device storage
  • Get albums available from a specific artist
  • Get albums available from a specific genre
  • Search albums matching a name
  • Album artwork included if available
  • Get songs all songs available on device storage
  • Get songs from a specific album
  • Songs already comes with album artwork cover if available
  • Get availables genre.
  • Get all playlists available
  • Create new playlists
  • Remove playlist
  • Add songs to playlist
  • Remove song from playlist
  • Multiple sort types for Artist, Album, Song, Genre, Playlist.

TO DO

  • Make this basic implementation for iOS.
  • Allow change playlist songs order
  • Streams support.
  • Improvements in background tasks.
  • More tests and probably bug fixes.

Usage

To use this plugin, add flutter_audio_query as a dependency in your pubspec.yaml file. For example:

  dependencies:
    flutter_audio_query: "^0.3.5+6"

API

FlutterAudioQuery

To get get audio files metadata info you just need FlutterAudioQuery object instance.

///you need include this file only.
import 'package:flutter_audio_query/flutter_audio_query.dart';
/// create a FlutterAudioQuery instance.
final FlutterAudioQuery audioQuery = FlutterAudioQuery();

Getting all artist available on device storage:

List<ArtistInfo> artists = await audioQuery.getArtists(); // returns all artists available

artists.forEach( (artist){
      print(artist); /// prints all artist property values
    } );

Getting albums data:

 /// getting all albums available on device storage
 List<AlbumInfo> albumList = await audioQuery.getAlbums();

/// getting all albums available from a specific artist
List<AlbumInfo> albums = await audioQuery.getAlbumsFromArtist(artist: artist.name);
    albums.forEach( (artistAlbum) {
      print(artistAlbum); //print all album property values
    });

Getting artwork on Android >= Q:

Since Android API level 29 ALBUM_ART constant is deprecated and plus scoped storage approach we can't load artwork from absolute image path. So if your app is running over Android API >= 29 you will get all artwork fields with null. To fetch images on these API levels you can use getArwork method.

 /// detecting, loading and displaying an artist artwork.
 
 ArtistInfo artist // assuming a non null instance

 // check if artistArtPath isn't available.

 (artist.artistArtPath == null)

    ? FutureBuilder<Uint8List>(
      future: audioQuery.getArtwork(

        type: ResourceType.ARTIST, id: artist.id),
        builder: (_, snapshot) {
          if (snapshot.data == null)
            return Container(
              height: 250.0,
              child: Center(
                child: CircularProgressIndicator(),
              ),
            );
            
            return CardItemWidget(
              height: 250.0,
              title: artist.name,
              subtitle: "Number of Albums: ${artist.numberOfAlbums}",
              infoText: "Number of Songs: ${artist.numberOfTracks}",
              // The image bytes
              // You can use Image.memory widget constructor 
              // or MemoryImage image provider class to load image from bytes
              // or a different approach.
              rawImage: snapshot.data,
            );
          }) :
          // or you can load image from File path if available.
          Image.file( File( artist.artistArtPath ) )

Getting genre data

/// getting all genres available
 List<GenreInfo> genreList = audioQuery.getGenres();

 genreList.foreach( (genre){
   /// getting all artists available from specific genre.
   await audioQuery.getArtistsFromGenre(genre: genre.name);

   /// getting all albums which appears on genre [genre].
   await audioQuery.getAlbumsFromGenre(genre: genre.name);

   /// getting all songs which appears on genre [genre]
   await audioQuery.getSongsFromGenre(genre: genre.name);
 } );

Getting songs data

/// getting all songs available on device storage
List<SongInfo> songs = await audioQuery.getSongs();

albumList.foreach( (album){
 /// getting songs from specific album
 audioQuery.getSongsFromAlbum(album: album.name);
} );

Getting playlist data

    /// getting all playlist available
    List<PlaylistInfo> playlist = await audioQuery.getPlaylists();

    /// Getting playlist songs
    List<SongInfo> songs = await audioQuery.getSongsFromPlaylist(playlist: playlist[0]);

    /// adding songs into a specific playlist
    PlaylistInfo updatedPlaylist = await playlist[0].addSong(song: songs[2] );

    //removing song from a specific playlist
    updatedPlaylist = await updatedPlaylist.removeSong(song: songs[2]);

Sorting queries

You can also define a sort query constraint to get the data already sorted using sort enums.ArtistSortType, AlbumSortType, SongSortType, GenreSortType, PlaylistSortType.

    /// Getting albums sorted by most recent year first
    audioQuery.getAlbums(sortType: AlbumSortType.MOST_RECENT_YEAR )

    /// getting artists sorted by number of songs
    audioQuery.getArtits(sortType: ArtistSortType.MORE_TRACKS_NUMBER_FIRST);
    /// and more...

Searching

You can search using search methods.

    ///searching for albums that title starts with 'a'
    List<AlbumInfo> albums = await audioQuery.searchAlbums(query "a");

    /// searching for songs that title starts with 'la'
    List<SongInfo> songs = await audioQuery.searchSongs(query: "la");

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT LICENSE

flutter_audio_query's People

Contributors

de7miii avatar sc4v3ng3r avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter_audio_query's Issues

Embedding V2

Since Flutter version 1.12 there is a new mechanism for invoking plugins for Flutter Android applications. Are there plans to make this plugin compatible with v2 embedding? Missing support could be the reason for issues in my current project which is mainly the reason I am asking.

I would love to help but I am

  1. Not a lot into the inner workings of this project and
  2. Have no clue how to properly set up this project so I can edit it with full autocompletion support.

If you could help me with 2 I can see what I can do adapting the plugin (unless you already started on it).

Crash program when I call getGeners

I get this error

E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): Failed to handle method call
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): java.lang.NullPointerException: Attempt to invoke interface method 'void io.flutter.plugin.common.MethodChannel$Result.success(java.lang.Object)' on a null object reference
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at com.ryanheise.audioservice.AudioServicePlugin.sendStartResult(AudioServicePlugin.java:143)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at com.ryanheise.audioservice.AudioServicePlugin.access$800(AudioServicePlugin.java:54)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at com.ryanheise.audioservice.AudioServicePlugin$BackgroundHandler.onMethodCall(AudioServicePlugin.java:617)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:231)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:93)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:642)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at android.os.MessageQueue.next(MessageQueue.java:376)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at android.os.Looper.loop(Looper.java:244)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at android.app.ActivityThread.main(ActivityThread.java:6706)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/MethodChannel#ryanheise.com/audioServiceBackground( 8672): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
E/DartMessenger( 8672): Uncaught exception in binary message listener
E/DartMessenger( 8672): java.lang.IllegalStateException: Reply already submitted
E/DartMessenger( 8672): 	at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:148)
E/DartMessenger( 8672): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:249)
E/DartMessenger( 8672): 	at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:93)
E/DartMessenger( 8672): 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:642)
E/DartMessenger( 8672): 	at android.os.MessageQueue.nativePollOnce(Native Method)
E/DartMessenger( 8672): 	at android.os.MessageQueue.next(MessageQueue.java:376)
E/DartMessenger( 8672): 	at android.os.Looper.loop(Looper.java:244)
E/DartMessenger( 8672): 	at android.app.ActivityThread.main(ActivityThread.java:6706)
E/DartMessenger( 8672): 	at java.lang.reflect.Method.invoke(Native Method)
E/DartMessenger( 8672): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/DartMessenger( 8672): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Error -32601 received from application: Method not found
Error -32601 received from application: Method not found
Restarted application in 1,769ms.
method not available: ext.flutter.platformOverride
Reloaded 3 of 757 libraries in 857ms.
Reloaded 3 of 757 libraries in 779ms.

οΏ½[38;5;248m════════ Exception caught by widgets library ═══════════════════════════════════�[39;49m
οΏ½[38;5;244mThe following assertion was thrown building Library(dirty, state: _LibraryState#71a6f):οΏ½[39;49m
'dart:ui/painting.dart': Failed assertion: line 188: '<optimized out>': is not true.


οΏ½[38;5;248mEither the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=BUG.md
οΏ½[39;49m

οΏ½[38;5;244mThe relevant error-causing widget wasοΏ½[39;49m
    οΏ½[38;5;248mLibraryοΏ½[39;49m
οΏ½[38;5;244mWhen the exception was thrown, this was the stackοΏ½[39;49m
οΏ½[38;5;244m#2      Color.withOpacity  (dart:ui/painting.dart:188:12)οΏ½[39;49m
οΏ½[38;5;248m#3      _LibraryState.buildοΏ½[39;49m
οΏ½[38;5;244m#4      StatefulElement.buildοΏ½[39;49m
οΏ½[38;5;244m#5      ComponentElement.performRebuildοΏ½[39;49m
οΏ½[38;5;244m#6      Element.rebuildοΏ½[39;49m
οΏ½[38;5;244m...οΏ½[39;49m
οΏ½[38;5;248m════════════════════════════════════════════════════════════════════════════════�[39;49m
Reloaded 3 of 757 libraries in 922ms.
Reloaded 3 of 757 libraries in 877ms.
Reloaded 3 of 757 libraries in 816ms.
E/AndroidRuntime( 8672): FATAL EXCEPTION: AsyncTask #40
E/AndroidRuntime( 8672): Process: com.example.musical, PID: 8672
E/AndroidRuntime( 8672): java.lang.RuntimeException: An error occurred while executing doInBackground()
E/AndroidRuntime( 8672): 	at android.os.AsyncTask$3.done(AsyncTask.java:354)
E/AndroidRuntime( 8672): 	at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
E/AndroidRuntime( 8672): 	at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
E/AndroidRuntime( 8672): 	at java.util.concurrent.FutureTask.run(FutureTask.java:271)
E/AndroidRuntime( 8672): 	at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
E/AndroidRuntime( 8672): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime( 8672): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime( 8672): 	at java.lang.Thread.run(Thread.java:764)
E/AndroidRuntime( 8672): Caused by: android.database.sqlite.SQLiteException: no such column: genre_name (code 1 SQLITE_ERROR): , while compiling: SELECT Distinct genre_name FROM audio ORDER BY genre_name ASC
E/AndroidRuntime( 8672): 	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:179)
E/AndroidRuntime( 8672): 	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
E/AndroidRuntime( 8672): 	at android.content.ContentProviderProxy.query(ContentProviderNative.java:418)
E/AndroidRuntime( 8672): 	at android.content.ContentResolver.query(ContentResolver.java:804)
E/AndroidRuntime( 8672): 	at android.content.ContentResolver.query(ContentResolver.java:753)
E/AndroidRuntime( 8672): 	at android.content.ContentResolver.query(ContentResolver.java:711)
E/AndroidRuntime( 8672): 	at boaventura.com.devel.br.flutteraudioquery.loaders.GenreLoader$GenreLoadTask.loadData(GenreLoader.java:111)
E/AndroidRuntime( 8672): 	at boaventura.com.devel.br.flutteraudioquery.loaders.GenreLoader$GenreLoadTask.loadData(GenreLoader.java:86)
E/AndroidRuntime( 8672): 	at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:45)
E/AndroidRuntime( 8672): 	at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:12)
E/AndroidRuntime( 8672): 	at android.os.AsyncTask$2.call(AsyncTask.java:333)
E/AndroidRuntime( 8672): 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/AndroidRuntime( 8672): 	... 4 more
I/Process ( 8672): Sending signal. PID: 8672 SIG: 9
Lost connection to device.
Exited (sigterm)

exception when working with Playlists on Android 10

We like this package, are you still working on it?

Anyone knows a workaround for getting playlist works on Android 10?

Please see:
https://issuetracker.google.com/issues/147619577

"has no access to content"

E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(10506): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(10506): at android.os.MessageQueue.next(MessageQueue.java:336)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(10506): at android.os.Looper.loop(Looper.java:174)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(10506): at android.app.ActivityThread.main(ActivityThread.java:7356)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(10506): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(10506): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(10506): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
E/flutter (10506): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(error, com.vsoft.dia has no access to content://media/external_primary/audio/media/29, null)
E/flutter (10506): #0 StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:569
E/flutter (10506): #1 MethodChannel._invokeMethod

Error while using getSongsByArtist() method in Android 10

Hello. I'm in Android 10 with ARM64 architecture. When I use the getSongsByArtist() method, I get the following:

E/AndroidRuntime( 1836): FATAL EXCEPTION: AsyncTask #1
E/AndroidRuntime( 1836): Process: com.pedrolemoz.music_player, PID: 1836
E/AndroidRuntime( 1836): java.lang.RuntimeException: An error occurred while executing doInBackground()
E/AndroidRuntime( 1836):        at android.os.AsyncTask$4.done(AsyncTask.java:399)
E/AndroidRuntime( 1836):        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
E/AndroidRuntime( 1836):        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
E/AndroidRuntime( 1836):        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
E/AndroidRuntime( 1836):        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
E/AndroidRuntime( 1836):        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime( 1836):        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime( 1836):        at java.lang.Thread.run(Thread.java:919)
E/AndroidRuntime( 1836): Caused by: java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: AsyncTask #1
E/AndroidRuntime( 1836):        at io.flutter.embedding.engine.FlutterJNI.ensureRunningOnMainThread(FlutterJNI.java:781)
E/AndroidRuntime( 1836):        at io.flutter.embedding.engine.FlutterJNI.invokePlatformMessageResponseCallback(FlutterJNI.java:718)
E/AndroidRuntime( 1836):        at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:144)
E/AndroidRuntime( 1836):        at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.error(MethodChannel.java:236)
E/AndroidRuntime( 1836):        at boaventura.com.devel.br.flutteraudioquery.loaders.SongLoader$SongTaskLoad.basicLoad(SongLoader.java:454)
E/AndroidRuntime( 1836):        at boaventura.com.devel.br.flutteraudioquery.loaders.SongLoader$SongTaskLoad.loadData(SongLoader.java:374)
E/AndroidRuntime( 1836):        at boaventura.com.devel.br.flutteraudioquery.loaders.SongLoader$SongTaskLoad.loadData(SongLoader.java:330)
E/AndroidRuntime( 1836):        at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:45)
E/AndroidRuntime( 1836):        at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:12)
E/AndroidRuntime( 1836):        at android.os.AsyncTask$3.call(AsyncTask.java:378)
E/AndroidRuntime( 1836):        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/AndroidRuntime( 1836):        ... 4 more
I/flutter ( 1836): Instance of 'Future<dynamic>'
I/System.out( 1836): SongLoader::basicLoad java.lang.IllegalArgumentException: the bind value at index 1 is null
I/Process ( 1836): Sending signal. PID: 1836 SIG: 9
Lost connection to device.

I wonder if any solution is avaliable.

Discord support for community.

It is difficult to ask question in GitHub. So if there is discord community for so we can help each other and learn and grow from it. Many other package authors such as audioplayers and flame etc open discord community. This step is really helpful for all type of developers from beginners to advanced level. And Thanks for making such an awesome package.

Cannot fetch genres

When trying to fetch genres i get a sqlite error
Column genre_name does not exist. Please do fix this issue.
Also any possibility of iOS support in the future.

_audioQuery.getAlbumsById(ids: [id]); not working

error -
E/AndroidRuntime(28187): Process: com.example.music_player, PID: 28187 E/AndroidRuntime(28187): java.lang.RuntimeException: An error occurred while executing doInBackground() E/AndroidRuntime(28187): at android.os.AsyncTask$3.done(AsyncTask.java:309) E/AndroidRuntime(28187): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354) E/AndroidRuntime(28187): at java.util.concurrent.FutureTask.setException(FutureTask.java:223) E/AndroidRuntime(28187): at java.util.concurrent.FutureTask.run(FutureTask.java:242) E/AndroidRuntime(28187): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) E/AndroidRuntime(28187): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) E/AndroidRuntime(28187): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) E/AndroidRuntime(28187): at java.lang.Thread.run(Thread.java:818) E/AndroidRuntime(28187): Caused by: java.lang.IllegalArgumentException: Cannot bind argument at index 1 because the index is out of range. The statement has 0 parameters. E/AndroidRuntime(28187): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165) E/AndroidRuntime(28187): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135) E/AndroidRuntime(28187): at android.content.ContentProviderProxy.query(ContentProviderNative.java:421) E/AndroidRuntime(28187): at android.content.ContentResolver.query(ContentResolver.java:502) E/AndroidRuntime(28187): at android.content.ContentResolver.query(ContentResolver.java:444) E/AndroidRuntime(28187): at boaventura.com.devel.br.flutteraudioquery.loaders.AlbumLoader$AlbumLoadTask.basicDataLoad(AlbumLoader.java:313) E/AndroidRuntime(28187): at boaventura.com.devel.br.flutteraudioquery.loaders.AlbumLoader$AlbumLoadTask.loadData(AlbumLoader.java:276) E/AndroidRuntime(28187): at boaventura.com.devel.br.flutteraudioquery.loaders.AlbumLoader$AlbumLoadTask.loadData(AlbumLoader.java:227) E/AndroidRuntime(28187): at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:45) E/AndroidRuntime(28187): at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:12) E/AndroidRuntime(28187): at android.os.AsyncTask$2.call(AsyncTask.java:295) E/AndroidRuntime(28187): at java.util.concurrent.FutureTask.run(FutureTask.java:237) E/AndroidRuntime(28187): ... 4 more I/Process (28187): Sending signal. PID: 28187 SIG: 9

App crashes when calling getAlbumsFromArtist method

As written on the title, the app crashes when the method get called. I'm using GetX state management and calling this method every time the activeArtIdx has changed.

playlist_controller.dart

class PlaylistController extends GetxController {
  static PlaylistController get to => Get.find();

  final _query = FlutterAudioQuery();
  final artists = <ArtistInfo>[].obs;
  final activeArtIdx = 0.obs;
  final albums = <AlbumInfo>[].obs;
  final activeAlbIdx = 0.obs;

  @override
  void onInit() {
    _fetchArtists();
    ever(activeArtIdx, _fetchAlbums); // call _fetchAlbums every time activeArtIdx is changed.
    super.onInit();
  }

  Future<void> _fetchArtists() async {
    final ars = await _query.getArtists(sortType: ArtistSortType.DEFAULT);
    final invalidChars = RegExp(r'.*[\\\\/:\"*<>;|].*$');
    final filtered = ars.where((ar) => !ar.name.contains(invalidChars));
    artists.assignAll(filtered);
  }

  // this crashes the app.
  Future<void> _fetchAlbums(int artIndex) async {
    final a = await _query.getAlbumsFromArtist(artist: artists[artIndex].name);
    a.forEach((alb) => print(alb));
  }
}

Stacktrace

E/AndroidRuntime( 4438): FATAL EXCEPTION: AsyncTask #1
E/AndroidRuntime( 4438): Process: com.example.mazeplayer, PID: 4438
E/AndroidRuntime( 4438): java.lang.RuntimeException: An error occurred while executing doInBackground()
E/AndroidRuntime( 4438): 	at android.os.AsyncTask$4.done(Unknown Source:27)
E/AndroidRuntime( 4438): 	at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
E/AndroidRuntime( 4438): 	at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
E/AndroidRuntime( 4438): 	at java.util.concurrent.FutureTask.run(FutureTask.java:271)
E/AndroidRuntime( 4438): 	at android.os.AsyncTask$SerialExecutor$1.run(Unknown Source:2)
E/AndroidRuntime( 4438): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime( 4438): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime( 4438): 	at java.lang.Thread.run(Thread.java:919)
E/AndroidRuntime( 4438): Caused by: android.database.sqlite.SQLiteException: near "GROUP": syntax error (code 1 SQLITE_ERROR): , while compiling: SELECT album_id, album, is_music FROM audio WHERE ((is_pending=0) AND (is_trashed=0) AND (volume_name IN ( 'external_primary' ))) AND ((artist=? and is_music=?) GROUP BY (album)) ORDER BY title_key
E/AndroidRuntime( 4438): 	at android.database.DatabaseUtils.readExceptionFromParcel(Unknown Source:15)
E/AndroidRuntime( 4438): 	at android.database.DatabaseUtils.readExceptionFromParcel(Unknown Source:11)
E/AndroidRuntime( 4438): 	at android.content.ContentProviderProxy.query(Unknown Source:77)
E/AndroidRuntime( 4438): 	at android.content.ContentResolver.query(Unknown Source:77)
E/AndroidRuntime( 4438): 	at android.content.ContentResolver.query(Unknown Source:4)
E/AndroidRuntime( 4438): 	at android.content.ContentResolver.query(Unknown Source:12)
E/AndroidRuntime( 4438): 	at boaventura.com.devel.br.flutteraudioquery.loaders.AlbumLoader$AlbumLoadTask.loadAlbumsInfoWithMediaSupport(AlbumLoader.java:380)
E/AndroidRuntime( 4438): 	at boaventura.com.devel.br.flutteraudioquery.loaders.AlbumLoader$AlbumLoadTask.loadData(AlbumLoader.java:299)
E/AndroidRuntime( 4438): 	at boaventura.com.devel.br.flutteraudioquery.loaders.AlbumLoader$AlbumLoadTask.loadData(AlbumLoader.java:227)
E/AndroidRuntime( 4438): 	at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:45)
E/AndroidRuntime( 4438): 	at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:12)
E/AndroidRuntime( 4438): 	at android.os.AsyncTask$3.call(Unknown Source:20)
E/AndroidRuntime( 4438): 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/AndroidRuntime( 4438): 	... 4 more
W/ActivityThread( 4438): SCHED: com.example.mazeplayer/.MainActivity [87, r=1593ms, a=228ms, w=23901ms]
I/Process ( 4438): Sending signal. PID: 4438 SIG: 9
Lost connection to device.
Exited (sigterm)

Health check

Device: Xiaomi Redmi Note 7 [lavender]
OS: Android 10
Dev.Machine: Microsoft Windows [Version 10.0.19042.804]

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 1.22.6, on Microsoft Windows [Version 10.0.19042.804], locale en-ID)

[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[!] Android Studio (version 4.1.0)
    X Flutter plugin not installed; this adds Flutter specific functionality.
    X Dart plugin not installed; this adds Dart specific functionality.
[√] VS Code, 64-bit edition (version 1.53.2)
[√] Connected device (1 available)

! Doctor found issues in 1 category.

Memory Issue with plugin

Running the example provided with this plugin I have monitored high memory usage.

Steps to produce issue:

  1. Run the example and run dart dev tools
  2. The songs load
  3. Now press back button (android phone back button) (note: the app is still debugging)
  4. Open app again (note: the app is still debugging)
  5. Memory keep's climbing up when viewed in dart dev tools
  6. Repeat step 3 and 4 to see major memory rise

This is a serious issue with the plugin. Please do look into this and provide a fix ASAP.

failed to cast String to bool for isMusic function in SongInfo class

I am using this version flutter_audio_query: ^0.2.1

and failed to check the SongInfo object object.isMusic due to below said error

E/flutter (23006): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type 'String' is not a subtype of type 'bool'
E/flutter (23006): #0 SongInfo.isMusic (package:flutter_audio_query/src/song_info.dart:55:23)

hope it will help to make this function mature.

await playlist[0].addSong(song: songs[2] ) ERROR on Android 10

I/flutter (18755): adding song 331 to playlist 1728
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): Failed to handle method call
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): java.lang.IllegalArgumentException: Invalid column count()
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:170)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.content.ContentProviderProxy.query(ContentProviderNative.java:423)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.content.ContentResolver.query(ContentResolver.java:951)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.content.ContentResolver.query(ContentResolver.java:887)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.content.ContentResolver.query(ContentResolver.java:843)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at boaventura.com.devel.br.flutteraudioquery.loaders.PlaylistLoader.getBase(PlaylistLoader.java:293)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at boaventura.com.devel.br.flutteraudioquery.loaders.PlaylistLoader.addSongToPlaylist(PlaylistLoader.java:195)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at boaventura.com.devel.br.flutteraudioquery.delegate.AudioQueryDelegate.handleWriteMethods(AudioQueryDelegate.java:457)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at boaventura.com.devel.br.flutteraudioquery.delegate.AudioQueryDelegate.playlistSourceHandler(AudioQueryDelegate.java:274)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at boaventura.com.devel.br.flutteraudioquery.FlutterAudioQueryPlugin.onMethodCall(FlutterAudioQueryPlugin.java:111)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:692)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.os.MessageQueue.next(MessageQueue.java:336)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.os.Looper.loop(Looper.java:197)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at android.app.ActivityThread.main(ActivityThread.java:7860)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(18755): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
E/flutter (18755): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: PlatformException(error, Invalid column count(
), null, java.lang.IllegalArgumentException: Invalid column count(*)
E/flutter (18755): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:170)
E/flutter (18755): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140)
E/flutter (18755): at android.content.ContentProviderProxy.query(ContentProviderNative.java:423)
E/flutter (18755): at android.content.ContentResolver.query(ContentResolver.java:951)
E/flutter (18755): at android.content.ContentResolver.query(ContentResolver.java:887)
E/flutter (18755): at android.content.ContentResolver.query(ContentResolver.java:843)
E/flutter (18755): at boaventura.com.devel.br.flutteraudioquery.loaders.PlaylistLoader.getBase(PlaylistLoader.java:293)
E/flutter (18755): at boaventura.com.devel.br.flutteraudioquery.loaders.PlaylistLoader.addSongToPlaylist(PlaylistLoader.java:195)
E/flutter (18755): at boaventura.com.devel.br.flutteraudioquery.delegate.AudioQueryDelegate.handleWriteMethods(AudioQueryDelegate.java:457)
E/flutter (18755): at boaventura.com.devel.br.flutteraudioquery.delegate.AudioQueryDelegate.playlistSourceHandler(AudioQueryDelegate.java:274)
E/flutter (18755): at boaventura.com.devel.br.flutteraudioquery.FlutterAudioQueryPlugin.onMethodCall(FlutterAudioQueryPlugin.java:111)
E/flutter (18755): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/flutter (18755): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/flutter (18755): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:692)
E/flutter (18755): at android.os.MessageQueue.nativePollOnce(Native Method)
E/flutter (18755): at android.os.MessageQueue.next(MessageQueue.java:336)
E/flutter (18755): at android.os.Looper.loop(Looper.java:197)
E/flutter (18755): at android.app.ActivityThread.main(ActivityThread.java:7860)
E/flutter (18755): at java.lang.reflect.Method.invoke(Native Method)
E/flutter (18755): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/flutter (18755): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
E/flutter (18755): )
E/flutter (18755): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:582:7)
E/flutter (18755): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:159:18)
E/flutter (18755):
E/flutter (18755): #2 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:332:12)
E/flutter (18755): #3 PlaylistInfo.addSong (package:flutter_audio_query/src/playlist_info.dart:30:41)
E/flutter (18755): #4 Biblioteca.addSongsToPlaylist (package:music/provider/biblioteca.dart:59:24)
E/flutter (18755):
E/flutter (18755): #5 _Page.build... (package:music/ui/play/screens/open.dart:111:54)
E/flutter (18755): #6 _rootRunUnary (dart:async/zone.dart:1198:47)
E/flutter (18755): #7 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (18755): #8 _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
E/flutter (18755): #9 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:696:45)
E/flutter (18755): #10 Future._propagateToListeners (dart:async/future_impl.dart:725:32)
E/flutter (18755): #11 Future._completeWithValue (dart:async/future_impl.dart:529:5)
E/flutter (18755): #12 Future._asyncCompleteWithValue. (dart:async/future_impl.dart:567:7)
E/flutter (18755): #13 _rootRun (dart:async/zone.dart:1190:13)
E/flutter (18755): #14 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (18755): #15 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (18755): #16 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1037:23)
E/flutter (18755): #17 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (18755): #18 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
E/flutter (18755):
W/System (18755): A resource failed to call close.

getSongs not retrieving new Songs

First, Thanks for the Plug InπŸ₯°

This plug-in was really useful for me. But now I have an issue with it.

IssueπŸ’”

I set up a download process in my application to download music files using the code below:

      file = File(path + '/$query.$fileFormat');
      var fileStream = file.openWrite();
      await stream.pipe(fileStream);

      //Flushing Stream
      await fileStream.flush();
      await fileStream.close();

The code works and I can view the file in my device explorer. However, the plugin is not adding this to the SongList.The code I used for retrieving songs is:

     this.audioQuery = FlutterAudioQuery();
     .
     .
     .
     this.songs = await audioQuery.getSongs();

I made sure to call this code after downloading and on startup of the code too. Is there any way to solve this. Your help is much appreciated.πŸ™‚
I have added relevent code here. Do let me know if you need anything more to work with. Thanks

getSongsById

crash application if memberIds contain only one song title.

Android 10 and Android 11 <unworking>

E/ERROR   (14793): SongLoader::basicLoad method exception
E/ERROR   (14793): the bind value at index 1 is null

error in the .getSongs () method to find all songs in the device on android 10 and later, probably due to depreciated API in Android API 29 and later
Annotation 2020-11-23 205222

New to this

Hello, please I'm in here fairly new to most of the concepts used in this project. All I want to build is a music player. But the example here only fetches all the files but doesn't have a play feature.
I'd appreciate if there were resources you could recommend so I can fetch all the audio files on the device. Just like in your example project.
Thanks

Song Issue

Hi there..
When I tapping on song is say:
opservice is null false

No implementation found for method getArtwork on channel boaventura.com.devel.br.flutteraudioquery

Hi,

Can you fix the unhandled exception?
The app can not be tested, basically. It freezes everything. It keeps crashing, no matter how many breakpoints I remove from vscode. Can you handle that exception, please?

My code is this:

Future getArtWork({SongInfo song}) async {
try {
return audioQuery.getArtwork(
type: ResourceType.SONG, id: song.id, size: Size(100, 100));
} catch (e) {
print("Error loading Artwork");
return null;
}
}

The error is the same as the other open issue. I am opening another issue because I would like to you this plugin and it is not working.

Probably cache issues after update

After the last flutter stable update, the album cover is not showing anymore for any song I've tried. It goes with the following error message:

I/flutter ( 2965): ══║ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
I/flutter ( 2965): The following FileSystemException was thrown resolving an image codec:
I/flutter ( 2965): Cannot open file, path =
I/flutter ( 2965): '/storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1571389004003' (OS Error:
I/flutter ( 2965): No such file or directory, errno = 2)
I/flutter ( 2965): When the exception was thrown, this was the stack:
I/flutter ( 2965): #0      _File.open.<anonymous closure> (dart:io/file_impl.dart:364:9)
I/flutter ( 2965): (elided 13 frames from package dart:async)
I/flutter ( 2965): ...
I/flutter ( 2965): Path: /storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1571389004003
I/flutter ( 2965): ════════════════════════════════════════════════════════════════════════════════════════════════════

_audioQuery.getSongsFromGenre() not working.

E/AndroidRuntime(13095): java.lang.RuntimeException: An error occurred while executing doInBackground()
E/AndroidRuntime(13095): at android.os.AsyncTask$3.done(AsyncTask.java:309)
E/AndroidRuntime(13095): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
E/AndroidRuntime(13095): at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
E/AndroidRuntime(13095): at java.util.concurrent.FutureTask.run(FutureTask.java:242)
E/AndroidRuntime(13095): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
E/AndroidRuntime(13095): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
E/AndroidRuntime(13095): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
E/AndroidRuntime(13095): at java.lang.Thread.run(Thread.java:818)
E/AndroidRuntime(13095): Caused by: android.database.sqlite.SQLiteException: no such column: genre_name (code 1): , while compiling: SELECT Distinct _id, genre_name FROM audio WHERE (genre_name =?)
E/AndroidRuntime(13095): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:179)
E/AndroidRuntime(13095): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
E/AndroidRuntime(13095): at android.content.ContentProviderProxy.query(ContentProviderNative.java:421)
E/AndroidRuntime(13095): at android.content.ContentResolver.query(ContentResolver.java:502)
E/AndroidRuntime(13095): at android.content.ContentResolver.query(ContentResolver.java:444)
E/AndroidRuntime(13095): at boaventura.com.devel.br.flutteraudioquery.loaders.SongLoader$SongTaskLoad.getSongIdsFromGenre(SongLoader.java:419)
E/AndroidRuntime(13095): at boaventura.com.devel.br.flutteraudioquery.loaders.SongLoader$SongTaskLoad.loadData(SongLoader.java:385)
E/AndroidRuntime(13095): at boaventura.com.devel.br.flutteraudioquery.loaders.SongLoader$SongTaskLoad.loadData(SongLoader.java:334)
E/AndroidRuntime(13095): at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:45)
E/AndroidRuntime(13095): at boaventura.com.devel.br.flutteraudioquery.loaders.tasks.AbstractLoadTask.doInBackground(AbstractLoadTask.java:12)
E/AndroidRuntime(13095): at android.os.AsyncTask$2.call(AsyncTask.java:295)
E/AndroidRuntime(13095): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
E/AndroidRuntime(13095): ... 4 more

Having an exception when trying to add Song to a playlist

I have looked at the other issues I made that change in PlaylistLoader getBase function
previously was failing with unrecognized column count(*)

Also noticed other weird bugs, like the activity can request permissions only once per session.

launching lib\main.dart on Android SDK built for x86 64 in debug mode...
lib\main.dart
√ Built build\app\outputs\flutter-apk\app-debug.apk.
Connecting to VM Service at ws://127.0.0.1:59923/-cWYEtA_3NU=/ws
D/EGL_emulation(17299): eglMakeCurrent: 0x779ed5d249c0: ver 2 0 (tinfo 0x779ed5eadb20)
D/eglCodecCommon(17299): setVertexArrayObject: set vao to 0 (0) 1 0
I/flutter (17299): adding song 24 to playlist 28
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): Failed to handle method call
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.database.AbstractCursor.checkPosition(AbstractCursor.java:515)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:138)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:70)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.database.CursorWrapper.getInt(CursorWrapper.java:126)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at boaventura.com.devel.br.flutteraudioquery.loaders.PlaylistLoader.getBase(PlaylistLoader.java:296)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at boaventura.com.devel.br.flutteraudioquery.loaders.PlaylistLoader.addSongToPlaylist(PlaylistLoader.java:195)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at boaventura.com.devel.br.flutteraudioquery.delegate.AudioQueryDelegate.handleWriteMethods(AudioQueryDelegate.java:457)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at boaventura.com.devel.br.flutteraudioquery.delegate.AudioQueryDelegate.playlistSourceHandler(AudioQueryDelegate.java:274)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at boaventura.com.devel.br.flutteraudioquery.FlutterAudioQueryPlugin.onMethodCall(FlutterAudioQueryPlugin.java:111)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:692)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.os.MessageQueue.next(MessageQueue.java:336)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.os.Looper.loop(Looper.java:174)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at android.app.ActivityThread.main(ActivityThread.java:7356)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/MethodChannel#boaventura.com.devel.br.flutteraudioquery(17299): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

_audioQuery.getAlbumsFromArtist return an error on android 10

error -
Caused by: android.database.sqlite.SQLiteException: near "GROUP": syntax error (code 1 SQLITE_ERROR): , while compiling: SELECT album_id, album, is_music FROM audio WHERE ((is_pending=0) AND (is_trashed=0) AND (volume_name IN ( 'external_primary' , '0f0c-181c' ))) AND ((artist=? and is_music=?) GROUP BY (album)) ORDER BY title_key

Android 10 null album art issue

Hi ,

Any active development happening in this package? I could use some help here. My audio player works file on <android9 but not in 10. I am not getting album art path , its returning null. Any solve or work around?

Thanks

Is there any way we can get selected audio files. Since audioQuery.getSongs(); gives all audio files from the device.?

List songs = await audioQuery.getSongs(); gives all the songs containing in the device. But what if when we want only selected songs from the device not all.
For example Audiobook Player app in which when user select perticular song from the device only that songs should be loaded on the screen. So my question is that there is any way that we can fetch only selected songs from the device only?

How to receive an audio file from an API and play it in flutter app?

Hi,
I'm trying to send an image to my python API from flutter app and then receive back an audio file as a response from flutter app. Then the app should be able to play it. Sending image to the API is fine. I checked API with postman also, it is sending mp3 file as output. But I don't know how to receive that mp3 file as a response in flutter app?
Can somebody help me with this please?

Thanks in advance.

How to get the file address of mp3

Use getSongs to get all the songs:

await audioQuery.getSongs()

And printed out the following data:

SongInfo({_data: /storage/emulated/0/netease/cloudmusic/Music/θŠ±γŸγ‚“ - 歌に归はγͺγ„γ‘γ‚Œγ©.mp3, album_artwork: /storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1557742806305, _display_name: θŠ±γŸγ‚“ - 歌に归はγͺγ„γ‘γ‚Œγ©.mp3, artist: θŠ±γŸγ‚“, year: 2013, album: Flower, composer: null, is_music: true, is_ringtone: false, title: 歌に归はγͺγ„γ‘γ‚Œγ©, uri: content://media/external/audio/media/26338, artist_id: 70, is_podcast: false, duration: 329953, _size: 13265380, is_alarm: false, bookmark: null, album_id: 11, is_notification: false, _id: 26338, track: 1015})

The data of _data is what I want, but it is private data. Which api should I use to get it?

No implementation found for method getArtwork on channel boaventura.com.devel.br.flutteraudioquery

Hi,

I'm getting No implementation found for method getArtwork on channel boaventura.com.devel.br.flutteraudioquery exception while trying to get the image for songs.

This happens in getArtwork().

return ListTile(
      leading: FutureBuilder(
          future: audioQuery.getArtwork(type: ResourceType.SONG, id: song.id),
          builder: (_, snapshot) {
            if (snapshot.data == null)
              return CircleAvatar(
                child: CircularProgressIndicator(),
              );
            return CircleAvatar(
              backgroundColor: Colors.transparent,
              backgroundImage: MemoryImage(
                snapshot.data,
              ),
            );
          }),

image

image

SongInfo is not comparable

Try:

Stream<List<SongInfo>> _songStream =
    Stream.fromFuture(audioQuery.getSongs());
_songStream.listen((List<SongInfo> _songList) {
  _songList.sort();
});

Error thrown in my code:

I/flutter (23594): ══║ EXCEPTION CAUGHT BY GESTURE β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
I/flutter (23594): The following assertion was thrown while handling a gesture:
I/flutter (23594): type 'SongInfo' is not a subtype of type 'Comparable<dynamic>'
I/flutter (23594): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter (23594): more information in this error message to help you determine and fix the underlying cause.
I/flutter (23594): In either case, please report this assertion by filing a bug on GitHub:
I/flutter (23594):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter (23594): When the exception was thrown, this was the stack:
I/flutter (23594): #0      ListMixin._compareAny (dart:collection/list.dart:341:31)
I/flutter (23594): #1      Sort._insertionSort (dart:_internal/sort.dart:69:36)
I/flutter (23594): #2      Sort._doSort (dart:_internal/sort.dart:58:7)
I/flutter (23594): #3      Sort.sort (dart:_internal/sort.dart:33:5)
I/flutter (23594): #4      ListMixin.sort (dart:collection/list.dart:335:10)
I/flutter (23594): #5      _PlayerState.onSet (package:stepslow/main.dart:379:15)
I/flutter (23594): #6      _PlayerState.build.<anonymous closure>.<anonymous closure> (package:stepslow/main.dart:1039:45)
I/flutter (23594): #7      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:654:14)
I/flutter (23594): #8      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:729:32)
I/flutter (23594): #9      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
I/flutter (23594): #10     TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)
I/flutter (23594): #11     TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:312:7)
I/flutter (23594): #12     GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
I/flutter (23594): #13     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:222:20)
I/flutter (23594): #14     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
I/flutter (23594): #15     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
I/flutter (23594): #16     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
I/flutter (23594): #17     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
I/flutter (23594): #21     _invoke1 (dart:ui/hooks.dart:263:10)
I/flutter (23594): #22     _dispatchPointerDataPacket (dart:ui/hooks.dart:172:5)
I/flutter (23594): (elided 3 frames from package dart:async)
I/flutter (23594): Handler: "onTap"
I/flutter (23594): Recognizer:
I/flutter (23594):   TapGestureRecognizer#e9d0d
I/flutter (23594): ════════════════════════════════════════════════════════════════════════════════════════════════════

Recommended patch:

class SongInfo implements Comparable<SongInfo> {

or maybe:

class DataModel implements Comparable<DataModel> {

instead of:

class SongInfo {

issues using the package

so when i tried to add the package in the pub.yaml i got this type of error

The plugin flutter_plugin_android_lifecycle doesn't have a main class defined in C:\Users\Ibrahim\Downloads\Compressed\flutter_windows_v1.9.1+hotfix.2-stable\flutter.pub-cache\hosted\pub.dartlang.org\flutter_plugin_android_lifecycle-1.0.7\android\src\main\java\io\flutter\plugins\flutter_plugin_android_lifecycle\FlutterAndroidLifecyclePlugin.java or C:\Users\Ibrahim\Downloads\Compressed\flutter_windows_v1.9.1+hotfix.2-stable\flutter.pub-cache\hosted\pub.dartlang.org\flutter_plugin_android_lifecycle-1.0.7\android\src\main\kotlin\io\flutter\plugins\flutter_plugin_android_lifecycle\FlutterAndroidLifecyclePlugin.kt. This is likely to due to an incorrect androidPackage: io.flutter.plugins.flutter_plugin_android_lifecycle or mainClass entry in the plugin's pubspec.yaml.
If you are the author of this plugin, fix the androidPackage entry or move the main class to any of locations used above. Otherwise, please contact the author of this plugin and consider using a different plugin in the meanwhile.
exit code 1

Infinity loading progress

I used your example and i faced a problem with loading album and artist it keep loading infinity but when i press another tab Bar everything loads, how to fix it?

The getter 'bloc' was called on null

Getting error at the time of compilation:

════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building MainScreen(dirty, state: _MainScreenState#4057c):
The getter 'bloc' was called on null.
Receiver: null
Tried calling: bloc

The relevant error-causing widget was
MainScreen
lib\main.dart:18
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 BlocProvider.of
package:flutter_audio_query_example/…/bloc/BlocProvider.dart:21
#2 _MainScreenState.build
package:flutter_audio_query_example/…/screens/MainScreen.dart:46
#3 StatefulElement.build
package:flutter/…/widgets/framework.dart:4744
#4 ComponentElement.performRebuild

any suggestion?? Please share. Thanks.

Issue Showing Some AlbumArt

Some of the Albums are not showing the Album Art, which Shows Album Art on Google Play Music or other basic music players. Please check this issue.
Anyway Good Work its a very useful package

crash audio_service when add flutter_audio_query to pubspec.yaml

Everything works fine

but when I add flutter_audio_query: "^ 0.3.4 + 1" to pubspec.yaml

and then click to stop button i get this error :

E/MethodChannel#ryanheise.com/audioServiceBackground(26360): Failed to handle method call
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): java.lang.NullPointerException: Attempt to invoke interface method 'void io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding.removeRequestPermissionsResultListener(io.flutter.plugin.common.PluginRegistry$RequestPermissionsResultListener)' on a null object reference
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at boaventura.com.devel.br.flutteraudioquery.FlutterAudioQueryPlugin.tearDown(FlutterAudioQueryPlugin.java:205)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at boaventura.com.devel.br.flutteraudioquery.FlutterAudioQueryPlugin.onDetachedFromEngine(FlutterAudioQueryPlugin.java:135)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.embedding.engine.FlutterEnginePluginRegistry.remove(FlutterEnginePluginRegistry.java:244)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.embedding.engine.FlutterEnginePluginRegistry.remove(FlutterEnginePluginRegistry.java:252)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.embedding.engine.FlutterEnginePluginRegistry.removeAll(FlutterEnginePluginRegistry.java:260)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.embedding.engine.FlutterEnginePluginRegistry.destroy(FlutterEnginePluginRegistry.java:116)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.embedding.engine.FlutterEngine.destroy(FlutterEngine.java:267)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at com.ryanheise.audioservice.AudioServicePlugin$BackgroundHandler.onMethodCall(AudioServicePlugin.java:677)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:231)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:93)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:642)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at android.os.MessageQueue.next(MessageQueue.java:376)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at android.os.Looper.loop(Looper.java:244)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at android.app.ActivityThread.main(ActivityThread.java:6706)
E/MethodChannel#ryanheise.com/audioServiceBackground(26360): 	at java.lang.reflect.Method.invoke(Native Method)


Also ryanheise/audio_service#203

This is basic code


import 'dart:async';

import 'package:flutter/material.dart';
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);



  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState() {
    super.initState();
    AudioService.connect();
  }


  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _shuffle,
        child: Icon(Icons.shuffle),
      ),
    );
  }

  _shuffle() async {
    if(! await AudioService.running){
    await AudioService.start(        // When user clicks button to start playback
      backgroundTaskEntrypoint: myBackgroundTaskEntrypoint,
      androidNotificationChannelName: 'Music Player',
      androidNotificationIcon: "mipmap/ic_launcher",
      enableQueue: true,
      androidStopForegroundOnPause: true,
      androidStopOnRemoveTask: true,
      shouldPreloadArtwork: true,
    );
  }
  await AudioService.addQueueItem(
    MediaItem(
      id: '/storage/emulated/0/Downloads/Imagine Dragons - Bad Liar.mp3',
      album: 'test',
      title: 'test',
      artUri: "${Uri.file('/storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1582602080590')}"
    )
  );
  }


}


void myBackgroundTaskEntrypoint() {
  AudioServiceBackground.run(() => CustomAudioPlayer());
}

class CustomAudioPlayer extends BackgroundAudioTask {
final _queue = <MediaItem>[];
  int _queueIndex = -1;
  AudioPlayer _audioPlayer = new AudioPlayer();
  Completer _completer = Completer();
  BasicPlaybackState _skipState;
  bool _playing;

  bool get hasNext => _queueIndex + 1 < _queue.length;

  bool get hasPrevious => _queueIndex > 0;

  MediaItem get mediaItem => _queue[_queueIndex];

  BasicPlaybackState _stateToBasicState(AudioPlaybackState state) {
    switch (state) {
      case AudioPlaybackState.none:
        return BasicPlaybackState.none;
      case AudioPlaybackState.stopped:
        return BasicPlaybackState.stopped;
      case AudioPlaybackState.paused:
        return BasicPlaybackState.paused;
      case AudioPlaybackState.playing:
        return BasicPlaybackState.playing;
      case AudioPlaybackState.connecting:
        return _skipState ?? BasicPlaybackState.connecting;
      case AudioPlaybackState.completed:
        return BasicPlaybackState.stopped;
      default:
        throw Exception("Illegal state");
    }
  }

  @override
  Future<void> onStart() async {
    var playerStateSubscription = _audioPlayer.playbackStateStream
        .where((state) => state == AudioPlaybackState.completed)
        .listen((state) {
      _handlePlaybackCompleted();
    });
    var eventSubscription = _audioPlayer.playbackEventStream.listen((event) {
      final state = _stateToBasicState(event.state);
      if (state != BasicPlaybackState.stopped) {
        _setState(
          state: state,
          position: event.position.inMilliseconds,
        );
      }
    });

    AudioServiceBackground.setQueue(_queue);
    await _completer.future;
    await playerStateSubscription.cancel();
    await eventSubscription.cancel();
  }

  void _handlePlaybackCompleted() {
    if (hasNext) {
      onSkipToNext();
    } else {
      onStop();
    }
  }

  void playPause() {
    if (AudioServiceBackground.state.basicState == BasicPlaybackState.playing)
      onPause();
    else
      onPlay();
  }

  @override
  Future<void> onSkipToNext() => _skip(1);

  @override
  Future<void> onSkipToPrevious() => _skip(-1);

  Future<void> _skip(int offset) async {
    final newPos = _queueIndex + offset;
    if (!(newPos >= 0 && newPos < _queue.length)) return;
    if (_playing == null) {
      // First time, we want to start playing
      _playing = true;
    } else if (_playing) {
      // Stop current item
      await _audioPlayer.stop();
    }
    // Load next item
    _queueIndex = newPos;
    AudioServiceBackground.setMediaItem(mediaItem);
    _skipState = offset > 0
        ? BasicPlaybackState.skippingToNext
        : BasicPlaybackState.skippingToPrevious;
    await _audioPlayer.setFilePath(mediaItem.id);
    _skipState = null;
    // Resume playback if we were playing
    if (_playing) {
      onPlay();
    } else {
      _setState(state: BasicPlaybackState.paused);
    }
  }

  @override
  void onPlay() async {
    if (_skipState == null) {
      _playing = true;
      _audioPlayer.play();
    }
  }

  @override
  void onPause() {
    if (_skipState == null) {
      _playing = false;
      _audioPlayer.pause();
    }
  }

  @override
  void onSeekTo(int position) {
    _audioPlayer.seek(Duration(milliseconds: position));
  }

  @override
  void onClick(MediaButton button) {
    playPause();
  }

  @override
  void onStop() {
    _audioPlayer.stop();
    _setState(state: BasicPlaybackState.stopped);
    _completer.complete();
  }


  
  @override
  void onAddQueueItem(MediaItem mediaItem) async {
    _queue.add(mediaItem);
    AudioServiceBackground.setQueue(_queue);
    await onSkipToNext();
  }

  void _setState({@required BasicPlaybackState state, int position}) {
    if (position == null) {
      position = _audioPlayer.playbackEvent.position.inMilliseconds;
    }
    AudioServiceBackground.setState(
      controls: getControls(state),
      systemActions: [MediaAction.seekTo],
      basicState: state,
      position: position,
    );
  }

  List<MediaControl> getControls(BasicPlaybackState state) {
    if (_playing) {
      return [
        skipToPreviousControl,
        pauseControl,
        stopControl,
        skipToNextControl
      ];
    } else {
      return [
        skipToPreviousControl,
        playControl,
        stopControl,
        skipToNextControl
      ];
    }
  }

}


MediaControl playControl = MediaControl(
  androidIcon: 'drawable/ic_action_play_arrow',
  label: 'Play',
  action: MediaAction.play,
);
MediaControl pauseControl = MediaControl(
  androidIcon: 'drawable/ic_action_pause',
  label: 'Pause',
  action: MediaAction.pause,
);
MediaControl skipToNextControl = MediaControl(
  androidIcon: 'drawable/ic_action_skip_next',
  label: 'Next',
  action: MediaAction.skipToNext,
);
MediaControl skipToPreviousControl = MediaControl(
  androidIcon: 'drawable/ic_action_skip_previous',
  label: 'Previous',
  action: MediaAction.skipToPrevious,
);
MediaControl stopControl = MediaControl(
  androidIcon: 'drawable/ic_action_stop',
  label: 'Stop',
  action: MediaAction.stop,
);



'ancestorWidgetOfExactType' is deprecated and shouldn't be used.

I am getting below error at the time of compilation:

'ancestorWidgetOfExactType' is deprecated and shouldn't be used. Use findAncestorWidgetOfExactType instead. This feature was deprecated after v1.12.1..
Try replacing the use of the deprecated member with the replacement.

this is the function which has error:

static T of(final BuildContext context) {
final type = _typeOf<BlocProvider>();
BlocProvider provider = context.ancestorWidgetOfExactType(type);
return provider.bloc;
}

I think 'ancestorWidgetOfExactType' method is not working, could you please suggest me how can we fix this issue. Look forward to hear you. Many Thanks.

Basic implementation for iOS >= 9.3

Hi,
first thank you for this package!
I needed iOS support, so I forked your project and did a basic implementation for iOS >= 9.3 in Swift, that I want to contribute.

What's working:

  • all read-only methods for all local files except for artworks (I'm working on it)
  • basic sorting (i still have to implement real alphabetical sorting)

What's not working:

  • create/change playlists (never will, these are read-only see Apple Developer Documentation )
  • some properties are not supported in iOS, like "year" or "bookmark" for songs

How would you like to handle iOS specific things like:

  • cloud items (I filtered them out, because you can't play them)
  • Podcasts (they will appear as normal songs, but I can put them in a new category, like playlists)
  • not supported properties (I just return "n/a" for the corresponding field in the map)

It's still a work in progress, needs some optimisation, but I will work on it in the next few days.
If everything works well I will create a pull request!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.