├── .gitignore ├── LICENSE.md ├── PRIVACY.md ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── ExampleInstrumentedTest.kt │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ ├── MusicRecognizerApp.kt │ │ ├── crash │ │ └── PermissionsCollector.kt │ │ ├── di │ │ ├── AndroidAppRestarter.kt │ │ ├── AppDeeplinkRouter.kt │ │ ├── GlueModule.kt │ │ └── ServiceStarter.kt │ │ └── presentation │ │ ├── AppNavigation.kt │ │ ├── AppNavigationBar.kt │ │ ├── AppNavigationRail.kt │ │ ├── MainActivity.kt │ │ ├── MainActivityViewModel.kt │ │ └── TopLevelDestination.kt │ └── res │ ├── drawable │ ├── ic_shortcut_background.xml │ └── ic_shortcut_recognize.xml │ ├── raw │ └── aboutlibraries.json │ ├── resources.properties │ ├── values-night │ └── themes.xml │ ├── values │ ├── colors.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ ├── data_extraction_rules.xml │ └── files.xml ├── build-logic ├── convention │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ ├── AndroidApplicationComposeConventionPlugin.kt │ │ ├── AndroidApplicationConventionPlugin.kt │ │ ├── AndroidFeatureConventionPlugin.kt │ │ ├── AndroidLibraryComposeConventionPlugin.kt │ │ ├── AndroidLibraryConventionPlugin.kt │ │ ├── HiltConventionPlugin.kt │ │ ├── JvmLibraryConventionPlugin.kt │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ ├── AndroidCompose.kt │ │ ├── Detekt.kt │ │ ├── KotlinAndroid.kt │ │ └── ProjectExtensions.kt ├── gradle.properties └── settings.gradle.kts ├── build.gradle.kts ├── compose_compiler_config.conf ├── core ├── audio │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── core │ │ │ └── audio │ │ │ ├── audioplayer │ │ │ ├── MediaPlayerController.kt │ │ │ ├── PlayerController.kt │ │ │ └── PlayerStatus.kt │ │ │ ├── audiorecord │ │ │ ├── AudioCaptureConfig.kt │ │ │ ├── AudioRecordDispatcher.kt │ │ │ ├── AudioRecordingControllerFactory.kt │ │ │ ├── DeviceFirstAdtsRecordingController.kt │ │ │ ├── encoder │ │ │ │ ├── AdtsRecordingController.kt │ │ │ │ └── UnsafeSilenceTracker.kt │ │ │ └── soundsource │ │ │ │ ├── DefaultSoundSource.kt │ │ │ │ ├── SoundLevelMeter.kt │ │ │ │ ├── SoundSource.kt │ │ │ │ ├── SoundSourceConfig.kt │ │ │ │ ├── SoundSourceConfigProvider.kt │ │ │ │ └── VisualizerSoundSource.kt │ │ │ └── di │ │ │ └── AudioModule.kt │ │ └── test │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── core │ │ └── audio │ │ └── audiorecord │ │ └── encoder │ │ └── UnsafeSilenceTrackerTest.kt ├── common │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── core │ │ └── common │ │ ├── BidirectionalMapper.kt │ │ ├── Containter.kt │ │ ├── DispatchersProvider.kt │ │ ├── Mapper.kt │ │ ├── di │ │ ├── CoroutineScopeModule.kt │ │ ├── DispatcherModule.kt │ │ ├── DispatchersProviderModule.kt │ │ └── UtilModule.kt │ │ └── util │ │ ├── AppDateTimeFormatter.kt │ │ ├── ContextExt.kt │ │ └── NavigationExt.kt ├── data │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── core │ │ └── data │ │ ├── ConnectivityManagerNetworkMonitor.kt │ │ ├── di │ │ └── RepositoryModule.kt │ │ ├── enqueued │ │ ├── EnqueuedRecognitionMapper.kt │ │ ├── EnqueuedRecognitionRepositoryImpl.kt │ │ ├── RecordingFileDataSource.kt │ │ └── RecordingFileDataSourceImpl.kt │ │ ├── preferences │ │ ├── PreferencesRepositoryImpl.kt │ │ ├── PreferencesToDomainMapper.kt │ │ └── PreferencesToProtoMapper.kt │ │ └── track │ │ ├── TrackMapper.kt │ │ ├── TrackPreviewMapper.kt │ │ └── TrackRepositoryImpl.kt ├── database │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── schemas │ │ └── com.mrsep.musicrecognizer.core.database.ApplicationDatabase │ │ │ ├── 1.json │ │ │ ├── 2.json │ │ │ ├── 3.json │ │ │ ├── 4.json │ │ │ ├── 5.json │ │ │ ├── 6.json │ │ │ ├── 7.json │ │ │ └── 8.json │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── core │ │ └── database │ │ ├── ApplicationDatabase.kt │ │ ├── DatabaseBackupProvider.kt │ │ ├── DatabaseUtils.kt │ │ ├── DurationRoomConverter.kt │ │ ├── FileRoomConverter.kt │ │ ├── InstantRoomConverter.kt │ │ ├── LocalDateRoomConverter.kt │ │ ├── di │ │ └── DatabaseModule.kt │ │ ├── enqueued │ │ ├── EnqueuedRecognitionDao.kt │ │ └── model │ │ │ ├── EnqueuedRecognitionEntity.kt │ │ │ ├── EnqueuedRecognitionEntityWithTrack.kt │ │ │ └── RemoteRecognitionResultType.kt │ │ ├── migration │ │ ├── AutoMigrationSpec3To4.kt │ │ ├── DatabaseMigrationUtils.kt │ │ ├── Migration5To6.kt │ │ ├── Migration6To7.kt │ │ └── Migration7To8.kt │ │ └── track │ │ ├── TrackDao.kt │ │ ├── TrackEntity.kt │ │ └── TrackPreviewTuple.kt ├── datastore │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── core │ │ │ └── datastore │ │ │ ├── DatastoreModule.kt │ │ │ ├── RequiredMusicServicesMigration.kt │ │ │ └── UserPreferencesProtoSerializer.kt │ │ └── proto │ │ ├── acr_cloud_config_proto.proto │ │ ├── audio_capture_mode_proto.proto │ │ ├── music_service_proto.proto │ │ ├── recognition_provider_proto.proto │ │ └── user_preferences_proto.proto ├── domain │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── core │ │ └── domain │ │ ├── preferences │ │ ├── FallbackPolicy.kt │ │ ├── HapticFeedback.kt │ │ ├── LyricsStyle.kt │ │ ├── PreferencesRepository.kt │ │ ├── RecognitionServiceConfig.kt │ │ ├── TrackFilter.kt │ │ └── UserPreferences.kt │ │ ├── recognition │ │ ├── AudioRecording.kt │ │ ├── AudioRecordingController.kt │ │ ├── ConfigValidator.kt │ │ ├── EnqueuedRecognitionRepository.kt │ │ ├── EnqueuedRecognitionScheduler.kt │ │ ├── NetworkMonitor.kt │ │ ├── RecognitionInteractor.kt │ │ ├── RecognitionServiceFactory.kt │ │ ├── RemoteRecognitionService.kt │ │ ├── TrackMetadataEnhancer.kt │ │ ├── TrackMetadataEnhancerScheduler.kt │ │ └── model │ │ │ ├── EnqueuedRecognition.kt │ │ │ ├── RecognitionProvider.kt │ │ │ ├── RecognitionResult.kt │ │ │ ├── RecognitionStatus.kt │ │ │ ├── RecognitionTask.kt │ │ │ ├── RecordingScheme.kt │ │ │ ├── RemoteMetadataEnhancingResult.kt │ │ │ └── RemoteRecognitionResult.kt │ │ └── track │ │ ├── TrackRepository.kt │ │ └── model │ │ ├── Lyrics.kt │ │ ├── MusicService.kt │ │ ├── SearchResult.kt │ │ ├── Track.kt │ │ ├── TrackDataField.kt │ │ └── TrackPreview.kt ├── network │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── core │ │ └── network │ │ ├── HttpFileLoggingInterceptor.kt │ │ └── NetworkModule.kt ├── recognition │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── core │ │ │ └── recognition │ │ │ └── lyrics │ │ │ └── LyricsConverterTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ └── test_sample_3500ms.ogg │ │ └── java │ │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── core │ │ │ └── recognition │ │ │ ├── ConfigValidatorImpl.kt │ │ │ ├── RecognitionServiceFactoryImpl.kt │ │ │ ├── acrcloud │ │ │ ├── AcrCloudRecognitionService.kt │ │ │ └── json │ │ │ │ ├── AcrCloudResponseJson.kt │ │ │ │ └── AcrCloudResponseJsonMapper.kt │ │ │ ├── artwork │ │ │ ├── ArtworkFetcher.kt │ │ │ ├── ArtworkFetcherImpl.kt │ │ │ └── TrackArtwork.kt │ │ │ ├── audd │ │ │ ├── AuddRecognitionService.kt │ │ │ ├── json │ │ │ │ ├── AppleMusicJson.kt │ │ │ │ ├── AuddResponseJson.kt │ │ │ │ ├── AuddResponseJsonMapper.kt │ │ │ │ ├── DeezerJson.kt │ │ │ │ ├── LyricsJson.kt │ │ │ │ ├── MusicbrainzJson.kt │ │ │ │ ├── NapsterJson.kt │ │ │ │ └── SpotifyJson.kt │ │ │ └── websocket │ │ │ │ ├── SocketEvent.kt │ │ │ │ ├── WebSocketSession.kt │ │ │ │ └── WebSocketSessionImpl.kt │ │ │ ├── di │ │ │ └── RecognitionModule.kt │ │ │ ├── enhancer │ │ │ └── odesli │ │ │ │ ├── OdesliApiProviderSerializer.kt │ │ │ │ ├── OdesliMetadataEnhancer.kt │ │ │ │ ├── OdesliResponseJson.kt │ │ │ │ └── OdesliResponseJsonMapper.kt │ │ │ └── lyrics │ │ │ ├── LrcLibResponseJson.kt │ │ │ ├── LyricsConverter.kt │ │ │ ├── LyricsFetcher.kt │ │ │ └── LyricsFetcherImpl.kt │ │ └── test │ │ ├── java │ │ ├── android │ │ │ └── util │ │ │ │ └── Log.kt │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── core │ │ │ └── recognition │ │ │ ├── AuddRecognitionServiceTest.kt │ │ │ ├── Fakes.kt │ │ │ └── WebSocketBaseFake.kt │ │ └── resources │ │ ├── audd_response_auth_error.json │ │ ├── audd_response_no_matches.json │ │ └── audd_response_success.json ├── strings │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── res │ │ ├── values-cs │ │ └── strings.xml │ │ ├── values-de │ │ └── strings.xml │ │ ├── values-es │ │ └── strings.xml │ │ ├── values-et │ │ └── strings.xml │ │ ├── values-fa │ │ └── strings.xml │ │ ├── values-fr │ │ └── strings.xml │ │ ├── values-gu │ │ └── strings.xml │ │ ├── values-it │ │ └── strings.xml │ │ ├── values-nl │ │ └── strings.xml │ │ ├── values-pl │ │ └── strings.xml │ │ ├── values-pt-rBR │ │ └── strings.xml │ │ ├── values-pt │ │ └── strings.xml │ │ ├── values-ro │ │ └── strings.xml │ │ ├── values-ru │ │ └── strings.xml │ │ ├── values-sk │ │ └── strings.xml │ │ ├── values-tr │ │ └── strings.xml │ │ ├── values-vi │ │ └── strings.xml │ │ └── values │ │ └── strings.xml └── ui │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ ├── debug │ └── res │ │ └── color │ │ └── gradient_ic_launcher_foreground.xml │ └── main │ ├── java │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── core │ │ └── ui │ │ ├── Extenstions.kt │ │ ├── components │ │ ├── DialogComponents.kt │ │ ├── LoadingStub.kt │ │ ├── MultiSelectionState.kt │ │ ├── PasswordInputField.kt │ │ ├── PermissionDialogs.kt │ │ ├── Vinyl.kt │ │ └── preferences │ │ │ ├── PreferenceClickableItem.kt │ │ │ ├── PreferenceGroup.kt │ │ │ └── PreferenceSwitchItem.kt │ │ ├── modifiers │ │ └── AnimationModifier.kt │ │ ├── theme │ │ ├── Color.kt │ │ ├── Theme.kt │ │ └── Type.kt │ │ └── util │ │ ├── ContextExt.kt │ │ ├── DimensionUtil.kt │ │ └── ForwardingPainter.kt │ └── res │ ├── color-night-v31 │ ├── surface.xml │ ├── surface_container_high.xml │ └── surface_container_highest.xml │ ├── color-v31 │ ├── surface.xml │ ├── surface_container_high.xml │ └── surface_container_highest.xml │ ├── color │ └── gradient_ic_launcher_foreground.xml │ ├── drawable │ ├── ic_amazon_24.xml │ ├── ic_anghami_24.xml │ ├── ic_apple_24.xml │ ├── ic_audiomack_24.xml │ ├── ic_audius_24.xml │ ├── ic_boomplay_24.xml │ ├── ic_deezer_24.xml │ ├── ic_launcher_background.xml │ ├── ic_launcher_foreground.xml │ ├── ic_lines_24.xml │ ├── ic_musicbrainz_24.xml │ ├── ic_napster_24.xml │ ├── ic_notification_listening.xml │ ├── ic_notification_ready.xml │ ├── ic_pandora_24.xml │ ├── ic_retro_microphone.xml │ ├── ic_soundcloud_24.xml │ ├── ic_splash.xml │ ├── ic_splash_foreground.xml │ ├── ic_spotify_24.xml │ ├── ic_tidal_24.xml │ ├── ic_yandex_music_24.xml │ ├── ic_youtube_24.xml │ ├── ic_youtube_music_24.xml │ ├── outline_album_24.xml │ ├── outline_album_fill1_24.xml │ ├── outline_arrow_back_24.xml │ ├── outline_arrow_forward_24.xml │ ├── outline_audio_file_24.xml │ ├── outline_audio_file_fill1_24.xml │ ├── outline_auto_mode_24.xml │ ├── outline_cancel_schedule_send_24.xml │ ├── outline_check_24.xml │ ├── outline_close_24.xml │ ├── outline_cloud_off_24.xml │ ├── outline_content_copy_24.xml │ ├── outline_dark_mode_24.xml │ ├── outline_dark_mode_fill1_24.xml │ ├── outline_delete_24.xml │ ├── outline_deselect_24.xml │ ├── outline_edit_24.xml │ ├── outline_error_24.xml │ ├── outline_favorite_24.xml │ ├── outline_favorite_fill1_24.xml │ ├── outline_filter_list_24.xml │ ├── outline_format_size_24.xml │ ├── outline_help_24.xml │ ├── outline_image_24.xml │ ├── outline_info_24.xml │ ├── outline_key_off_24.xml │ ├── outline_keyboard_arrow_down_24.xml │ ├── outline_keyboard_arrow_up_24.xml │ ├── outline_library_music_24.xml │ ├── outline_library_music_fill1_24.xml │ ├── outline_light_mode_24.xml │ ├── outline_light_mode_fill1_24.xml │ ├── outline_lines_48.xml │ ├── outline_lines_shift1_48.xml │ ├── outline_link_24.xml │ ├── outline_list_24.xml │ ├── outline_lyrics_24.xml │ ├── outline_more_vert_24.xml │ ├── outline_overview_24.xml │ ├── outline_overview_fill1_24.xml │ ├── outline_pause_24.xml │ ├── outline_pause_fill1_24.xml │ ├── outline_play_arrow_24.xml │ ├── outline_play_arrow_fill1_24.xml │ ├── outline_replay_24.xml │ ├── outline_schedule_send_24.xml │ ├── outline_search_24.xml │ ├── outline_select_all_24.xml │ ├── outline_send_24.xml │ ├── outline_settings_24.xml │ ├── outline_settings_fill1_24.xml │ ├── outline_share_24.xml │ ├── outline_speed_24.xml │ ├── outline_stop_fill1_24.xml │ ├── outline_travel_explore_24.xml │ ├── outline_tune_24.xml │ ├── outline_visibility_24.xml │ ├── outline_visibility_off_24.xml │ ├── rounded_bug_report_fill1_24.xml │ ├── rounded_music_note_48.xml │ ├── rounded_pause_48.xml │ ├── rounded_play_arrow_48.xml │ ├── rounded_priority_high_48.xml │ └── rounded_question_mark_48.xml │ ├── mipmap-anydpi-v26 │ └── ic_launcher.xml │ ├── values-night-v31 │ └── colors.xml │ ├── values-night-v34 │ └── colors.xml │ ├── values-night │ └── colors.xml │ ├── values-v31 │ └── colors.xml │ ├── values-v34 │ └── colors.xml │ └── values │ └── colors.xml ├── fastlane └── metadata │ └── android │ ├── cs │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt │ ├── en-US │ ├── changelogs │ │ ├── 1.txt │ │ ├── 10.txt │ │ ├── 11.txt │ │ ├── 12.txt │ │ ├── 13.txt │ │ ├── 14.txt │ │ ├── 15.txt │ │ ├── 16.txt │ │ ├── 17.txt │ │ ├── 18.txt │ │ ├── 19.txt │ │ ├── 2.txt │ │ ├── 20.txt │ │ ├── 21.txt │ │ ├── 22.txt │ │ ├── 23.txt │ │ ├── 24.txt │ │ ├── 25.txt │ │ ├── 26.txt │ │ ├── 27.txt │ │ ├── 28.txt │ │ ├── 29.txt │ │ ├── 3.txt │ │ ├── 30.txt │ │ ├── 4.txt │ │ ├── 5.txt │ │ ├── 6.txt │ │ ├── 7.txt │ │ ├── 8.txt │ │ └── 9.txt │ ├── full_description.txt │ ├── images │ │ ├── featureGraphic.png │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 00.png │ │ │ ├── 01.png │ │ │ ├── 02.png │ │ │ ├── 03.png │ │ │ ├── 04.png │ │ │ ├── 05.png │ │ │ ├── 06.png │ │ │ └── 07.png │ ├── short_description.txt │ └── title.txt │ ├── es-ES │ ├── full_description.txt │ └── short_description.txt │ ├── et │ ├── full_description.txt │ └── short_description.txt │ ├── fr │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt │ ├── it-IT │ ├── full_description.txt │ └── short_description.txt │ ├── pl-PL │ └── short_description.txt │ ├── pt-BR │ ├── full_description.txt │ └── short_description.txt │ ├── pt │ ├── full_description.txt │ └── short_description.txt │ ├── ru │ ├── changelogs │ │ ├── 1.txt │ │ ├── 10.txt │ │ ├── 11.txt │ │ ├── 12.txt │ │ ├── 13.txt │ │ ├── 14.txt │ │ ├── 15.txt │ │ ├── 16.txt │ │ ├── 17.txt │ │ ├── 18.txt │ │ ├── 19.txt │ │ ├── 2.txt │ │ ├── 20.txt │ │ ├── 21.txt │ │ ├── 22.txt │ │ ├── 23.txt │ │ ├── 24.txt │ │ ├── 25.txt │ │ ├── 26.txt │ │ ├── 27.txt │ │ ├── 28.txt │ │ ├── 29.txt │ │ ├── 3.txt │ │ ├── 30.txt │ │ ├── 4.txt │ │ ├── 5.txt │ │ ├── 6.txt │ │ ├── 7.txt │ │ ├── 8.txt │ │ └── 9.txt │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt │ ├── sk │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt │ └── tr │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt ├── feature ├── backup │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── feature │ │ └── backup │ │ ├── AppBackupManager.kt │ │ ├── AppRestartManager.kt │ │ ├── data │ │ ├── AppBackupManagerImpl.kt │ │ ├── DatabaseBackupProviderImpl.kt │ │ └── InstantJsonSerializer.kt │ │ ├── di │ │ └── BackupModule.kt │ │ └── presentation │ │ ├── BackupDialog.kt │ │ ├── ExperimentalFeaturesScreen.kt │ │ ├── ExperimentalFeaturesScreenNavigation.kt │ │ ├── ExperimentalFeaturesViewModel.kt │ │ └── RestoreDialog.kt ├── developer-mode │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── feature │ │ │ └── developermode │ │ │ └── ExampleInstrumentedTest.kt │ │ └── main │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── feature │ │ └── developermode │ │ └── presentation │ │ ├── AmplitudeVisualizer.kt │ │ ├── DeveloperScreen.kt │ │ ├── DeveloperScreenNavigation.kt │ │ ├── DeveloperScreenTopBar.kt │ │ └── DeveloperViewModel.kt ├── library │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── feature │ │ └── library │ │ └── presentation │ │ ├── library │ │ ├── DeleteSelectedDialog.kt │ │ ├── EmptyLibraryMessage.kt │ │ ├── LibraryScreen.kt │ │ ├── LibraryScreenNavigation.kt │ │ ├── LibraryScreenTopBar.kt │ │ ├── LibraryViewModel.kt │ │ ├── NoFilteredTracksMessage.kt │ │ ├── TrackFilterBottomSheet.kt │ │ ├── TrackFilterState.kt │ │ ├── TrackLazyColumn.kt │ │ ├── TrackLazyGrid.kt │ │ └── UnviewedTrackBadge.kt │ │ ├── model │ │ └── TrackUi.kt │ │ └── search │ │ ├── LibrarySearchScreen.kt │ │ ├── LibrarySearchScreenNavigation.kt │ │ ├── LibrarySearchViewModel.kt │ │ ├── SearchResultUi.kt │ │ ├── SearchScopeDropdownMenu.kt │ │ ├── SearchScreenTopBar.kt │ │ └── TrackSearchItem.kt ├── onboarding │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── feature │ │ │ └── onboarding │ │ │ └── ExampleInstrumentedTest.kt │ │ └── main │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── feature │ │ └── onboarding │ │ └── presentation │ │ ├── FinalPage.kt │ │ ├── OnboardingNavigation.kt │ │ ├── OnboardingScreen.kt │ │ ├── OnboardingViewModel.kt │ │ ├── PermissionsPage.kt │ │ ├── TokenPage.kt │ │ ├── WelcomePage.kt │ │ └── common │ │ ├── PageIndicator.kt │ │ └── PagerControls.kt ├── preferences │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── feature │ │ │ └── preferences │ │ │ └── ExampleInstrumentedTest.kt │ │ └── main │ │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── feature │ │ └── preferences │ │ ├── RecognitionServiceStarter.kt │ │ └── presentation │ │ ├── AudioSourceDialog.kt │ │ ├── FallbackPolicyDialog.kt │ │ ├── HapticFeedbackDialog.kt │ │ ├── NotificationServiceSwitch.kt │ │ ├── PreferencesNavigation.kt │ │ ├── PreferencesScreen.kt │ │ ├── PreferencesTopBar.kt │ │ ├── PreferencesViewModel.kt │ │ ├── RequiredServicesDialog.kt │ │ ├── ThemeDialog.kt │ │ ├── about │ │ ├── AboutScreen.kt │ │ ├── AboutScreenNavigation.kt │ │ ├── AboutScreenTopBar.kt │ │ ├── AppLicenseScreen.kt │ │ ├── AppLicenseScreenNavigation.kt │ │ ├── SoftwareDetailsScreen.kt │ │ ├── SoftwareDetailsScreenNavigation.kt │ │ ├── SoftwareScreen.kt │ │ └── SoftwareScreenNavigation.kt │ │ └── serviceconfig │ │ ├── AcrCloudHelpDialog.kt │ │ ├── AcrCloudPreferences.kt │ │ ├── AuddHelpDialog.kt │ │ ├── AuddPreferences.kt │ │ └── RecognitionServiceDialog.kt ├── recognition │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── mrsep │ │ │ └── musicrecognizer │ │ │ └── feature │ │ │ └── recognition │ │ │ ├── DeeplinkRouter.kt │ │ │ ├── RecognitionStatusHolders.kt │ │ │ ├── di │ │ │ ├── PlatformModule.kt │ │ │ ├── RecognitionModule.kt │ │ │ └── RecognitionStatusHolderModule.kt │ │ │ ├── domain │ │ │ └── RecognitionInteractorImpl.kt │ │ │ ├── platform │ │ │ ├── VibrationManager.kt │ │ │ └── VibrationManagerImpl.kt │ │ │ ├── presentation │ │ │ ├── model │ │ │ │ ├── EnqueuedRecognitionUi.kt │ │ │ │ ├── PlayerStatusUi.kt │ │ │ │ ├── RemoteRecognitionResultUi.kt │ │ │ │ └── TrackUi.kt │ │ │ ├── queuescreen │ │ │ │ ├── DeleteSelectedDialog.kt │ │ │ │ ├── EmptyQueueMessage.kt │ │ │ │ ├── QueueScreen.kt │ │ │ │ ├── QueueScreenNavigation.kt │ │ │ │ ├── QueueScreenTopBar.kt │ │ │ │ ├── QueueScreenViewModel.kt │ │ │ │ ├── RecognitionActionsBottomSheet.kt │ │ │ │ ├── RecognitionLazyColumn.kt │ │ │ │ ├── RecognitionLazyColumnItem.kt │ │ │ │ ├── RecognitionLazyGrid.kt │ │ │ │ ├── RecognitionLazyGridItem.kt │ │ │ │ ├── RecordingShareUtils.kt │ │ │ │ └── RenameRecognitionDialog.kt │ │ │ └── recognitionscreen │ │ │ │ ├── BasicRecognitionButton.kt │ │ │ │ ├── DebugBuildLabel.kt │ │ │ │ ├── OfflineModePopup.kt │ │ │ │ ├── RecognitionButtonWithTitle.kt │ │ │ │ ├── RecognitionNavigation.kt │ │ │ │ ├── RecognitionScreen.kt │ │ │ │ ├── RecognitionViewModel.kt │ │ │ │ ├── RippleAnimated.kt │ │ │ │ ├── WaveAnimated.kt │ │ │ │ └── shields │ │ │ │ ├── ApiUsageLimitedShield.kt │ │ │ │ ├── AuthErrorShield.kt │ │ │ │ ├── BadConnectionShield.kt │ │ │ │ ├── BaseShield.kt │ │ │ │ ├── FatalErrorShield.kt │ │ │ │ ├── NoMatchesShield.kt │ │ │ │ └── ScheduledOfflineShield.kt │ │ │ ├── scheduler │ │ │ ├── EnqueuedRecognitionSchedulerImpl.kt │ │ │ ├── EnqueuedRecognitionWorker.kt │ │ │ ├── TrackMetadataEnhancerSchedulerImpl.kt │ │ │ └── TrackMetadataEnhancerWorker.kt │ │ │ ├── service │ │ │ ├── DisableRecognitionControlServiceReceiver.kt │ │ │ ├── OneTimeRecognitionTileService.kt │ │ │ ├── RecognitionControlActivity.kt │ │ │ ├── RecognitionControlService.kt │ │ │ ├── ResultNotificationHelper.kt │ │ │ ├── ServiceNotificationHelper.kt │ │ │ ├── ServiceStartupReceiver.kt │ │ │ └── ext │ │ │ │ └── ImageUtil.kt │ │ │ └── widget │ │ │ ├── RecognitionWidget.kt │ │ │ ├── RecognitionWidgetEntryPoint.kt │ │ │ ├── RecognitionWidgetReceiver.kt │ │ │ ├── ResetWidgetStatusWorker.kt │ │ │ ├── WidgetUiState.kt │ │ │ ├── ui │ │ │ ├── AnimatedRecognitionButton.kt │ │ │ ├── ArtworkRoundedPlaceholder.kt │ │ │ ├── CircleLayoutContent.kt │ │ │ ├── HorizontalLayoutContent.kt │ │ │ ├── SquareLayoutContent.kt │ │ │ ├── StatusInfo.kt │ │ │ ├── TrackInfo.kt │ │ │ ├── VerticalLayoutContent.kt │ │ │ ├── WidgetBackground.kt │ │ │ ├── WidgetLayout.kt │ │ │ └── WidgetVerticalDivider.kt │ │ │ └── util │ │ │ ├── FontUtils.kt │ │ │ └── ImageUtils.kt │ │ └── res │ │ ├── anim │ │ ├── widget_recognition_button_scale_in.xml │ │ └── widget_recognition_button_scale_out.xml │ │ ├── color │ │ └── widget_artwork_background.xml │ │ ├── drawable-night-xxhdpi │ │ └── recognition_widget_preview.webp │ │ ├── drawable-xxhdpi │ │ └── recognition_widget_preview.webp │ │ ├── drawable │ │ ├── widget_artwork_fade_gradient.xml │ │ ├── widget_artwork_shape.xml │ │ ├── widget_background_shape.xml │ │ ├── widget_circle_background_shape.xml │ │ └── widget_recognition_button_shape.xml │ │ ├── layout-v31 │ │ └── recognition_widget_preview.xml │ │ ├── layout │ │ ├── recognition_widget_loading.xml │ │ └── widget_flipper_container.xml │ │ ├── values-v31 │ │ └── dimens.xml │ │ ├── values-v33 │ │ └── styles.xml │ │ ├── values │ │ └── dimens.xml │ │ └── xml │ │ ├── recognition_widget_info.xml │ │ └── recognition_widget_samsung_info.xml └── track │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mrsep │ │ └── musicrecognizer │ │ └── feature │ │ └── track │ │ └── ExampleInstrumentedTest.kt │ └── main │ └── java │ └── com │ └── mrsep │ └── musicrecognizer │ └── feature │ └── track │ └── presentation │ ├── lyrics │ ├── AutoScrollToolbar.kt │ ├── FontSizeSwitcher.kt │ ├── LyricsPlayer.kt │ ├── LyricsScreen.kt │ ├── LyricsScreenNavigation.kt │ ├── LyricsScreenTopBar.kt │ ├── LyricsStyleBottomSheet.kt │ ├── LyricsViewModel.kt │ ├── PlainLyricsContent.kt │ └── SyncedLyricsContent.kt │ ├── track │ ├── AlbumArtwork.kt │ ├── AlbumArtworkShield.kt │ ├── FadeModifiers.kt │ ├── MusicServiceChipsFlowRow.kt │ ├── ShareBottomSheet.kt │ ├── TrackActionsBottomBar.kt │ ├── TrackExtrasDialog.kt │ ├── TrackInfoColumn.kt │ ├── TrackNotFoundMessage.kt │ ├── TrackScreen.kt │ ├── TrackScreenNavigation.kt │ ├── TrackScreenTopBar.kt │ ├── TrackSection.kt │ ├── TrackUi.kt │ ├── TrackViewModel.kt │ └── WebSearchBottomSheet.kt │ └── utils │ ├── ColorUtils.kt │ └── ImageShareUtils.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── get-it-on-f-droid.png └── get-it-on-github.png └── settings.gradle.kts /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # With R8 full mode generic signatures are stripped for classes that are not kept. 24 | # Suspend functions are wrapped in continuations where the type argument is used. 25 | -keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation -------------------------------------------------------------------------------- /app/src/androidTest/java/com/mrsep/musicrecognizer/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.mrsep.musicrecognizer 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.mrsep.musicrecognizer", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mrsep/musicrecognizer/di/AndroidAppRestarter.kt: -------------------------------------------------------------------------------- 1 | package com.mrsep.musicrecognizer.di 2 | 3 | import android.content.Context 4 | import com.mrsep.musicrecognizer.feature.backup.AppRestartManager 5 | import com.mrsep.musicrecognizer.presentation.MainActivity.Companion.restartApplicationOnRestore 6 | import dagger.hilt.android.qualifiers.ApplicationContext 7 | import javax.inject.Inject 8 | 9 | class AndroidAppRestarter @Inject constructor( 10 | @ApplicationContext private val appContext: Context, 11 | ): AppRestartManager { 12 | 13 | override fun restartApplicationOnRestore() { 14 | appContext.restartApplicationOnRestore() 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mrsep/musicrecognizer/di/GlueModule.kt: -------------------------------------------------------------------------------- 1 | package com.mrsep.musicrecognizer.di 2 | 3 | import com.mrsep.musicrecognizer.feature.backup.AppRestartManager 4 | import com.mrsep.musicrecognizer.feature.preferences.RecognitionServiceStarter 5 | import com.mrsep.musicrecognizer.feature.recognition.DeeplinkRouter 6 | import dagger.Binds 7 | import dagger.Module 8 | import dagger.hilt.InstallIn 9 | import dagger.hilt.components.SingletonComponent 10 | 11 | @Suppress("unused") 12 | @Module 13 | @InstallIn(SingletonComponent::class) 14 | interface GlueModule { 15 | 16 | @Binds 17 | fun bindAppRestartManager(impl: AndroidAppRestarter): AppRestartManager 18 | 19 | @Binds 20 | fun bindDeeplinkRouter(impl: AppDeeplinkRouter): DeeplinkRouter 21 | 22 | @Binds 23 | fun bindRecognitionServiceStarter(impl: ServiceStarter): RecognitionServiceStarter 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mrsep/musicrecognizer/di/ServiceStarter.kt: -------------------------------------------------------------------------------- 1 | package com.mrsep.musicrecognizer.di 2 | 3 | import android.content.Context 4 | import com.mrsep.musicrecognizer.feature.preferences.RecognitionServiceStarter 5 | import com.mrsep.musicrecognizer.feature.recognition.service.RecognitionControlService 6 | import dagger.hilt.android.qualifiers.ApplicationContext 7 | import javax.inject.Inject 8 | 9 | class ServiceStarter @Inject constructor( 10 | @ApplicationContext private val appContext: Context, 11 | ) : RecognitionServiceStarter { 12 | 13 | override fun startServiceHoldMode() { 14 | RecognitionControlService.startHoldMode(appContext, false) 15 | } 16 | 17 | override fun stopServiceHoldMode() { 18 | RecognitionControlService.stopHoldMode(appContext) 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_shortcut_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_shortcut_recognize.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/resources.properties: -------------------------------------------------------------------------------- 1 | unqualifiedResLocale=en-US 2 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 12 | 13 | 8 | -------------------------------------------------------------------------------- /feature/recognition/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.15 4 | 16dp 5 | 12dp 6 | -------------------------------------------------------------------------------- /feature/recognition/src/main/res/xml/recognition_widget_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | -------------------------------------------------------------------------------- /feature/recognition/src/main/res/xml/recognition_widget_samsung_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /feature/track/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /feature/track/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.musicrecognizer.android.feature) 3 | alias(libs.plugins.musicrecognizer.android.library.compose) 4 | } 5 | 6 | android { 7 | namespace = "com.mrsep.musicrecognizer.feature.track" 8 | } 9 | 10 | dependencies { 11 | implementation(projects.core.domain) 12 | 13 | implementation(libs.androidx.palette) 14 | implementation(libs.coil.compose) 15 | implementation(libs.materialKolor) 16 | implementation(libs.zoomable) 17 | } -------------------------------------------------------------------------------- /feature/track/src/androidTest/java/com/mrsep/musicrecognizer/feature/track/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.mrsep.musicrecognizer.feature.track 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.mrsep.musicrecognizer.feature.track.test", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleksey-saenko/MusicRecognizer/ddf4ebf34c27d4e9ad21bff794811cf9ff214602/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jan 19 23:46:53 MSK 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /img/get-it-on-f-droid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleksey-saenko/MusicRecognizer/ddf4ebf34c27d4e9ad21bff794811cf9ff214602/img/get-it-on-f-droid.png -------------------------------------------------------------------------------- /img/get-it-on-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleksey-saenko/MusicRecognizer/ddf4ebf34c27d4e9ad21bff794811cf9ff214602/img/get-it-on-github.png -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | pluginManagement { 4 | includeBuild("build-logic") 5 | repositories { 6 | google() 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | dependencyResolutionManagement { 12 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | rootProject.name = "MusicRecognizer" 19 | include(":app") 20 | include(":core:database") 21 | include(":core:datastore") 22 | include(":core:network") 23 | include(":core:data") 24 | include(":core:audio") 25 | include(":core:recognition") 26 | include(":core:domain") 27 | include(":core:strings") 28 | include(":core:ui") 29 | include(":core:common") 30 | include(":feature:recognition") 31 | include(":feature:track") 32 | include(":feature:library") 33 | include(":feature:preferences") 34 | include(":feature:backup") 35 | include(":feature:onboarding") 36 | include(":feature:developer-mode") --------------------------------------------------------------------------------