Compare commits

..

10 Commits

Author SHA1 Message Date
neonItem
f611e719db
Merge 729bdd43b9 into 4ed40d95b2 2025-09-09 22:29:19 +05:30
Kingkor Roy Tirtho
4ed40d95b2 chore: remove print 2025-09-09 21:18:54 +06:00
Kingkor Roy Tirtho
b24dcd2951 chore: show loading indicator for alternative sourced track 2025-09-09 21:18:10 +06:00
Kingkor Roy Tirtho
8ff90bafd7 chore: fix not alternative source not working 2025-09-09 21:09:45 +06:00
Kingkor Roy Tirtho
9190af92ef chore: fix shuffling not working 2025-09-09 20:54:22 +06:00
Kingkor Roy Tirtho
151a440e7e chore: bump version to v5 and generate changelogs 2025-09-09 00:51:09 +06:00
Kingkor Roy Tirtho
9471e008e3 fix(ui): lyrics white text in white background and small player buttons 2025-09-09 00:45:45 +06:00
Kingkor Roy Tirtho
ecc0bdcc42 chore: slate color by default 2025-09-09 00:13:43 +06:00
Kingkor Roy Tirtho
49c04af302 chore: add translation attribute for conventional-commit 2025-09-08 23:47:55 +06:00
Kingkor Roy Tirtho
afe0bea306 docs: add updated screenshots 2025-09-08 22:50:06 +06:00
51 changed files with 1447 additions and 211 deletions

View File

@ -1,5 +1,68 @@
# Changelog # Changelog
## [5.0.0](https://github.com/KRTirtho/spotube/compare/v4.0.2...v5.0.0) (2025-09-08)
### Features
- Add ISRC track search for YouTube ([#2594](https://github.com/KRTirtho/spotube/issues/2594))
- Add new icons #2676 by @alexio-dev ([#2678](https://github.com/KRTirtho/spotube/issues/2678))
- Add connect confirmation dialog
- Add metadata api service and models
- **metadata-plugin**: Add pagination support, feed and playlist CRUD endpoints
- **metadata-plugin**: Add local storage api
- Add webview, totp and setInterval apis for plugins
- Enhance local storage and webview APIs with improved error handling and resource management
- **metadata_plugin**: Add logout method
- Update plugin configuration with more fields
- Implement metadata plugins based on hetu
- Update models to match hetu_spotube_plugin signature
- Add user endpoint calls in metadata and paginated async notifiers
- Add playlist endpoint and providers
- Add albums metadata endpoint and provider
- Add artist and album providers
- Add track endpoint for metadata service
- Remove green corp names formally
- **metadata**: Add plugin form
- Add support for entity specific search
- Enhance image handling
- Add support for automatic plugin repository from github and codeberg
- Use isolate for youtube_explode engine
- Add repository and plugin API version fields to metadata plugins
- Update new pipe version
- **metadata**: Add plugin update checker and dialog for available updates
- Optimize track options and related artists
- Add plugin scrobbling support and support button
- Add ErrorBox and NoDefaultMetadataPlugin components
### Bug Fixes
- Calling /track/:streamId endpoint causes active sourced track to be anything
- **mobile**: Dialogs in bottom sheet are not opening
- Default accent color is orange but it shows blue in settings
- Artist images are not loading up
- CVE: Remote path traversal through websocket when devices are on same network
- Endless playback not working
- **android**: NewPipe invalid search content filters
- Make YoutubeExplode engine faster
- Create and delete playlist not working
- Local track not working and images of local not showing up
- Local playback not working for tracks with special # (hashtag) characters
- Inaccessible streaming url causing rapid skips
- **yt**: Fallback to different search result if all streaming url is inaccessible
- **playback**: Skip network requests if cached file already exists
- Yt-dlp playback not working and add partial support for HLS streaming
- Windows webview2 environment permission issue
- **playback**: Play not fetching full playlist if playlist is too long
- **track_options**: Tapping on option doesn't close the menu
- **playback**: Alternative track sources switch not working
- **ui**: Lyrics white text in white background and small player buttons
### Translation
- Add Traditional Chinese translation ([#2762](https://github.com/KRTirtho/spotube/issues/2762))
- Fix Japanese translations ([#2732](https://github.com/KRTirtho/spotube/issues/2732))
- Correction of the dutch language ([#1306](https://github.com/KRTirtho/spotube/issues/1306))
## [4.0.2](https://github.com/krtirtho/spotube/compare/v4.0.1...v4.0.2) (2025-03-16) ## [4.0.2](https://github.com/krtirtho/spotube/compare/v4.0.1...v4.0.2) (2025-03-16)
### Bug Fixes ### Bug Fixes

View File

@ -18,6 +18,10 @@ Btw it's not just another Electron app 😉
--- ---
![Spotube Desktop](assets/branding/spotube-screenshot.png)
![Spotube Mobile](assets/branding/mobile-screenshots/combined.jpg)
</div> </div>
## 🌃 Features ## 🌃 Features

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1006 KiB

After

Width:  |  Height:  |  Size: 771 KiB

View File

@ -61,7 +61,7 @@ protect_breaking_commits = false
commit_parsers = [ commit_parsers = [
{ message = "^feat", group = "<!-- 0 -->Features" }, { message = "^feat", group = "<!-- 0 -->Features" },
{ message = "^fix", group = "<!-- 1 -->Bug Fixes" }, { message = "^fix", group = "<!-- 1 -->Bug Fixes" },
# { message = "^doc", group = "<!-- 3 -->📚 Documentation" }, { message = "^translation", group = "<!-- 3 --> Translation" },
# { message = "^perf", group = "<!-- 4 -->⚡ Performance" }, # { message = "^perf", group = "<!-- 4 -->⚡ Performance" },
# { message = "^refactor", group = "<!-- 2 -->🚜 Refactor" }, # { message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
# { message = "^style", group = "<!-- 5 -->🎨 Styling" }, # { message = "^style", group = "<!-- 5 -->🎨 Styling" },

File diff suppressed because one or more lines are too long

View File

@ -13,7 +13,7 @@ class BackButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return IconButton.ghost( return IconButton.ghost(
size: const ButtonSize(.9), size: const ButtonSize(1.2),
icon: Icon(icon, color: color), icon: Icon(icon, color: color),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
); );

View File

@ -287,7 +287,7 @@
"genres": "Genres", "genres": "Genres",
"explore_genres": "Genres verkennen", "explore_genres": "Genres verkennen",
"friends": "Vrienden", "friends": "Vrienden",
"no_lyrics_available": "Sorry, geen teksten gevonden voor dit nummer" "no_lyrics_available": "Sorry, geen teksten gevonden voor dit nummer",
"start_a_radio": "Een radio starten", "start_a_radio": "Een radio starten",
"how_to_start_radio": "Hoe wil je de radio starten?", "how_to_start_radio": "Hoe wil je de radio starten?",
"replace_queue_question": "Wil je de huidige wachtrij vervangen of eraan toevoegen?", "replace_queue_question": "Wil je de huidige wachtrij vervangen of eraan toevoegen?",

View File

@ -39,7 +39,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get featured => 'Aanbevolen'; String get featured => 'Aanbevolen';
@override @override
String get new_releases => 'Nieuwe uitgaves'; String get new_releases => 'Nieuwe uitgaven';
@override @override
String get songs => 'Liedjes'; String get songs => 'Liedjes';
@ -139,7 +139,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get sort_album => 'Sorteren op album'; String get sort_album => 'Sorteren op album';
@override @override
String get sort_duration => 'Sorteer op Duur'; String get sort_duration => 'Sorteren op lengte';
@override @override
String get sort_tracks => 'Nummers sorteren'; String get sort_tracks => 'Nummers sorteren';
@ -150,7 +150,7 @@ class AppLocalizationsNl extends AppLocalizations {
} }
@override @override
String get cancel_all => 'Alle annuleren'; String get cancel_all => 'Alles annuleren';
@override @override
String get filter_artist => 'Artiesten filteren…'; String get filter_artist => 'Artiesten filteren…';
@ -164,10 +164,10 @@ class AppLocalizationsNl extends AppLocalizations {
String get add_artist_to_blacklist => 'Artiest toevoegen aan zwarte lijst'; String get add_artist_to_blacklist => 'Artiest toevoegen aan zwarte lijst';
@override @override
String get top_tracks => 'Topsporen'; String get top_tracks => 'Topnummers';
@override @override
String get fans_also_like => 'Liefhebbers willen ook'; String get fans_also_like => 'Fans luisteren ook';
@override @override
String get loading => 'Laden…'; String get loading => 'Laden…';
@ -312,10 +312,10 @@ class AppLocalizationsNl extends AppLocalizations {
String get slide_to_seek => 'Schuiven om vooruit of achteruit te zoeken'; String get slide_to_seek => 'Schuiven om vooruit of achteruit te zoeken';
@override @override
String get shuffle_playlist => 'Afspeellijst schuifelen'; String get shuffle_playlist => 'Afspeellijst willekeurig';
@override @override
String get unshuffle_playlist => 'Afspeellijst onschuifelen'; String get unshuffle_playlist => 'Afspeellijst op volgorde';
@override @override
String get previous_track => 'Vorige nummer'; String get previous_track => 'Vorige nummer';
@ -342,7 +342,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get queue => 'Wachtrij'; String get queue => 'Wachtrij';
@override @override
String get alternative_track_sources => 'Alternatieve nummerbronnen'; String get alternative_track_sources => 'Alternatieve bronnen voor nummers';
@override @override
String get download_track => 'Nummer downloaden'; String get download_track => 'Nummer downloaden';
@ -776,10 +776,10 @@ class AppLocalizationsNl extends AppLocalizations {
String get stop => 'Stoppen'; String get stop => 'Stoppen';
@override @override
String get sort_newest => 'Sorteren op nieuwste toegevoegd'; String get sort_newest => 'Sorteren op recent toegevoegd';
@override @override
String get sort_oldest => 'Sorteren op oudste toegevoegd'; String get sort_oldest => 'Sorteren op langst toegevoegd';
@override @override
String get sleep_timer => 'Slaaptimer'; String get sleep_timer => 'Slaaptimer';
@ -815,7 +815,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get search_mode => 'Zoekmodus'; String get search_mode => 'Zoekmodus';
@override @override
String get audio_source => 'Audiobron'; String get audio_source => 'Audio Source';
@override @override
String get ok => 'Oké'; String get ok => 'Oké';
@ -927,57 +927,56 @@ class AppLocalizationsNl extends AppLocalizations {
'Sorry, geen teksten gevonden voor dit nummer'; 'Sorry, geen teksten gevonden voor dit nummer';
@override @override
String get start_a_radio => 'Start een Radio'; String get start_a_radio => 'Een radio starten';
@override @override
String get how_to_start_radio => 'Hoe wilt u de radio starten?'; String get how_to_start_radio => 'Hoe wil je de radio starten?';
@override @override
String get replace_queue_question => String get replace_queue_question =>
'Wilt u de huidige wachtrij vervangen of eraan toevoegen?'; 'Wil je de huidige wachtrij vervangen of eraan toevoegen?';
@override @override
String get endless_playback => 'Eindeloze Afspelen'; String get endless_playback => 'Oneindig afspelen';
@override @override
String get delete_playlist => 'Verwijder Afspeellijst'; String get delete_playlist => 'Afspeellijst verwijderen';
@override @override
String get delete_playlist_confirmation => String get delete_playlist_confirmation =>
'Weet u zeker dat u deze afspeellijst wilt verwijderen?'; 'Weet je zeker dat je deze afspeellijst wilt verwijderen?';
@override @override
String get local_tracks => 'Lokale Nummers'; String get local_tracks => 'Lokale nummers';
@override @override
String get local_tab => 'Lokaal'; String get local_tab => 'Lokaal';
@override @override
String get song_link => 'Nummer Link'; String get song_link => 'Song-link';
@override @override
String get skip_this_nonsense => 'Sla deze onzin over'; String get skip_this_nonsense => 'Deze onzin overslaan';
@override @override
String get freedom_of_music => '“Vrijheid van Muziek”'; String get freedom_of_music => '“Vrijheid van muziek”';
@override @override
String get freedom_of_music_palm => String get freedom_of_music_palm => '“Vrijheid van muziek in je hand”';
'“Vrijheid van Muziek in de palm van je hand”';
@override @override
String get get_started => 'Laten we beginnen'; String get get_started => 'Laten we beginnen';
@override @override
String get youtube_source_description => 'Aanbevolen en werkt het beste.'; String get youtube_source_description => 'Aangeraden en werkt het best.';
@override @override
String get piped_source_description => String get piped_source_description =>
'Voel je vrij? Hetzelfde als YouTube maar veel gratis.'; 'Voel je je vrij? Net als YouTube, maar meer vrij.';
@override @override
String get jiosaavn_source_description => String get jiosaavn_source_description =>
'Het beste voor de Zuid-Aziatische regio.'; 'Het beste voor de regio Zuid-Azië.';
@override @override
String get invidious_source_description => String get invidious_source_description =>
@ -985,41 +984,41 @@ class AppLocalizationsNl extends AppLocalizations {
@override @override
String highest_quality(Object quality) { String highest_quality(Object quality) {
return 'Hoogste Kwaliteit: $quality'; return 'Hoogste kwaliteit: $quality';
} }
@override @override
String get select_audio_source => 'Selecteer Audiobron'; String get select_audio_source => 'Audiobron kiezen';
@override @override
String get endless_playback_description => String get endless_playback_description =>
'Voeg automatisch nieuwe nummers toe aan het einde van de wachtrij'; 'Nieuwe nummers automatisch achteraan de wachtrij toevoegen';
@override @override
String get choose_your_region => 'Kies uw regio'; String get choose_your_region => 'Kies je regio';
@override @override
String get choose_your_region_description => String get choose_your_region_description =>
'Dit zal Spotube helpen om de juiste inhoud voor uw locatie te tonen.'; 'Dit helpt Spotube om de juiste inhoud\nvoor jouw locatie te tonen.';
@override @override
String get choose_your_language => 'Kies uw taal'; String get choose_your_language => 'Kies je taal';
@override @override
String get help_project_grow => 'Help dit project groeien'; String get help_project_grow => 'Help dit project met groeien';
@override @override
String get help_project_grow_description => String get help_project_grow_description =>
'Spotube is een open-source project. U kunt dit project helpen groeien door bij te dragen aan het project, bugs te melden of nieuwe functies voor te stellen.'; 'Spotube is een open-source project. Je kunt dit project helpen groeien door eraan bij te dragen, problemen te melden of nieuwe functies voor te stellen.';
@override @override
String get contribute_on_github => 'Bijdragen op GitHub'; String get contribute_on_github => 'Bijdragen on GitHub';
@override @override
String get donate_on_open_collective => 'Doneren op Open Collective'; String get donate_on_open_collective => 'Doneren on Open Collective';
@override @override
String get browse_anonymously => 'Anoniem Bladeren'; String get browse_anonymously => 'Anoniem browsen';
@override @override
String get enable_connect => 'Verbinding inschakelen'; String get enable_connect => 'Verbinding inschakelen';

View File

@ -217,7 +217,7 @@ class Spotube extends HookConsumerWidget {
iconTheme: const IconThemeProperties(), iconTheme: const IconThemeProperties(),
colorScheme: colorScheme:
colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.light) ?? colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.light) ??
LegacyColorSchemes.lightOrange(), LegacyColorSchemes.lightSlate(),
surfaceOpacity: .8, surfaceOpacity: .8,
surfaceBlur: 10, surfaceBlur: 10,
), ),
@ -226,7 +226,7 @@ class Spotube extends HookConsumerWidget {
iconTheme: const IconThemeProperties(), iconTheme: const IconThemeProperties(),
colorScheme: colorScheme:
colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.dark) ?? colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.dark) ??
LegacyColorSchemes.darkOrange(), LegacyColorSchemes.darkSlate(),
surfaceOpacity: .8, surfaceOpacity: .8,
surfaceBlur: 10, surfaceBlur: 10,
), ),

View File

@ -102,7 +102,7 @@ class AppDatabase extends _$AppDatabase {
); );
await customStatement( await customStatement(
"ALTER TABLE $tableName " "ALTER TABLE $tableName "
"ADD COLUMN $columnName TEXT NOT NULL DEFAULT 'Orange:0xFFf97315'", "ADD COLUMN $columnName TEXT NOT NULL DEFAULT 'Slate:0xff64748b'",
); );
await customStatement( await customStatement(
"UPDATE $tableName " "UPDATE $tableName "
@ -114,7 +114,7 @@ class AppDatabase extends _$AppDatabase {
); );
await customStatement( await customStatement(
"UPDATE $tableName " "UPDATE $tableName "
"SET $columnName = 'Orange:0xFFf97315' WHERE $columnName = 'Blue:0xFF2196F3'", "SET $columnName = 'Slate:0xff64748b' WHERE $columnName = 'Blue:0xFF2196F3'",
); );
}, },
from5To6: (m, schema) async { from5To6: (m, schema) async {

View File

@ -666,7 +666,7 @@ class $PreferencesTableTable extends PreferencesTable
'accent_color_scheme', aliasedName, false, 'accent_color_scheme', aliasedName, false,
type: DriftSqlType.string, type: DriftSqlType.string,
requiredDuringInsert: false, requiredDuringInsert: false,
defaultValue: const Constant("Orange:0xFFf97315")) defaultValue: const Constant("Slate:0xff64748b"))
.withConverter<SpotubeColor>( .withConverter<SpotubeColor>(
$PreferencesTableTable.$converteraccentColorScheme); $PreferencesTableTable.$converteraccentColorScheme);
static const VerificationMeta _layoutModeMeta = static const VerificationMeta _layoutModeMeta =

View File

@ -1407,7 +1407,7 @@ final class Schema5 extends i0.VersionedSchema {
i1.GeneratedColumn<String> _column_55(String aliasedName) => i1.GeneratedColumn<String> _column_55(String aliasedName) =>
i1.GeneratedColumn<String>('accent_color_scheme', aliasedName, false, i1.GeneratedColumn<String>('accent_color_scheme', aliasedName, false,
type: i1.DriftSqlType.string, type: i1.DriftSqlType.string,
defaultValue: const Constant("Orange:0xFFf97315")); defaultValue: const Constant("Slate:0xff64748b"));
final class Schema6 extends i0.VersionedSchema { final class Schema6 extends i0.VersionedSchema {
Schema6({required super.database}) : super(version: 6); Schema6({required super.database}) : super(version: 6);

View File

@ -79,7 +79,7 @@ class PreferencesTable extends Table {
TextColumn get closeBehavior => textEnum<CloseBehavior>() TextColumn get closeBehavior => textEnum<CloseBehavior>()
.withDefault(Constant(CloseBehavior.close.name))(); .withDefault(Constant(CloseBehavior.close.name))();
TextColumn get accentColorScheme => text() TextColumn get accentColorScheme => text()
.withDefault(const Constant("Orange:0xFFf97315")) .withDefault(const Constant("Slate:0xff64748b"))
.map(const SpotubeColorConverter())(); .map(const SpotubeColorConverter())();
TextColumn get layoutMode => TextColumn get layoutMode =>
textEnum<LayoutMode>().withDefault(Constant(LayoutMode.adaptive.name))(); textEnum<LayoutMode>().withDefault(Constant(LayoutMode.adaptive.name))();
@ -131,7 +131,7 @@ class PreferencesTable extends Table {
systemTitleBar: false, systemTitleBar: false,
skipNonMusic: false, skipNonMusic: false,
closeBehavior: CloseBehavior.close, closeBehavior: CloseBehavior.close,
accentColorScheme: SpotubeColor(Colors.orange.value, name: "Orange"), accentColorScheme: SpotubeColor(Colors.slate.value, name: "Slate"),
layoutMode: LayoutMode.adaptive, layoutMode: LayoutMode.adaptive,
locale: const Locale("system", "system"), locale: const Locale("system", "system"),
market: Market.US, market: Market.US,

View File

@ -21,7 +21,6 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/context.dart';
import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/metadata_plugin/core/auth.dart';
import 'package:spotube/provider/server/active_track_sources.dart'; import 'package:spotube/provider/server/active_track_sources.dart';
import 'package:spotube/provider/volume_provider.dart'; import 'package:spotube/provider/volume_provider.dart';
import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/services/sourced_track/sources/youtube.dart';
@ -40,7 +39,6 @@ class PlayerView extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context); final theme = Theme.of(context);
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
final sourcedCurrentTrack = ref.watch(activeTrackSourcesProvider); final sourcedCurrentTrack = ref.watch(activeTrackSourcesProvider);
final currentActiveTrack = final currentActiveTrack =
ref.watch(audioPlayerProvider.select((s) => s.activeTrack)); ref.watch(audioPlayerProvider.select((s) => s.activeTrack));
@ -105,13 +103,15 @@ class PlayerView extends HookConsumerWidget {
surfaceBlur: 0, surfaceBlur: 0,
leading: [ leading: [
IconButton.ghost( IconButton.ghost(
icon: const Icon(SpotubeIcons.angleDown, size: 18), size: const ButtonSize(1.2),
icon: const Icon(SpotubeIcons.angleDown),
onPressed: panelController.close, onPressed: panelController.close,
) )
], ],
trailing: [ trailing: [
if (currentActiveTrackSource is YoutubeSourcedTrack) if (currentActiveTrackSource is YoutubeSourcedTrack)
TextButton( TextButton(
size: const ButtonSize(1.2),
leading: Assets.images.logos.songlinkTransparent.image( leading: Assets.images.logos.songlinkTransparent.image(
width: 20, width: 20,
height: 20, height: 20,
@ -131,7 +131,8 @@ class PlayerView extends HookConsumerWidget {
child: Text(context.l10n.details), child: Text(context.l10n.details),
).call, ).call,
child: IconButton.ghost( child: IconButton.ghost(
icon: const Icon(SpotubeIcons.info, size: 18), size: const ButtonSize(1.2),
icon: const Icon(SpotubeIcons.info),
onPressed: currentActiveTrackSource == null onPressed: currentActiveTrackSource == null
? null ? null
: () { : () {
@ -239,9 +240,7 @@ class PlayerView extends HookConsumerWidget {
}, },
), ),
), ),
if (authenticated.asData?.value == true)
const SizedBox(width: 10), const SizedBox(width: 10),
if (authenticated.asData?.value == true)
Expanded( Expanded(
child: OutlineButton( child: OutlineButton(
leading: const Icon(SpotubeIcons.music), leading: const Icon(SpotubeIcons.music),

View File

@ -3,7 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:media_kit/media_kit.dart'; import 'package:media_kit/media_kit.dart';
import 'package:palette_generator/palette_generator.dart'; import 'package:palette_generator/palette_generator.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer; import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/collections/intents.dart'; import 'package:spotube/collections/intents.dart';
@ -14,6 +14,7 @@ import 'package:spotube/modules/player/use_progress.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/utils/platform.dart';
class PlayerControls extends HookConsumerWidget { class PlayerControls extends HookConsumerWidget {
final PaletteGenerator? palette; final PaletteGenerator? palette;
@ -48,6 +49,9 @@ class PlayerControls extends HookConsumerWidget {
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
final theme = Theme.of(context); final theme = Theme.of(context);
final buttonSize =
kIsMobile ? const ButtonSize(1.5) : const ButtonSize(1.2);
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
onTap: () { onTap: () {
@ -149,9 +153,11 @@ class PlayerControls extends HookConsumerWidget {
), ),
).call, ).call,
child: IconButton( child: IconButton(
size: buttonSize,
icon: Icon( icon: Icon(
SpotubeIcons.shuffle, SpotubeIcons.shuffle,
color: shuffled ? theme.colorScheme.primary : null, color: shuffled ? theme.colorScheme.primary : null,
size: 22,
), ),
variance: shuffled variance: shuffled
? ButtonVariance.secondary ? ButtonVariance.secondary
@ -170,8 +176,10 @@ class PlayerControls extends HookConsumerWidget {
}), }),
Tooltip( Tooltip(
tooltip: TooltipContainer( tooltip: TooltipContainer(
child: Text(context.l10n.previous_track)).call, child: Text(context.l10n.previous_track),
).call,
child: IconButton.ghost( child: IconButton.ghost(
size: buttonSize,
enabled: !isFetchingActiveTrack, enabled: !isFetchingActiveTrack,
icon: const Icon(SpotubeIcons.skipBack), icon: const Icon(SpotubeIcons.skipBack),
onPressed: audioPlayer.skipToPrevious, onPressed: audioPlayer.skipToPrevious,
@ -186,6 +194,7 @@ class PlayerControls extends HookConsumerWidget {
), ),
).call, ).call,
child: IconButton.primary( child: IconButton.primary(
size: buttonSize,
shape: ButtonShape.circle, shape: ButtonShape.circle,
icon: isFetchingActiveTrack icon: isFetchingActiveTrack
? const SizedBox( ? const SizedBox(
@ -206,8 +215,10 @@ class PlayerControls extends HookConsumerWidget {
), ),
Tooltip( Tooltip(
tooltip: tooltip:
TooltipContainer(child: Text(context.l10n.next_track)).call, TooltipContainer(child: Text(context.l10n.next_track))
.call,
child: IconButton.ghost( child: IconButton.ghost(
size: buttonSize,
icon: const Icon(SpotubeIcons.skipForward), icon: const Icon(SpotubeIcons.skipForward),
onPressed: onPressed:
isFetchingActiveTrack ? null : audioPlayer.skipToNext, isFetchingActiveTrack ? null : audioPlayer.skipToNext,
@ -228,6 +239,7 @@ class PlayerControls extends HookConsumerWidget {
), ),
).call, ).call,
child: IconButton( child: IconButton(
size: buttonSize,
icon: Icon( icon: Icon(
loopMode == PlaylistMode.single loopMode == PlaylistMode.single
? SpotubeIcons.repeatOne ? SpotubeIcons.repeatOne

View File

@ -47,10 +47,8 @@ class PlayerTrackDetails extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(height: 4), const SizedBox(height: 4),
LinkText( Text(
playback.activeTrack?.name ?? "", playback.activeTrack?.name ?? "",
TrackRoute(trackId: playback.activeTrack?.id ?? ""),
push: true,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: theme.typography.normal.copyWith( style: theme.typography.normal.copyWith(
color: color, color: color,

View File

@ -70,6 +70,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
final preferences = ref.watch(userPreferencesProvider); final preferences = ref.watch(userPreferencesProvider);
final youtubeEngine = ref.watch(youtubeEngineProvider); final youtubeEngine = ref.watch(youtubeEngineProvider);
final isLoading = useState(false);
final isSearching = useState(false); final isSearching = useState(false);
final searchMode = useState(preferences.searchMode); final searchMode = useState(preferences.searchMode);
final activeTrackSources = ref.watch(activeTrackSourcesProvider); final activeTrackSources = ref.watch(activeTrackSourcesProvider);
@ -195,12 +196,14 @@ class SiblingTracksSheet extends HookConsumerWidget {
), ),
], ],
), ),
enabled: !isFetchingActiveTrack, enabled: !isFetchingActiveTrack && !isLoading.value,
selected: !isFetchingActiveTrack && selected: !isFetchingActiveTrack &&
sourceInfo.id == activeTrackSource?.info.id, sourceInfo.id == activeTrackSource?.info.id,
onPressed: () async { onPressed: () async {
if (!isFetchingActiveTrack && if (!isFetchingActiveTrack &&
sourceInfo.id != activeTrackSource?.info.id) { sourceInfo.id != activeTrackSource?.info.id) {
try {
isLoading.value = true;
await activeTrackNotifier?.swapWithSibling(sourceInfo); await activeTrackNotifier?.swapWithSibling(sourceInfo);
await ref.read(audioPlayerProvider.notifier).swapActiveSource(); await ref.read(audioPlayerProvider.notifier).swapActiveSource();
@ -211,11 +214,22 @@ class SiblingTracksSheet extends HookConsumerWidget {
closeDrawer(context); closeDrawer(context);
} }
} }
} finally {
if (context.mounted) {
isLoading.value = false;
}
}
} }
}, },
); );
}, },
[activeTrackSource, activeTrackNotifier, siblings], [
activeTrackSource,
activeTrackNotifier,
siblings,
isFetchingActiveTrack,
isLoading.value,
],
); );
final scale = context.theme.scaling; final scale = context.theme.scaling;
@ -293,6 +307,15 @@ class SiblingTracksSheet extends HookConsumerWidget {
], ],
), ),
), ),
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: isLoading.value
? const SizedBox(
width: double.infinity,
child: LinearProgressIndicator(),
)
: const SizedBox.shrink(),
),
Expanded( Expanded(
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
@ -307,7 +330,9 @@ class SiblingTracksSheet extends HookConsumerWidget {
itemCount: siblings.length, itemCount: siblings.length,
separatorBuilder: (context, index) => const Gap(8), separatorBuilder: (context, index) => const Gap(8),
itemBuilder: (context, index) => itemBuilder( itemBuilder: (context, index) => itemBuilder(
siblings[index], activeTrackSource!.source), siblings[index],
activeTrackSource!.source,
),
), ),
true => FutureBuilder( true => FutureBuilder(
future: searchRequest, future: searchRequest,

View File

@ -3,7 +3,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:spotube/collections/assets.gen.dart';
import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/collections/side_bar_tiles.dart';
import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/database/database.dart';
import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/constrains.dart';
@ -20,19 +19,6 @@ class Sidebar extends HookConsumerWidget {
super.key, super.key,
}); });
static Widget brandLogo(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(50),
),
child: Assets.branding.spotubeLogoPng.image(
height: 50,
cacheHeight: (100 * MediaQuery.devicePixelRatioOf(context)).toInt(),
),
);
}
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final ThemeData(:colorScheme) = Theme.of(context); final ThemeData(:colorScheme) = Theme.of(context);

View File

@ -3,8 +3,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/assets.gen.dart';
import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/database/database.dart';
@ -43,19 +41,17 @@ class HomePage extends HookConsumerWidget {
if (mediaQuery.smAndDown || layoutMode == LayoutMode.compact) if (mediaQuery.smAndDown || layoutMode == LayoutMode.compact)
SliverAppBar( SliverAppBar(
floating: true, floating: true,
title: Image.asset( title: DefaultTextStyle(
theme.brightness == Brightness.dark style: TextStyle(
? Assets.branding.spotubeLogoPng.path fontFamily: "Cookie",
: Assets.branding.spotubeLogoLight.path, fontSize: 30,
height: 45, letterSpacing: 1.8,
width: 45, color: theme.colorScheme.foreground,
color: theme.colorScheme.background,
colorBlendMode: BlendMode.saturation,
cacheHeight:
(100 * MediaQuery.devicePixelRatioOf(context)).toInt(),
), ),
backgroundColor: context.theme.colorScheme.background, child: const Text("Spotube"),
foregroundColor: context.theme.colorScheme.foreground, ),
backgroundColor: theme.colorScheme.background,
foregroundColor: theme.colorScheme.foreground,
actions: [ actions: [
const ConnectDeviceButton(), const ConnectDeviceButton(),
const Gap(10), const Gap(10),

View File

@ -18,8 +18,6 @@ import 'package:spotube/provider/lyrics/synced.dart';
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/logger/logger.dart'; import 'package:spotube/services/logger/logger.dart';
import 'package:stroke_text/stroke_text.dart';
class SyncedLyrics extends HookConsumerWidget { class SyncedLyrics extends HookConsumerWidget {
final PaletteColor palette; final PaletteColor palette;
final bool? isModal; final bool? isModal;
@ -160,6 +158,9 @@ class SyncedLyrics extends HookConsumerWidget {
child: AnimatedDefaultTextStyle( child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
style: TextStyle( style: TextStyle(
color: isActive
? theme.colorScheme.foreground
: theme.colorScheme.mutedForeground,
fontWeight: isActive fontWeight: isActive
? FontWeight.w500 ? FontWeight.w500
: FontWeight.normal, : FontWeight.normal,
@ -181,25 +182,7 @@ class SyncedLyrics extends HookConsumerWidget {
} }
audioPlayer.seek(time); audioPlayer.seek(time);
}, },
child: Builder(builder: (context) { child: Text(lyricSlice.text),
return StrokeText(
text: lyricSlice.text,
textStyle:
DefaultTextStyle.of(context).style,
textColor: switch ((
isActive,
isModal == true
)) {
(true, _) => Colors.white,
(_, true) =>
theme.colorScheme.mutedForeground,
(_, _) => palette.bodyTextColor,
},
strokeColor: isActive
? Colors.black
: Colors.transparent,
);
}),
), ),
), ),
), ),

View File

@ -28,9 +28,7 @@ class PlayerLyricsPage extends HookConsumerWidget {
final selectedIndex = useState(0); final selectedIndex = useState(0);
final palette = usePaletteColor(albumArt, ref); final palette = usePaletteColor(albumArt, ref);
final tabbar = Padding( final tabbar = TabList(
padding: const EdgeInsets.all(10),
child: TabList(
index: selectedIndex.value, index: selectedIndex.value,
onChanged: (index) => selectedIndex.value = index, onChanged: (index) => selectedIndex.value = index,
children: [ children: [
@ -41,7 +39,7 @@ class PlayerLyricsPage extends HookConsumerWidget {
child: Text(context.l10n.plain), child: Text(context.l10n.plain),
), ),
], ],
)); );
return Scaffold( return Scaffold(
headers: [ headers: [

View File

@ -13,7 +13,6 @@ import 'package:spotube/l10n/l10n.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
final localWithName = L10n.all.map((e) { final localWithName = L10n.all.map((e) {
print(e);
final isoCodeName = final isoCodeName =
LanguageLocals.getDisplayLanguage(e.languageCode, e.countryCode); LanguageLocals.getDisplayLanguage(e.languageCode, e.countryCode);
return ( return (

View File

@ -147,21 +147,29 @@ class AudioPlayerNotifier extends Notifier<AudioPlayerState> {
try { try {
// Playlist and state has to be in sync. This is only meant for // Playlist and state has to be in sync. This is only meant for
// the shuffle/re-ordering indices to be in sync // the shuffle/re-ordering indices to be in sync
if (playlist.medias.length != state.tracks.length) return; if (playlist.medias.length != state.tracks.length) {
AppLogger.log.w(
final queries = playlist.medias "Playlist length does not match state tracks length. Ignoring... "
.map((media) => TrackSourceQuery.parseUri(media.uri)) "Playlist length: ${playlist.medias.length}, "
.toList(); "State tracks length: ${state.tracks.length}",
);
return;
}
final trackGroupedById = groupBy( final trackGroupedById = groupBy(
state.tracks, state.tracks,
(query) => query.id, (query) => query.id,
); );
final tracks = queries final tracks = <SpotubeTrackObject>[];
.map((query) => trackGroupedById[query.id]?.firstOrNull)
.nonNulls for (final media in playlist.medias) {
.toList(); final trackQuery = TrackSourceQuery.parseUri(media.uri);
final track = trackGroupedById[trackQuery.id]?.firstOrNull;
if (track != null) {
tracks.add(track);
}
}
if (tracks.length != state.tracks.length) { if (tracks.length != state.tracks.length) {
AppLogger.log.w("Mismatch in tracks after reordering/shuffling."); AppLogger.log.w("Mismatch in tracks after reordering/shuffling.");

View File

@ -146,7 +146,5 @@ mixin SpotubeAudioPlayersStreams on AudioPlayerInterface {
Stream<String> get errorStream => _mkPlayer.stream.error; Stream<String> get errorStream => _mkPlayer.stream.error;
Stream<mk.Playlist> get playlistStream => _mkPlayer.stream.playlist.map((s) { Stream<mk.Playlist> get playlistStream => _mkPlayer.stream.playlist;
return s;
});
} }

View File

@ -12,19 +12,15 @@ import 'package:spotube/utils/platform.dart';
/// This class adds a state stream to the [Player] class. /// This class adds a state stream to the [Player] class.
class CustomPlayer extends Player { class CustomPlayer extends Player {
final StreamController<AudioPlaybackState> _playerStateStream; final StreamController<AudioPlaybackState> _playerStateStream;
final StreamController<bool> _shuffleStream;
late final List<StreamSubscription> _subscriptions; late final List<StreamSubscription> _subscriptions;
bool _shuffled;
int _androidAudioSessionId = 0; int _androidAudioSessionId = 0;
String _packageName = ""; String _packageName = "";
AndroidAudioManager? _androidAudioManager; AndroidAudioManager? _androidAudioManager;
CustomPlayer({super.configuration}) CustomPlayer({super.configuration})
: _playerStateStream = StreamController.broadcast(), : _playerStateStream = StreamController.broadcast() {
_shuffleStream = StreamController.broadcast(),
_shuffled = false {
nativePlayer.setProperty("network-timeout", "120"); nativePlayer.setProperty("network-timeout", "120");
_subscriptions = [ _subscriptions = [
@ -86,10 +82,10 @@ class CustomPlayer extends Player {
} }
} }
bool get shuffled => _shuffled; bool get shuffled => state.shuffle;
Stream<AudioPlaybackState> get playerStateStream => _playerStateStream.stream; Stream<AudioPlaybackState> get playerStateStream => _playerStateStream.stream;
Stream<bool> get shuffleStream => _shuffleStream.stream; Stream<bool> get shuffleStream => stream.shuffle;
Stream<int> get indexChangeStream { Stream<int> get indexChangeStream {
int oldIndex = state.playlist.index; int oldIndex = state.playlist.index;
return stream.playlist.map((event) => event.index).where((newIndex) { return stream.playlist.map((event) => event.index).where((newIndex) {
@ -103,22 +99,14 @@ class CustomPlayer extends Player {
@override @override
Future<void> setShuffle(bool shuffle) async { Future<void> setShuffle(bool shuffle) async {
_shuffled = shuffle;
await super.setShuffle(shuffle); await super.setShuffle(shuffle);
_shuffleStream.add(shuffle);
await Future.delayed(const Duration(milliseconds: 100));
if (shuffle) {
await move(state.playlist.index, 0);
}
} }
@override @override
Future<void> stop() async { Future<void> stop() async {
await super.stop(); await super.stop();
_shuffled = false;
_playerStateStream.add(AudioPlaybackState.stopped); _playerStateStream.add(AudioPlaybackState.stopped);
_shuffleStream.add(false);
} }
@override @override
@ -134,7 +122,8 @@ class CustomPlayer extends Player {
Future<void> insert(int index, Media media) async { Future<void> insert(int index, Media media) async {
await add(media); await add(media);
await move(state.playlist.medias.length, index); await Future.delayed(const Duration(milliseconds: 100));
await move(state.playlist.medias.length - 1, index);
} }
Future<void> setAudioNormalization(bool normalize) async { Future<void> setAudioNormalization(bool normalize) async {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@ -1570,58 +1570,65 @@ packages:
media_kit: media_kit:
dependency: "direct main" dependency: "direct main"
description: description:
name: media_kit path: media_kit
sha256: "48c10c3785df5d88f0eef970743f8c99b2e5da2b34b9d8f9876e598f62d9e776" ref: HEAD
url: "https://pub.dev" resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1
source: hosted url: "https://github.com/media-kit/media-kit"
source: git
version: "1.2.0" version: "1.2.0"
media_kit_libs_android_audio: media_kit_libs_android_audio:
dependency: transitive dependency: "direct overridden"
description: description:
name: media_kit_libs_android_audio path: "libs/android/media_kit_libs_android_audio"
sha256: d0923d251c1232880e755b44555ce31b9e7068a29f05e01ed2fb510956bba851 ref: HEAD
url: "https://pub.dev" resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1
source: hosted url: "https://github.com/media-kit/media-kit"
source: git
version: "1.3.7" version: "1.3.7"
media_kit_libs_audio: media_kit_libs_audio:
dependency: "direct main" dependency: "direct main"
description: description:
name: media_kit_libs_audio path: "libs/universal/media_kit_libs_audio"
sha256: f5ea1eb414c4ee4994f36de36c7ce11577a249e058e907e7eb6e656513bccbfb ref: HEAD
url: "https://pub.dev" resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1
source: hosted url: "https://github.com/media-kit/media-kit"
source: git
version: "1.0.6" version: "1.0.6"
media_kit_libs_ios_audio: media_kit_libs_ios_audio:
dependency: transitive dependency: "direct overridden"
description: description:
name: media_kit_libs_ios_audio path: "libs/ios/media_kit_libs_ios_audio"
sha256: "78ccf04e27d6b4ba00a355578ccb39b772f00d48269a6ac3db076edf2d51934f" ref: HEAD
url: "https://pub.dev" resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1
source: hosted url: "https://github.com/media-kit/media-kit"
source: git
version: "1.1.4" version: "1.1.4"
media_kit_libs_linux: media_kit_libs_linux:
dependency: transitive dependency: "direct overridden"
description: description:
name: media_kit_libs_linux path: "libs/linux/media_kit_libs_linux"
sha256: "2b473399a49ec94452c4d4ae51cfc0f6585074398d74216092bf3d54aac37ecf" ref: HEAD
url: "https://pub.dev" resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1
source: hosted url: "https://github.com/media-kit/media-kit"
source: git
version: "1.2.1" version: "1.2.1"
media_kit_libs_macos_audio: media_kit_libs_macos_audio:
dependency: transitive dependency: "direct overridden"
description: description:
name: media_kit_libs_macos_audio path: "libs/macos/media_kit_libs_macos_audio"
sha256: "3be21844df98f286de32808592835073cdef2c1a10078bac135da790badca950" ref: HEAD
url: "https://pub.dev" resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1
source: hosted url: "https://github.com/media-kit/media-kit"
source: git
version: "1.1.4" version: "1.1.4"
media_kit_libs_windows_audio: media_kit_libs_windows_audio:
dependency: transitive dependency: "direct overridden"
description: description:
name: media_kit_libs_windows_audio path: "libs/windows/media_kit_libs_windows_audio"
sha256: c2fd558cc87b9d89a801141fcdffe02e338a3b21a41a18fbd63d5b221a1b8e53 ref: HEAD
url: "https://pub.dev" resolved-ref: c9617f570b8c0ba02857e721997f78c053a856c1
source: hosted url: "https://github.com/media-kit/media-kit"
source: git
version: "1.0.9" version: "1.0.9"
menu_base: menu_base:
dependency: transitive dependency: transitive

View File

@ -3,7 +3,7 @@ description: Open source extensible music streaming platform and app, based on B
publish_to: "none" publish_to: "none"
version: 4.0.2+41 version: 5.0.0+42
homepage: https://spotube.krtirtho.dev homepage: https://spotube.krtirtho.dev
repository: https://github.com/KRTirtho/spotube repository: https://github.com/KRTirtho/spotube
@ -84,8 +84,14 @@ dependencies:
logger: ^2.0.2 logger: ^2.0.2
logging: ^1.3.0 logging: ^1.3.0
lrc: ^1.0.2 lrc: ^1.0.2
media_kit: ^1.1.10+1 media_kit:
media_kit_libs_audio: ^1.0.4 git:
url: https://github.com/media-kit/media-kit
path: media_kit
media_kit_libs_audio:
git:
url: https://github.com/media-kit/media-kit
path: libs/universal/media_kit_libs_audio
metadata_god: ^1.1.0 metadata_god: ^1.1.0
mime: ^2.0.0 mime: ^2.0.0
open_file: ^3.5.10 open_file: ^3.5.10
@ -194,6 +200,26 @@ dependency_overrides:
ref: patch-2 ref: patch-2
path: flutter_secure_storage_linux path: flutter_secure_storage_linux
flutter_secure_storage_platform_interface: 2.0.0 flutter_secure_storage_platform_interface: 2.0.0
media_kit_libs_android_audio:
git:
url: https://github.com/media-kit/media-kit
path: libs/android/media_kit_libs_android_audio
media_kit_libs_ios_audio:
git:
url: https://github.com/media-kit/media-kit
path: libs/ios/media_kit_libs_ios_audio
media_kit_libs_macos_audio:
git:
url: https://github.com/media-kit/media-kit
path: libs/macos/media_kit_libs_macos_audio
media_kit_libs_windows_audio:
git:
url: https://github.com/media-kit/media-kit
path: libs/windows/media_kit_libs_windows_audio
media_kit_libs_linux:
git:
url: https://github.com/media-kit/media-kit
path: libs/linux/media_kit_libs_linux
flutter: flutter:
generate: true generate: true

View File

@ -525,7 +525,7 @@ class PreferencesTable extends Table
GeneratedColumn<String>('accent_color_scheme', aliasedName, false, GeneratedColumn<String>('accent_color_scheme', aliasedName, false,
type: DriftSqlType.string, type: DriftSqlType.string,
requiredDuringInsert: false, requiredDuringInsert: false,
defaultValue: const Constant("Orange:0xFFf97315")); defaultValue: const Constant("Slate:0xff64748b"));
late final GeneratedColumn<String> layoutMode = GeneratedColumn<String>( late final GeneratedColumn<String> layoutMode = GeneratedColumn<String>(
'layout_mode', aliasedName, false, 'layout_mode', aliasedName, false,
type: DriftSqlType.string, type: DriftSqlType.string,

View File

@ -1 +1,5 @@
{} {
"nl": [
"audio_source"
]
}