diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3229a158..8ae9c74f 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -9,6 +9,7 @@
"fuzzywuzzy",
"gapless",
"instrumentalness",
+ "isrc",
"Mpris",
"RGBO",
"riverpod",
diff --git a/README.md b/README.md
index b2c388e4..03205741 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,8 @@
-An open source, cross-platform Spotify client compatible across multiple platforms
-utilizing Spotify's data API and YouTube, Piped.video or JioSaavn as an audio source,
-eliminating the need for Spotify Premium
+An open source, cross-platform music client
+utilizing selected music provider API and YouTube, Piped.video or JioSaavn as an audio source
Btw it's not just another Electron app 😉
@@ -27,7 +26,7 @@ Btw it's not just another Electron app 😉
## 🌃 Features
-- 🚫 No ads, thanks to the use of public & free Spotify and YT Music APIs¹
+- 🚫 No ads, thanks to the use of public & free music metadata providers and YT Music APIs¹
- ⬇️ Freely downloadable tracks
- 🖥️ 📱 Cross-platform support
- 🪶 Small size & less data usage
@@ -38,12 +37,12 @@ Btw it's not just another Electron app 😉
- 📖 Open source/libre software
- 🔉 Playback control is done locally, not on the server
-**¹** It is still **recommended** to support creators by engaging with their YouTube channels/Spotify tracks (or preferably by buying their merch/concert tickets/physical media).
+**¹** It is still **recommended** to support creators by engaging with their YouTube channels/tracks in music platforms (or preferably by buying their merch/concert tickets/physical media).
### ❌ Unsupported features
-- 🗣️ **Spotify Shows & Podcasts:** Shows and Podcasts will
**never be supported** because the audio tracks are
_only_ available on Spotify and accessing them would require Spotify Premium.
-- 🎧 **Spotify Listen Along:** [Coming soon!](https://github.com/KRTirtho/spotube/issues/8)
+- 🗣️ **Shows & Podcasts:** Shows and Podcasts will
**never be supported** because the audio tracks are
_only_ available on music providers and accessing them would require premium.
+- 🎧 **Listen Along:** [Coming soon!](https://github.com/KRTirtho/spotube/issues/8)
## 📜 ⬇️ Installation guide
@@ -210,7 +209,6 @@ If you are concerned, you can [read the reason of choosing this license](https:/
1. [Flutter](https://flutter.dev) - Flutter transforms the app development process. Build, test, and deploy beautiful mobile, web, desktop, and embedded apps from a single codebase
1. [MPV](https://mpv.io) - mpv is a free (as in freedom) media player for the command line. It supports a wide variety of media file formats, audio and video codecs, and subtitle types.
-1. [Spotify API](https://developer.spotify.com/documentation/web-api) - The Spotify Web API is a RESTful API that provides access to Spotify data
1. [Piped](https://piped-docs.kavin.rocks/) - Piped is a privacy friendly alternative YouTube frontend, which is efficient and scalable by design.
1. [Invidious](https://invidious.io/) - Invidious is an open source alternative front-end to YouTube.
1. [YouTube](https://youtube.com/) - YouTube is an American online video-sharing platform headquartered in San Bruno, California. Three former PayPal employees—Chad Hurley, Steve Chen, and Jawed Karim—created the service in February 2005
@@ -304,7 +302,6 @@ If you are concerned, you can [read the reason of choosing this license](https:/
1. [sliding_up_panel](https://github.com/akshathjain/sliding_up_panel) - A draggable Flutter widget that makes implementing a SlidingUpPanel much easier!
1. [sliver_tools](https://github.com/Kavantix) - A set of useful sliver tools that are missing from the flutter framework
1. [smtc_windows](https://pub.dev/packages/smtc_windows) - Windows `SystemMediaTransportControls` implementation for Flutter giving access to Windows OS Media Control applet.
-1. [spotify](https://github.com/rinukkusu/spotify-dart) - An incomplete dart library for interfacing with the Spotify Web API.
1. [sqlite3](https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3) - Provides lightweight yet convenient bindings to SQLite by using dart:ffi
1. [sqlite3_flutter_libs](https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3_flutter_libs) - Flutter plugin to include native sqlite3 libraries with your app
1. [stroke_text](https://github.com/MohamedAbd0/stroke_text) - A Simple Flutter plugin for applying stroke (border) style to a text widget
@@ -350,4 +347,4 @@ If you are concerned, you can [read the reason of choosing this license](https:/
1. [flutter_new_pipe_extractor](https://github.com/KRTirtho/flutter_new_pipe_extractor) - NewPipeExtractor binding for Flutter (Android only)
-
© Copyright Spotube 2024
+
© Copyright Spotube 2025
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
index 700901e8..17a13e9d 100644
--- a/android/app/proguard-rules.pro
+++ b/android/app/proguard-rules.pro
@@ -18,4 +18,33 @@
-keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; }
-keep class org.mozilla.javascript.** { *; }
-keep class org.mozilla.classfile.ClassFileWriter
--dontwarn org.mozilla.javascript.tools.**
\ No newline at end of file
+-dontwarn org.mozilla.javascript.tools.**
+
+-dontwarn javax.script.AbstractScriptEngine
+-dontwarn javax.script.Bindings
+-dontwarn javax.script.Compilable
+-dontwarn javax.script.CompiledScript
+-dontwarn javax.script.Invocable
+-dontwarn javax.script.ScriptContext
+-dontwarn javax.script.ScriptEngine
+-dontwarn javax.script.ScriptEngineFactory
+-dontwarn javax.script.ScriptException
+-dontwarn javax.script.SimpleBindings
+-dontwarn jdk.dynalink.CallSiteDescriptor
+-dontwarn jdk.dynalink.DynamicLinker
+-dontwarn jdk.dynalink.DynamicLinkerFactory
+-dontwarn jdk.dynalink.NamedOperation
+-dontwarn jdk.dynalink.Namespace
+-dontwarn jdk.dynalink.NamespaceOperation
+-dontwarn jdk.dynalink.Operation
+-dontwarn jdk.dynalink.RelinkableCallSite
+-dontwarn jdk.dynalink.StandardNamespace
+-dontwarn jdk.dynalink.StandardOperation
+-dontwarn jdk.dynalink.linker.GuardedInvocation
+-dontwarn jdk.dynalink.linker.GuardingDynamicLinker
+-dontwarn jdk.dynalink.linker.LinkRequest
+-dontwarn jdk.dynalink.linker.LinkerServices
+-dontwarn jdk.dynalink.linker.TypeBasedGuardingDynamicLinker
+-dontwarn jdk.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker
+-dontwarn jdk.dynalink.linker.support.Guards
+-dontwarn jdk.dynalink.support.ChainedCallSite
\ No newline at end of file
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index a32d12af..400c91e8 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -3,4 +3,17 @@
to allow setting breakpoints, to provide hot reload, etc.
-->
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable-hdpi-v31/android12branding.png b/android/app/src/main/res/drawable-hdpi-v31/android12branding.png
index fff3f148..22a9b8d3 100644
Binary files a/android/app/src/main/res/drawable-hdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-hdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/android12splash.png b/android/app/src/main/res/drawable-hdpi/android12splash.png
index 0d4e1c68..adeebcd1 100644
Binary files a/android/app/src/main/res/drawable-hdpi/android12splash.png and b/android/app/src/main/res/drawable-hdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/branding.png b/android/app/src/main/res/drawable-hdpi/branding.png
index fff3f148..22a9b8d3 100644
Binary files a/android/app/src/main/res/drawable-hdpi/branding.png and b/android/app/src/main/res/drawable-hdpi/branding.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png
index a65caa1b..204ffe94 100644
Binary files a/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png
index 0979b5e4..87eebe5c 100644
Binary files a/android/app/src/main/res/drawable-hdpi/splash.png and b/android/app/src/main/res/drawable-hdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-mdpi-v31/android12branding.png b/android/app/src/main/res/drawable-mdpi-v31/android12branding.png
index 5a197da3..3ff2a2da 100644
Binary files a/android/app/src/main/res/drawable-mdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-mdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/android12splash.png b/android/app/src/main/res/drawable-mdpi/android12splash.png
index 5d9760d4..72c22614 100644
Binary files a/android/app/src/main/res/drawable-mdpi/android12splash.png and b/android/app/src/main/res/drawable-mdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/branding.png b/android/app/src/main/res/drawable-mdpi/branding.png
index 5a197da3..3ff2a2da 100644
Binary files a/android/app/src/main/res/drawable-mdpi/branding.png and b/android/app/src/main/res/drawable-mdpi/branding.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png
index 3ad0f47e..e7a75c9a 100644
Binary files a/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png
index c5e4aca0..6e04efdc 100644
Binary files a/android/app/src/main/res/drawable-mdpi/splash.png and b/android/app/src/main/res/drawable-mdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-night-hdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-hdpi-v31/android12branding.png
index fff3f148..22a9b8d3 100644
Binary files a/android/app/src/main/res/drawable-night-hdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-night-hdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/android/app/src/main/res/drawable-night-hdpi/android12splash.png
index 0d4e1c68..adeebcd1 100644
Binary files a/android/app/src/main/res/drawable-night-hdpi/android12splash.png and b/android/app/src/main/res/drawable-night-hdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-night-mdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-mdpi-v31/android12branding.png
index 5a197da3..3ff2a2da 100644
Binary files a/android/app/src/main/res/drawable-night-mdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-night-mdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/android/app/src/main/res/drawable-night-mdpi/android12splash.png
index 5d9760d4..72c22614 100644
Binary files a/android/app/src/main/res/drawable-night-mdpi/android12splash.png and b/android/app/src/main/res/drawable-night-mdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-night-xhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-xhdpi-v31/android12branding.png
index efc7e6c8..8e2bb197 100644
Binary files a/android/app/src/main/res/drawable-night-xhdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-night-xhdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xhdpi/android12splash.png
index 8e5ceb0a..5adba278 100644
Binary files a/android/app/src/main/res/drawable-night-xhdpi/android12splash.png and b/android/app/src/main/res/drawable-night-xhdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-night-xxhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-xxhdpi-v31/android12branding.png
index 593877e0..d301093a 100644
Binary files a/android/app/src/main/res/drawable-night-xxhdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-night-xxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png
index fb89da37..4e294a2d 100644
Binary files a/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png and b/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-night-xxxhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-xxxhdpi-v31/android12branding.png
index 9d233302..42b0bdc2 100644
Binary files a/android/app/src/main/res/drawable-night-xxxhdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-night-xxxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png
index 38e4a12c..dcc70377 100644
Binary files a/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png and b/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png
index 203fc77a..4bebb9de 100644
Binary files a/android/app/src/main/res/drawable-v21/background.png and b/android/app/src/main/res/drawable-v21/background.png differ
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
index 52e8749e..5367a886 100644
--- a/android/app/src/main/res/drawable-v21/launch_background.xml
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -6,7 +6,7 @@
-
-
-
+
-
diff --git a/android/app/src/main/res/drawable-xhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-xhdpi-v31/android12branding.png
index efc7e6c8..8e2bb197 100644
Binary files a/android/app/src/main/res/drawable-xhdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-xhdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/android12splash.png b/android/app/src/main/res/drawable-xhdpi/android12splash.png
index 8e5ceb0a..5adba278 100644
Binary files a/android/app/src/main/res/drawable-xhdpi/android12splash.png and b/android/app/src/main/res/drawable-xhdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/branding.png b/android/app/src/main/res/drawable-xhdpi/branding.png
index efc7e6c8..8e2bb197 100644
Binary files a/android/app/src/main/res/drawable-xhdpi/branding.png and b/android/app/src/main/res/drawable-xhdpi/branding.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png
index 8774c0ff..b608dca7 100644
Binary files a/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png
index 41222c6c..51a669aa 100644
Binary files a/android/app/src/main/res/drawable-xhdpi/splash.png and b/android/app/src/main/res/drawable-xhdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-xxhdpi-v31/android12branding.png
index 593877e0..d301093a 100644
Binary files a/android/app/src/main/res/drawable-xxhdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-xxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/android/app/src/main/res/drawable-xxhdpi/android12splash.png
index fb89da37..4e294a2d 100644
Binary files a/android/app/src/main/res/drawable-xxhdpi/android12splash.png and b/android/app/src/main/res/drawable-xxhdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/branding.png b/android/app/src/main/res/drawable-xxhdpi/branding.png
index 593877e0..d301093a 100644
Binary files a/android/app/src/main/res/drawable-xxhdpi/branding.png and b/android/app/src/main/res/drawable-xxhdpi/branding.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png
index a379c006..b1e93458 100644
Binary files a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png
index 5ab19d32..cc79cb85 100644
Binary files a/android/app/src/main/res/drawable-xxhdpi/splash.png and b/android/app/src/main/res/drawable-xxhdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-xxxhdpi-v31/android12branding.png
index 9d233302..42b0bdc2 100644
Binary files a/android/app/src/main/res/drawable-xxxhdpi-v31/android12branding.png and b/android/app/src/main/res/drawable-xxxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/android/app/src/main/res/drawable-xxxhdpi/android12splash.png
index 38e4a12c..dcc70377 100644
Binary files a/android/app/src/main/res/drawable-xxxhdpi/android12splash.png and b/android/app/src/main/res/drawable-xxxhdpi/android12splash.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/branding.png b/android/app/src/main/res/drawable-xxxhdpi/branding.png
index 9d233302..42b0bdc2 100644
Binary files a/android/app/src/main/res/drawable-xxxhdpi/branding.png and b/android/app/src/main/res/drawable-xxxhdpi/branding.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png
index 44621df8..d178ba12 100644
Binary files a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png
index a6d40b89..f526b26d 100644
Binary files a/android/app/src/main/res/drawable-xxxhdpi/splash.png and b/android/app/src/main/res/drawable-xxxhdpi/splash.png differ
diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png
index 203fc77a..4bebb9de 100644
Binary files a/android/app/src/main/res/drawable/background.png and b/android/app/src/main/res/drawable/background.png differ
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 52e8749e..5367a886 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -6,7 +6,7 @@
-
- -
+
-
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index f606c4d8..c79c58a3 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,6 +1,9 @@
-
-
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
index d26a3a6e..c9e5cfad 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
index 63d16c60..159b302f 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index fe2957ad..9c81fb60 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 85c1d793..3450fb00 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index f22fa5cf..f94fd407 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/nightly/res/drawable-hdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-hdpi-v31/android12branding.png
index 9e62c813..22a9b8d3 100644
Binary files a/android/app/src/nightly/res/drawable-hdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-hdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-hdpi/android12splash.png b/android/app/src/nightly/res/drawable-hdpi/android12splash.png
index 98fd87f4..1d1cb853 100644
Binary files a/android/app/src/nightly/res/drawable-hdpi/android12splash.png and b/android/app/src/nightly/res/drawable-hdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-hdpi/branding.png b/android/app/src/nightly/res/drawable-hdpi/branding.png
index 9e62c813..22a9b8d3 100644
Binary files a/android/app/src/nightly/res/drawable-hdpi/branding.png and b/android/app/src/nightly/res/drawable-hdpi/branding.png differ
diff --git a/android/app/src/nightly/res/drawable-hdpi/ic_launcher_foreground.png b/android/app/src/nightly/res/drawable-hdpi/ic_launcher_foreground.png
index 20a57ba2..7373eec1 100644
Binary files a/android/app/src/nightly/res/drawable-hdpi/ic_launcher_foreground.png and b/android/app/src/nightly/res/drawable-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/nightly/res/drawable-hdpi/splash.png b/android/app/src/nightly/res/drawable-hdpi/splash.png
index 07c7024a..e3869211 100644
Binary files a/android/app/src/nightly/res/drawable-hdpi/splash.png and b/android/app/src/nightly/res/drawable-hdpi/splash.png differ
diff --git a/android/app/src/nightly/res/drawable-mdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-mdpi-v31/android12branding.png
index 80579983..3ff2a2da 100644
Binary files a/android/app/src/nightly/res/drawable-mdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-mdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-mdpi/android12splash.png b/android/app/src/nightly/res/drawable-mdpi/android12splash.png
index a86a2222..3f2a1a0a 100644
Binary files a/android/app/src/nightly/res/drawable-mdpi/android12splash.png and b/android/app/src/nightly/res/drawable-mdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-mdpi/branding.png b/android/app/src/nightly/res/drawable-mdpi/branding.png
index 80579983..3ff2a2da 100644
Binary files a/android/app/src/nightly/res/drawable-mdpi/branding.png and b/android/app/src/nightly/res/drawable-mdpi/branding.png differ
diff --git a/android/app/src/nightly/res/drawable-mdpi/ic_launcher_foreground.png b/android/app/src/nightly/res/drawable-mdpi/ic_launcher_foreground.png
index 43f5e0fe..8d5a9656 100644
Binary files a/android/app/src/nightly/res/drawable-mdpi/ic_launcher_foreground.png and b/android/app/src/nightly/res/drawable-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/nightly/res/drawable-mdpi/splash.png b/android/app/src/nightly/res/drawable-mdpi/splash.png
index 86d3fe74..d8f7cc0e 100644
Binary files a/android/app/src/nightly/res/drawable-mdpi/splash.png and b/android/app/src/nightly/res/drawable-mdpi/splash.png differ
diff --git a/android/app/src/nightly/res/drawable-night-hdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-night-hdpi-v31/android12branding.png
index 9e62c813..22a9b8d3 100644
Binary files a/android/app/src/nightly/res/drawable-night-hdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-night-hdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-night-hdpi/android12splash.png b/android/app/src/nightly/res/drawable-night-hdpi/android12splash.png
index 98fd87f4..1d1cb853 100644
Binary files a/android/app/src/nightly/res/drawable-night-hdpi/android12splash.png and b/android/app/src/nightly/res/drawable-night-hdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-night-mdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-night-mdpi-v31/android12branding.png
index 80579983..3ff2a2da 100644
Binary files a/android/app/src/nightly/res/drawable-night-mdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-night-mdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-night-mdpi/android12splash.png b/android/app/src/nightly/res/drawable-night-mdpi/android12splash.png
index a86a2222..3f2a1a0a 100644
Binary files a/android/app/src/nightly/res/drawable-night-mdpi/android12splash.png and b/android/app/src/nightly/res/drawable-night-mdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-night-xhdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-night-xhdpi-v31/android12branding.png
index 0bcf138d..8e2bb197 100644
Binary files a/android/app/src/nightly/res/drawable-night-xhdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-night-xhdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-night-xhdpi/android12splash.png b/android/app/src/nightly/res/drawable-night-xhdpi/android12splash.png
index ad3f39d0..ba73b0e2 100644
Binary files a/android/app/src/nightly/res/drawable-night-xhdpi/android12splash.png and b/android/app/src/nightly/res/drawable-night-xhdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-night-xxhdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-night-xxhdpi-v31/android12branding.png
index c7d01776..d301093a 100644
Binary files a/android/app/src/nightly/res/drawable-night-xxhdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-night-xxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-night-xxhdpi/android12splash.png b/android/app/src/nightly/res/drawable-night-xxhdpi/android12splash.png
index 133fb647..5e5cdc45 100644
Binary files a/android/app/src/nightly/res/drawable-night-xxhdpi/android12splash.png and b/android/app/src/nightly/res/drawable-night-xxhdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-night-xxxhdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-night-xxxhdpi-v31/android12branding.png
index 5477b799..42b0bdc2 100644
Binary files a/android/app/src/nightly/res/drawable-night-xxxhdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-night-xxxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-night-xxxhdpi/android12splash.png b/android/app/src/nightly/res/drawable-night-xxxhdpi/android12splash.png
index fa5a8c92..adff9bec 100644
Binary files a/android/app/src/nightly/res/drawable-night-xxxhdpi/android12splash.png and b/android/app/src/nightly/res/drawable-night-xxxhdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-v21/background.png b/android/app/src/nightly/res/drawable-v21/background.png
index 203fc77a..4bebb9de 100644
Binary files a/android/app/src/nightly/res/drawable-v21/background.png and b/android/app/src/nightly/res/drawable-v21/background.png differ
diff --git a/android/app/src/nightly/res/drawable-v21/launch_background.xml b/android/app/src/nightly/res/drawable-v21/launch_background.xml
index 52e8749e..5367a886 100644
--- a/android/app/src/nightly/res/drawable-v21/launch_background.xml
+++ b/android/app/src/nightly/res/drawable-v21/launch_background.xml
@@ -6,7 +6,7 @@
-
- -
+
-
diff --git a/android/app/src/nightly/res/drawable-xhdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-xhdpi-v31/android12branding.png
index 0bcf138d..8e2bb197 100644
Binary files a/android/app/src/nightly/res/drawable-xhdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-xhdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-xhdpi/android12splash.png b/android/app/src/nightly/res/drawable-xhdpi/android12splash.png
index ad3f39d0..ba73b0e2 100644
Binary files a/android/app/src/nightly/res/drawable-xhdpi/android12splash.png and b/android/app/src/nightly/res/drawable-xhdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-xhdpi/branding.png b/android/app/src/nightly/res/drawable-xhdpi/branding.png
index 0bcf138d..8e2bb197 100644
Binary files a/android/app/src/nightly/res/drawable-xhdpi/branding.png and b/android/app/src/nightly/res/drawable-xhdpi/branding.png differ
diff --git a/android/app/src/nightly/res/drawable-xhdpi/ic_launcher_foreground.png b/android/app/src/nightly/res/drawable-xhdpi/ic_launcher_foreground.png
index 4cf86d25..f4f416f7 100644
Binary files a/android/app/src/nightly/res/drawable-xhdpi/ic_launcher_foreground.png and b/android/app/src/nightly/res/drawable-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/nightly/res/drawable-xhdpi/splash.png b/android/app/src/nightly/res/drawable-xhdpi/splash.png
index dbb0ea02..17a2c373 100644
Binary files a/android/app/src/nightly/res/drawable-xhdpi/splash.png and b/android/app/src/nightly/res/drawable-xhdpi/splash.png differ
diff --git a/android/app/src/nightly/res/drawable-xxhdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-xxhdpi-v31/android12branding.png
index c7d01776..d301093a 100644
Binary files a/android/app/src/nightly/res/drawable-xxhdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-xxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-xxhdpi/android12splash.png b/android/app/src/nightly/res/drawable-xxhdpi/android12splash.png
index 133fb647..5e5cdc45 100644
Binary files a/android/app/src/nightly/res/drawable-xxhdpi/android12splash.png and b/android/app/src/nightly/res/drawable-xxhdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-xxhdpi/branding.png b/android/app/src/nightly/res/drawable-xxhdpi/branding.png
index c7d01776..d301093a 100644
Binary files a/android/app/src/nightly/res/drawable-xxhdpi/branding.png and b/android/app/src/nightly/res/drawable-xxhdpi/branding.png differ
diff --git a/android/app/src/nightly/res/drawable-xxhdpi/ic_launcher_foreground.png b/android/app/src/nightly/res/drawable-xxhdpi/ic_launcher_foreground.png
index 95fa3443..9f88e976 100644
Binary files a/android/app/src/nightly/res/drawable-xxhdpi/ic_launcher_foreground.png and b/android/app/src/nightly/res/drawable-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/nightly/res/drawable-xxhdpi/splash.png b/android/app/src/nightly/res/drawable-xxhdpi/splash.png
index 12eb5531..db53f016 100644
Binary files a/android/app/src/nightly/res/drawable-xxhdpi/splash.png and b/android/app/src/nightly/res/drawable-xxhdpi/splash.png differ
diff --git a/android/app/src/nightly/res/drawable-xxxhdpi-v31/android12branding.png b/android/app/src/nightly/res/drawable-xxxhdpi-v31/android12branding.png
index 5477b799..42b0bdc2 100644
Binary files a/android/app/src/nightly/res/drawable-xxxhdpi-v31/android12branding.png and b/android/app/src/nightly/res/drawable-xxxhdpi-v31/android12branding.png differ
diff --git a/android/app/src/nightly/res/drawable-xxxhdpi/android12splash.png b/android/app/src/nightly/res/drawable-xxxhdpi/android12splash.png
index fa5a8c92..adff9bec 100644
Binary files a/android/app/src/nightly/res/drawable-xxxhdpi/android12splash.png and b/android/app/src/nightly/res/drawable-xxxhdpi/android12splash.png differ
diff --git a/android/app/src/nightly/res/drawable-xxxhdpi/branding.png b/android/app/src/nightly/res/drawable-xxxhdpi/branding.png
index 5477b799..42b0bdc2 100644
Binary files a/android/app/src/nightly/res/drawable-xxxhdpi/branding.png and b/android/app/src/nightly/res/drawable-xxxhdpi/branding.png differ
diff --git a/android/app/src/nightly/res/drawable-xxxhdpi/ic_launcher_foreground.png b/android/app/src/nightly/res/drawable-xxxhdpi/ic_launcher_foreground.png
index 3de8a2ee..7e2bb4c3 100644
Binary files a/android/app/src/nightly/res/drawable-xxxhdpi/ic_launcher_foreground.png and b/android/app/src/nightly/res/drawable-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/nightly/res/drawable-xxxhdpi/splash.png b/android/app/src/nightly/res/drawable-xxxhdpi/splash.png
index 68e806f4..a74c95a4 100644
Binary files a/android/app/src/nightly/res/drawable-xxxhdpi/splash.png and b/android/app/src/nightly/res/drawable-xxxhdpi/splash.png differ
diff --git a/android/app/src/nightly/res/drawable/background.png b/android/app/src/nightly/res/drawable/background.png
index 203fc77a..4bebb9de 100644
Binary files a/android/app/src/nightly/res/drawable/background.png and b/android/app/src/nightly/res/drawable/background.png differ
diff --git a/android/app/src/nightly/res/drawable/launch_background.xml b/android/app/src/nightly/res/drawable/launch_background.xml
index 52e8749e..5367a886 100644
--- a/android/app/src/nightly/res/drawable/launch_background.xml
+++ b/android/app/src/nightly/res/drawable/launch_background.xml
@@ -6,7 +6,7 @@
-
- -
+
-
diff --git a/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml
index 83e651db..c79c58a3 100644
--- a/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,6 +1,9 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
+
diff --git a/android/app/src/nightly/res/mipmap-hdpi/ic_launcher.png b/android/app/src/nightly/res/mipmap-hdpi/ic_launcher.png
index a826bb73..8164cc67 100644
Binary files a/android/app/src/nightly/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/nightly/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/nightly/res/mipmap-mdpi/ic_launcher.png b/android/app/src/nightly/res/mipmap-mdpi/ic_launcher.png
index 3743861d..bff95e97 100644
Binary files a/android/app/src/nightly/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/nightly/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/nightly/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/nightly/res/mipmap-xhdpi/ic_launcher.png
index 1be1daa7..df515ed1 100644
Binary files a/android/app/src/nightly/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/nightly/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/nightly/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/nightly/res/mipmap-xxhdpi/ic_launcher.png
index 3a8a7832..e58ef25f 100644
Binary files a/android/app/src/nightly/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/nightly/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/nightly/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/nightly/res/mipmap-xxxhdpi/ic_launcher.png
index 781c9c1a..d39a5e64 100644
Binary files a/android/app/src/nightly/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/nightly/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/assets/fonts/Cookie-Regular.ttf b/assets/fonts/Cookie-Regular.ttf
new file mode 100644
index 00000000..e3ac74eb
Binary files /dev/null and b/assets/fonts/Cookie-Regular.ttf differ
diff --git a/assets/mobile-screenshots/android-4.jpg b/assets/mobile-screenshots/android-4.jpg
index 3057c69a..278aae21 100644
Binary files a/assets/mobile-screenshots/android-4.jpg and b/assets/mobile-screenshots/android-4.jpg differ
diff --git a/assets/mobile-screenshots/combined.png b/assets/mobile-screenshots/combined.png
index 9584e9c7..a7a394f6 100644
Binary files a/assets/mobile-screenshots/combined.png and b/assets/mobile-screenshots/combined.png differ
diff --git a/assets/spotube-logo-foreground.jpg b/assets/spotube-logo-foreground.jpg
deleted file mode 100644
index 0af774c9..00000000
Binary files a/assets/spotube-logo-foreground.jpg and /dev/null differ
diff --git a/assets/spotube-logo-foreground.png b/assets/spotube-logo-foreground.png
new file mode 100644
index 00000000..997d3209
Binary files /dev/null and b/assets/spotube-logo-foreground.png differ
diff --git a/assets/spotube-logo-item.png b/assets/spotube-logo-item.png
new file mode 100644
index 00000000..476dda29
Binary files /dev/null and b/assets/spotube-logo-item.png differ
diff --git a/assets/spotube-logo-light.png b/assets/spotube-logo-light.png
new file mode 100644
index 00000000..8c86d621
Binary files /dev/null and b/assets/spotube-logo-light.png differ
diff --git a/assets/spotube-logo-macos.png b/assets/spotube-logo-macos.png
index b14a7691..2694b530 100644
Binary files a/assets/spotube-logo-macos.png and b/assets/spotube-logo-macos.png differ
diff --git a/assets/spotube-logo.bmp b/assets/spotube-logo.bmp
index c3503e85..f95df092 100644
Binary files a/assets/spotube-logo.bmp and b/assets/spotube-logo.bmp differ
diff --git a/assets/spotube-logo.ico b/assets/spotube-logo.ico
index 84906308..562110b9 100644
Binary files a/assets/spotube-logo.ico and b/assets/spotube-logo.ico differ
diff --git a/assets/spotube-logo.png b/assets/spotube-logo.png
index b24a8c23..d46d9ce5 100644
Binary files a/assets/spotube-logo.png and b/assets/spotube-logo.png differ
diff --git a/assets/spotube-logo.svg b/assets/spotube-logo.svg
deleted file mode 100644
index 5cd88f8e..00000000
--- a/assets/spotube-logo.svg
+++ /dev/null
@@ -1,349 +0,0 @@
-
-
diff --git a/assets/spotube-logo_android12.png b/assets/spotube-logo_android12.png
index f04e25b0..4af89de4 100644
Binary files a/assets/spotube-logo_android12.png and b/assets/spotube-logo_android12.png differ
diff --git a/assets/spotube-nightly-item.png b/assets/spotube-nightly-item.png
new file mode 100644
index 00000000..61ef1c5d
Binary files /dev/null and b/assets/spotube-nightly-item.png differ
diff --git a/assets/spotube-nightly-logo-foreground.jpg b/assets/spotube-nightly-logo-foreground.jpg
deleted file mode 100644
index a0c849b6..00000000
Binary files a/assets/spotube-nightly-logo-foreground.jpg and /dev/null differ
diff --git a/assets/spotube-nightly-logo-foreground.png b/assets/spotube-nightly-logo-foreground.png
new file mode 100644
index 00000000..def278cf
Binary files /dev/null and b/assets/spotube-nightly-logo-foreground.png differ
diff --git a/assets/spotube-nightly-logo-foreground.svg b/assets/spotube-nightly-logo-foreground.svg
new file mode 100644
index 00000000..de2bf370
--- /dev/null
+++ b/assets/spotube-nightly-logo-foreground.svg
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/spotube-nightly-logo.png b/assets/spotube-nightly-logo.png
index ea7a8b20..269aaabc 100644
Binary files a/assets/spotube-nightly-logo.png and b/assets/spotube-nightly-logo.png differ
diff --git a/assets/spotube-nightly-logo.svg b/assets/spotube-nightly-logo.svg
deleted file mode 100644
index 7601108e..00000000
--- a/assets/spotube-nightly-logo.svg
+++ /dev/null
@@ -1,359 +0,0 @@
-
-
diff --git a/assets/spotube-nightly-logo_android12.png b/assets/spotube-nightly-logo_android12.png
index 1a5bf4f1..e5683399 100644
Binary files a/assets/spotube-nightly-logo_android12.png and b/assets/spotube-nightly-logo_android12.png differ
diff --git a/assets/spotube-tall-capsule.png b/assets/spotube-tall-capsule.png
index 43fb8229..53bff791 100644
Binary files a/assets/spotube-tall-capsule.png and b/assets/spotube-tall-capsule.png differ
diff --git a/assets/spotube-wide-capsule-large.png b/assets/spotube-wide-capsule-large.png
index 09a93d83..41614c80 100644
Binary files a/assets/spotube-wide-capsule-large.png and b/assets/spotube-wide-capsule-large.png differ
diff --git a/assets/spotube-wide-capsule-small.png b/assets/spotube-wide-capsule-small.png
index 17566550..e0717dc5 100644
Binary files a/assets/spotube-wide-capsule-small.png and b/assets/spotube-wide-capsule-small.png differ
diff --git a/assets/spotube_banner.png b/assets/spotube_banner.png
index b2be4539..c9450265 100644
Binary files a/assets/spotube_banner.png and b/assets/spotube_banner.png differ
diff --git a/aur-struct/.SRCINFO b/aur-struct/.SRCINFO
index 772594f6..0460932b 100644
--- a/aur-struct/.SRCINFO
+++ b/aur-struct/.SRCINFO
@@ -1,5 +1,5 @@
pkgbase = spotube-bin
-pkgdesc = Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!
+pkgdesc = Open source Music client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!
pkgver = 4.0.0
pkgrel = 1
url = https://spotube.krtirtho.dev
diff --git a/aur-struct/PKGBUILD b/aur-struct/PKGBUILD
index cf6c0134..4f884f0d 100644
--- a/aur-struct/PKGBUILD
+++ b/aur-struct/PKGBUILD
@@ -3,7 +3,7 @@ pkgname=spotube-bin
pkgver=%{{SPOTUBE_VERSION}}%
pkgrel=%{{PKGREL}}%
epoch=
-pkgdesc="Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!"
+pkgdesc="Open source Music client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!"
arch=(x86_64)
url="https://spotube.krtirtho.dev"
license=('BSD-4-Clause')
diff --git a/choco-struct/spotube.nuspec b/choco-struct/spotube.nuspec
index 1ebcd3c7..e3588d98 100644
--- a/choco-struct/spotube.nuspec
+++ b/choco-struct/spotube.nuspec
@@ -23,12 +23,13 @@ enclosed in quotation marks, you should use an editor that supports UTF-8, not t
https://github.com/KRTirtho/spotube
https://spotube.krtirtho.dev
https://github.com/KRTirtho/spotube/issues/new
- spotube music audio spotify youtube flutter
- 🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available
+ spotube music audio youtube flutter
+ 🎧 Open source music client that doesn't require Premium nor uses Electron! Available
for both desktop & mobile!
- Spotube is a Flutter based lightweight spotify client. It utilizes the power
- of Spotify & Youtube's public API & creates a hazardless, performant & resource
+ Spotube is a Flutter based lightweight music client. It utilizes the power
+ of music metadata providers & Youtube's public API & creates a hazardless, performant
+ & resource
friendly User Experience
# Features
@@ -40,10 +41,9 @@ enclosed in quotation marks, you should use an editor that supports UTF-8, not t
- Native performance (Thanks to Flutter+Skia)
- Playback control is done locally instead of on the server
- Small size & less data usage
- - No Spotify or YouTube ads since it uses all public & free APIs (It is still recommended
+ - No ads since it uses all public & free APIs (It is still recommended
to support the creators by watching/liking/subscribing to the artists' YouTube channels or
- liking their tracks on Spotify. Purchasing Spotify Premium is usually the best way to support
- their valuable creations.)
+ liking their tracks on different music platforms.)
- Time synced lyrics
- Downloadable tracks
diff --git a/drift_schemas/app_db/drift_schema_v5.json b/drift_schemas/app_db/drift_schema_v5.json
new file mode 100644
index 00000000..eefe0205
--- /dev/null
+++ b/drift_schemas/app_db/drift_schema_v5.json
@@ -0,0 +1 @@
+{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"authentication_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"cookie","getter_name":"cookie","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"access_token","getter_name":"accessToken","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"expiration","getter_name":"expiration","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":1,"references":[],"type":"table","data":{"name":"blacklist_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"element_type","getter_name":"elementType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(BlacklistedType.values)","dart_type_name":"BlacklistedType"}},{"name":"element_id","getter_name":"elementId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":2,"references":[],"type":"table","data":{"name":"preferences_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"audio_quality","getter_name":"audioQuality","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceQualities.high.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceQualities.values)","dart_type_name":"SourceQualities"}},{"name":"album_color_sync","getter_name":"albumColorSync","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"album_color_sync\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"album_color_sync\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"amoled_dark_theme","getter_name":"amoledDarkTheme","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"amoled_dark_theme\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"amoled_dark_theme\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"check_update","getter_name":"checkUpdate","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"check_update\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"check_update\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"normalize_audio","getter_name":"normalizeAudio","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"normalize_audio\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"normalize_audio\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"show_system_tray_icon","getter_name":"showSystemTrayIcon","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"show_system_tray_icon\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"show_system_tray_icon\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"system_title_bar","getter_name":"systemTitleBar","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"system_title_bar\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"system_title_bar\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"skip_non_music","getter_name":"skipNonMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"skip_non_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"skip_non_music\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"close_behavior","getter_name":"closeBehavior","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(CloseBehavior.close.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(CloseBehavior.values)","dart_type_name":"CloseBehavior"}},{"name":"accent_color_scheme","getter_name":"accentColorScheme","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"Orange:0xFFf97315\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SpotubeColorConverter()","dart_type_name":"SpotubeColor"}},{"name":"layout_mode","getter_name":"layoutMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(LayoutMode.adaptive.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(LayoutMode.values)","dart_type_name":"LayoutMode"}},{"name":"locale","getter_name":"locale","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant('{\"languageCode\":\"system\",\"countryCode\":\"system\"}')","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const LocaleConverter()","dart_type_name":"Locale"}},{"name":"market","getter_name":"market","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(Market.US.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(Market.values)","dart_type_name":"Market"}},{"name":"search_mode","getter_name":"searchMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SearchMode.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SearchMode.values)","dart_type_name":"SearchMode"}},{"name":"download_location","getter_name":"downloadLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[]},{"name":"local_library_location","getter_name":"localLibraryLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}},{"name":"piped_instance","getter_name":"pipedInstance","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"https://pipedapi.kavin.rocks\")","default_client_dart":null,"dsl_features":[]},{"name":"invidious_instance","getter_name":"invidiousInstance","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"https://inv.nadeko.net\")","default_client_dart":null,"dsl_features":[]},{"name":"theme_mode","getter_name":"themeMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(ThemeMode.system.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(ThemeMode.values)","dart_type_name":"ThemeMode"}},{"name":"audio_source","getter_name":"audioSource","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(AudioSource.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(AudioSource.values)","dart_type_name":"AudioSource"}},{"name":"youtube_client_engine","getter_name":"youtubeClientEngine","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(YoutubeClientEngine.youtubeExplode.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(YoutubeClientEngine.values)","dart_type_name":"YoutubeClientEngine"}},{"name":"stream_music_codec","getter_name":"streamMusicCodec","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceCodecs.weba.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceCodecs.values)","dart_type_name":"SourceCodecs"}},{"name":"download_music_codec","getter_name":"downloadMusicCodec","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceCodecs.m4a.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceCodecs.values)","dart_type_name":"SourceCodecs"}},{"name":"discord_presence","getter_name":"discordPresence","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"discord_presence\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"discord_presence\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"endless_playback","getter_name":"endlessPlayback","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"endless_playback\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"endless_playback\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"enable_connect","getter_name":"enableConnect","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"enable_connect\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"enable_connect\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"cache_music","getter_name":"cacheMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"cache_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"cache_music\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":3,"references":[],"type":"table","data":{"name":"scrobbler_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"username","getter_name":"username","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"password_hash","getter_name":"passwordHash","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":4,"references":[],"type":"table","data":{"name":"skip_segment_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"start","getter_name":"start","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"end","getter_name":"end","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":5,"references":[],"type":"table","data":{"name":"source_match_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_id","getter_name":"sourceId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceType.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceType.values)","dart_type_name":"SourceType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":6,"references":[],"type":"table","data":{"name":"audio_player_state_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"playing","getter_name":"playing","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"playing\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"playing\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"loop_mode","getter_name":"loopMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(PlaylistMode.values)","dart_type_name":"PlaylistMode"}},{"name":"shuffled","getter_name":"shuffled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"shuffled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"shuffled\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"collections","getter_name":"collections","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":7,"references":[6],"type":"table","data":{"name":"playlist_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"audio_player_state_id","getter_name":"audioPlayerStateId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES audio_player_state_table (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES audio_player_state_table (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"index","getter_name":"index","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":8,"references":[7],"type":"table","data":{"name":"playlist_media_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"playlist_id","getter_name":"playlistId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES playlist_table (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES playlist_table (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"uri","getter_name":"uri","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"extras","getter_name":"extras","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}},{"name":"http_headers","getter_name":"httpHeaders","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":9,"references":[],"type":"table","data":{"name":"history_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(HistoryEntryType.values)","dart_type_name":"HistoryEntryType"}},{"name":"item_id","getter_name":"itemId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":10,"references":[],"type":"table","data":{"name":"lyrics_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"SubtitleTypeConverter()","dart_type_name":"SubtitleSimple"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":11,"references":[1],"type":"index","data":{"on":1,"name":"unique_blacklist","sql":null,"unique":true,"columns":["element_type","element_id"]}},{"id":12,"references":[5],"type":"index","data":{"on":5,"name":"uniq_track_match","sql":null,"unique":true,"columns":["track_id","source_id","source_type"]}}]}
\ No newline at end of file
diff --git a/drift_schemas/app_db/drift_schema_v6.json b/drift_schemas/app_db/drift_schema_v6.json
new file mode 100644
index 00000000..8a646be1
--- /dev/null
+++ b/drift_schemas/app_db/drift_schema_v6.json
@@ -0,0 +1 @@
+{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"authentication_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"cookie","getter_name":"cookie","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"access_token","getter_name":"accessToken","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"expiration","getter_name":"expiration","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":1,"references":[],"type":"table","data":{"name":"blacklist_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"element_type","getter_name":"elementType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(BlacklistedType.values)","dart_type_name":"BlacklistedType"}},{"name":"element_id","getter_name":"elementId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":2,"references":[],"type":"table","data":{"name":"preferences_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"audio_quality","getter_name":"audioQuality","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceQualities.high.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceQualities.values)","dart_type_name":"SourceQualities"}},{"name":"album_color_sync","getter_name":"albumColorSync","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"album_color_sync\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"album_color_sync\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"amoled_dark_theme","getter_name":"amoledDarkTheme","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"amoled_dark_theme\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"amoled_dark_theme\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"check_update","getter_name":"checkUpdate","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"check_update\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"check_update\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"normalize_audio","getter_name":"normalizeAudio","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"normalize_audio\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"normalize_audio\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"show_system_tray_icon","getter_name":"showSystemTrayIcon","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"show_system_tray_icon\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"show_system_tray_icon\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"system_title_bar","getter_name":"systemTitleBar","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"system_title_bar\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"system_title_bar\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"skip_non_music","getter_name":"skipNonMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"skip_non_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"skip_non_music\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"close_behavior","getter_name":"closeBehavior","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(CloseBehavior.close.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(CloseBehavior.values)","dart_type_name":"CloseBehavior"}},{"name":"accent_color_scheme","getter_name":"accentColorScheme","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"Orange:0xFFf97315\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SpotubeColorConverter()","dart_type_name":"SpotubeColor"}},{"name":"layout_mode","getter_name":"layoutMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(LayoutMode.adaptive.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(LayoutMode.values)","dart_type_name":"LayoutMode"}},{"name":"locale","getter_name":"locale","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant('{\"languageCode\":\"system\",\"countryCode\":\"system\"}')","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const LocaleConverter()","dart_type_name":"Locale"}},{"name":"market","getter_name":"market","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(Market.US.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(Market.values)","dart_type_name":"Market"}},{"name":"search_mode","getter_name":"searchMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SearchMode.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SearchMode.values)","dart_type_name":"SearchMode"}},{"name":"download_location","getter_name":"downloadLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[]},{"name":"local_library_location","getter_name":"localLibraryLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}},{"name":"piped_instance","getter_name":"pipedInstance","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"https://pipedapi.kavin.rocks\")","default_client_dart":null,"dsl_features":[]},{"name":"invidious_instance","getter_name":"invidiousInstance","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"https://inv.nadeko.net\")","default_client_dart":null,"dsl_features":[]},{"name":"theme_mode","getter_name":"themeMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(ThemeMode.system.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(ThemeMode.values)","dart_type_name":"ThemeMode"}},{"name":"audio_source","getter_name":"audioSource","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(AudioSource.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(AudioSource.values)","dart_type_name":"AudioSource"}},{"name":"youtube_client_engine","getter_name":"youtubeClientEngine","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(YoutubeClientEngine.youtubeExplode.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(YoutubeClientEngine.values)","dart_type_name":"YoutubeClientEngine"}},{"name":"stream_music_codec","getter_name":"streamMusicCodec","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceCodecs.weba.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceCodecs.values)","dart_type_name":"SourceCodecs"}},{"name":"download_music_codec","getter_name":"downloadMusicCodec","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceCodecs.m4a.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceCodecs.values)","dart_type_name":"SourceCodecs"}},{"name":"discord_presence","getter_name":"discordPresence","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"discord_presence\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"discord_presence\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"endless_playback","getter_name":"endlessPlayback","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"endless_playback\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"endless_playback\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"enable_connect","getter_name":"enableConnect","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"enable_connect\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"enable_connect\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"connect_port","getter_name":"connectPort","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const Constant(-1)","default_client_dart":null,"dsl_features":[]},{"name":"cache_music","getter_name":"cacheMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"cache_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"cache_music\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":3,"references":[],"type":"table","data":{"name":"scrobbler_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"username","getter_name":"username","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"password_hash","getter_name":"passwordHash","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":4,"references":[],"type":"table","data":{"name":"skip_segment_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"start","getter_name":"start","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"end","getter_name":"end","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":5,"references":[],"type":"table","data":{"name":"source_match_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_id","getter_name":"sourceId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceType.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceType.values)","dart_type_name":"SourceType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":6,"references":[],"type":"table","data":{"name":"audio_player_state_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"playing","getter_name":"playing","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"playing\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"playing\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"loop_mode","getter_name":"loopMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(PlaylistMode.values)","dart_type_name":"PlaylistMode"}},{"name":"shuffled","getter_name":"shuffled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"shuffled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"shuffled\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"collections","getter_name":"collections","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":7,"references":[6],"type":"table","data":{"name":"playlist_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"audio_player_state_id","getter_name":"audioPlayerStateId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES audio_player_state_table (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES audio_player_state_table (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"index","getter_name":"index","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":8,"references":[7],"type":"table","data":{"name":"playlist_media_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"playlist_id","getter_name":"playlistId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES playlist_table (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES playlist_table (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"uri","getter_name":"uri","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"extras","getter_name":"extras","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}},{"name":"http_headers","getter_name":"httpHeaders","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":9,"references":[],"type":"table","data":{"name":"history_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(HistoryEntryType.values)","dart_type_name":"HistoryEntryType"}},{"name":"item_id","getter_name":"itemId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":10,"references":[],"type":"table","data":{"name":"lyrics_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"SubtitleTypeConverter()","dart_type_name":"SubtitleSimple"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":11,"references":[1],"type":"index","data":{"on":1,"name":"unique_blacklist","sql":null,"unique":true,"columns":["element_type","element_id"]}},{"id":12,"references":[5],"type":"index","data":{"on":5,"name":"uniq_track_match","sql":null,"unique":true,"columns":["track_id","source_id","source_type"]}}]}
\ No newline at end of file
diff --git a/flutter_launcher_icons-nightly.yaml b/flutter_launcher_icons-nightly.yaml
index c6892d4b..770033bd 100644
--- a/flutter_launcher_icons-nightly.yaml
+++ b/flutter_launcher_icons-nightly.yaml
@@ -2,5 +2,5 @@ flutter_launcher_icons:
android: true
ios: true
image_path: "assets/spotube-nightly-logo.png"
- adaptive_icon_foreground: "assets/spotube-nightly-logo-foreground.jpg"
+ adaptive_icon_foreground: "assets/spotube-nightly-logo-foreground.png"
adaptive_icon_background: "#242832"
diff --git a/flutter_launcher_icons.yaml b/flutter_launcher_icons.yaml
index 372117b1..2c558583 100644
--- a/flutter_launcher_icons.yaml
+++ b/flutter_launcher_icons.yaml
@@ -6,7 +6,7 @@ flutter_launcher_icons:
# image_path_android: "assets/icon/icon.png"
min_sdk_android: 21 # android min sdk min:16, default 21
adaptive_icon_background: "#242832"
- adaptive_icon_foreground: "assets/spotube-logo-foreground.jpg"
+ adaptive_icon_foreground: "assets/spotube-logo-foreground.png"
# adaptive_icon_monochrome: "assets/icon/monochrome.png"
ios: true
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index bbfc1404..88a40d6f 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -2135,7 +2135,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2159,7 +2159,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2183,7 +2183,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2207,7 +2207,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2230,7 +2230,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2253,7 +2253,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2276,7 +2276,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2299,7 +2299,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2322,7 +2322,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2472,7 +2472,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2617,7 +2617,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2759,7 +2759,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
@@ -2781,9 +2781,9 @@
E612EC4A2D0F07AD0022720C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -2824,9 +2824,9 @@
E612EC4B2D0F07AD0022720C /* Debug-nightly */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -2867,9 +2867,9 @@
E612EC4C2D0F07AD0022720C /* Debug-dev */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -2910,9 +2910,9 @@
E612EC4D2D0F07AD0022720C /* Debug-stable */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -2953,9 +2953,9 @@
E612EC4E2D0F07AD0022720C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -2993,9 +2993,9 @@
E612EC4F2D0F07AD0022720C /* Release-nightly */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -3033,9 +3033,9 @@
E612EC502D0F07AD0022720C /* Release-dev */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -3073,9 +3073,9 @@
E612EC512D0F07AD0022720C /* Release-stable */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -3113,9 +3113,9 @@
E612EC522D0F07AD0022720C /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -3153,9 +3153,9 @@
E612EC532D0F07AD0022720C /* Profile-nightly */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -3193,9 +3193,9 @@
E612EC542D0F07AD0022720C /* Profile-dev */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
@@ -3233,9 +3233,9 @@
E612EC552D0F07AD0022720C /* Profile-stable */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-1024x1024@1x.png
index dbc4596b..2185c35d 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-1024x1024@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@1x.png
index 4836771d..172bc383 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@2x.png
index 90954ce9..876617d9 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@3x.png
index 9c0ebd5f..fec86d87 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@1x.png
index 94cd79be..fbb0f45a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@2x.png
index ff70cab7..854e1e45 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@3x.png
index 6cdda1b6..420d2a17 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@1x.png
index 90954ce9..876617d9 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@2x.png
index 5184f84f..6b7a608d 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@3x.png
index 57e21a75..d871fa3f 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@1x.png
index 93e157b6..e77b38df 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@2x.png
index d175beb2..358cb28f 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@1x.png
index 6d634c87..87f4290b 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@2x.png
index 22da4950..53c10a09 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@2x.png
index 57e21a75..d871fa3f 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@3x.png
index 3cfd01c2..4bb39789 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@1x.png
index a826bb73..8164cc67 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@2x.png
index 3a8a7832..e58ef25f 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@1x.png
index f233322b..f5e1ae5a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@2x.png
index 2f5b082a..99bd36c9 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-83.5x83.5@2x.png
index e4ecc19a..8d199658 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-83.5x83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
index 05843b52..d0d98aa1 100644
--- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1 +1 @@
-{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
+{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 00000000..59407b44
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 00000000..5eacaa5f
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 00000000..bbb9f839
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 00000000..28d0d8a8
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 00000000..b1df0e72
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 00000000..24b76e25
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 00000000..5c0b6d57
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 00000000..bbb9f839
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 00000000..bdc5656b
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 00000000..c03c89fe
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
new file mode 100644
index 00000000..40b88968
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
new file mode 100644
index 00000000..2050f427
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
new file mode 100644
index 00000000..d1ccab30
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
new file mode 100644
index 00000000..47c629f3
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 00000000..c03c89fe
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 00000000..22d28c12
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
new file mode 100644
index 00000000..c9e5cfad
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
new file mode 100644
index 00000000..3450fb00
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 00000000..3dd3eda3
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 00000000..2e69c843
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 00000000..f769eb6e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png b/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png
index 5a197da3..3ff2a2da 100644
Binary files a/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png and b/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png differ
diff --git a/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png b/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png
index efc7e6c8..8e2bb197 100644
Binary files a/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png and b/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png b/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png
index 593877e0..d301093a 100644
Binary files a/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png and b/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage.png b/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage.png
index 80579983..3ff2a2da 100644
Binary files a/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage.png and b/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage.png differ
diff --git a/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@2x.png b/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@2x.png
index 0bcf138d..8e2bb197 100644
Binary files a/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@2x.png and b/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@3x.png b/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@3x.png
index c7d01776..d301093a 100644
Binary files a/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@3x.png and b/ios/Runner/Assets.xcassets/BrandingImageNightly.imageset/BrandingImage@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png
index 203fc77a..4bebb9de 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchBackgroundNightly.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackgroundNightly.imageset/background.png
index 203fc77a..4bebb9de 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchBackgroundNightly.imageset/background.png and b/ios/Runner/Assets.xcassets/LaunchBackgroundNightly.imageset/background.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
index c5e4aca0..6e04efdc 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
index 41222c6c..51a669aa 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
index 5ab19d32..cc79cb85 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage.png
index 86d3fe74..d8f7cc0e 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage.png and b/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@2x.png
index dbb0ea02..17a2c373 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@2x.png and b/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@3x.png
index 12eb5531..db53f016 100644
Binary files a/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@3x.png and b/ios/Runner/Assets.xcassets/LaunchImageNightly.imageset/LaunchImage@3x.png differ
diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard
index 208e1c53..ec8a1de3 100644
--- a/ios/Runner/Base.lproj/LaunchScreen.storyboard
+++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -22,7 +22,7 @@
-
+
diff --git a/ios/Runner/Base.lproj/LaunchScreenNightly.storyboard b/ios/Runner/Base.lproj/LaunchScreenNightly.storyboard
index 6869214f..645a417f 100644
--- a/ios/Runner/Base.lproj/LaunchScreenNightly.storyboard
+++ b/ios/Runner/Base.lproj/LaunchScreenNightly.storyboard
@@ -22,7 +22,7 @@
-
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 91b7ad94..8d6c09a2 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -1,82 +1,82 @@
-
- CADisableMinimumFrameDurationOnPhone
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- Spotube
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- spotube
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- $(FLUTTER_BUILD_NAME)
- CFBundleSignature
- ????
- CFBundleVersion
- $(FLUTTER_BUILD_NUMBER)
- LSRequiresIPhoneOS
-
- NSAppTransportSecurity
-
- NSAllowsArbitraryLoads
-
- NSAllowsArbitraryLoadsForMedia
-
-
- NSCameraUsageDescription
- This app require access to the device camera
- NSMicrophoneUsageDescription
- This app does not require access to the device microphone
- NSPhotoLibraryUsageDescription
- This app require access to the photo library
- UIApplicationSupportsIndirectInputEvents
-
- UIBackgroundModes
-
- audio
-
- UILaunchStoryboardName
- LaunchScreen
- UIMainStoryboardFile
- Main
- UIStatusBarHidden
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UISupportedInterfaceOrientations~ipad
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UIViewControllerBasedStatusBarAppearance
-
- NSLocalNetworkUsageDescription
- To allow other devices on the network control playback of Spotube securely.
- NSBonjourServices
-
- _spotube._tcp
-
- UIFileSharingEnabled
-
- LSSupportsOpeningDocumentsInPlace
-
- UISupportsDocumentBrowser
-
-
+
+ CADisableMinimumFrameDurationOnPhone
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Spotube
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ spotube
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+ NSAllowsArbitraryLoadsForMedia
+
+
+ NSCameraUsageDescription
+ This app require access to the device camera
+ NSMicrophoneUsageDescription
+ This app does not require access to the device microphone
+ NSPhotoLibraryUsageDescription
+ This app require access to the photo library
+ UIApplicationSupportsIndirectInputEvents
+
+ UIBackgroundModes
+
+ audio
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIStatusBarHidden
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ NSLocalNetworkUsageDescription
+ To allow other devices on the network control playback of Spotube securely.
+ NSBonjourServices
+
+ _spotube._tcp
+
+ UIFileSharingEnabled
+
+ LSSupportsOpeningDocumentsInPlace
+
+ UISupportsDocumentBrowser
+
+
diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart
index 004001f2..09b6cdd2 100644
--- a/lib/collections/assets.gen.dart
+++ b/lib/collections/assets.gen.dart
@@ -151,7 +151,11 @@ class Assets {
static const AssetGenImage spotubeHeroBanner =
AssetGenImage('assets/spotube-hero-banner.png');
static const AssetGenImage spotubeLogoForeground =
- AssetGenImage('assets/spotube-logo-foreground.jpg');
+ AssetGenImage('assets/spotube-logo-foreground.png');
+ static const AssetGenImage spotubeLogoItem =
+ AssetGenImage('assets/spotube-logo-item.png');
+ static const AssetGenImage spotubeLogoLight =
+ AssetGenImage('assets/spotube-logo-light.png');
static const AssetGenImage spotubeLogoMacos =
AssetGenImage('assets/spotube-logo-macos.png');
static const AssetGenImage spotubeLogoBmp =
@@ -159,14 +163,16 @@ class Assets {
static const String spotubeLogoIco = 'assets/spotube-logo.ico';
static const AssetGenImage spotubeLogoPng =
AssetGenImage('assets/spotube-logo.png');
- static const String spotubeLogoSvg = 'assets/spotube-logo.svg';
static const AssetGenImage spotubeLogoAndroid12 =
AssetGenImage('assets/spotube-logo_android12.png');
- static const AssetGenImage spotubeNightlyLogoForeground =
- AssetGenImage('assets/spotube-nightly-logo-foreground.jpg');
- static const AssetGenImage spotubeNightlyLogoPng =
+ static const AssetGenImage spotubeNightlyItem =
+ AssetGenImage('assets/spotube-nightly-item.png');
+ static const AssetGenImage spotubeNightlyLogoForegroundPng =
+ AssetGenImage('assets/spotube-nightly-logo-foreground.png');
+ static const String spotubeNightlyLogoForegroundSvg =
+ 'assets/spotube-nightly-logo-foreground.svg';
+ static const AssetGenImage spotubeNightlyLogo =
AssetGenImage('assets/spotube-nightly-logo.png');
- static const String spotubeNightlyLogoSvg = 'assets/spotube-nightly-logo.svg';
static const AssetGenImage spotubeNightlyLogoAndroid12 =
AssetGenImage('assets/spotube-nightly-logo_android12.png');
static const AssetGenImage spotubeScreenshot =
@@ -197,15 +203,17 @@ class Assets {
placeholder,
spotubeHeroBanner,
spotubeLogoForeground,
+ spotubeLogoItem,
+ spotubeLogoLight,
spotubeLogoMacos,
spotubeLogoBmp,
spotubeLogoIco,
spotubeLogoPng,
- spotubeLogoSvg,
spotubeLogoAndroid12,
- spotubeNightlyLogoForeground,
- spotubeNightlyLogoPng,
- spotubeNightlyLogoSvg,
+ spotubeNightlyItem,
+ spotubeNightlyLogoForegroundPng,
+ spotubeNightlyLogoForegroundSvg,
+ spotubeNightlyLogo,
spotubeNightlyLogoAndroid12,
spotubeScreenshot,
spotubeTallCapsule,
diff --git a/lib/collections/fake.dart b/lib/collections/fake.dart
index 31f97e0c..8af40e71 100644
--- a/lib/collections/fake.dart
+++ b/lib/collections/fake.dart
@@ -94,6 +94,7 @@ abstract class FakeData {
..trackNumber = 1
..type = "type"
..uri = "uri"
+ ..externalIds = externalIds
..isPlayable = true
..explicit = false
..linkedFrom = trackLink;
diff --git a/lib/collections/intents.dart b/lib/collections/intents.dart
index e4e3fa07..42c580ca 100644
--- a/lib/collections/intents.dart
+++ b/lib/collections/intents.dart
@@ -75,7 +75,7 @@ class HomeTabAction extends Action {
router.navigate(const SearchRoute());
break;
case HomeTabs.lyrics:
- router.navigate(LyricsRoute());
+ router.navigate(const LyricsRoute());
break;
case HomeTabs.userPlaylists:
router.navigate(const UserPlaylistsRoute());
diff --git a/lib/collections/side_bar_tiles.dart b/lib/collections/side_bar_tiles.dart
index 80ca7306..c647c9fb 100644
--- a/lib/collections/side_bar_tiles.dart
+++ b/lib/collections/side_bar_tiles.dart
@@ -38,7 +38,7 @@ List getSidebarTileList(AppLocalizations l10n) => [
SideBarTiles(
id: "lyrics",
pathPrefix: "/lyrics",
- route: LyricsRoute(),
+ route: const LyricsRoute(),
icon: SpotubeIcons.music,
title: l10n.lyrics,
),
diff --git a/lib/components/adaptive/adaptive_pop_sheet_list.dart b/lib/components/adaptive/adaptive_pop_sheet_list.dart
index 0f02ee73..6eba1148 100644
--- a/lib/components/adaptive/adaptive_pop_sheet_list.dart
+++ b/lib/components/adaptive/adaptive_pop_sheet_list.dart
@@ -1,4 +1,3 @@
-import 'package:flutter/material.dart' show showModalBottomSheet;
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/spotube_icons.dart';
@@ -26,7 +25,7 @@ class AdaptiveMenuButton extends MenuButton {
/// An adaptive widget that shows a [PopupMenuButton] when screen size is above
/// or equal to 640px
-/// In smaller screen, a [IconButton] with a [showModalBottomSheet] is shown
+/// In smaller screen, a [IconButton] with a [openDrawer] is shown
class AdaptivePopSheetList extends StatelessWidget {
final List> Function(BuildContext context) items;
final Widget? icon;
@@ -39,7 +38,7 @@ class AdaptivePopSheetList extends StatelessWidget {
final Offset offset;
- final ButtonVariance variance;
+ final AbstractButtonStyle variance;
const AdaptivePopSheetList({
super.key,
@@ -92,23 +91,23 @@ class AdaptivePopSheetList extends StatelessWidget {
// ),
position: position,
builder: (context) {
- return DropdownMenu(
- children: childrenModified(context),
+ return WidgetStatesProvider.boundary(
+ child: DropdownMenu(
+ children: childrenModified(context),
+ ),
);
},
).future;
return;
}
- showModalBottomSheet(
+ await openDrawer(
context: context,
- enableDrag: true,
+ draggable: true,
showDragHandle: true,
- useRootNavigator: true,
- shape: RoundedRectangleBorder(
- borderRadius: context.theme.borderRadiusMd,
- ),
- backgroundColor: context.theme.colorScheme.card,
+ position: OverlayPosition.bottom,
+ borderRadius: context.theme.borderRadiusMd,
+ transformBackdrop: false,
builder: (context) {
final children = childrenModified(context);
return ListView.builder(
@@ -125,7 +124,7 @@ class AdaptivePopSheetList extends StatelessWidget {
onPressed: () {
data.onPressed?.call(context);
if (data.autoClose) {
- Navigator.of(context).pop();
+ closeDrawer(context);
}
},
leading: data.leading,
@@ -147,7 +146,7 @@ class AdaptivePopSheetList extends StatelessWidget {
return Tooltip(
tooltip: TooltipContainer(
child: Text(tooltip),
- ),
+ ).call,
child: IconButton(
variance: variance,
icon: icon ?? const Icon(SpotubeIcons.moreVertical),
@@ -171,7 +170,7 @@ class AdaptivePopSheetList extends StatelessWidget {
if (child != null) {
return Tooltip(
- tooltip: TooltipContainer(child: Text(tooltip)),
+ tooltip: TooltipContainer(child: Text(tooltip)).call,
child: Button(
onPressed: () => showDropdownMenu(context, Offset.zero),
style: variance,
@@ -181,7 +180,7 @@ class AdaptivePopSheetList extends StatelessWidget {
}
return Tooltip(
- tooltip: TooltipContainer(child: Text(tooltip)),
+ tooltip: TooltipContainer(child: Text(tooltip)).call,
child: IconButton(
variance: variance,
icon: icon ?? const Icon(SpotubeIcons.moreVertical),
diff --git a/lib/components/expandable_search/expandable_search.dart b/lib/components/expandable_search/expandable_search.dart
index 0c40b843..279a3e5f 100644
--- a/lib/components/expandable_search/expandable_search.dart
+++ b/lib/components/expandable_search/expandable_search.dart
@@ -40,7 +40,9 @@ class ExpandableSearchField extends StatelessWidget {
focusNode: searchFocus,
controller: searchController,
placeholder: Text(context.l10n.search_tracks),
- leading: const Icon(SpotubeIcons.search),
+ features: const [
+ InputFeature.leading(Icon(SpotubeIcons.search))
+ ],
),
),
),
diff --git a/lib/components/form/text_form_field.dart b/lib/components/form/text_form_field.dart
index 56ef34a5..b07c33e3 100644
--- a/lib/components/form/text_form_field.dart
+++ b/lib/components/form/text_form_field.dart
@@ -15,8 +15,7 @@ class TextFormBuilderField extends StatelessWidget {
// final AlignmentGeometry? leadingAlignment;
// final AlignmentGeometry? trailingAlignment;
final bool border;
- final Widget? leading;
- final Widget? trailing;
+ final List features;
final EdgeInsetsGeometry? padding;
final ValueChanged? onSubmitted;
final VoidCallback? onEditingComplete;
@@ -63,8 +62,6 @@ class TextFormBuilderField extends StatelessWidget {
this.filled = false,
this.placeholder,
this.border = true,
- this.leading,
- this.trailing,
this.padding,
this.onSubmitted,
this.onEditingComplete,
@@ -96,6 +93,7 @@ class TextFormBuilderField extends StatelessWidget {
// this.leadingAlignment,
// this.trailingAlignment,
this.statesController,
+ this.features = const [],
});
@override
@@ -130,8 +128,7 @@ class TextFormBuilderField extends StatelessWidget {
filled: filled,
placeholder: placeholder,
border: border,
- leading: leading,
- trailing: trailing,
+ features: features,
padding: padding,
onSubmitted: (value) {
field.validate();
diff --git a/lib/components/heart_button/heart_button.dart b/lib/components/heart_button/heart_button.dart
index 56cb22ab..275d5db1 100644
--- a/lib/components/heart_button/heart_button.dart
+++ b/lib/components/heart_button/heart_button.dart
@@ -13,7 +13,7 @@ class HeartButton extends HookConsumerWidget {
final IconData? icon;
final Color? color;
final String? tooltip;
- final ButtonVariance variance;
+ final AbstractButtonStyle variance;
final ButtonSize size;
const HeartButton({
required this.isLiked,
@@ -33,7 +33,7 @@ class HeartButton extends HookConsumerWidget {
if (auth.asData?.value == null) return const SizedBox.shrink();
return Tooltip(
- tooltip: TooltipContainer(child: Text(tooltip ?? "")),
+ tooltip: TooltipContainer(child: Text(tooltip ?? "")).call,
child: IconButton(
variance: variance,
size: size,
diff --git a/lib/components/playbutton_view/playbutton_card.dart b/lib/components/playbutton_view/playbutton_card.dart
index 0b47ae28..ea28c738 100644
--- a/lib/components/playbutton_view/playbutton_card.dart
+++ b/lib/components/playbutton_view/playbutton_card.dart
@@ -151,7 +151,7 @@ class PlaybuttonCard extends StatelessWidget {
],
),
title: Tooltip(
- tooltip: TooltipContainer(child: Text(title)),
+ tooltip: TooltipContainer(child: Text(title)).call,
child: Text(
title,
maxLines: 1,
diff --git a/lib/components/playbutton_view/playbutton_tile.dart b/lib/components/playbutton_view/playbutton_tile.dart
index ec1ca95f..7470105d 100644
--- a/lib/components/playbutton_view/playbutton_tile.dart
+++ b/lib/components/playbutton_view/playbutton_tile.dart
@@ -71,7 +71,7 @@ class PlaybuttonTile extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Tooltip(
- tooltip: TooltipContainer(child: Text(context.l10n.add_to_queue)),
+ tooltip: TooltipContainer(child: Text(context.l10n.add_to_queue)).call,
child: IconButton.outline(
icon: const Icon(SpotubeIcons.queueAdd),
onPressed: onAddToQueuePressed,
@@ -80,7 +80,7 @@ class PlaybuttonTile extends StatelessWidget {
),
const Gap(8),
Tooltip(
- tooltip: TooltipContainer(child: Text(context.l10n.play)),
+ tooltip: TooltipContainer(child: Text(context.l10n.play)).call,
child: IconButton.secondary(
icon: switch ((isLoading, isPlaying)) {
(true, _) => const CircularProgressIndicator(
diff --git a/lib/components/shimmers/shimmer_lyrics.dart b/lib/components/shimmers/shimmer_lyrics.dart
index f8d29722..9312865e 100644
--- a/lib/components/shimmers/shimmer_lyrics.dart
+++ b/lib/components/shimmers/shimmer_lyrics.dart
@@ -1,6 +1,5 @@
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:gap/gap.dart';
import 'package:skeletonizer/skeletonizer.dart';
diff --git a/lib/components/titlebar/titlebar_icon_buttons.dart b/lib/components/titlebar/titlebar_icon_buttons.dart
index 481a22ce..0a3f6178 100644
--- a/lib/components/titlebar/titlebar_icon_buttons.dart
+++ b/lib/components/titlebar/titlebar_icon_buttons.dart
@@ -1,7 +1,6 @@
import 'dart:math';
import 'package:shadcn_flutter/shadcn_flutter.dart';
-import 'package:spotube/extensions/button_variance.dart';
class ShadcnWindowButton extends StatelessWidget {
final Widget icon;
@@ -22,7 +21,7 @@ class ShadcnWindowButton extends StatelessWidget {
height: 32,
child: IconButton(
variance: ButtonVariance.ghost.copyWith(
- decoration: (context, states) {
+ decoration: (context, states, value) {
final decoration = ButtonVariance.ghost.decoration(context, states)
as BoxDecoration;
if (hoverBackgroundColor != null &&
diff --git a/lib/components/track_presentation/presentation_actions.dart b/lib/components/track_presentation/presentation_actions.dart
index 4948cf69..bbeb90a5 100644
--- a/lib/components/track_presentation/presentation_actions.dart
+++ b/lib/components/track_presentation/presentation_actions.dart
@@ -74,6 +74,26 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
ref.watch(presentationStateProvider(options.collection).notifier);
final selectedTracks = state.selectedTracks;
+ Future actionDownloadTracks({
+ required BuildContext context,
+ required List tracks,
+ required String action,
+ }) async {
+ final confirmed = audioSource == AudioSource.piped ||
+ (await showDialog(
+ context: context,
+ builder: (context) {
+ return const ConfirmDownloadDialog();
+ },
+ ) ??
+ false);
+ if (confirmed != true) return;
+ downloader.batchAddToQueue(tracks);
+ notifier.deselectAllTracks();
+ if (!context.mounted) return;
+ showToastForAction(context, action, tracks.length);
+ }
+
return AdaptivePopSheetList(
tooltip: context.l10n.more_actions,
headings: [
@@ -95,22 +115,12 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
switch (action) {
case "download":
- {
- final confirmed = audioSource == AudioSource.piped ||
- (await showDialog(
- context: context,
- builder: (context) {
- return const ConfirmDownloadDialog();
- },
- ) ??
- false);
- if (confirmed != true) return;
- downloader.batchAddToQueue(tracks);
- notifier.deselectAllTracks();
- if (!context.mounted) return;
- showToastForAction(context, action, tracks.length);
- break;
- }
+ await actionDownloadTracks(
+ context: context,
+ tracks: tracks,
+ action: action,
+ );
+ break;
case "add-to-playlist":
{
if (context.mounted) {
diff --git a/lib/components/track_presentation/presentation_modifiers.dart b/lib/components/track_presentation/presentation_modifiers.dart
index c46fef3f..42c3cb4f 100644
--- a/lib/components/track_presentation/presentation_modifiers.dart
+++ b/lib/components/track_presentation/presentation_modifiers.dart
@@ -67,10 +67,6 @@ class TrackPresentationModifiersSection extends HookConsumerWidget {
child: TextField(
controller: controller,
focusNode: focusNode,
- leading: Icon(
- SpotubeIcons.search,
- color: context.theme.colorScheme.mutedForeground,
- ),
placeholder: Text(context.l10n.search_tracks),
onChanged: (value) {
if (value.isEmpty) {
@@ -79,30 +75,41 @@ class TrackPresentationModifiersSection extends HookConsumerWidget {
notifier.filterTracks(value);
}
},
- trailing: ListenableBuilder(
- listenable: controller,
- builder: (context, _) {
- return AnimatedCrossFade(
- duration: const Duration(milliseconds: 300),
- crossFadeState: controller.text.isEmpty
- ? CrossFadeState.showFirst
- : CrossFadeState.showSecond,
- firstChild:
- const SizedBox.square(dimension: 20),
- secondChild: AnimatedScale(
- duration: const Duration(milliseconds: 300),
- scale: controller.text.isEmpty ? 0 : 1,
- child: IconButton.ghost(
- size: const ButtonSize(.6),
- icon: const Icon(SpotubeIcons.close),
- onPressed: () {
- controller.clear();
- notifier.clearFilter();
- },
- ),
- ),
- );
- }),
+ features: [
+ InputFeature.leading(
+ Icon(
+ SpotubeIcons.search,
+ color: context.theme.colorScheme.mutedForeground,
+ ),
+ ),
+ InputFeature.trailing(
+ ListenableBuilder(
+ listenable: controller,
+ builder: (context, _) {
+ return AnimatedCrossFade(
+ duration: const Duration(milliseconds: 300),
+ crossFadeState: controller.text.isEmpty
+ ? CrossFadeState.showFirst
+ : CrossFadeState.showSecond,
+ firstChild:
+ const SizedBox.square(dimension: 20),
+ secondChild: AnimatedScale(
+ duration:
+ const Duration(milliseconds: 300),
+ scale: controller.text.isEmpty ? 0 : 1,
+ child: IconButton.ghost(
+ size: const ButtonSize(.6),
+ icon: const Icon(SpotubeIcons.close),
+ onPressed: () {
+ controller.clear();
+ notifier.clearFilter();
+ },
+ ),
+ ),
+ );
+ }),
+ )
+ ],
),
),
),
diff --git a/lib/components/track_presentation/presentation_top.dart b/lib/components/track_presentation/presentation_top.dart
index 8da2f51c..5935fa13 100644
--- a/lib/components/track_presentation/presentation_top.dart
+++ b/lib/components/track_presentation/presentation_top.dart
@@ -57,7 +57,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.shuffle_playlist),
- ),
+ ).call,
child: IconButton.secondary(
icon: isLoading
? const Center(
@@ -73,7 +73,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.add_to_queue),
- ),
+ ).call,
child: IconButton.secondary(
icon: const Icon(SpotubeIcons.queueAdd),
enabled: !isLoading && !isActive,
@@ -126,7 +126,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.share),
- ),
+ ).call,
child: IconButton.outline(
icon: const Icon(SpotubeIcons.share),
size: ButtonSize.small,
diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart
index 05e67d02..a0738165 100644
--- a/lib/components/track_tile/track_options.dart
+++ b/lib/components/track_tile/track_options.dart
@@ -91,24 +91,14 @@ class TrackOptions extends HookConsumerWidget {
) {
/// showDialog doesn't work for some reason. So we have to
/// manually push a Dialog Route in the Navigator to get it working
- Navigator.push(
- context,
- DialogRoute(
- alignment: Alignment.bottomCenter,
- transitionBuilder: (context, animation, secondaryAnimation, child) {
- return FadeTransition(opacity: animation, child: child);
- },
- context: context,
- barrierColor: Colors.black.withValues(alpha: 0.5),
- builder: (context) {
- return Center(
- child: PlaylistAddTrackDialog(
- tracks: [track],
- openFromPlaylist: playlistId,
- ),
- );
- },
- ),
+ showDialog(
+ context: context,
+ builder: (context) {
+ return PlaylistAddTrackDialog(
+ tracks: [track],
+ openFromPlaylist: playlistId,
+ );
+ },
);
}
@@ -338,6 +328,7 @@ class TrackOptions extends HookConsumerWidget {
}
},
icon: icon ?? const Icon(SpotubeIcons.moreHorizontal),
+ variance: ButtonVariance.outline,
headings: [
Basic(
leading: AspectRatio(
@@ -483,7 +474,7 @@ class TrackOptions extends HookConsumerWidget {
leading: Assets.logos.songlinkTransparent.image(
width: 22,
height: 22,
- color: colorScheme.foreground.withOpacity(0.5),
+ color: colorScheme.foreground.withValues(alpha: 0.5),
),
child: Text(context.l10n.song_link),
),
diff --git a/lib/components/track_tile/track_tile.dart b/lib/components/track_tile/track_tile.dart
index 524575e5..f47980cd 100644
--- a/lib/components/track_tile/track_tile.dart
+++ b/lib/components/track_tile/track_tile.dart
@@ -5,7 +5,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:skeletonizer/skeletonizer.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/collections/routes.gr.dart';
@@ -17,7 +17,6 @@ import 'package:spotube/components/links/link_text.dart';
import 'package:spotube/components/track_tile/track_options.dart';
import 'package:spotube/components/ui/button_tile.dart';
import 'package:spotube/extensions/artist_simple.dart';
-import 'package:spotube/extensions/button_variance.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/duration.dart';
import 'package:spotube/extensions/image.dart';
@@ -108,7 +107,7 @@ class TrackTile extends HookConsumerWidget {
? ButtonVariance.destructive
: ButtonVariance.ghost)
.copyWith(
- padding: (context, states) =>
+ padding: (context, states, value) =>
const EdgeInsets.symmetric(vertical: 8, horizontal: 0),
),
leading: Row(
@@ -229,7 +228,8 @@ class TrackTile extends HookConsumerWidget {
Flexible(
child: Button(
style: ButtonVariance.link.copyWith(
- padding: (context, states) => EdgeInsets.zero,
+ padding: (context, states, value) =>
+ EdgeInsets.zero,
),
onPressed: () {
context
diff --git a/lib/components/ui/button_tile.dart b/lib/components/ui/button_tile.dart
index 8f5a7581..e31a09a5 100644
--- a/lib/components/ui/button_tile.dart
+++ b/lib/components/ui/button_tile.dart
@@ -9,7 +9,7 @@ class ButtonTile extends StatelessWidget {
final VoidCallback? onPressed;
final VoidCallback? onLongPress;
final bool selected;
- final ButtonVariance style;
+ final AbstractButtonStyle style;
final EdgeInsets? padding;
const ButtonTile({
diff --git a/lib/extensions/track.dart b/lib/extensions/track.dart
index 215a5ab2..92d8b0da 100644
--- a/lib/extensions/track.dart
+++ b/lib/extensions/track.dart
@@ -4,7 +4,9 @@ import 'dart:typed_data';
import 'package:metadata_god/metadata_god.dart';
import 'package:path/path.dart';
import 'package:spotify/spotify.dart';
+import 'package:spotube/provider/spotify/spotify.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
+import 'package:spotube/services/logger/logger.dart';
extension TrackExtensions on Track {
Track fromFile(
@@ -67,27 +69,40 @@ extension TrackExtensions on Track {
}
}
-extension TrackSimpleExtensions on TrackSimple {
- Track asTrack(AlbumSimple album) {
- Track track = Track();
- track.name = name;
- track.album = album;
- track.artists = artists;
- track.availableMarkets = availableMarkets;
- track.discNumber = discNumber;
- track.durationMs = durationMs;
- track.explicit = explicit;
- track.externalUrls = externalUrls;
- track.href = href;
- track.id = id;
- track.isPlayable = isPlayable;
- track.linkedFrom = linkedFrom;
- track.name = name;
- track.previewUrl = previewUrl;
- track.trackNumber = trackNumber;
- track.type = type;
- track.uri = uri;
- return track;
+extension IterableTrackSimpleExtensions on Iterable {
+ Future> asTracks(AlbumSimple album, ref) async {
+ try {
+ final spotify = ref.read(spotifyProvider);
+ final tracks = await spotify.invoke(
+ (api) => api.tracks.list(map((trackSimple) => trackSimple.id!).toList()));
+ return tracks.toList();
+ } catch (e, stack) {
+ // Ignore errors and create the track locally
+ AppLogger.reportError(e, stack);
+
+ List tracks = [];
+ for (final trackSimple in this) {
+ Track track = Track();
+ track.album = album;
+ track.name = trackSimple.name;
+ track.artists = trackSimple.artists;
+ track.availableMarkets = trackSimple.availableMarkets;
+ track.discNumber = trackSimple.discNumber;
+ track.durationMs = trackSimple.durationMs;
+ track.explicit = trackSimple.explicit;
+ track.externalUrls = trackSimple.externalUrls;
+ track.href = trackSimple.href;
+ track.id = trackSimple.id;
+ track.isPlayable = trackSimple.isPlayable;
+ track.linkedFrom = trackSimple.linkedFrom;
+ track.previewUrl = trackSimple.previewUrl;
+ track.trackNumber = trackSimple.trackNumber;
+ track.type = trackSimple.type;
+ track.uri = trackSimple.uri;
+ tracks.add(track);
+ }
+ return tracks;
+ }
}
}
diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb
index f4cbde9b..4a7f176d 100644
--- a/lib/l10n/app_ar.arb
+++ b/lib/l10n/app_ar.arb
@@ -426,5 +426,9 @@
"download": "تنزيل",
"file_not_found": "الملف غير موجود",
"custom": "مخصص",
- "add_custom_url": "إضافة URL مخصص"
+ "add_custom_url": "إضافة URL مخصص",
+ "edit_port": "تعديل المنفذ",
+ "port_helper_msg": "القيمة الافتراضية هي -1 والتي تشير إلى رقم عشوائي. إذا كان لديك جدار ناري مُعد، يُوصى بتعيين هذا.",
+ "connect_request": "السماح لـ {client} بالاتصال؟",
+ "connection_request_denied": "تم رفض الاتصال. المستخدم رفض الوصول."
}
\ No newline at end of file
diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb
index cc2971ce..7d5a3e5a 100644
--- a/lib/l10n/app_bn.arb
+++ b/lib/l10n/app_bn.arb
@@ -426,5 +426,9 @@
"download": "ডাউনলোড",
"file_not_found": "ফাইল পাওয়া যায়নি",
"custom": "কাস্টম",
- "add_custom_url": "কাস্টম URL যোগ করুন"
+ "add_custom_url": "কাস্টম URL যোগ করুন",
+ "edit_port": "পোর্ট সম্পাদনা করুন",
+ "port_helper_msg": "ডিফল্ট হল -1 যা এলোমেলো সংখ্যা নির্দেশ করে। যদি আপনার ফায়ারওয়াল কনফিগার করা থাকে, তবে এটি সেট করা সুপারিশ করা হয়।",
+ "connect_request": "{client} কে সংযোগ করতে অনুমতি দেবেন?",
+ "connection_request_denied": "সংযোগ অস্বীকৃত। ব্যবহারকারী প্রবেশাধিকার অস্বীকার করেছে।"
}
\ No newline at end of file
diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb
index 7cb007c4..8afb33f3 100644
--- a/lib/l10n/app_ca.arb
+++ b/lib/l10n/app_ca.arb
@@ -426,5 +426,9 @@
"download": "Descarregar",
"file_not_found": "Fitxer no trobat",
"custom": "Personalitzat",
- "add_custom_url": "Afegir URL personalitzada"
+ "add_custom_url": "Afegir URL personalitzada",
+ "edit_port": "Editar port",
+ "port_helper_msg": "El valor per defecte és -1, que indica un número aleatori. Si teniu un tallafoc configurat, es recomana establir-ho.",
+ "connect_request": "Permetre que {client} es connecti?",
+ "connection_request_denied": "Connexió denegada. L'usuari ha denegat l'accés."
}
\ No newline at end of file
diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb
index a6fdf25c..44631945 100644
--- a/lib/l10n/app_cs.arb
+++ b/lib/l10n/app_cs.arb
@@ -426,5 +426,9 @@
"download": "Stáhnout",
"file_not_found": "Soubor nenalezen",
"custom": "Vlastní",
- "add_custom_url": "Přidat vlastní URL"
+ "add_custom_url": "Přidat vlastní URL",
+ "edit_port": "Upravit port",
+ "port_helper_msg": "Výchozí hodnota je -1, což znamená náhodné číslo. Pokud máte nakonfigurován firewall, doporučuje se to nastavit.",
+ "connect_request": "Povolit {client} připojení?",
+ "connection_request_denied": "Připojení bylo zamítnuto. Uživatel odmítl přístup."
}
\ No newline at end of file
diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb
index af2b26ad..7ce9c333 100644
--- a/lib/l10n/app_de.arb
+++ b/lib/l10n/app_de.arb
@@ -426,5 +426,9 @@
"download": "Herunterladen",
"file_not_found": "Datei nicht gefunden",
"custom": "Benutzerdefiniert",
- "add_custom_url": "Benutzerdefinierte URL hinzufügen"
+ "add_custom_url": "Benutzerdefinierte URL hinzufügen",
+ "edit_port": "Port bearbeiten",
+ "port_helper_msg": "Der Standardwert ist -1, was eine zufällige Zahl bedeutet. Wenn Sie eine Firewall konfiguriert haben, wird empfohlen, dies einzustellen.",
+ "connect_request": "{client} die Verbindung erlauben?",
+ "connection_request_denied": "Verbindung abgelehnt. Benutzer hat den Zugriff verweigert."
}
\ No newline at end of file
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index e3e6d330..4da423a8 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -424,5 +424,9 @@
"download": "Download",
"file_not_found": "File not found",
"custom": "Custom",
- "add_custom_url": "Add custom URL"
+ "add_custom_url": "Add custom URL",
+ "edit_port": "Edit port",
+ "port_helper_msg": "Default is -1 which indicates random number. If you've firewall configured, setting this is recommended.",
+ "connect_request": "Allow {client} to connect?",
+ "connection_request_denied": "Connection denied. User denied access."
}
diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb
index 565c786a..8a6e02ad 100644
--- a/lib/l10n/app_es.arb
+++ b/lib/l10n/app_es.arb
@@ -426,5 +426,9 @@
"download": "Descargar",
"file_not_found": "Archivo no encontrado",
"custom": "Personalizado",
- "add_custom_url": "Agregar URL personalizada"
+ "add_custom_url": "Agregar URL personalizada",
+ "edit_port": "Editar puerto",
+ "port_helper_msg": "El valor predeterminado es -1, lo que indica un número aleatorio. Si tienes un firewall configurado, se recomienda establecer esto.",
+ "connect_request": "¿Permitir que {client} se conecte?",
+ "connection_request_denied": "Conexión denegada. El usuario denegó el acceso."
}
\ No newline at end of file
diff --git a/lib/l10n/app_eu.arb b/lib/l10n/app_eu.arb
index 70a581a7..f28d5f8e 100644
--- a/lib/l10n/app_eu.arb
+++ b/lib/l10n/app_eu.arb
@@ -426,5 +426,9 @@
"download": "Deskargatu",
"file_not_found": "Fitxategia ez da aurkitu",
"custom": "Pertsonalizatua",
- "add_custom_url": "Gehitu URL pertsonalizatua"
+ "add_custom_url": "Gehitu URL pertsonalizatua",
+ "edit_port": "Editatu portua",
+ "port_helper_msg": "Lehenetsitako balioa -1 da, zenbaki aleatorioa adierazten duena. Su firewall konfiguratu baduzu, gomendatzen da hau ezartzea.",
+ "connect_request": "{client} konektatzea baimendu?",
+ "connection_request_denied": "Konektatzea ukatu da. Erabiltzaileak sarbidea ukatu du."
}
\ No newline at end of file
diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb
index d3918e55..0791d0b6 100644
--- a/lib/l10n/app_fa.arb
+++ b/lib/l10n/app_fa.arb
@@ -426,5 +426,9 @@
"download": "دانلود",
"file_not_found": "فایل پیدا نشد",
"custom": "شخصیسازی شده",
- "add_custom_url": "اضافه کردن URL سفارشی"
+ "add_custom_url": "اضافه کردن URL سفارشی",
+ "edit_port": "ویرایش پورت",
+ "port_helper_msg": "پیشفرض -1 است که نشاندهنده یک عدد تصادفی است. اگر فایروال شما پیکربندی شده است، توصیه میشود این را تنظیم کنید.",
+ "connect_request": "آیا اجازه میدهید {client} متصل شود؟",
+ "connection_request_denied": "اتصال رد شد. کاربر دسترسی را رد کرد."
}
\ No newline at end of file
diff --git a/lib/l10n/app_fi.arb b/lib/l10n/app_fi.arb
index 797c36f7..57a5a0b8 100644
--- a/lib/l10n/app_fi.arb
+++ b/lib/l10n/app_fi.arb
@@ -426,5 +426,9 @@
"download": "Lataa",
"file_not_found": "Tiedostoa ei löydy",
"custom": "Mukautettu",
- "add_custom_url": "Lisää mukautettu URL"
+ "add_custom_url": "Lisää mukautettu URL",
+ "edit_port": "Muokkaa porttia",
+ "port_helper_msg": "Oletusarvo on -1, mikä tarkoittaa satunnaista numeroa. Jos sinulla on palomuuri määritetty, tämän asettamista suositellaan.",
+ "connect_request": "Salli {client} yhdistää?",
+ "connection_request_denied": "Yhteys evätty. Käyttäjä eväsi pääsyn."
}
\ No newline at end of file
diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb
index 636cffec..192b6c5c 100644
--- a/lib/l10n/app_fr.arb
+++ b/lib/l10n/app_fr.arb
@@ -426,5 +426,9 @@
"download": "Télécharger",
"file_not_found": "Fichier non trouvé",
"custom": "Personnalisé",
- "add_custom_url": "Ajouter une URL personnalisée"
+ "add_custom_url": "Ajouter une URL personnalisée",
+ "edit_port": "Modifier le port",
+ "port_helper_msg": "La valeur par défaut est -1, ce qui indique un nombre aléatoire. Si vous avez configuré un pare-feu, il est recommandé de le définir.",
+ "connect_request": "Autoriser {client} à se connecter ?",
+ "connection_request_denied ": "Connexion refusée. L'utilisateur a refusé l'accès."
}
\ No newline at end of file
diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb
index fc59d31a..124d0634 100644
--- a/lib/l10n/app_hi.arb
+++ b/lib/l10n/app_hi.arb
@@ -426,5 +426,9 @@
"download": "डाउनलोड करें",
"file_not_found": "फाइल नहीं मिली",
"custom": "कस्टम",
- "add_custom_url": "कस्टम URL जोड़ें"
+ "add_custom_url": "कस्टम URL जोड़ें",
+ "edit_port": "पोर्ट संपादित करें",
+ "port_helper_msg": "डिफ़ॉल्ट -1 है जो यादृच्छिक संख्या को दर्शाता है। यदि आपने फ़ायरवॉल कॉन्फ़िगर किया है, तो इसे सेट करना अनुशंसित है।",
+ "connect_request": "{client} को कनेक्ट करने की अनुमति दें?",
+ "connection_request_denied": "कनेक्शन अस्वीकृत। उपयोगकर्ता ने पहुंच अस्वीकृत कर दी।"
}
\ No newline at end of file
diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb
index 91bc9aef..ffe36295 100644
--- a/lib/l10n/app_id.arb
+++ b/lib/l10n/app_id.arb
@@ -426,5 +426,9 @@
"download": "Download",
"file_not_found": "File not found",
"custom": "Custom",
- "add_custom_url": "Add custom URL"
+ "add_custom_url": "Add custom URL",
+ "edit_port": "Edit port",
+ "port_helper_msg": "Default adalah -1 yang menunjukkan angka acak. Jika Anda telah mengonfigurasi firewall, disarankan untuk mengatur ini.",
+ "connect_request": "Izinkan {client} untuk terhubung?",
+ "connection_request_denied": "Koneksi ditolak. Pengguna menolak akses."
}
\ No newline at end of file
diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb
index f598d363..1c7dc114 100644
--- a/lib/l10n/app_it.arb
+++ b/lib/l10n/app_it.arb
@@ -427,5 +427,9 @@
"download": "Scarica",
"file_not_found": "File non trovato",
"custom": "Personalizzato",
- "add_custom_url": "Aggiungi URL personalizzato"
+ "add_custom_url": "Aggiungi URL personalizzato",
+ "edit_port": "Modifica porta",
+ "port_helper_msg": "Il valore predefinito è -1, che indica un numero casuale. Se hai configurato un firewall, si consiglia di impostarlo.",
+ "connect_request": "Consentire a {client} di connettersi?",
+ "connection_request_denied": "Connessione negata. L'utente ha negato l'accesso."
}
\ No newline at end of file
diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb
index b885fa59..230b2b49 100644
--- a/lib/l10n/app_ja.arb
+++ b/lib/l10n/app_ja.arb
@@ -426,5 +426,9 @@
"download": "ダウンロード",
"file_not_found": "ファイルが見つかりません",
"custom": "カスタム",
- "add_custom_url": "カスタムURLを追加"
+ "add_custom_url": "カスタムURLを追加",
+ "edit_port": "ポートを編集",
+ "port_helper_msg": "デフォルトは-1で、ランダムな番号を示します。ファイアウォールを設定している場合は、これを設定することをお勧めします。",
+ "connect_request": "{client}の接続を許可しますか?",
+ "connection_request_denied": "接続が拒否されました。ユーザーがアクセスを拒否しました。"
}
\ No newline at end of file
diff --git a/lib/l10n/app_ka.arb b/lib/l10n/app_ka.arb
index 8bc9cf36..67f90361 100644
--- a/lib/l10n/app_ka.arb
+++ b/lib/l10n/app_ka.arb
@@ -426,5 +426,9 @@
"download": "ჩამოტვირთვა",
"file_not_found": "ფაილი ვერ მოიძებნა",
"custom": "პერსონალიზირებული",
- "add_custom_url": "დამატება პერსონალური URL"
+ "add_custom_url": "დამატება პერსონალური URL",
+ "edit_port": "პორტის რედაქტირება",
+ "port_helper_msg": "ნაგულისხმევი არის -1, რაც შემთხვევითი ნომრის მითითებას ნიშნავს. თუ لديك firewall настроен, рекомендуется установить это.",
+ "connect_request": "{client}-ის დაკავშირების ნებართვა?",
+ "connection_request_denied": "კავშირი უარყოფილია. მომხმარებელმა უარყო წვდომა."
}
\ No newline at end of file
diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb
index 6c8031b5..037e1fb1 100644
--- a/lib/l10n/app_ko.arb
+++ b/lib/l10n/app_ko.arb
@@ -427,5 +427,9 @@
"download": "다운로드",
"file_not_found": "파일을 찾을 수 없습니다",
"custom": "사용자 정의",
- "add_custom_url": "사용자 정의 URL 추가"
+ "add_custom_url": "사용자 정의 URL 추가",
+ "edit_port": "포트 편집",
+ "port_helper_msg": "기본값은 -1로 무작위 숫자를 나타냅니다. 방화벽이 구성된 경우 이를 설정하는 것이 좋습니다.",
+ "connect_request": "{client}의 연결을 허용하시겠습니까?",
+ "connection_request_denied": "연결이 거부되었습니다. 사용자가 액세스를 거부했습니다."
}
\ No newline at end of file
diff --git a/lib/l10n/app_ne.arb b/lib/l10n/app_ne.arb
index beddc3ad..823dadb1 100644
--- a/lib/l10n/app_ne.arb
+++ b/lib/l10n/app_ne.arb
@@ -426,5 +426,9 @@
"download": "डाउनलोड",
"file_not_found": "फ़ाइल नहीं मिली",
"custom": "कस्टम",
- "add_custom_url": "कस्टम URL जोड़ें"
+ "add_custom_url": "कस्टम URL जोड़ें",
+ "edit_port": "पोर्ट सम्पादन गर्नुहोस्",
+ "port_helper_msg": "डिफ़ॉल्ट -1 हो जुन यादृच्छिक संख्या जनाउँछ। यदि तपाईंले फायरवाल कन्फिगर गर्नुभएको छ भने, यसलाई सेट गर्न सिफारिस गरिन्छ।",
+ "connect_request": "{client} लाई जडान गर्न अनुमति दिनुहोस्?",
+ "connection_request_denied": "जडान अस्वीकृत। प्रयोगकर्ताले पहुँच अस्वीकृत गर्यो।"
}
\ No newline at end of file
diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb
index 2127b382..01aa6ef8 100644
--- a/lib/l10n/app_nl.arb
+++ b/lib/l10n/app_nl.arb
@@ -427,5 +427,9 @@
"download": "Downloaden",
"file_not_found": "Bestand niet gevonden",
"custom": "Aangepast",
- "add_custom_url": "Voeg aangepaste URL toe"
+ "add_custom_url": "Voeg aangepaste URL toe",
+ "edit_port": "Poort bewerken",
+ "port_helper_msg": "Standaard is -1, wat een willekeurig nummer aangeeft. Als je een firewall hebt geconfigureerd, wordt aanbevolen dit in te stellen.",
+ "connect_request": "Toestaan dat {client} verbinding maakt?",
+ "connection_request_denied": "Verbinding geweigerd. Gebruiker heeft toegang geweigerd."
}
\ No newline at end of file
diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb
index ade74c90..a2388614 100644
--- a/lib/l10n/app_pl.arb
+++ b/lib/l10n/app_pl.arb
@@ -426,5 +426,9 @@
"download": "Pobierz",
"file_not_found": "Plik nie znaleziony",
"custom": "Niestandardowy",
- "add_custom_url": "Dodaj niestandardowy URL"
+ "add_custom_url": "Dodaj niestandardowy URL",
+ "edit_port": "Edytuj port",
+ "port_helper_msg": "Domyślna wartość to -1, co oznacza losową liczbę. Jeśli masz skonfigurowany zaporę, zaleca się jej ustawienie.",
+ "connect_request": "Zezwolić {client} na połączenie?",
+ "connection_request_denied": "Połączenie odrzucone. Użytkownik odmówił dostępu."
}
\ No newline at end of file
diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb
index 6b1098a9..bec4f7c9 100644
--- a/lib/l10n/app_pt.arb
+++ b/lib/l10n/app_pt.arb
@@ -426,5 +426,9 @@
"download": "Baixar",
"file_not_found": "Arquivo não encontrado",
"custom": "Personalizado",
- "add_custom_url": "Adicionar URL personalizada"
+ "add_custom_url": "Adicionar URL personalizada",
+ "edit_port": "Editar porta",
+ "port_helper_msg": "O padrão é -1, que indica um número aleatório. Se você tiver um firewall configurado, é recomendável definir isso.",
+ "connect_request": "Permitir que {client} se conecte?",
+ "connection_request_denied": "Conexão negada. O usuário negou o acesso ."
}
\ No newline at end of file
diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb
index 461e8da8..9e8cbb3f 100644
--- a/lib/l10n/app_ru.arb
+++ b/lib/l10n/app_ru.arb
@@ -426,5 +426,9 @@
"download": "Скачать",
"file_not_found": "Файл не найден",
"custom": "Пользовательский",
- "add_custom_url": "Добавить пользовательский URL"
+ "add_custom_url": "Добавить пользовательский URL",
+ "edit_port": "Редактировать порт",
+ "port_helper_msg": "По умолчанию -1, что означает случайное число. Если у вас настроен брандмауэр, рекомендуется установить это.",
+ "connect_request": "Разрешить {client} подключение?",
+ "connection_request_denied": "Подключение отклонено. Пользователь отказал в доступе."
}
\ No newline at end of file
diff --git a/lib/l10n/app_ta.arb b/lib/l10n/app_ta.arb
index 396a16fb..15c8d54f 100644
--- a/lib/l10n/app_ta.arb
+++ b/lib/l10n/app_ta.arb
@@ -1,428 +1,432 @@
{
- "guest": "விருந்தினர்",
- "browse": "உலாவு",
- "search": "தேடுக",
- "library": "நூலகம்",
- "lyrics": "பாடல் வரிகள்",
- "settings": "அமைப்புகள்",
- "genre_categories_filter": "வகைகள் அல்லது பாணிகளை வடிகட்டுக...",
- "genre": "பாணி",
- "personalized": "தனிப்பயனாக்கப்பட்ட",
- "featured": "சிறப்பிடம் பெற்ற",
- "new_releases": "புதிய வெளியீடுகள்",
- "songs": "பாடல்கள்",
- "playing_track": "{track} இயங்குகிறது",
- "queue_clear_alert": "இது தற்போதைய வரிசையை அழிக்கும். {track_length} பாடல்கள் நீக்கப்படும்\nதொடர விரும்புகிறீர்களா?",
- "load_more": "மேலும் ஏற்றுக",
- "playlists": "பாடல் பட்டியல்கள்",
- "artists": "கலைஞர்கள்",
- "albums": "ஆல்பங்கள்",
- "tracks": "பாடல்கள்",
- "downloads": "பதிவிறக்கங்கள்",
- "filter_playlists": "உங்கள் பாடல் பட்டியல்களை வடிகட்டுக...",
- "liked_tracks": "விரும்பிய பாடல்கள்",
- "liked_tracks_description": "உங்கள் விரும்பிய பாடல்கள் அனைத்தும்",
- "playlist": "பாடல் பட்டியல்",
- "create_a_playlist": "பாடல் பட்டியலை உருவாக்குக",
- "update_playlist": "பாடல் பட்டியலைப் புதுப்பிக்க",
- "create": "உருவாக்கு",
- "cancel": "ரத்து செய்",
- "update": "புதுப்பி",
- "playlist_name": "பாடல் பட்டியல் பெயர்",
- "name_of_playlist": "பாடல் பட்டியலின் பெயர்",
- "description": "விளக்கம்",
- "public": "பொது",
- "collaborative": "கூட்டு",
- "search_local_tracks": "உள்ளூர் பாடல்களைத் தேடுக...",
- "play": "இயக்கு",
- "delete": "அழி",
- "none": "எதுவுமில்லை",
- "sort_a_z": "A-Z வரிசைப்படுத்து",
- "sort_z_a": "Z-A வரிசைப்படுத்து",
- "sort_artist": "கலைஞர் மூலம் வரிசைப்படுத்து",
- "sort_album": "ஆல்பம் மூலம் வரிசைப்படுத்து",
- "sort_duration": "கால அளவு மூலம் வரிசைப்படுத்து",
- "sort_tracks": "பாடல்களை வரிசைப்படுத்து",
- "currently_downloading": "தற்போது பதிவிறக்குகிறது ({tracks_length})",
- "cancel_all": "அனைத்தையும் ரத்து செய்",
- "filter_artist": "கலைஞர்களை வடிகட்டுக...",
- "followers": "{followers} பின்தொடர்பவர்கள்",
- "add_artist_to_blacklist": "கலைஞரை தடைப்பட்டியலில் சேர்க்க",
- "top_tracks": "சிறந்த பாடல்கள்",
- "fans_also_like": "ரசிகர்கள் விரும்புவது",
- "loading": "ஏற்றுகிறது...",
- "artist": "கலைஞர்",
- "blacklisted": "தடைப்பட்டியலில் உள்ளது",
- "following": "பின்தொடர்கிறது",
- "follow": "பின்தொடர்",
- "artist_url_copied": "கலைஞர் URL கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது",
- "added_to_queue": "{tracks} பாடல்கள் வரிசையில் சேர்க்கப்பட்டன",
- "filter_albums": "ஆல்பங்களை வடிகட்டுக...",
- "synced": "ஒத்திசைக்கப்பட்டது",
- "plain": "சாதாரண",
- "shuffle": "கலக்கு",
- "search_tracks": "பாடல்களைத் தேடுக...",
- "released": "வெளியிடப்பட்டது",
- "error": "பிழை {error}",
- "title": "தலைப்பு",
- "time": "நேரம்",
- "more_actions": "மேலும் செயல்கள்",
- "download_count": "பதிவிறக்கு ({count})",
- "add_count_to_playlist": "({count}) பாடல் பட்டியலில் சேர்",
- "add_count_to_queue": "({count}) வரிசையில் சேர்",
- "play_count_next": "({count}) அடுத்து இயக்கு",
- "album": "ஆல்பம்",
- "copied_to_clipboard": "{data} கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது",
- "add_to_following_playlists": "{track} பின்வரும் பாடல் பட்டியல்களில் சேர்",
- "add": "சேர்",
- "added_track_to_queue": "{track} வரிசையில் சேர்க்கப்பட்டது",
- "add_to_queue": "வரிசையில் சேர்",
- "track_will_play_next": "{track} அடுத்து இயக்கப்படும்",
- "play_next": "அடுத்து இயக்கு",
- "removed_track_from_queue": "{track} வரிசையிலிருந்து நீக்கப்பட்டது",
- "remove_from_queue": "வரிசையிலிருந்து நீக்கு",
- "remove_from_favorites": "பிடித்தவையிலிருந்து நீக்கு",
- "save_as_favorite": "பிடித்தவையாக சேமி",
- "add_to_playlist": "பாடல் பட்டியலில் சேர்",
- "remove_from_playlist": "பாடல் பட்டியலிலிருந்து நீக்கு",
- "add_to_blacklist": "தடைப்பட்டியலில் சேர்",
- "remove_from_blacklist": "தடைப்பட்டியலிலிருந்து நீக்கு",
- "share": "பகிர்",
- "mini_player": "சிறிய இயக்கி",
- "slide_to_seek": "முன்னோக்கி அல்லது பின்னோக்கி செல்ல சறுக்கவும்",
- "shuffle_playlist": "பாடல் பட்டியலை கலக்கு",
- "unshuffle_playlist": "பாடல் பட்டியலை கலக்காதே",
- "previous_track": "முந்தைய பாடல்",
- "next_track": "அடுத்த பாடல்",
- "pause_playback": "இயக்கத்தை நிறுத்து",
- "resume_playback": "இயக்கத்தை தொடர்",
- "loop_track": "பாடலை சுழற்று",
- "no_loop": "சுழற்சி இல்லை",
- "repeat_playlist": "பாடல் பட்டியலை மீண்டும் இயக்கு",
- "queue": "வரிசை",
- "alternative_track_sources": "மாற்று பாடல் மூலங்கள்",
- "download_track": "பாடலைப் பதிவிறக்கு",
- "tracks_in_queue": "வரிசையில் {tracks} பாடல்கள்",
- "clear_all": "அனைத்தையும் அழி",
- "show_hide_ui_on_hover": "மேலே வரும்போது UI ஐக் காட்டு/மறை",
- "always_on_top": "எப்போதும் மேலே",
- "exit_mini_player": "சிறிய இயக்கியிலிருந்து வெளியேறு",
- "download_location": "பதிவிறக்க இடம்",
- "local_library": "உள்ளூர் நூலகம்",
- "add_library_location": "நூலகத்தில் சேர்",
- "remove_library_location": "நூலகத்திலிருந்து நீக்கு",
- "account": "கணக்கு",
- "login_with_spotify": "உங்கள் Spotify கணக்கில் உள்நுழைக",
- "connect_with_spotify": "Spotify உடன் இணைக்கவும்",
- "logout": "வெளியேறு",
- "logout_of_this_account": "இந்த கணக்கிலிருந்து வெளியேறு",
- "language_region": "மொழி & பிராந்தியம்",
- "language": "மொழி",
- "system_default": "கணினி இயல்புநிலை",
- "market_place_region": "சந்தை பிராந்தியம்",
- "recommendation_country": "பரிந்துரை நாடு",
- "appearance": "தோற்றம்",
- "layout_mode": "அமைப்பு முறை",
- "override_layout_settings": "தளவமைப்பு அமைப்புகளை மாற்றியமை",
- "adaptive": "தகவமைப்பு",
- "compact": "சுருக்கமான",
- "extended": "விரிவான",
- "theme": "தீம்",
- "dark": "இருள்",
- "light": "வெளிர்",
- "system": "கணினி வழி",
- "accent_color": "அழுத்த நிறம்",
- "sync_album_color": "ஆல்பம் நிறத்தை ஒத்திசை",
- "sync_album_color_description": "ஆல்பம் படத்தின் முக்கிய நிறத்தை அழுத்த நிறமாகப் பயன்படுத்துகிறது",
- "playback": "பின்னணி",
- "audio_quality": "ஒலி தரம்",
- "high": "உயர்",
- "low": "குறைந்த",
- "pre_download_play": "முன்பதிவிறக்கம் மற்றும் இயக்கம்",
- "pre_download_play_description": "ஒலியை ஸ்ட்ரீம் செய்வதற்குப் பதிலாக, பைட்டுகளைப் பதிவிறக்கி இயக்கவும் (அதிக பேண்ட்விட்த் பயனர்களுக்கு பரிந்துரைக்கப்படுகிறது)",
- "skip_non_music": "இசையல்லாத பகுதிகளைத் தவிர் (SponsorBlock)",
- "blacklist_description": "தடைசெய்யப்பட்ட பாடல்கள் மற்றும் கலைஞர்கள்",
- "wait_for_download_to_finish": "தற்போதைய பதிவிறக்கம் முடியும் வரை காத்திருக்கவும்",
- "desktop": "கணினி",
- "close_behavior": "மூடும் நடத்தை",
- "close": "மூடு",
- "minimize_to_tray": "ட்ரேயை குறைக்கவும்",
- "show_tray_icon": "ட்ரே ஐகானைக் காட்டு",
- "about": "பற்றி",
- "u_love_spotube": "நீங்கள் Spotube ஐ நேசிக்கிறீர்கள் என்பது எங்களுக்குத் தெரியும்",
- "check_for_updates": "புதுப்பிப்புகளைச் சரிபார்",
- "about_spotube": "Spotube பற்றி",
- "blacklist": "தடைப்பட்டியல்",
- "please_sponsor": "தயவுசெய்து ஆதரவு/நன்கொடை அளியுங்கள்",
- "spotube_description": "Spotube, ஒரு லேசான, பல தளங்களில் இயங்கும், அனைவருக்கும் இலவசமான spotify கிளையன்ட்",
- "version": "பதிப்பு",
- "build_number": "கட்டமைப்பு எண்",
- "founder": "நிறுவனர்",
- "repository": "களஞ்சியம்",
- "bug_issues": "பிழை_சிக்கல்கள்",
- "made_with": "வங்காளதேசத்திலிருந்து🇧🇩 ❤️ உருவாக்கப்பட்டது",
- "kingkor_roy_tirtho": "கிங்கர் ராய் திர்தோ",
- "copyright": "© 2021-{current_year} கிங்கர் ராய் திர்தோ",
- "license": "உரிமம்",
- "add_spotify_credentials": "தொடங்குவதற்கு உங்கள் spotify சான்றுகளைச் சேர்க்கவும்",
- "credentials_will_not_be_shared_disclaimer": "கவலைப்பட வேண்டாம், உங்கள் சான்றுகள் எதுவும் சேகரிக்கப்படாது அல்லது யாருடனும் பகிரப்படாது",
- "know_how_to_login": "இதை எப்படி செய்வது என்று தெரியவில்லையா?",
- "follow_step_by_step_guide": "படிப்படியான வழிகாட்டியைப் பின்பற்றவும்",
- "spotify_cookie": "Spotify {name} நட்புநிரல்",
- "cookie_name_cookie": "{name} நட்புநிரல்",
- "fill_in_all_fields": "அனைத்து களங்களையும் நிரப்பவும்",
- "submit": "சமர்ப்பி",
- "exit": "வெளியேறு",
- "previous": "முந்தைய",
- "next": "அடுத்து",
- "done": "முடிந்தது",
- "step_1": "முதல் படி",
- "first_go_to": "முதலில், செல்லவேண்டியது",
- "login_if_not_logged_in": "நீங்கள் உள்நுழையவில்லை என்றால் உள்நுழைக/பதிவுசெய்க",
- "step_2": "இரண்டாம் படி",
- "step_2_steps": "1. நீங்கள் உள்நுழைந்தவுடன், F12 ஐ அழுத்தவும் அல்லது வலது கிளிக் செய்து > ஆய்வு செய்யவும் உலாவி டெவ்டூல்களைத் திறக்கவும்.\n2. பின்னர் \"பயன்பாடு\" தாவலுக்குச் செல்லவும் (Chrome, Edge, Brave போன்றவை) அல்லது \"சேமிப்பகம்\" தாவல் (Firefox, Palemoon போன்றவை)\n3. \"குக்கிகள்\" பிரிவுக்குச் சென்று பின்னர் \"https://accounts.spotify.com\" பிரிவுக்குச் செல்லவும்",
- "step_3": "மூன்றாம் படி",
- "step_3_steps": "\"sp_dc\" நட்புநிரலின் மதிப்பை நகலெடுக்கவும்",
- "success_emoji": "வெற்றி🥳",
- "success_message": "இப்போது நீங்கள் உங்கள் Spotify கணக்கில் வெற்றிகரமாக உள்நுழைந்துள்ளீர்கள். நல்லது, நண்பரே!",
- "step_4": "நான்காம் படி",
- "step_4_steps": "நகலெடுக்கப்பட்ட \"sp_dc\" மதிப்பை ஒட்டவும்",
- "something_went_wrong": "ஏதோ தவறு நடந்துவிட்டது",
- "piped_instance": "Piped சேவையகம் நிகழ்வு",
- "piped_description": "பாடல் பொருத்தத்திற்குப் பயன்படுத்த வேண்டிய Piped சேவையகம் நிகழ்வு",
- "piped_warning": "அவற்றில் சில நன்றாக வேலை செய்யாமல் இருக்கலாம். எனவே உங்கள் சொந்த ஆபத்தில் பயன்படுத்தவும்",
- "invidious_instance": "Invidious சேவையக நிகழ்வு",
- "invidious_description": "பாடல் பொருத்தத்திற்குப் பயன்படுத்த வேண்டிய Invidious சேவையக நிகழ்வு",
- "invidious_warning": "அவற்றில் சில நன்றாக வேலை செய்யாமல் இருக்கலாம். எனவே உங்கள் சொந்த ஆபத்தில் பயன்படுத்தவும்",
- "generate": "உருவாக்கு",
- "track_exists": "பாடல் {track} ஏற்கனவே உள்ளது",
- "replace_downloaded_tracks": "பதிவிறக்கம் செய்யப்பட்ட அனைத்து பாடல்களையும் மாற்றவும்",
- "skip_download_tracks": "பதிவிறக்கம் செய்யப்பட்ட அனைத்து பாடல்களையும் தவிர்க்கவும்",
- "do_you_want_to_replace": "ஏற்கனவே உள்ள பாடலை மாற்ற விரும்புகிறீர்களா?",
- "replace": "மாற்று",
- "skip": "தவிர்",
- "select_up_to_count_type": "{count} {type} வரை தேர்ந்தெடுக்கவும்",
- "select_genres": "வகைகளைத் தேர்ந்தெடுக்கவும்",
- "add_genres": "வகைகளைச் சேர்க்கவும்",
- "country": "நாடு",
- "number_of_tracks_generate": "உருவாக்க வேண்டிய பாடல்களின் எண்ணிக்கை",
- "acousticness": "அகவுஸ்டிக்னெஸ்",
- "danceability": "நடனத்தன்மை",
- "energy": "ஆற்றல்",
- "instrumentalness": "கருவித்தன்மை",
- "liveness": "உயிர்ப்புத்தன்மை",
- "loudness": "ஒலி அளவு",
- "speechiness": "பேச்சுத்தன்மை",
- "valence": "உணர்வு",
- "popularity": "பிரபலம்",
- "key": "இசை குறிப்பு",
- "duration": "கால அளவு (வினாடிகள்)",
- "tempo": "வேகம் (BPM)",
- "mode": "முறை",
- "time_signature": "நேர கையொப்பம்",
- "short": "குறுகிய",
- "medium": "நடுத்தர",
- "long": "நீண்ட",
- "min": "குறைந்தபட்சம்",
- "max": "அதிகபட்சம்",
- "target": "இலக்கு",
- "moderate": "மிதமான",
- "deselect_all": "அனைத்தையும் தேர்வுநீக்கு",
- "select_all": "அனைத்தையும் தேர்ந்தெடு",
- "are_you_sure": "உறுதியாக இருக்கிறீர்களா?",
- "generating_playlist": "உங்கள் தனிப்பயன்பாட்டிற்கான பாடல் பட்டியலை உருவாக்குகிறது...",
- "selected_count_tracks": "{count} பாடல்கள் தேர்ந்தெடுக்கப்பட்டன",
- "download_warning": "நீங்கள் அனைத்து பாடல்களையும் மொத்தமாக பதிவிறக்கினால், நீங்கள் தெளிவாக இசையைத் திருடுகிறீர்கள் மற்றும் இசையின் படைப்பாற்றல் சமூகத்திற்கு சேதம் விளைவிக்கிறீர்கள். நீங்கள் இதை அறிந்திருக்கிறீர்கள் என்று நம்புகிறேன். எப்போதும், கலைஞரின் கடின உழைப்பை மதித்து ஆதரிக்க முயற்சி செய்யுங்கள்",
- "download_ip_ban_warning": "மேலும், அதிகப்படியான பதிவிறக்க கோரிக்கைகள் காரணமாக உங்கள் IP YouTube இல் தடைசெய்யப்படலாம். IP தடை என்பது குறைந்தது 2-3 மாதங்களுக்கு அந்த IP சாதனத்திலிருந்து YouTube ஐப் பயன்படுத்த முடியாது (நீங்கள் உள்நுழைந்திருந்தாலும் கூட). இது ஒருபோதும் நடந்தால் Spotube பொறுப்பேற்காது",
- "by_clicking_accept_terms": "'ஏற்றுக்கொள்' என்பதைக் கிளிக் செய்வதன் மூலம் பின்வரும் விதிமுறைகளுக்கு நீங்கள் ஒப்புக்கொள்கிறீர்கள்:",
- "download_agreement_1": "நான் இசையைத் திருடுகிறேன் என்பது எனக்குத் தெரியும். நான் கெட்டவன்",
- "download_agreement_2": "நான் கலைஞரை முடிந்தவரை ஆதரிப்பேன், அவர்களின் கலைக்கு பணம் செலுத்த எனக்கு பணம் இல்லாததால் மட்டுமே இதைச் செய்கிறேன்",
- "download_agreement_3": "என் IP YouTube இல் தடைசெய்யப்படலாம் என்பதை நான் முழுமையாக அறிவேன், மேலும் என் தற்போதைய செயலால் ஏற்படும் எந்த விபத்துகளுக்கும் Spotube அல்லது அதன் உரிமையாளர்கள்/பங்களிப்பாளர்களை பொறுப்பாக்க மாட்டேன்",
- "decline": "மறு",
- "accept": "ஏற்றுக்கொள்",
- "details": "விவரங்கள்",
- "youtube": "YouTube",
- "channel": "சேனல்",
- "likes": "விருப்பங்கள்",
- "dislikes": "விருப்பமில்லாதவை",
- "views": "பார்வைகள்",
- "streamUrl": "ஸ்ட்ரீம் URL",
- "stop": "நிறுத்து",
- "sort_newest": "புதிதாக சேர்க்கப்பட்டவற்றை வரிசைப்படுத்து",
- "sort_oldest": "பழமையானவற்றை வரிசைப்படுத்து",
- "sleep_timer": "உறக்க நேரம்",
- "mins": "{minutes} நிமிடங்கள்",
- "hours": "{hours} மணிநேரங்கள்",
- "hour": "{hours} மணிநேரம்",
- "custom_hours": "தனிப்பயன் மணிநேரங்கள்",
- "logs": "பதிவுகள்",
- "developers": "உருவாக்குநர்கள்",
- "not_logged_in": "நீங்கள் உள்நுழையவில்லை",
- "search_mode": "தேடல் முறை",
- "audio_source": "ஒலி மூலம்",
- "ok": "சரி",
- "failed_to_encrypt": "குறியாக்கம் தோல்வியடைந்தது",
- "encryption_failed_warning": "Spotube உங்கள் தரவை பாதுகாப்பாக சேமிக்க குறியாக்கத்தைப் பயன்படுத்துகிறது. ஆனால் அவ்வாறு செய்ய முடியவில்லை. எனவே இது பாதுகாப்பற்ற சேமிப்பகத்திற்கு மாறும்\nநீங்கள் லினக்ஸ் பயன்படுத்துகிறீர்கள் என்றால், எந்த ரகசிய சேவையும் (gnome-keyring, kde-wallet, keepassxc போன்றவை) நிறுவப்பட்டுள்ளதா என்பதை உறுதிப்படுத்தவும்",
- "querying_info": "தகவலைக் கேட்கிறது...",
- "piped_api_down": "Piped API செயலிழந்துள்ளது",
- "piped_down_error_instructions": "Piped நிகழ்வு {pipedInstance} தற்போது செயலிழந்துள்ளது\n\nநிகழ்வை மாற்றவும் அல்லது 'API வகை'யை அதிகாரப்பூர்வ YouTube API க்கு மாற்றவும்\n\nமாற்றத்திற்குப் பிறகு பயன்பாட்டை மறுதொடக்கம் செய்வதை உறுதிப்படுத்தவும்",
- "you_are_offline": "நீங்கள் தற்போது ஆஃப்லைனில் உள்ளீர்கள்",
- "connection_restored": "உங்கள் இணைய இணைப்பு மீட்டெடுக்கப்பட்டது",
- "use_system_title_bar": "கணினி தலைப்புப் பட்டியைப் பயன்படுத்தவும்",
- "crunching_results": "முடிவுகளை செயலாக்குகிறது...",
- "search_to_get_results": "முடிவுகளைப் பெற தேடவும்",
- "use_amoled_mode": "கருமை நிற இருண்ட தீம்",
- "pitch_dark_theme": "AMOLED முறை",
- "normalize_audio": "ஒலியை சீரமை",
- "change_cover": "அட்டையை மாற்று",
- "add_cover": "அட்டையைச் சேர்",
- "restore_defaults": "இயல்புநிலைகளை மீட்டமை",
- "download_music_codec": "இசை கோடெக்கை பதிவிறக்கு",
- "streaming_music_codec": "இசை கோடெக்கை ஸ்ட்ரீம் செய்",
- "login_with_lastfm": "Last.fm உடன் உள்நுழைக",
- "connect": "இணை",
- "disconnect_lastfm": "Last.fm இலிருந்து துண்டி",
- "disconnect": "துண்டி",
- "username": "பயனர்பெயர்",
- "password": "கடவுச்சொல்",
- "login": "உள்நுழைக",
- "login_with_your_lastfm": "உங்கள் Last.fm கணக்குடன் உள்நுழைக",
- "scrobble_to_lastfm": "Last.fm க்கு ஸ்க்ரோபிள் செய்",
- "go_to_album": "ஆல்பத்திற்குச் செல்",
- "discord_rich_presence": "Discord செழுமையான தோற்றம்",
- "browse_all": "அனைத்தையும் உலாவு",
- "genres": "வகைகள்",
- "explore_genres": "வகைகளை ஆராயுங்கள்",
- "friends": "நண்பர்கள்",
- "no_lyrics_available": "மன்னிக்கவும், இந்தப் பாடலுக்கான பாடல் வரிகளைக் கண்டுபிடிக்க முடியவில்லை",
- "start_a_radio": "வானொலியைத் தொடங்கு",
- "how_to_start_radio": "வானொலியை எவ்வாறு தொடங்க விரும்புகிறீர்கள்?",
- "replace_queue_question": "தற்போதைய வரிசையை மாற்ற விரும்புகிறீர்களா அல்லது அதனுடன் சேர்க்க விரும்புகிறீர்களா?",
- "endless_playback": "முடிவற்ற இயக்கம்",
- "delete_playlist": "பாடல் பட்டியலை நீக்கு",
- "delete_playlist_confirmation": "இந்த பாடல் பட்டியலை நீக்க விரும்புகிறீர்களா?",
- "local_tracks": "உள்ளூர் பாடல்கள்",
- "local_tab": "உள்ளூர்",
- "song_link": "பாடல் இணைப்பு",
- "skip_this_nonsense": "இந்த அர்த்தமற்றதைத் தவிர்",
- "freedom_of_music": "\"இசையின் சுதந்திரம்\"",
- "freedom_of_music_palm": "\"உங்கள் கைகளில் இசையின் சுதந்திரம்\"",
- "get_started": "தொடங்குவோம்",
- "youtube_source_description": "பரிந்துரைக்கப்படுகிறது மற்றும் சிறப்பாக செயல்படுகிறது.",
- "piped_source_description": "சுதந்திரமாக உணர்கிறீர்களா? YouTube போலவே ஆனால் மிகவும் சுதந்திரமானது.",
- "jiosaavn_source_description": "தெற்காசியப் பிராந்தியத்திற்கு சிறந்தது.",
- "invidious_source_description": "Piped ஐப் போன்றது ஆனால் அதிக கிடைக்கும் தன்மையுடன்.",
- "highest_quality": "உயர்ந்த தரம்: {quality}",
- "select_audio_source": "ஒலி மூலத்தைத் தேர்ந்தெடுக்கவும்",
- "endless_playback_description": "வரிசையின் இறுதியில் புதிய பாடல்களை\nதானாகவே சேர்க்கவும்",
- "choose_your_region": "உங்கள் பிராந்தியத்தைத் தேர்ந்தெடுக்கவும்",
- "choose_your_region_description": "இது உங்கள் இருப்பிடத்திற்கான சரியான உள்ளடக்கத்தை\nSpotube காட்ட உதவும்.",
- "choose_your_language": "உங்கள் மொழியைத் தேர்ந்தெடுக்கவும்",
- "help_project_grow": "இந்த திட்டம் வளர உதவுங்கள்",
- "help_project_grow_description": "Spotube ஒரு திறந்த மூல திட்டம். திட்டத்திற்கு பங்களிப்பு செய்வதன் மூலம், பிழைகளைப் புகாரளிப்பதன் மூலம் அல்லது புதிய அம்சங்களைப் பரிந்துரைப்பதன் மூலம் இந்தத் திட்டம் வளர உதவலாம்.",
- "contribute_on_github": "GitHub இல் பங்களியுங்கள்",
- "donate_on_open_collective": "Open Collective இல் நன்கொடை அளியுங்கள்",
- "browse_anonymously": "அநாமதேயமாக உலாவுக",
- "enable_connect": "இணைப்பை இயக்கு",
- "enable_connect_description": "மற்ற சாதனங்களிலிருந்து Spotube ஐக் கட்டுப்படுத்தவும்",
- "devices": "சாதனங்கள்",
- "select": "தேர்ந்தெடு",
- "connect_client_alert": "நீங்கள் {client} ஆல் கட்டுப்படுத்தப்படுகிறீர்கள்",
- "this_device": "இந்த சாதனம்",
- "remote": "தொலைநிலை",
- "stats": "புள்ளிவிவரங்கள்",
- "and_n_more": "மற்றும் {count} கூடுதலாக",
- "recently_played": "சமீபத்தில் இயக்கியவை",
- "browse_more": "மேலும் உலாவு",
- "no_title": "தலைப்பு இல்லை",
- "not_playing": "இயக்கப்படவில்லை",
- "epic_failure": "மோசமான தோல்வி!",
- "added_num_tracks_to_queue": "{tracks_length} பாடல்கள் வரிசையில் சேர்க்கப்பட்டன",
- "spotube_has_an_update": "Spotube க்கு ஒரு புதுப்பிப்பு உள்ளது",
- "download_now": "இப்போது பதிவிறக்கு",
- "nightly_version": "Spotube Nightly {nightlyBuildNum} வெளியிடப்பட்டுள்ளது",
- "release_version": "Spotube v{version} வெளியிடப்பட்டுள்ளது",
- "read_the_latest": "சமீபத்திய ",
- "release_notes": "வெளியீட்டு குறிப்புகளைப் படிக்கவும்",
- "pick_color_scheme": "வண்ணத் திட்டத்தைத் தேர்ந்தெடுக்கவும்",
- "save": "சேமி",
- "choose_the_device": "சாதனத்தைத் தேர்ந்தெடுக்கவும்:",
- "multiple_device_connected": "பல சாதனங்கள் இணைக்கப்பட்டுள்ளன.\nஇந்த செயல் நடைபெற வேண்டிய சாதனத்தைத் தேர்ந்தெடுக்கவும்",
- "nothing_found": "எதுவும் கிடைக்கவில்லை",
- "the_box_is_empty": "பெட்டி காலியாக உள்ளது",
- "top_artists": "சிறந்த கலைஞர்கள்",
- "top_albums": "சிறந்த ஆல்பங்கள்",
- "this_week": "இந்த வாரம்",
- "this_month": "இந்த மாதம்",
- "last_6_months": "கடந்த 6 மாதங்கள்",
- "this_year": "இந்த ஆண்டு",
- "last_2_years": "கடந்த 2 ஆண்டுகள்",
- "all_time": "எல்லா நேரமும்",
- "powered_by_provider": "{providerName} ஆல் இயக்கப்படுகிறது",
- "email": "மின்னஞ்சல்",
- "profile_followers": "பின்தொடர்பவர்கள்",
- "birthday": "பிறந்த நாள்",
- "subscription": "சந்தா",
- "not_born": "பிறக்கவில்லை",
- "hacker": "ஹேக்கர்",
- "profile": "சுயவிவரம்",
- "no_name": "பெயர் இல்லை",
- "edit": "திருத்து",
- "user_profile": "பயனர் சுயவிவரம்",
- "count_plays": "{count} முறை இசைக்கப்பட்டது",
- "streaming_fees_hypothetical": "ஸ்ட்ரீமிங் கட்டணங்கள் (கற்பனை)",
- "minutes_listened": "காலம் கேட்டது",
- "streamed_songs": "ஸ்ட்ரீமிங் செய்யப்பட்ட பாடல்கள்",
- "count_streams": "{count} ஸ்ட்ரீம்கள்",
- "owned_by_you": "உங்களால் கொண்டது",
- "copied_shareurl_to_clipboard": "நகலெடுக்கப்பட்டது {shareUrl} கிளிப்போர்டுக்காக",
- "spotify_hipotetical_calculation": "*இது Spotify இன் ஒவ்வொரு ஸ்ட்ரீமிற்கும்\n$0.003 முதல் $0.005 வரை அளவீடு அடிப்படையில் கணக்கிடப்படுகிறது. இது ஒரு கற்பனை\nகணக்கீடு ஆகும், பயனர் எந்த அளவிற்கு கலைஞர்களுக்கு\nஅதோர் பாடலை Spotify மென்பொருளில் கேட்டால் எவ்வளவு பணம் செலுத்தினார்கள் என்பதைக் கண்டுபிடிக்க.",
- "count_mins": "{minutes} நிமிடங்கள்",
- "summary_minutes": "நிமிடங்கள்",
- "summary_listened_to_music": "இசை கேட்டது",
- "summary_songs": "பாடல்கள்",
- "summary_streamed_overall": "மொத்தமாக ஸ்ட்ரீமிங்",
- "summary_owed_to_artists": "கலைஞர்களுக்கு\nஇந்த மாதம் சொந்தமானது",
- "summary_artists": "கலைஞர்கள்",
- "summary_music_reached_you": "இசை உங்களுக்கு வந்தது",
- "summary_full_albums": "முழு ஆல்பங்கள்",
- "summary_got_your_love": "உங்கள் அன்பை பெற்றுக்கொண்டேன்",
- "summary_playlists": "பாடல் பட்டியல்கள்",
- "summary_were_on_repeat": "மீண்டும் மீண்டும் இருந்தன",
- "total_money": "மொத்தம் {money}",
- "webview_not_found": "வெப்வியூ கிடைக்கவில்லை",
- "webview_not_found_description": "உங்கள் சாதனத்தில் எந்தவொரு வெப்வியூ இயக்கத்தை நிறுவவில்லை.\nஇது நிறுவப்பட்டிருந்தால், சுற்றுச்சூழல் பாதையில் PATH உள்ளது என்பதை உறுதிபடுத்தவும்\n\nநிறுவித்த பிறகு, செயலியை மறுதொடக்கம் செய்யவும்",
- "unsupported_platform": "அதிர்ஷ்டகாத உருப்படியை ஆதரிக்கவில்லை",
- "cache_music": "இசையை கேஷ் செய்",
- "open": "திறக்கவும்",
- "cache_folder": "கேஷ் அடைவு",
- "export": "ஏற்றுமதி",
- "clear_cache": "கேஷ் அழிக்கவும்",
- "clear_cache_confirmation": "கேஷைப் அழிக்க விரும்புகிறீர்களா?",
- "export_cache_files": "கேஷில் உள்ள கோப்புகளை ஏற்றுமதி செய்யவும்",
- "found_n_files": "{count} கோப்புகள் கிடைத்தன",
- "export_cache_confirmation": "இந்த கோப்புகளை ஏற்றுமதி செய்ய விரும்புகிறீர்களா?",
- "exported_n_out_of_m_files": "{filesExported} கோப்புகள் ஏற்றுமதி செய்யப்பட்டன, {files} கோப்புகளில்",
- "undo": "செயல்தவிர்",
- "download_all": "அனைத்தையும் பதிவிறக்குக",
- "add_all_to_playlist": "அனைத்தையும் பாடல் பட்டியலில் சேர்க்கவும்",
- "add_all_to_queue": "அனைத்தையும் வரிசைப்படுத்து",
- "play_all_next": "அடுத்த உள்ள அனைத்தையும் இயக்கு",
- "pause": "நிறுத்து",
- "view_all": "அனைத்தையும் காண்க",
- "no_tracks_added_yet": "உங்கள் பாடல்களை இன்னும் சேர்க்கவில்லை என்றால் தெரியாதே",
- "no_tracks": "இங்கு பாடல்கள் எதுவும் இல்லை",
- "no_tracks_listened_yet": "இன்னும் எதையும் கேள்வியில்லை",
- "not_following_artists": "நீங்கள் எந்த கலைஞரையும் பின்தொடரவில்லை",
- "no_favorite_albums_yet": "நீங்கள் இன்னும் எந்த ஆல்பங்களையும் பிடித்தவையாகச் சேர்க்கவில்லை",
- "no_logs_found": "பதிவுகள் எதுவும் கிடைக்கவில்லை",
- "youtube_engine": "YouTube இயந்திரம்",
- "youtube_engine_not_installed_title": "{engine} நிறுவியதில்லை",
- "youtube_engine_not_installed_message": "{engine} உங்கள் கணினியில் நிறுவியதில்லை.",
- "youtube_engine_set_path": "PATH மாறியில் கிடைக்கிறதா என்பதை உறுதிப்படுத்தவும் அல்லது\n{engine} செயல் செய்யக்கூடிய முறையை கீழே அமைக்கவும்",
- "youtube_engine_unix_issue_message": "macOS/Linux/unix போல் OS இல், .zshrc/.bashrc/.bash_profile போன்றவை அமைப்பில் பாதையை PATH அமைப்பது இயலாது.\nநீங்கள்.shell configuration file இல் பாதையை அமைக்க வேண்டும்",
- "download": "பதிவிறக்கு",
- "file_not_found": "கோப்பு கிடைக்கவில்லை",
- "custom": "தனிப்பயன்",
- "add_custom_url": "தனிப்பயன் URL ஐச் சேர்க்கவும்"
+ "guest": "விருந்தினர்",
+ "browse": "உலாவு",
+ "search": "தேடுக",
+ "library": "நூலகம்",
+ "lyrics": "பாடல் வரிகள்",
+ "settings": "அமைப்புகள்",
+ "genre_categories_filter": "வகைகள் அல்லது பாணிகளை வடிகட்டுக...",
+ "genre": "பாணி",
+ "personalized": "தனிப்பயனாக்கப்பட்ட",
+ "featured": "சிறப்பிடம் பெற்ற",
+ "new_releases": "புதிய வெளியீடுகள்",
+ "songs": "பாடல்கள்",
+ "playing_track": "{track} இயங்குகிறது",
+ "queue_clear_alert": "இது தற்போதைய வரிசையை அழிக்கும். {track_length} பாடல்கள் நீக்கப்படும்\nதொடர விரும்புகிறீர்களா?",
+ "load_more": "மேலும் ஏற்றுக",
+ "playlists": "பாடல் பட்டியல்கள்",
+ "artists": "கலைஞர்கள்",
+ "albums": "ஆல்பங்கள்",
+ "tracks": "பாடல்கள்",
+ "downloads": "பதிவிறக்கங்கள்",
+ "filter_playlists": "உங்கள் பாடல் பட்டியல்களை வடிகட்டுக...",
+ "liked_tracks": "விரும்பிய பாடல்கள்",
+ "liked_tracks_description": "உங்கள் விரும்பிய பாடல்கள் அனைத்தும்",
+ "playlist": "பாடல் பட்டியல்",
+ "create_a_playlist": "பாடல் பட்டியலை உருவாக்குக",
+ "update_playlist": "பாடல் பட்டியலைப் புதுப்பிக்க",
+ "create": "உருவாக்கு",
+ "cancel": "ரத்து செய்",
+ "update": "புதுப்பி",
+ "playlist_name": "பாடல் பட்டியல் பெயர்",
+ "name_of_playlist": "பாடல் பட்டியலின் பெயர்",
+ "description": "விளக்கம்",
+ "public": "பொது",
+ "collaborative": "கூட்டு",
+ "search_local_tracks": "உள்ளூர் பாடல்களைத் தேடுக...",
+ "play": "இயக்கு",
+ "delete": "அழி",
+ "none": "எதுவுமில்லை",
+ "sort_a_z": "A-Z வரிசைப்படுத்து",
+ "sort_z_a": "Z-A வரிசைப்படுத்து",
+ "sort_artist": "கலைஞர் மூலம் வரிசைப்படுத்து",
+ "sort_album": "ஆல்பம் மூலம் வரிசைப்படுத்து",
+ "sort_duration": "கால அளவு மூலம் வரிசைப்படுத்து",
+ "sort_tracks": "பாடல்களை வரிசைப்படுத்து",
+ "currently_downloading": "தற்போது பதிவிறக்குகிறது ({tracks_length})",
+ "cancel_all": "அனைத்தையும் ரத்து செய்",
+ "filter_artist": "கலைஞர்களை வடிகட்டுக...",
+ "followers": "{followers} பின்தொடர்பவர்கள்",
+ "add_artist_to_blacklist": "கலைஞரை தடைப்பட்டியலில் சேர்க்க",
+ "top_tracks": "சிறந்த பாடல்கள்",
+ "fans_also_like": "ரசிகர்கள் விரும்புவது",
+ "loading": "ஏற்றுகிறது...",
+ "artist": "கலைஞர்",
+ "blacklisted": "தடைப்பட்டியலில் உள்ளது",
+ "following": "பின்தொடர்கிறது",
+ "follow": "பின்தொடர்",
+ "artist_url_copied": "கலைஞர் URL கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது",
+ "added_to_queue": "{tracks} பாடல்கள் வரிசையில் சேர்க்கப்பட்டன",
+ "filter_albums": "ஆல்பங்களை வடிகட்டுக...",
+ "synced": "ஒத்திசைக்கப்பட்டது",
+ "plain": "சாதாரண",
+ "shuffle": "கலக்கு",
+ "search_tracks": "பாடல்களைத் தேடுக...",
+ "released": "வெளியிடப்பட்டது",
+ "error": "பிழை {error}",
+ "title": "தலைப்பு",
+ "time": "நேரம்",
+ "more_actions": "மேலும் செயல்கள்",
+ "download_count": "பதிவிறக்கு ({count})",
+ "add_count_to_playlist": "({count}) பாடல் பட்டியலில் சேர்",
+ "add_count_to_queue": "({count}) வரிசையில் சேர்",
+ "play_count_next": "({count}) அடுத்து இயக்கு",
+ "album": "ஆல்பம்",
+ "copied_to_clipboard": "{data} கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது",
+ "add_to_following_playlists": "{track} பின்வரும் பாடல் பட்டியல்களில் சேர்",
+ "add": "சேர்",
+ "added_track_to_queue": "{track} வரிசையில் சேர்க்கப்பட்டது",
+ "add_to_queue": "வரிசையில் சேர்",
+ "track_will_play_next": "{track} அடுத்து இயக்கப்படும்",
+ "play_next": "அடுத்து இயக்கு",
+ "removed_track_from_queue": "{track} வரிசையிலிருந்து நீக்கப்பட்டது",
+ "remove_from_queue": "வரிசையிலிருந்து நீக்கு",
+ "remove_from_favorites": "பிடித்தவையிலிருந்து நீக்கு",
+ "save_as_favorite": "பிடித்தவையாக சேமி",
+ "add_to_playlist": "பாடல் பட்டியலில் சேர்",
+ "remove_from_playlist": "பாடல் பட்டியலிலிருந்து நீக்கு",
+ "add_to_blacklist": "தடைப்பட்டியலில் சேர்",
+ "remove_from_blacklist": "தடைப்பட்டியலிலிருந்து நீக்கு",
+ "share": "பகிர்",
+ "mini_player": "சிறிய இயக்கி",
+ "slide_to_seek": "முன்னோக்கி அல்லது பின்னோக்கி செல்ல சறுக்கவும்",
+ "shuffle_playlist": "பாடல் பட்டியலை கலக்கு",
+ "unshuffle_playlist": "பாடல் பட்டியலை கலக்காதே",
+ "previous_track": "முந்தைய பாடல்",
+ "next_track": "அடுத்த பாடல்",
+ "pause_playback": "இயக்கத்தை நிறுத்து",
+ "resume_playback": "இயக்கத்தை தொடர்",
+ "loop_track": "பாடலை சுழற்று",
+ "no_loop": "சுழற்சி இல்லை",
+ "repeat_playlist": "பாடல் பட்டியலை மீண்டும் இயக்கு",
+ "queue": "வரிசை",
+ "alternative_track_sources": "மாற்று பாடல் மூலங்கள்",
+ "download_track": "பாடலைப் பதிவிறக்கு",
+ "tracks_in_queue": "வரிசையில் {tracks} பாடல்கள்",
+ "clear_all": "அனைத்தையும் அழி",
+ "show_hide_ui_on_hover": "மேலே வரும்போது UI ஐக் காட்டு/மறை",
+ "always_on_top": "எப்போதும் மேலே",
+ "exit_mini_player": "சிறிய இயக்கியிலிருந்து வெளியேறு",
+ "download_location": "பதிவிறக்க இடம்",
+ "local_library": "உள்ளூர் நூலகம்",
+ "add_library_location": "நூலகத்தில் சேர்",
+ "remove_library_location": "நூலகத்திலிருந்து நீக்கு",
+ "account": "கணக்கு",
+ "login_with_spotify": "உங்கள் Spotify கணக்கில் உள்நுழைக",
+ "connect_with_spotify": "Spotify உடன் இணைக்கவும்",
+ "logout": "வெளியேறு",
+ "logout_of_this_account": "இந்த கணக்கிலிருந்து வெளியேறு",
+ "language_region": "மொழி & பிராந்தியம்",
+ "language": "மொழி",
+ "system_default": "கணினி இயல்புநிலை",
+ "market_place_region": "சந்தை பிராந்தியம்",
+ "recommendation_country": "பரிந்துரை நாடு",
+ "appearance": "தோற்றம்",
+ "layout_mode": "அமைப்பு முறை",
+ "override_layout_settings": "தளவமைப்பு அமைப்புகளை மாற்றியமை",
+ "adaptive": "தகவமைப்பு",
+ "compact": "சுருக்கமான",
+ "extended": "விரிவான",
+ "theme": "தீம்",
+ "dark": "இருள்",
+ "light": "வெளிர்",
+ "system": "கணினி வழி",
+ "accent_color": "அழுத்த நிறம்",
+ "sync_album_color": "ஆல்பம் நிறத்தை ஒத்திசை",
+ "sync_album_color_description": "ஆல்பம் படத்தின் முக்கிய நிறத்தை அழுத்த நிறமாகப் பயன்படுத்துகிறது",
+ "playback": "பின்னணி",
+ "audio_quality": "ஒலி தரம்",
+ "high": "உயர்",
+ "low": "குறைந்த",
+ "pre_download_play": "முன்பதிவிறக்கம் மற்றும் இயக்கம்",
+ "pre_download_play_description": "ஒலியை ஸ்ட்ரீம் செய்வதற்குப் பதிலாக, பைட்டுகளைப் பதிவிறக்கி இயக்கவும் (அதிக பேண்ட்விட்த் பயனர்களுக்கு பரிந்துரைக்கப்படுகிறது)",
+ "skip_non_music": "இசையல்லாத பகுதிகளைத் தவிர் (SponsorBlock)",
+ "blacklist_description": "தடைசெய்யப்பட்ட பாடல்கள் மற்றும் கலைஞர்கள்",
+ "wait_for_download_to_finish": "தற்போதைய பதிவிறக்கம் முடியும் வரை காத்திருக்கவும்",
+ "desktop": "கணினி",
+ "close_behavior": "மூடும் நடத்தை",
+ "close": "மூடு",
+ "minimize_to_tray": "ட்ரேயை குறைக்கவும்",
+ "show_tray_icon": "ட்ரே ஐகானைக் காட்டு",
+ "about": "பற்றி",
+ "u_love_spotube": "நீங்கள் Spotube ஐ நேசிக்கிறீர்கள் என்பது எங்களுக்குத் தெரியும்",
+ "check_for_updates": "புதுப்பிப்புகளைச் சரிபார்",
+ "about_spotube": "Spotube பற்றி",
+ "blacklist": "தடைப்பட்டியல்",
+ "please_sponsor": "தயவுசெய்து ஆதரவு/நன்கொடை அளியுங்கள்",
+ "spotube_description": "Spotube, ஒரு லேசான, பல தளங்களில் இயங்கும், அனைவருக்கும் இலவசமான spotify கிளையன்ட்",
+ "version": "பதிப்பு",
+ "build_number": "கட்டமைப்பு எண்",
+ "founder": "நிறுவனர்",
+ "repository": "களஞ்சியம்",
+ "bug_issues": "பிழை_சிக்கல்கள்",
+ "made_with": "வங்காளதேசத்திலிருந்து🇧🇩 ❤️ உருவாக்கப்பட்டது",
+ "kingkor_roy_tirtho": "கிங்கர் ராய் திர்தோ",
+ "copyright": "© 2021-{current_year} கிங்கர் ராய் திர்தோ",
+ "license": "உரிமம்",
+ "add_spotify_credentials": "தொடங்குவதற்கு உங்கள் spotify சான்றுகளைச் சேர்க்கவும்",
+ "credentials_will_not_be_shared_disclaimer": "கவலைப்பட வேண்டாம், உங்கள் சான்றுகள் எதுவும் சேகரிக்கப்படாது அல்லது யாருடனும் பகிரப்படாது",
+ "know_how_to_login": "இதை எப்படி செய்வது என்று தெரியவில்லையா?",
+ "follow_step_by_step_guide": "படிப்படியான வழிகாட்டியைப் பின்பற்றவும்",
+ "spotify_cookie": "Spotify {name} நட்புநிரல்",
+ "cookie_name_cookie": "{name} நட்புநிரல்",
+ "fill_in_all_fields": "அனைத்து களங்களையும் நிரப்பவும்",
+ "submit": "சமர்ப்பி",
+ "exit": "வெளியேறு",
+ "previous": "முந்தைய",
+ "next": "அடுத்து",
+ "done": "முடிந்தது",
+ "step_1": "முதல் படி",
+ "first_go_to": "முதலில், செல்லவேண்டியது",
+ "login_if_not_logged_in": "நீங்கள் உள்நுழையவில்லை என்றால் உள்நுழைக/பதிவுசெய்க",
+ "step_2": "இரண்டாம் படி",
+ "step_2_steps": "1. நீங்கள் உள்நுழைந்தவுடன், F12 ஐ அழுத்தவும் அல்லது வலது கிளிக் செய்து > ஆய்வு செய்யவும் உலாவி டெவ்டூல்களைத் திறக்கவும்.\n2. பின்னர் \"பயன்பாடு\" தாவலுக்குச் செல்லவும் (Chrome, Edge, Brave போன்றவை) அல்லது \"சேமிப்பகம்\" தாவல் (Firefox, Palemoon போன்றவை)\n3. \"குக்கிகள்\" பிரிவுக்குச் சென்று பின்னர் \"https://accounts.spotify.com\" பிரிவுக்குச் செல்லவும்",
+ "step_3": "மூன்றாம் படி",
+ "step_3_steps": "\"sp_dc\" நட்புநிரலின் மதிப்பை நகலெடுக்கவும்",
+ "success_emoji": "வெற்றி🥳",
+ "success_message": "இப்போது நீங்கள் உங்கள் Spotify கணக்கில் வெற்றிகரமாக உள்நுழைந்துள்ளீர்கள். நல்லது, நண்பரே!",
+ "step_4": "நான்காம் படி",
+ "step_4_steps": "நகலெடுக்கப்பட்ட \"sp_dc\" மதிப்பை ஒட்டவும்",
+ "something_went_wrong": "ஏதோ தவறு நடந்துவிட்டது",
+ "piped_instance": "Piped சேவையகம் நிகழ்வு",
+ "piped_description": "பாடல் பொருத்தத்திற்குப் பயன்படுத்த வேண்டிய Piped சேவையகம் நிகழ்வு",
+ "piped_warning": "அவற்றில் சில நன்றாக வேலை செய்யாமல் இருக்கலாம். எனவே உங்கள் சொந்த ஆபத்தில் பயன்படுத்தவும்",
+ "invidious_instance": "Invidious சேவையக நிகழ்வு",
+ "invidious_description": "பாடல் பொருத்தத்திற்குப் பயன்படுத்த வேண்டிய Invidious சேவையக நிகழ்வு",
+ "invidious_warning": "அவற்றில் சில நன்றாக வேலை செய்யாமல் இருக்கலாம். எனவே உங்கள் சொந்த ஆபத்தில் பயன்படுத்தவும்",
+ "generate": "உருவாக்கு",
+ "track_exists": "பாடல் {track} ஏற்கனவே உள்ளது",
+ "replace_downloaded_tracks": "பதிவிறக்கம் செய்யப்பட்ட அனைத்து பாடல்களையும் மாற்றவும்",
+ "skip_download_tracks": "பதிவிறக்கம் செய்யப்பட்ட அனைத்து பாடல்களையும் தவிர்க்கவும்",
+ "do_you_want_to_replace": "ஏற்கனவே உள்ள பாடலை மாற்ற விரும்புகிறீர்களா?",
+ "replace": "மாற்று",
+ "skip": "தவிர்",
+ "select_up_to_count_type": "{count} {type} வரை தேர்ந்தெடுக்கவும்",
+ "select_genres": "வகைகளைத் தேர்ந்தெடுக்கவும்",
+ "add_genres": "வகைகளைச் சேர்க்கவும்",
+ "country": "நாடு",
+ "number_of_tracks_generate": "உருவாக்க வேண்டிய பாடல்களின் எண்ணிக்கை",
+ "acousticness": "அகவுஸ்டிக்னெஸ்",
+ "danceability": "நடனத்தன்மை",
+ "energy": "ஆற்றல்",
+ "instrumentalness": "கருவித்தன்மை",
+ "liveness": "உயிர்ப்புத்தன்மை",
+ "loudness": "ஒலி அளவு",
+ "speechiness": "பேச்சுத்தன்மை",
+ "valence": "உணர்வு",
+ "popularity": "பிரபலம்",
+ "key": "இசை குறிப்பு",
+ "duration": "கால அளவு (வினாடிகள்)",
+ "tempo": "வேகம் (BPM)",
+ "mode": "முறை",
+ "time_signature": "நேர கையொப்பம்",
+ "short": "குறுகிய",
+ "medium": "நடுத்தர",
+ "long": "நீண்ட",
+ "min": "குறைந்தபட்சம்",
+ "max": "அதிகபட்சம்",
+ "target": "இலக்கு",
+ "moderate": "மிதமான",
+ "deselect_all": "அனைத்தையும் தேர்வுநீக்கு",
+ "select_all": "அனைத்தையும் தேர்ந்தெடு",
+ "are_you_sure": "உறுதியாக இருக்கிறீர்களா?",
+ "generating_playlist": "உங்கள் தனிப்பயன்பாட்டிற்கான பாடல் பட்டியலை உருவாக்குகிறது...",
+ "selected_count_tracks": "{count} பாடல்கள் தேர்ந்தெடுக்கப்பட்டன",
+ "download_warning": "நீங்கள் அனைத்து பாடல்களையும் மொத்தமாக பதிவிறக்கினால், நீங்கள் தெளிவாக இசையைத் திருடுகிறீர்கள் மற்றும் இசையின் படைப்பாற்றல் சமூகத்திற்கு சேதம் விளைவிக்கிறீர்கள். நீங்கள் இதை அறிந்திருக்கிறீர்கள் என்று நம்புகிறேன். எப்போதும், கலைஞரின் கடின உழைப்பை மதித்து ஆதரிக்க முயற்சி செய்யுங்கள்",
+ "download_ip_ban_warning": "மேலும், அதிகப்படியான பதிவிறக்க கோரிக்கைகள் காரணமாக உங்கள் IP YouTube இல் தடைசெய்யப்படலாம். IP தடை என்பது குறைந்தது 2-3 மாதங்களுக்கு அந்த IP சாதனத்திலிருந்து YouTube ஐப் பயன்படுத்த முடியாது (நீங்கள் உள்நுழைந்திருந்தாலும் கூட). இது ஒருபோதும் நடந்தால் Spotube பொறுப்பேற்காது",
+ "by_clicking_accept_terms": "'ஏற்றுக்கொள்' என்பதைக் கிளிக் செய்வதன் மூலம் பின்வரும் விதிமுறைகளுக்கு நீங்கள் ஒப்புக்கொள்கிறீர்கள்:",
+ "download_agreement_1": "நான் இசையைத் திருடுகிறேன் என்பது எனக்குத் தெரியும். நான் கெட்டவன்",
+ "download_agreement_2": "நான் கலைஞரை முடிந்தவரை ஆதரிப்பேன், அவர்களின் கலைக்கு பணம் செலுத்த எனக்கு பணம் இல்லாததால் மட்டுமே இதைச் செய்கிறேன்",
+ "download_agreement_3": "என் IP YouTube இல் தடைசெய்யப்படலாம் என்பதை நான் முழுமையாக அறிவேன், மேலும் என் தற்போதைய செயலால் ஏற்படும் எந்த விபத்துகளுக்கும் Spotube அல்லது அதன் உரிமையாளர்கள்/பங்களிப்பாளர்களை பொறுப்பாக்க மாட்டேன்",
+ "decline": "மறு",
+ "accept": "ஏற்றுக்கொள்",
+ "details": "விவரங்கள்",
+ "youtube": "YouTube",
+ "channel": "சேனல்",
+ "likes": "விருப்பங்கள்",
+ "dislikes": "விருப்பமில்லாதவை",
+ "views": "பார்வைகள்",
+ "streamUrl": "ஸ்ட்ரீம் URL",
+ "stop": "நிறுத்து",
+ "sort_newest": "புதிதாக சேர்க்கப்பட்டவற்றை வரிசைப்படுத்து",
+ "sort_oldest": "பழமையானவற்றை வரிசைப்படுத்து",
+ "sleep_timer": "உறக்க நேரம்",
+ "mins": "{minutes} நிமிடங்கள்",
+ "hours": "{hours} மணிநேரங்கள்",
+ "hour": "{hours} மணிநேரம்",
+ "custom_hours": "தனிப்பயன் மணிநேரங்கள்",
+ "logs": "பதிவுகள்",
+ "developers": "உருவாக்குநர்கள்",
+ "not_logged_in": "நீங்கள் உள்நுழையவில்லை",
+ "search_mode": "தேடல் முறை",
+ "audio_source": "ஒலி மூலம்",
+ "ok": "சரி",
+ "failed_to_encrypt": "குறியாக்கம் தோல்வியடைந்தது",
+ "encryption_failed_warning": "Spotube உங்கள் தரவை பாதுகாப்பாக சேமிக்க குறியாக்கத்தைப் பயன்படுத்துகிறது. ஆனால் அவ்வாறு செய்ய முடியவில்லை. எனவே இது பாதுகாப்பற்ற சேமிப்பகத்திற்கு மாறும்\nநீங்கள் லினக்ஸ் பயன்படுத்துகிறீர்கள் என்றால், எந்த ரகசிய சேவையும் (gnome-keyring, kde-wallet, keepassxc போன்றவை) நிறுவப்பட்டுள்ளதா என்பதை உறுதிப்படுத்தவும்",
+ "querying_info": "தகவலைக் கேட்கிறது...",
+ "piped_api_down": "Piped API செயலிழந்துள்ளது",
+ "piped_down_error_instructions": "Piped நிகழ்வு {pipedInstance} தற்போது செயலிழந்துள்ளது\n\nநிகழ்வை மாற்றவும் அல்லது 'API வகை'யை அதிகாரப்பூர்வ YouTube API க்கு மாற்றவும்\n\nமாற்றத்திற்குப் பிறகு பயன்பாட்டை மறுதொடக்கம் செய்வதை உறுதிப்படுத்தவும்",
+ "you_are_offline": "நீங்கள் தற்போது ஆஃப்லைனில் உள்ளீர்கள்",
+ "connection_restored": "உங்கள் இணைய இணைப்பு மீட்டெடுக்கப்பட்டது",
+ "use_system_title_bar": "கணினி தலைப்புப் பட்டியைப் பயன்படுத்தவும்",
+ "crunching_results": "முடிவுகளை செயலாக்குகிறது...",
+ "search_to_get_results": "முடிவுகளைப் பெற தேடவும்",
+ "use_amoled_mode": "கருமை நிற இருண்ட தீம்",
+ "pitch_dark_theme": "AMOLED முறை",
+ "normalize_audio": "ஒலியை சீரமை",
+ "change_cover": "அட்டையை மாற்று",
+ "add_cover": "அட்டையைச் சேர்",
+ "restore_defaults": "இயல்புநிலைகளை மீட்டமை",
+ "download_music_codec": "இசை கோடெக்கை பதிவிறக்கு",
+ "streaming_music_codec": "இசை கோடெக்கை ஸ்ட்ரீம் செய்",
+ "login_with_lastfm": "Last.fm உடன் உள்நுழைக",
+ "connect": "இணை",
+ "disconnect_lastfm": "Last.fm இலிருந்து துண்டி",
+ "disconnect": "துண்டி",
+ "username": "பயனர்பெயர்",
+ "password": "கடவுச்சொல்",
+ "login": "உள்நுழைக",
+ "login_with_your_lastfm": "உங்கள் Last.fm கணக்குடன் உள்நுழைக",
+ "scrobble_to_lastfm": "Last.fm க்கு ஸ்க்ரோபிள் செய்",
+ "go_to_album": "ஆல்பத்திற்குச் செல்",
+ "discord_rich_presence": "Discord செழுமையான தோற்றம்",
+ "browse_all": "அனைத்தையும் உலாவு",
+ "genres": "வகைகள்",
+ "explore_genres": "வகைகளை ஆராயுங்கள்",
+ "friends": "நண்பர்கள்",
+ "no_lyrics_available": "மன்னிக்கவும், இந்தப் பாடலுக்கான பாடல் வரிகளைக் கண்டுபிடிக்க முடியவில்லை",
+ "start_a_radio": "வானொலியைத் தொடங்கு",
+ "how_to_start_radio": "வானொலியை எவ்வாறு தொடங்க விரும்புகிறீர்கள்?",
+ "replace_queue_question": "தற்போதைய வரிசையை மாற்ற விரும்புகிறீர்களா அல்லது அதனுடன் சேர்க்க விரும்புகிறீர்களா?",
+ "endless_playback": "முடிவற்ற இயக்கம்",
+ "delete_playlist": "பாடல் பட்டியலை நீக்கு",
+ "delete_playlist_confirmation": "இந்த பாடல் பட்டியலை நீக்க விரும்புகிறீர்களா?",
+ "local_tracks": "உள்ளூர் பாடல்கள்",
+ "local_tab": "உள்ளூர்",
+ "song_link": "பாடல் இணைப்பு",
+ "skip_this_nonsense": "இந்த அர்த்தமற்றதைத் தவிர்",
+ "freedom_of_music": "\"இசையின் சுதந்திரம்\"",
+ "freedom_of_music_palm": "\"உங்கள் கைகளில் இசையின் சுதந்திரம்\"",
+ "get_started": "தொடங்குவோம்",
+ "youtube_source_description": "பரிந்துரைக்கப்படுகிறது மற்றும் சிறப்பாக செயல்படுகிறது.",
+ "piped_source_description": "சுதந்திரமாக உணர்கிறீர்களா? YouTube போலவே ஆனால் மிகவும் சுதந்திரமானது.",
+ "jiosaavn_source_description": "தெற்காசியப் பிராந்தியத்திற்கு சிறந்தது.",
+ "invidious_source_description": "Piped ஐப் போன்றது ஆனால் அதிக கிடைக்கும் தன்மையுடன்.",
+ "highest_quality": "உயர்ந்த தரம்: {quality}",
+ "select_audio_source": "ஒலி மூலத்தைத் தேர்ந்தெடுக்கவும்",
+ "endless_playback_description": "வரிசையின் இறுதியில் புதிய பாடல்களை\nதானாகவே சேர்க்கவும்",
+ "choose_your_region": "உங்கள் பிராந்தியத்தைத் தேர்ந்தெடுக்கவும்",
+ "choose_your_region_description": "இது உங்கள் இருப்பிடத்திற்கான சரியான உள்ளடக்கத்தை\nSpotube காட்ட உதவும்.",
+ "choose_your_language": "உங்கள் மொழியைத் தேர்ந்தெடுக்கவும்",
+ "help_project_grow": "இந்த திட்டம் வளர உதவுங்கள்",
+ "help_project_grow_description": "Spotube ஒரு திறந்த மூல திட்டம். திட்டத்திற்கு பங்களிப்பு செய்வதன் மூலம், பிழைகளைப் புகாரளிப்பதன் மூலம் அல்லது புதிய அம்சங்களைப் பரிந்துரைப்பதன் மூலம் இந்தத் திட்டம் வளர உதவலாம்.",
+ "contribute_on_github": "GitHub இல் பங்களியுங்கள்",
+ "donate_on_open_collective": "Open Collective இல் நன்கொடை அளியுங்கள்",
+ "browse_anonymously": "அநாமதேயமாக உலாவுக",
+ "enable_connect": "இணைப்பை இயக்கு",
+ "enable_connect_description": "மற்ற சாதனங்களிலிருந்து Spotube ஐக் கட்டுப்படுத்தவும்",
+ "devices": "சாதனங்கள்",
+ "select": "தேர்ந்தெடு",
+ "connect_client_alert": "நீங்கள் {client} ஆல் கட்டுப்படுத்தப்படுகிறீர்கள்",
+ "this_device": "இந்த சாதனம்",
+ "remote": "தொலைநிலை",
+ "stats": "புள்ளிவிவரங்கள்",
+ "and_n_more": "மற்றும் {count} கூடுதலாக",
+ "recently_played": "சமீபத்தில் இயக்கியவை",
+ "browse_more": "மேலும் உலாவு",
+ "no_title": "தலைப்பு இல்லை",
+ "not_playing": "இயக்கப்படவில்லை",
+ "epic_failure": "மோசமான தோல்வி!",
+ "added_num_tracks_to_queue": "{tracks_length} பாடல்கள் வரிசையில் சேர்க்கப்பட்டன",
+ "spotube_has_an_update": "Spotube க்கு ஒரு புதுப்பிப்பு உள்ளது",
+ "download_now": "இப்போது பதிவிறக்கு",
+ "nightly_version": "Spotube Nightly {nightlyBuildNum} வெளியிடப்பட்டுள்ளது",
+ "release_version": "Spotube v{version} வெளியிடப்பட்டுள்ளது",
+ "read_the_latest": "சமீபத்திய ",
+ "release_notes": "வெளியீட்டு குறிப்புகளைப் படிக்கவும்",
+ "pick_color_scheme": "வண்ணத் திட்டத்தைத் தேர்ந்தெடுக்கவும்",
+ "save": "சேமி",
+ "choose_the_device": "சாதனத்தைத் தேர்ந்தெடுக்கவும்:",
+ "multiple_device_connected": "பல சாதனங்கள் இணைக்கப்பட்டுள்ளன.\nஇந்த செயல் நடைபெற வேண்டிய சாதனத்தைத் தேர்ந்தெடுக்கவும்",
+ "nothing_found": "எதுவும் கிடைக்கவில்லை",
+ "the_box_is_empty": "பெட்டி காலியாக உள்ளது",
+ "top_artists": "சிறந்த கலைஞர்கள்",
+ "top_albums": "சிறந்த ஆல்பங்கள்",
+ "this_week": "இந்த வாரம்",
+ "this_month": "இந்த மாதம்",
+ "last_6_months": "கடந்த 6 மாதங்கள்",
+ "this_year": "இந்த ஆண்டு",
+ "last_2_years": "கடந்த 2 ஆண்டுகள்",
+ "all_time": "எல்லா நேரமும்",
+ "powered_by_provider": "{providerName} ஆல் இயக்கப்படுகிறது",
+ "email": "மின்னஞ்சல்",
+ "profile_followers": "பின்தொடர்பவர்கள்",
+ "birthday": "பிறந்த நாள்",
+ "subscription": "சந்தா",
+ "not_born": "பிறக்கவில்லை",
+ "hacker": "ஹேக்கர்",
+ "profile": "சுயவிவரம்",
+ "no_name": "பெயர் இல்லை",
+ "edit": "திருத்து",
+ "user_profile": "பயனர் சுயவிவரம்",
+ "count_plays": "{count} முறை இசைக்கப்பட்டது",
+ "streaming_fees_hypothetical": "ஸ்ட்ரீமிங் கட்டணங்கள் (கற்பனை)",
+ "minutes_listened": "காலம் கேட்டது",
+ "streamed_songs": "ஸ்ட்ரீமிங் செய்யப்பட்ட பாடல்கள்",
+ "count_streams": "{count} ஸ்ட்ரீம்கள்",
+ "owned_by_you": "உங்களால் கொண்டது",
+ "copied_shareurl_to_clipboard": "நகலெடுக்கப்பட்டது {shareUrl} கிளிப்போர்டுக்காக",
+ "spotify_hipotetical_calculation": "*இது Spotify இன் ஒவ்வொரு ஸ்ட்ரீமிற்கும்\n$0.003 முதல் $0.005 வரை அளவீடு அடிப்படையில் கணக்கிடப்படுகிறது. இது ஒரு கற்பனை\nகணக்கீடு ஆகும், பயனர் எந்த அளவிற்கு கலைஞர்களுக்கு\nஅதோர் பாடலை Spotify மென்பொருளில் கேட்டால் எவ்வளவு பணம் செலுத்தினார்கள் என்பதைக் கண்டுபிடிக்க.",
+ "count_mins": "{minutes} நிமிடங்கள்",
+ "summary_minutes": "நிமிடங்கள்",
+ "summary_listened_to_music": "இசை கேட்டது",
+ "summary_songs": "பாடல்கள்",
+ "summary_streamed_overall": "மொத்தமாக ஸ்ட்ரீமிங்",
+ "summary_owed_to_artists": "கலைஞர்களுக்கு\nஇந்த மாதம் சொந்தமானது",
+ "summary_artists": "கலைஞர்கள்",
+ "summary_music_reached_you": "இசை உங்களுக்கு வந்தது",
+ "summary_full_albums": "முழு ஆல்பங்கள்",
+ "summary_got_your_love": "உங்கள் அன்பை பெற்றுக்கொண்டேன்",
+ "summary_playlists": "பாடல் பட்டியல்கள்",
+ "summary_were_on_repeat": "மீண்டும் மீண்டும் இருந்தன",
+ "total_money": "மொத்தம் {money}",
+ "webview_not_found": "வெப்வியூ கிடைக்கவில்லை",
+ "webview_not_found_description": "உங்கள் சாதனத்தில் எந்தவொரு வெப்வியூ இயக்கத்தை நிறுவவில்லை.\nஇது நிறுவப்பட்டிருந்தால், சுற்றுச்சூழல் பாதையில் PATH உள்ளது என்பதை உறுதிபடுத்தவும்\n\nநிறுவித்த பிறகு, செயலியை மறுதொடக்கம் செய்யவும்",
+ "unsupported_platform": "அதிர்ஷ்டகாத உருப்படியை ஆதரிக்கவில்லை",
+ "cache_music": "இசையை கேஷ் செய்",
+ "open": "திறக்கவும்",
+ "cache_folder": "கேஷ் அடைவு",
+ "export": "ஏற்றுமதி",
+ "clear_cache": "கேஷ் அழிக்கவும்",
+ "clear_cache_confirmation": "கேஷைப் அழிக்க விரும்புகிறீர்களா?",
+ "export_cache_files": "கேஷில் உள்ள கோப்புகளை ஏற்றுமதி செய்யவும்",
+ "found_n_files": "{count} கோப்புகள் கிடைத்தன",
+ "export_cache_confirmation": "இந்த கோப்புகளை ஏற்றுமதி செய்ய விரும்புகிறீர்களா?",
+ "exported_n_out_of_m_files": "{filesExported} கோப்புகள் ஏற்றுமதி செய்யப்பட்டன, {files} கோப்புகளில்",
+ "undo": "செயல்தவிர்",
+ "download_all": "அனைத்தையும் பதிவிறக்குக",
+ "add_all_to_playlist": "அனைத்தையும் பாடல் பட்டியலில் சேர்க்கவும்",
+ "add_all_to_queue": "அனைத்தையும் வரிசைப்படுத்து",
+ "play_all_next": "அடுத்த உள்ள அனைத்தையும் இயக்கு",
+ "pause": "நிறுத்து",
+ "view_all": "அனைத்தையும் காண்க",
+ "no_tracks_added_yet": "உங்கள் பாடல்களை இன்னும் சேர்க்கவில்லை என்றால் தெரியாதே",
+ "no_tracks": "இங்கு பாடல்கள் எதுவும் இல்லை",
+ "no_tracks_listened_yet": "இன்னும் எதையும் கேள்வியில்லை",
+ "not_following_artists": "நீங்கள் எந்த கலைஞரையும் பின்தொடரவில்லை",
+ "no_favorite_albums_yet": "நீங்கள் இன்னும் எந்த ஆல்பங்களையும் பிடித்தவையாகச் சேர்க்கவில்லை",
+ "no_logs_found": "பதிவுகள் எதுவும் கிடைக்கவில்லை",
+ "youtube_engine": "YouTube இயந்திரம்",
+ "youtube_engine_not_installed_title": "{engine} நிறுவியதில்லை",
+ "youtube_engine_not_installed_message": "{engine} உங்கள் கணினியில் நிறுவியதில்லை.",
+ "youtube_engine_set_path": "PATH மாறியில் கிடைக்கிறதா என்பதை உறுதிப்படுத்தவும் அல்லது\n{engine} செயல் செய்யக்கூடிய முறையை கீழே அமைக்கவும்",
+ "youtube_engine_unix_issue_message": "macOS/Linux/unix போல் OS இல், .zshrc/.bashrc/.bash_profile போன்றவை அமைப்பில் பாதையை PATH அமைப்பது இயலாது.\nநீங்கள்.shell configuration file இல் பாதையை அமைக்க வேண்டும்",
+ "download": "பதிவிறக்கு",
+ "file_not_found": "கோப்பு கிடைக்கவில்லை",
+ "custom": "தனிப்பயன்",
+ "add_custom_url": "தனிப்பயன் URL ஐச் சேர்க்கவும்",
+ "edit_port": "போர்டு திருத்தவும்",
+ "port_helper_msg": "இயல்புநிலை -1 ஆகும், இது சீரற்ற எண்ணை குறிக்கிறது. நீங்கள் தீயணைப்பு அமைக்கப்பட்டிருந்தால், இதை அமைப்பது பரிந்துரைக்கப்படுகிறது.",
+ "connect_request": "{client} க்கு இணைக்க அனுமதிக்கவா?",
+ "connection_request_denied": "இணைப்பு மறுக்கப்பட்டது. பயனர் அணுகலை மறுத்தார்."
}
\ No newline at end of file
diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb
index 8e9a0318..38decf66 100644
--- a/lib/l10n/app_th.arb
+++ b/lib/l10n/app_th.arb
@@ -427,5 +427,9 @@
"download": "ดาวน์โหลด",
"file_not_found": "ไม่พบไฟล์",
"custom": "กำหนดเอง",
- "add_custom_url": "เพิ่ม URL แบบกำหนดเอง"
+ "add_custom_url": "เพิ่ม URL แบบกำหนดเอง",
+ "edit_port": "แก้ไขพอร์ต",
+ "port_helper_msg": "ค่าเริ่มต้นคือ -1 ซึ่งหมายถึงหมายเลขสุ่ม หากคุณได้กำหนดค่าไฟร์วอลล์แล้ว แนะนำให้ตั้งค่านี้",
+ "connect_request": "อนุญาตให้ {client} เชื่อมต่อหรือไม่?",
+ "connection_request_denied": "การเชื่อมต่อล้มเหลว ผู้ใช้ปฏิเสธการเข้าถึง"
}
\ No newline at end of file
diff --git a/lib/l10n/app_tl.arb b/lib/l10n/app_tl.arb
index c395cdc7..a1c4264c 100644
--- a/lib/l10n/app_tl.arb
+++ b/lib/l10n/app_tl.arb
@@ -1,428 +1,432 @@
{
- "guest": "Bisita",
- "browse": "Mag-browse",
- "search": "Maghanap",
- "library": "Silid-aklatan",
- "lyrics": "Mga Liriko",
- "settings": "Mga Setting",
- "genre_categories_filter": "I-filter ang mga kategorya o genre...",
- "genre": "Genre",
- "personalized": "Naka-personalize",
- "featured": "Tampok",
- "new_releases": "Mga Bagong Paglabas",
- "songs": "Mga Kanta",
- "playing_track": "Tumutugtog ang {track}",
- "queue_clear_alert": "Ito ay magbubura ng kasalukuyang pila. {track_length} na mga track ang tatanggalin\nGusto mo bang magpatuloy?",
- "load_more": "Mag-load pa",
- "playlists": "Mga Playlist",
- "artists": "Mga Artista",
- "albums": "Mga Album",
- "tracks": "Mga Track",
- "downloads": "Mga Download",
- "filter_playlists": "I-filter ang iyong mga playlist...",
- "liked_tracks": "Mga Nagustuhang Track",
- "liked_tracks_description": "Lahat ng mga track na iyong nagustuhan",
- "playlist": "Playlist",
- "create_a_playlist": "Gumawa ng playlist",
- "update_playlist": "I-update ang playlist",
- "create": "Lumikha",
- "cancel": "Ikansela",
- "update": "I-update",
- "playlist_name": "Pangalan ng Playlist",
- "name_of_playlist": "Pangalan ng playlist",
- "description": "Paglalarawan",
- "public": "Pampubliko",
- "collaborative": "Pakikipagtulungan",
- "search_local_tracks": "Maghanap ng mga lokal na track...",
- "play": "I-play",
- "delete": "Burahin",
- "none": "Wala",
- "sort_a_z": "Ayusin ayon sa A-Z",
- "sort_z_a": "Ayusin ayon sa Z-A",
- "sort_artist": "Ayusin ayon sa Artista",
- "sort_album": "Ayusin ayon sa Album",
- "sort_duration": "Ayusin ayon sa Tagal",
- "sort_tracks": "Ayusin ang mga Track",
- "currently_downloading": "Kasalukuyang Nagda-download ({tracks_length})",
- "cancel_all": "Kanselahin Lahat",
- "filter_artist": "I-filter ang mga artista...",
- "followers": "{followers} na mga Tagasunod",
- "add_artist_to_blacklist": "Idagdag ang artista sa blacklist",
- "top_tracks": "Mga Nangungunang Track",
- "fans_also_like": "Gusto rin ng mga tagahanga",
- "loading": "Naglo-load...",
- "artist": "Artista",
- "blacklisted": "Naka-blacklist",
- "following": "Sinusundan",
- "follow": "Sundan",
- "artist_url_copied": "Na-copy sa clipboard ang URL ng artista",
- "added_to_queue": "Idinagdag ang {tracks} na mga track sa pila",
- "filter_albums": "I-filter ang mga album...",
- "synced": "Naka-sync",
- "plain": "Simpleng",
- "shuffle": "I-shuffle",
- "search_tracks": "Maghanap ng mga track...",
- "released": "Inilabas",
- "error": "Error {error}",
- "title": "Pamagat",
- "time": "Oras",
- "more_actions": "Higit pang mga aksyon",
- "download_count": "I-download ({count})",
- "add_count_to_playlist": "Idagdag ({count}) sa Playlist",
- "add_count_to_queue": "Idagdag ({count}) sa Pila",
- "play_count_next": "I-play ({count}) kasunod",
- "album": "Album",
- "copied_to_clipboard": "Na-copy ang {data} sa clipboard",
- "add_to_following_playlists": "Idagdag ang {track} sa mga sumusunod na Playlist",
- "add": "Idagdag",
- "added_track_to_queue": "Idinagdag ang {track} sa pila",
- "add_to_queue": "Idagdag sa pila",
- "track_will_play_next": "Ang {track} ay tutugtog susunod",
- "play_next": "I-play susunod",
- "removed_track_from_queue": "Tinanggal ang {track} mula sa pila",
- "remove_from_queue": "Alisin mula sa pila",
- "remove_from_favorites": "Alisin mula sa mga paborito",
- "save_as_favorite": "I-save bilang paborito",
- "add_to_playlist": "Idagdag sa playlist",
- "remove_from_playlist": "Alisin mula sa playlist",
- "add_to_blacklist": "Idagdag sa blacklist",
- "remove_from_blacklist": "Alisin mula sa blacklist",
- "share": "Ibahagi",
- "mini_player": "Mini Player",
- "slide_to_seek": "I-slide para mag-seek pasulong o pabalik",
- "shuffle_playlist": "I-shuffle ang playlist",
- "unshuffle_playlist": "I-unshuffle ang playlist",
- "previous_track": "Nakaraang track",
- "next_track": "Susunod na track",
- "pause_playback": "I-pause ang Playback",
- "resume_playback": "Ipagpatuloy ang Playback",
- "loop_track": "I-loop ang track",
- "no_loop": "Walang loop",
- "repeat_playlist": "Ulitin ang playlist",
- "queue": "Pila",
- "alternative_track_sources": "Alternatibong mga pinagmulan ng track",
- "download_track": "I-download ang track",
- "tracks_in_queue": "{tracks} na mga track sa pila",
- "clear_all": "Burahin lahat",
- "show_hide_ui_on_hover": "Ipakita/Itago ang UI sa hover",
- "always_on_top": "Palaging nasa ibabaw",
- "exit_mini_player": "Lumabas sa Mini player",
- "download_location": "Lokasyon ng pag-download",
- "local_library": "Lokal na silid-aklatan",
- "add_library_location": "Idagdag sa silid-aklatan",
- "remove_library_location": "Alisin mula sa silid-aklatan",
- "account": "Account",
- "login_with_spotify": "Mag-login gamit ang iyong Spotify account",
- "connect_with_spotify": "Kumonekta sa Spotify",
- "logout": "Mag-logout",
- "logout_of_this_account": "Mag-logout sa account na ito",
- "language_region": "Wika at Rehiyon",
- "language": "Wika",
- "system_default": "Default ng Sistema",
- "market_place_region": "Rehiyon ng Marketplace",
- "recommendation_country": "Bansang Inirerekomenda",
- "appearance": "Hitsura",
- "layout_mode": "Mode ng Layout",
- "override_layout_settings": "I-override ang mga setting ng responsive layout mode",
- "adaptive": "Umaangkop",
- "compact": "Kompakto",
- "extended": "Pinalawig",
- "theme": "Tema",
- "dark": "Madilim",
- "light": "Maliwanag",
- "system": "Sistema",
- "accent_color": "Kulay ng Accent",
- "sync_album_color": "I-sync ang kulay ng album",
- "sync_album_color_description": "Ginagamit ang pangunahing kulay ng album art bilang kulay ng accent",
- "playback": "Playback",
- "audio_quality": "Kalidad ng Audio",
- "high": "Mataas",
- "low": "Mababa",
- "pre_download_play": "Mag-pre-download at i-play",
- "pre_download_play_description": "Sa halip na mag-stream ng audio, mag-download ng bytes at i-play sa halip (Inirerekomenda para sa mga gumagamit ng mataas na bandwidth)",
- "skip_non_music": "Laktawan ang mga segment na hindi musika (SponsorBlock)",
- "blacklist_description": "Mga track at artista na nasa blacklist",
- "wait_for_download_to_finish": "Mangyaring maghintay para matapos ang kasalukuyang pag-download",
- "desktop": "Desktop",
- "close_behavior": "Pag-uugali ng Pagsara",
- "close": "Isara",
- "minimize_to_tray": "I-minimize sa tray",
- "show_tray_icon": "Ipakita ang icon ng System tray",
- "about": "Tungkol sa",
- "u_love_spotube": "Alam naming gusto mo ang Spotube",
- "check_for_updates": "Maghanap ng mga update",
- "about_spotube": "Tungkol sa Spotube",
- "blacklist": "Blacklist",
- "please_sponsor": "Mangyaring Mag-sponsor/Mag-donate",
- "spotube_description": "Spotube, isang magaan, cross-platform, libreng-para-sa-lahat na spotify client",
- "version": "Bersyon",
- "build_number": "Build Number",
- "founder": "Nagtatag",
- "repository": "Repository",
- "bug_issues": "Bug+Mga Isyu",
- "made_with": "Ginawa nang may ❤️ sa Bangladesh🇧🇩",
- "kingkor_roy_tirtho": "Kingkor Roy Tirtho",
- "copyright": "© 2021-{current_year} Kingkor Roy Tirtho",
- "license": "Lisensya",
- "add_spotify_credentials": "Idagdag ang iyong mga kredensyal sa spotify para makapagsimula",
- "credentials_will_not_be_shared_disclaimer": "Huwag mag-alala, ang alinman sa iyong mga kredensyal ay hindi kokolektahin o ibabahagi sa sinuman",
- "know_how_to_login": "Hindi mo alam kung paano gawin ito?",
- "follow_step_by_step_guide": "Sundin ang Hakbang-hakbang na gabay",
- "spotify_cookie": "Spotify {name} Cookie",
- "cookie_name_cookie": "{name} Cookie",
- "fill_in_all_fields": "Mangyaring punan ang lahat ng field",
- "submit": "Isumite",
- "exit": "Lumabas",
- "previous": "Nakaraan",
- "next": "Susunod",
- "done": "Tapos na",
- "step_1": "Hakbang 1",
- "first_go_to": "Una, Pumunta sa",
- "login_if_not_logged_in": "at Mag-login/Mag-signup kung hindi ka naka-log in",
- "step_2": "Hakbang 2",
- "step_2_steps": "1. Kapag naka-log in ka na, pindutin ang F12 o i-right click ang Mouse > Inspect para Buksan ang Browser devtools.\n2. Pagkatapos ay pumunta sa \"Application\" Tab (Chrome, Edge, Brave atbp..) o \"Storage\" Tab (Firefox, Palemoon atbp..)\n3. Pumunta sa \"Cookies\" na seksyon at pagkatapos sa \"https://accounts.spotify.com\" na subseksyon",
- "step_3": "Hakbang 3",
- "step_3_steps": "Kopyahin ang halaga ng \"sp_dc\" Cookie",
- "success_emoji": "Tagumpay🥳",
- "success_message": "Ngayon ay matagumpay kang Naka-log in gamit ang iyong Spotify account. Magaling, kaibigan!",
- "step_4": "Hakbang 4",
- "step_4_steps": "I-paste ang na-kopyang halaga ng \"sp_dc\"",
- "something_went_wrong": "May nangyaring mali",
- "piped_instance": "Instance ng Piped Server",
- "piped_description": "Ang instance ng Piped server na gagamitin para sa pagtutugma ng track",
- "piped_warning": "Maaaring hindi gumagana nang mabuti ang ilan sa mga ito. Kaya gamitin sa sarili mong peligro",
- "invidious_instance": "Instance ng Invidious Server",
- "invidious_description": "Ang instance ng Invidious server na gagamitin para sa pagtutugma ng track",
- "invidious_warning": "Maaaring hindi gumagana nang mabuti ang ilan sa mga ito. Kaya gamitin sa sarili mong peligro",
- "generate": "Gumawa",
- "track_exists": "Ang Track na {track} ay umiiral na",
- "replace_downloaded_tracks": "Palitan ang lahat ng na-download na mga track",
- "skip_download_tracks": "Laktawan ang pag-download ng lahat ng na-download na mga track",
- "do_you_want_to_replace": "Gusto mo bang palitan ang umiiral na track??",
- "replace": "Palitan",
- "skip": "Laktawan",
- "select_up_to_count_type": "Pumili ng hanggang {count} {type}",
- "select_genres": "Pumili ng mga Genre",
- "add_genres": "Magdagdag ng mga Genre",
- "country": "Bansa",
- "number_of_tracks_generate": "Bilang ng mga track na gagawin",
- "acousticness": "Acoustic-ness",
- "danceability": "Kakayahang Sayawin",
- "energy": "Enerhiya",
- "instrumentalness": "Instrumental-ness",
- "liveness": "Liveness",
- "loudness": "Lakas",
- "speechiness": "Pagsasalita",
- "valence": "Valence",
- "popularity": "Popularidad",
- "key": "Key",
- "duration": "Tagal (s)",
- "tempo": "Tempo (BPM)",
- "mode": "Mode",
- "time_signature": "Time Signature",
- "short": "Maikli",
- "medium": "Katamtaman",
- "long": "Mahaba",
- "min": "Min",
- "max": "Max",
- "target": "Target",
- "moderate": "Katamtaman",
- "deselect_all": "Alisin ang Pagkakapili sa Lahat",
- "select_all": "Piliin Lahat",
- "are_you_sure": "Sigurado ka ba?",
- "generating_playlist": "Gumagawa ng iyong custom na playlist...",
- "selected_count_tracks": "Napili ang {count} na mga track",
- "download_warning": "Kung nag-download ka ng lahat ng Track sa maramihan, malinaw na nagpa-pirate ka ng Musika at nagsasanhi ng pinsala sa creative society ng Musika. Sana ay alam mo ito. Palaging, subukang igalang at suportahan ang masipag na paggawa ng Artist",
- "download_ip_ban_warning": "Sa nga pala, ang iyong IP ay maaaring ma-block sa YouTube dahil sa sobrang mga kahilingan sa pag-download kaysa sa karaniwan. Ang IP block ay nangangahulugang hindi mo magagamit ang YouTube (kahit na naka-log in ka) sa loob ng hindi bababa sa 2-3 buwan mula sa device na may IP na iyon. At hindi pinanghahawakan ng Spotube ang anumang responsibilidad kung mangyayari ito",
- "by_clicking_accept_terms": "Sa pamamagitan ng pag-click sa 'tanggapin', sumasang-ayon ka sa mga sumusunod na tuntunin:",
- "download_agreement_1": "Alam kong nagpa-pirate ako ng Musika. Masama ako",
- "download_agreement_2": "Susuportahan ko ang Artist saan man ako maaari at ginagawa ko lang ito dahil wala akong pera para bumili ng kanilang sining",
- "download_agreement_3": "Lubos kong nauunawaan na ang aking IP ay maaaring ma-block sa YouTube at hindi ko pinanghahawakan ang Spotube o ang kanyang mga may-ari/nag-ambag na responsable para sa anumang aksidente na sanhi ng aking kasalukuyang aksyon",
- "decline": "Tanggihan",
- "accept": "Tanggapin",
- "details": "Mga Detalye",
- "youtube": "YouTube",
- "channel": "Channel",
- "likes": "Mga Like",
- "dislikes": "Mga Dislike",
- "views": "Mga View",
- "streamUrl": "Stream URL",
- "stop": "Ihinto",
- "sort_newest": "Ayusin ayon sa pinakabagong idinagdag",
- "sort_oldest": "Ayusin ayon sa pinakalumang idinagdag",
- "sleep_timer": "Sleep Timer",
- "mins": "{minutes} Minuto",
- "hours": "{hours} Oras",
- "hour": "{hours} Oras",
- "custom_hours": "Custom na Oras",
- "logs": "Mga Log",
- "developers": "Mga Developer",
- "not_logged_in": "Hindi ka naka-log in",
- "search_mode": "Mode ng Paghahanap",
- "audio_source": "Pinagmulan ng Audio",
- "ok": "Ok",
- "failed_to_encrypt": "Nabigong i-encrypt",
- "encryption_failed_warning": "Gumagamit ng encryption ang Spotube para ligtas na i-store ang iyong data. Ngunit nabigo. Kaya babalik ito sa hindi secure na storage\nKung gumagamit ka ng linux, mangyaring tiyakin na mayroon kang anumang secret-service na naka-install (gnome-keyring, kde-wallet, keepassxc atbp)",
- "querying_info": "Kinukuha ang impormasyon...",
- "piped_api_down": "Ang Piped API ay hindi gumagana",
- "piped_down_error_instructions": "Ang instance ng Piped na {pipedInstance} ay kasalukuyang hindi gumagana\n\nMaaari mong baguhin ang instance o baguhin ang 'Uri ng API' sa opisyal na YouTube API\n\nSiguraduhing i-restart ang app pagkatapos ng pagbabago",
- "you_are_offline": "Kasalukuyan kang offline",
- "connection_restored": "Naibalik na ang iyong koneksyon sa internet",
- "use_system_title_bar": "Gamitin ang title bar ng system",
- "crunching_results": "Pinaproseso ang mga resulta...",
- "search_to_get_results": "Maghanap para makakuha ng mga resulta",
- "use_amoled_mode": "Matingkad na itim na madilim na tema",
- "pitch_dark_theme": "AMOLED Mode",
- "normalize_audio": "I-normalize ang audio",
- "change_cover": "Baguhin ang cover",
- "add_cover": "Magdagdag ng cover",
- "restore_defaults": "Ibalik ang mga default",
- "download_music_codec": "Codec para sa pag-download ng musika",
- "streaming_music_codec": "Codec para sa pag-stream ng musika",
- "login_with_lastfm": "Mag-login gamit ang Last.fm",
- "connect": "Kumonekta",
- "disconnect_lastfm": "Idiskonekta ang Last.fm",
- "disconnect": "Idiskonekta",
- "username": "Username",
- "password": "Password",
- "login": "Mag-login",
- "login_with_your_lastfm": "Mag-login gamit ang iyong Last.fm account",
- "scrobble_to_lastfm": "I-scrobble sa Last.fm",
- "go_to_album": "Pumunta sa Album",
- "discord_rich_presence": "Discord Rich Presence",
- "browse_all": "I-browse Lahat",
- "genres": "Mga Genre",
- "explore_genres": "Tuklasin ang mga Genre",
- "friends": "Mga Kaibigan",
- "no_lyrics_available": "Paumanhin, hindi mahanap ang lyrics para sa track na ito",
- "start_a_radio": "Magsimula ng Radio",
- "how_to_start_radio": "Paano mo gustong simulan ang radio?",
- "replace_queue_question": "Gusto mo bang palitan ang kasalukuyang pila o idagdag dito?",
- "endless_playback": "Walang Hanggang Playback",
- "delete_playlist": "Burahin ang Playlist",
- "delete_playlist_confirmation": "Sigurado ka bang gusto mong burahin ang playlist na ito?",
- "local_tracks": "Mga Lokal na Track",
- "local_tab": "Lokal",
- "song_link": "Link ng Kanta",
- "skip_this_nonsense": "Laktawan ang kalokohan na ito",
- "freedom_of_music": "\"Kalayaan ng Musika\"",
- "freedom_of_music_palm": "\"Kalayaan ng Musika sa iyong palad\"",
- "get_started": "Magsimula na tayo",
- "youtube_source_description": "Inirerekomenda at pinakamahusay na gumagana.",
- "piped_source_description": "Gusto ng kalayaan? Kapareho ng YouTube ngunit mas malaya.",
- "jiosaavn_source_description": "Pinakamahusay para sa rehiyon ng South Asia.",
- "invidious_source_description": "Katulad ng Piped ngunit may mas mataas na availability.",
- "highest_quality": "Pinakamataas na Kalidad: {quality}",
- "select_audio_source": "Pumili ng Pinagmulan ng Audio",
- "endless_playback_description": "Awtomatikong magdagdag ng mga bagong kanta\nsa dulo ng pila",
- "choose_your_region": "Piliin ang iyong rehiyon",
- "choose_your_region_description": "Ito ay tutulong sa Spotube na ipakita sa iyo ang tamang content\npara sa iyong lokasyon.",
- "choose_your_language": "Piliin ang iyong wika",
- "help_project_grow": "Tulungan ang proyektong ito na lumago",
- "help_project_grow_description": "Ang Spotube ay isang open-source na proyekto. Maaari mong tulungan ang proyektong ito na lumago sa pamamagitan ng pag-contribute sa proyekto, pag-ulat ng mga bug, o pagmungkahi ng mga bagong feature.",
- "contribute_on_github": "Mag-contribute sa GitHub",
- "donate_on_open_collective": "Mag-donate sa Open Collective",
- "browse_anonymously": "Mag-browse nang Anonymous",
- "enable_connect": "I-enable ang Connect",
- "enable_connect_description": "Kontrolin ang Spotube mula sa ibang mga device",
- "devices": "Mga Device",
- "select": "Pumili",
- "connect_client_alert": "Ikaw ay kontrolado ng {client}",
- "this_device": "Ang Device na ito",
- "remote": "Remote",
- "stats": "Mga Stat",
- "and_n_more": "at {count} pa",
- "recently_played": "Kamakailan Lang na Ni-play",
- "browse_more": "Mag-browse pa",
- "no_title": "Walang Pamagat",
- "not_playing": "Hindi tumutugtog",
- "epic_failure": "Epic na pagkabigo!",
- "added_num_tracks_to_queue": "Nagdagdag ng {tracks_length} na mga track sa pila",
- "spotube_has_an_update": "Ang Spotube ay may update",
- "download_now": "I-download Ngayon",
- "nightly_version": "Ang Spotube Nightly {nightlyBuildNum} ay inilabas na",
- "release_version": "Ang Spotube v{version} ay inilabas na",
- "read_the_latest": "Basahin ang pinakabagong ",
- "release_notes": "release notes",
- "pick_color_scheme": "Pumili ng color scheme",
- "save": "I-save",
- "choose_the_device": "Piliin ang device:",
- "multiple_device_connected": "Mayroong maraming device na nakakonekta.\nPiliin ang device kung saan mo gustong maganap ang aksyon na ito",
- "nothing_found": "Walang nahanap",
- "the_box_is_empty": "Ang kahon ay walang laman",
- "top_artists": "Nangungunang mga Artista",
- "top_albums": "Nangungunang mga Album",
- "this_week": "Ngayong linggo",
- "this_month": "Ngayong buwan",
- "last_6_months": "Nakaraang 6 na buwan",
- "this_year": "Ngayong taon",
- "last_2_years": "Nakaraang 2 taon",
- "all_time": "Lahat ng panahon",
- "powered_by_provider": "Pinapagana ng {providerName}",
- "email": "Email",
- "profile_followers": "Mga Tagasunod",
- "birthday": "Kaarawan",
- "subscription": "Subscription",
- "not_born": "Hindi pa ipinanganak",
- "hacker": "Hacker",
- "profile": "Profile",
- "no_name": "Walang Pangalan",
- "edit": "I-edit",
- "user_profile": "Profile ng User",
- "count_plays": "{count} na mga play",
- "streaming_fees_hypothetical": "Mga bayarin sa streaming (hypothetical)",
- "minutes_listened": "Mga minutong pinapakinggan",
- "streamed_songs": "Mga na-stream na kanta",
- "count_streams": "{count} na mga stream",
- "owned_by_you": "Pag-aari mo",
- "copied_shareurl_to_clipboard": "Na-kopya ang {shareUrl} sa clipboard",
- "spotify_hipotetical_calculation": "*Ito ay kinalkula batay sa bawat stream\nna bayad ng Spotify na $0.003 hanggang $0.005. Ito ay isang hypothetical\nna pagkalkula para bigyan ang user ng ideya kung magkano\nang kanilang ibabayad sa mga artista kung sila ay nakikinig\nng kanilang kanta sa Spotify.",
- "count_mins": "{minutes} minuto",
- "summary_minutes": "minuto",
- "summary_listened_to_music": "Nakinig sa musika",
- "summary_songs": "mga kanta",
- "summary_streamed_overall": "Na-stream sa kabuuan",
- "summary_owed_to_artists": "Utang sa mga artista\nngayong buwan",
- "summary_artists": "artista",
- "summary_music_reached_you": "Umabot sa iyo ang musika",
- "summary_full_albums": "buong album",
- "summary_got_your_love": "Nakuha ang iyong pagmamahal",
- "summary_playlists": "mga playlist",
- "summary_were_on_repeat": "Pinu-playlst muli",
- "total_money": "Kabuuang {money}",
- "webview_not_found": "Hindi nahanap ang Webview",
- "webview_not_found_description": "Walang webview runtime na naka-install sa iyong device.\nKung naka-install ito, siguraduhing nasa Environment PATH\n\nPagkatapos mag-install, i-restart ang app",
- "unsupported_platform": "Hindi suportadong platform",
- "cache_music": "I-cache ang musika",
- "open": "Buksan",
- "cache_folder": "Folder ng cache",
- "export": "I-export",
- "clear_cache": "Burahin ang cache",
- "clear_cache_confirmation": "Gusto mo bang burahin ang cache?",
- "export_cache_files": "I-export ang mga Naka-cache na File",
- "found_n_files": "Nahanap ang {count} na mga file",
- "export_cache_confirmation": "Gusto mo bang i-export ang mga file na ito sa",
- "exported_n_out_of_m_files": "Na-export ang {filesExported} mula sa {files} na mga file",
- "undo": "I-undo",
- "download_all": "I-download lahat",
- "add_all_to_playlist": "Idagdag lahat sa playlist",
- "add_all_to_queue": "Idagdag lahat sa pila",
- "play_all_next": "I-play lahat susunod",
- "pause": "Pause",
- "view_all": "Tingnan lahat",
- "no_tracks_added_yet": "Mukhang wala ka pang idinaragdag na mga track",
- "no_tracks": "Mukhang walang mga track dito",
- "no_tracks_listened_yet": "Mukhang wala ka pang pinakikinggan",
- "not_following_artists": "Hindi ka sumusunod sa anumang mga artista",
- "no_favorite_albums_yet": "Mukhang wala ka pang idinagdag na anumang mga album sa iyong mga paborito",
- "no_logs_found": "Walang nahanap na mga log",
- "youtube_engine": "YouTube Engine",
- "youtube_engine_not_installed_title": "Hindi naka-install ang {engine}",
- "youtube_engine_not_installed_message": "Hindi naka-install ang {engine} sa iyong sistema.",
- "youtube_engine_set_path": "Siguraduhing available ito sa PATH variable o\ni-set ang absolute path sa {engine} executable sa ibaba",
- "youtube_engine_unix_issue_message": "Sa macOS/Linux/unix tulad ng OS, ang pag-set ng path sa .zshrc/.bashrc/.bash_profile atbp. ay hindi gagana.\nKailangan mong i-set ang path sa configuration file ng shell",
- "download": "I-download",
- "file_not_found": "Hindi nahanap ang file",
- "custom": "Custom",
- "add_custom_url": "Magdagdag ng custom URL"
-}
\ No newline at end of file
+ "guest": "Bisita",
+ "browse": "Mag-browse",
+ "search": "Maghanap",
+ "library": "Silid-aklatan",
+ "lyrics": "Mga Liriko",
+ "settings": "Mga Setting",
+ "genre_categories_filter": "I-filter ang mga kategorya o genre...",
+ "genre": "Genre",
+ "personalized": "Naka-personalize",
+ "featured": "Tampok",
+ "new_releases": "Mga Bagong Paglabas",
+ "songs": "Mga Kanta",
+ "playing_track": "Tumutugtog ang {track}",
+ "queue_clear_alert": "Ito ay magbubura ng kasalukuyang pila. {track_length} na mga track ang tatanggalin\nGusto mo bang magpatuloy?",
+ "load_more": "Mag-load pa",
+ "playlists": "Mga Playlist",
+ "artists": "Mga Artista",
+ "albums": "Mga Album",
+ "tracks": "Mga Track",
+ "downloads": "Mga Download",
+ "filter_playlists": "I-filter ang iyong mga playlist...",
+ "liked_tracks": "Mga Nagustuhang Track",
+ "liked_tracks_description": "Lahat ng mga track na iyong nagustuhan",
+ "playlist": "Playlist",
+ "create_a_playlist": "Gumawa ng playlist",
+ "update_playlist": "I-update ang playlist",
+ "create": "Lumikha",
+ "cancel": "Ikansela",
+ "update": "I-update",
+ "playlist_name": "Pangalan ng Playlist",
+ "name_of_playlist": "Pangalan ng playlist",
+ "description": "Paglalarawan",
+ "public": "Pampubliko",
+ "collaborative": "Pakikipagtulungan",
+ "search_local_tracks": "Maghanap ng mga lokal na track...",
+ "play": "I-play",
+ "delete": "Burahin",
+ "none": "Wala",
+ "sort_a_z": "Ayusin ayon sa A-Z",
+ "sort_z_a": "Ayusin ayon sa Z-A",
+ "sort_artist": "Ayusin ayon sa Artista",
+ "sort_album": "Ayusin ayon sa Album",
+ "sort_duration": "Ayusin ayon sa Tagal",
+ "sort_tracks": "Ayusin ang mga Track",
+ "currently_downloading": "Kasalukuyang Nagda-download ({tracks_length})",
+ "cancel_all": "Kanselahin Lahat",
+ "filter_artist": "I-filter ang mga artista...",
+ "followers": "{followers} na mga Tagasunod",
+ "add_artist_to_blacklist": "Idagdag ang artista sa blacklist",
+ "top_tracks": "Mga Nangungunang Track",
+ "fans_also_like": "Gusto rin ng mga tagahanga",
+ "loading": "Naglo-load...",
+ "artist": "Artista",
+ "blacklisted": "Naka-blacklist",
+ "following": "Sinusundan",
+ "follow": "Sundan",
+ "artist_url_copied": "Na-copy sa clipboard ang URL ng artista",
+ "added_to_queue": "Idinagdag ang {tracks} na mga track sa pila",
+ "filter_albums": "I-filter ang mga album...",
+ "synced": "Naka-sync",
+ "plain": "Simpleng",
+ "shuffle": "I-shuffle",
+ "search_tracks": "Maghanap ng mga track...",
+ "released": "Inilabas",
+ "error": "Error {error}",
+ "title": "Pamagat",
+ "time": "Oras",
+ "more_actions": "Higit pang mga aksyon",
+ "download_count": "I-download ({count})",
+ "add_count_to_playlist": "Idagdag ({count}) sa Playlist",
+ "add_count_to_queue": "Idagdag ({count}) sa Pila",
+ "play_count_next": "I-play ({count}) kasunod",
+ "album": "Album",
+ "copied_to_clipboard": "Na-copy ang {data} sa clipboard",
+ "add_to_following_playlists": "Idagdag ang {track} sa mga sumusunod na Playlist",
+ "add": "Idagdag",
+ "added_track_to_queue": "Idinagdag ang {track} sa pila",
+ "add_to_queue": "Idagdag sa pila",
+ "track_will_play_next": "Ang {track} ay tutugtog susunod",
+ "play_next": "I-play susunod",
+ "removed_track_from_queue": "Tinanggal ang {track} mula sa pila",
+ "remove_from_queue": "Alisin mula sa pila",
+ "remove_from_favorites": "Alisin mula sa mga paborito",
+ "save_as_favorite": "I-save bilang paborito",
+ "add_to_playlist": "Idagdag sa playlist",
+ "remove_from_playlist": "Alisin mula sa playlist",
+ "add_to_blacklist": "Idagdag sa blacklist",
+ "remove_from_blacklist": "Alisin mula sa blacklist",
+ "share": "Ibahagi",
+ "mini_player": "Mini Player",
+ "slide_to_seek": "I-slide para mag-seek pasulong o pabalik",
+ "shuffle_playlist": "I-shuffle ang playlist",
+ "unshuffle_playlist": "I-unshuffle ang playlist",
+ "previous_track": "Nakaraang track",
+ "next_track": "Susunod na track",
+ "pause_playback": "I-pause ang Playback",
+ "resume_playback": "Ipagpatuloy ang Playback",
+ "loop_track": "I-loop ang track",
+ "no_loop": "Walang loop",
+ "repeat_playlist": "Ulitin ang playlist",
+ "queue": "Pila",
+ "alternative_track_sources": "Alternatibong mga pinagmulan ng track",
+ "download_track": "I-download ang track",
+ "tracks_in_queue": "{tracks} na mga track sa pila",
+ "clear_all": "Burahin lahat",
+ "show_hide_ui_on_hover": "Ipakita/Itago ang UI sa hover",
+ "always_on_top": "Palaging nasa ibabaw",
+ "exit_mini_player": "Lumabas sa Mini player",
+ "download_location": "Lokasyon ng pag-download",
+ "local_library": "Lokal na silid-aklatan",
+ "add_library_location": "Idagdag sa silid-aklatan",
+ "remove_library_location": "Alisin mula sa silid-aklatan",
+ "account": "Account",
+ "login_with_spotify": "Mag-login gamit ang iyong Spotify account",
+ "connect_with_spotify": "Kumonekta sa Spotify",
+ "logout": "Mag-logout",
+ "logout_of_this_account": "Mag-logout sa account na ito",
+ "language_region": "Wika at Rehiyon",
+ "language": "Wika",
+ "system_default": "Default ng Sistema",
+ "market_place_region": "Rehiyon ng Marketplace",
+ "recommendation_country": "Bansang Inirerekomenda",
+ "appearance": "Hitsura",
+ "layout_mode": "Mode ng Layout",
+ "override_layout_settings": "I-override ang mga setting ng responsive layout mode",
+ "adaptive": "Umaangkop",
+ "compact": "Kompakto",
+ "extended": "Pinalawig",
+ "theme": "Tema",
+ "dark": "Madilim",
+ "light": "Maliwanag",
+ "system": "Sistema",
+ "accent_color": "Kulay ng Accent",
+ "sync_album_color": "I-sync ang kulay ng album",
+ "sync_album_color_description": "Ginagamit ang pangunahing kulay ng album art bilang kulay ng accent",
+ "playback": "Playback",
+ "audio_quality": "Kalidad ng Audio",
+ "high": "Mataas",
+ "low": "Mababa",
+ "pre_download_play": "Mag-pre-download at i-play",
+ "pre_download_play_description": "Sa halip na mag-stream ng audio, mag-download ng bytes at i-play sa halip (Inirerekomenda para sa mga gumagamit ng mataas na bandwidth)",
+ "skip_non_music": "Laktawan ang mga segment na hindi musika (SponsorBlock)",
+ "blacklist_description": "Mga track at artista na nasa blacklist",
+ "wait_for_download_to_finish": "Mangyaring maghintay para matapos ang kasalukuyang pag-download",
+ "desktop": "Desktop",
+ "close_behavior": "Pag-uugali ng Pagsara",
+ "close": "Isara",
+ "minimize_to_tray": "I-minimize sa tray",
+ "show_tray_icon": "Ipakita ang icon ng System tray",
+ "about": "Tungkol sa",
+ "u_love_spotube": "Alam naming gusto mo ang Spotube",
+ "check_for_updates": "Maghanap ng mga update",
+ "about_spotube": "Tungkol sa Spotube",
+ "blacklist": "Blacklist",
+ "please_sponsor": "Mangyaring Mag-sponsor/Mag-donate",
+ "spotube_description": "Spotube, isang magaan, cross-platform, libreng-para-sa-lahat na spotify client",
+ "version": "Bersyon",
+ "build_number": "Build Number",
+ "founder": "Nagtatag",
+ "repository": "Repository",
+ "bug_issues": "Bug+Mga Isyu",
+ "made_with": "Ginawa nang may ❤️ sa Bangladesh🇧🇩",
+ "kingkor_roy_tirtho": "Kingkor Roy Tirtho",
+ "copyright": "© 2021-{current_year} Kingkor Roy Tirtho",
+ "license": "Lisensya",
+ "add_spotify_credentials": "Idagdag ang iyong mga kredensyal sa spotify para makapagsimula",
+ "credentials_will_not_be_shared_disclaimer": "Huwag mag-alala, ang alinman sa iyong mga kredensyal ay hindi kokolektahin o ibabahagi sa sinuman",
+ "know_how_to_login": "Hindi mo alam kung paano gawin ito?",
+ "follow_step_by_step_guide": "Sundin ang Hakbang-hakbang na gabay",
+ "spotify_cookie": "Spotify {name} Cookie",
+ "cookie_name_cookie": "{name} Cookie",
+ "fill_in_all_fields": "Mangyaring punan ang lahat ng field",
+ "submit": "Isumite",
+ "exit": "Lumabas",
+ "previous": "Nakaraan",
+ "next": "Susunod",
+ "done": "Tapos na",
+ "step_1": "Hakbang 1",
+ "first_go_to": "Una, Pumunta sa",
+ "login_if_not_logged_in": "at Mag-login/Mag-signup kung hindi ka naka-log in",
+ "step_2": "Hakbang 2",
+ "step_2_steps": "1. Kapag naka-log in ka na, pindutin ang F12 o i-right click ang Mouse > Inspect para Buksan ang Browser devtools.\n2. Pagkatapos ay pumunta sa \"Application\" Tab (Chrome, Edge, Brave atbp..) o \"Storage\" Tab (Firefox, Palemoon atbp..)\n3. Pumunta sa \"Cookies\" na seksyon at pagkatapos sa \"https://accounts.spotify.com\" na subseksyon",
+ "step_3": "Hakbang 3",
+ "step_3_steps": "Kopyahin ang halaga ng \"sp_dc\" Cookie",
+ "success_emoji": "Tagumpay🥳",
+ "success_message": "Ngayon ay matagumpay kang Naka-log in gamit ang iyong Spotify account. Magaling, kaibigan!",
+ "step_4": "Hakbang 4",
+ "step_4_steps": "I-paste ang na-kopyang halaga ng \"sp_dc\"",
+ "something_went_wrong": "May nangyaring mali",
+ "piped_instance": "Instance ng Piped Server",
+ "piped_description": "Ang instance ng Piped server na gagamitin para sa pagtutugma ng track",
+ "piped_warning": "Maaaring hindi gumagana nang mabuti ang ilan sa mga ito. Kaya gamitin sa sarili mong peligro",
+ "invidious_instance": "Instance ng Invidious Server",
+ "invidious_description": "Ang instance ng Invidious server na gagamitin para sa pagtutugma ng track",
+ "invidious_warning": "Maaaring hindi gumagana nang mabuti ang ilan sa mga ito. Kaya gamitin sa sarili mong peligro",
+ "generate": "Gumawa",
+ "track_exists": "Ang Track na {track} ay umiiral na",
+ "replace_downloaded_tracks": "Palitan ang lahat ng na-download na mga track",
+ "skip_download_tracks": "Laktawan ang pag-download ng lahat ng na-download na mga track",
+ "do_you_want_to_replace": "Gusto mo bang palitan ang umiiral na track??",
+ "replace": "Palitan",
+ "skip": "Laktawan",
+ "select_up_to_count_type": "Pumili ng hanggang {count} {type}",
+ "select_genres": "Pumili ng mga Genre",
+ "add_genres": "Magdagdag ng mga Genre",
+ "country": "Bansa",
+ "number_of_tracks_generate": "Bilang ng mga track na gagawin",
+ "acousticness": "Acoustic-ness",
+ "danceability": "Kakayahang Sayawin",
+ "energy": "Enerhiya",
+ "instrumentalness": "Instrumental-ness",
+ "liveness": "Liveness",
+ "loudness": "Lakas",
+ "speechiness": "Pagsasalita",
+ "valence": "Valence",
+ "popularity": "Popularidad",
+ "key": "Key",
+ "duration": "Tagal (s)",
+ "tempo": "Tempo (BPM)",
+ "mode": "Mode",
+ "time_signature": "Time Signature",
+ "short": "Maikli",
+ "medium": "Katamtaman",
+ "long": "Mahaba",
+ "min": "Min",
+ "max": "Max",
+ "target": "Target",
+ "moderate": "Katamtaman",
+ "deselect_all": "Alisin ang Pagkakapili sa Lahat",
+ "select_all": "Piliin Lahat",
+ "are_you_sure": "Sigurado ka ba?",
+ "generating_playlist": "Gumagawa ng iyong custom na playlist...",
+ "selected_count_tracks": "Napili ang {count} na mga track",
+ "download_warning": "Kung nag-download ka ng lahat ng Track sa maramihan, malinaw na nagpa-pirate ka ng Musika at nagsasanhi ng pinsala sa creative society ng Musika. Sana ay alam mo ito. Palaging, subukang igalang at suportahan ang masipag na paggawa ng Artist",
+ "download_ip_ban_warning": "Sa nga pala, ang iyong IP ay maaaring ma-block sa YouTube dahil sa sobrang mga kahilingan sa pag-download kaysa sa karaniwan. Ang IP block ay nangangahulugang hindi mo magagamit ang YouTube (kahit na naka-log in ka) sa loob ng hindi bababa sa 2-3 buwan mula sa device na may IP na iyon. At hindi pinanghahawakan ng Spotube ang anumang responsibilidad kung mangyayari ito",
+ "by_clicking_accept_terms": "Sa pamamagitan ng pag-click sa 'tanggapin', sumasang-ayon ka sa mga sumusunod na tuntunin:",
+ "download_agreement_1": "Alam kong nagpa-pirate ako ng Musika. Masama ako",
+ "download_agreement_2": "Susuportahan ko ang Artist saan man ako maaari at ginagawa ko lang ito dahil wala akong pera para bumili ng kanilang sining",
+ "download_agreement_3": "Lubos kong nauunawaan na ang aking IP ay maaaring ma-block sa YouTube at hindi ko pinanghahawakan ang Spotube o ang kanyang mga may-ari/nag-ambag na responsable para sa anumang aksidente na sanhi ng aking kasalukuyang aksyon",
+ "decline": "Tanggihan",
+ "accept": "Tanggapin",
+ "details": "Mga Detalye",
+ "youtube": "YouTube",
+ "channel": "Channel",
+ "likes": "Mga Like",
+ "dislikes": "Mga Dislike",
+ "views": "Mga View",
+ "streamUrl": "Stream URL",
+ "stop": "Ihinto",
+ "sort_newest": "Ayusin ayon sa pinakabagong idinagdag",
+ "sort_oldest": "Ayusin ayon sa pinakalumang idinagdag",
+ "sleep_timer": "Sleep Timer",
+ "mins": "{minutes} Minuto",
+ "hours": "{hours} Oras",
+ "hour": "{hours} Oras",
+ "custom_hours": "Custom na Oras",
+ "logs": "Mga Log",
+ "developers": "Mga Developer",
+ "not_logged_in": "Hindi ka naka-log in",
+ "search_mode": "Mode ng Paghahanap",
+ "audio_source": "Pinagmulan ng Audio",
+ "ok": "Ok",
+ "failed_to_encrypt": "Nabigong i-encrypt",
+ "encryption_failed_warning": "Gumagamit ng encryption ang Spotube para ligtas na i-store ang iyong data. Ngunit nabigo. Kaya babalik ito sa hindi secure na storage\nKung gumagamit ka ng linux, mangyaring tiyakin na mayroon kang anumang secret-service na naka-install (gnome-keyring, kde-wallet, keepassxc atbp)",
+ "querying_info": "Kinukuha ang impormasyon...",
+ "piped_api_down": "Ang Piped API ay hindi gumagana",
+ "piped_down_error_instructions": "Ang instance ng Piped na {pipedInstance} ay kasalukuyang hindi gumagana\n\nMaaari mong baguhin ang instance o baguhin ang 'Uri ng API' sa opisyal na YouTube API\n\nSiguraduhing i-restart ang app pagkatapos ng pagbabago",
+ "you_are_offline": "Kasalukuyan kang offline",
+ "connection_restored": "Naibalik na ang iyong koneksyon sa internet",
+ "use_system_title_bar": "Gamitin ang title bar ng system",
+ "crunching_results": "Pinaproseso ang mga resulta...",
+ "search_to_get_results": "Maghanap para makakuha ng mga resulta",
+ "use_amoled_mode": "Matingkad na itim na madilim na tema",
+ "pitch_dark_theme": "AMOLED Mode",
+ "normalize_audio": "I-normalize ang audio",
+ "change_cover": "Baguhin ang cover",
+ "add_cover": "Magdagdag ng cover",
+ "restore_defaults": "Ibalik ang mga default",
+ "download_music_codec": "Codec para sa pag-download ng musika",
+ "streaming_music_codec": "Codec para sa pag-stream ng musika",
+ "login_with_lastfm": "Mag-login gamit ang Last.fm",
+ "connect": "Kumonekta",
+ "disconnect_lastfm": "Idiskonekta ang Last.fm",
+ "disconnect": "Idiskonekta",
+ "username": "Username",
+ "password": "Password",
+ "login": "Mag-login",
+ "login_with_your_lastfm": "Mag-login gamit ang iyong Last.fm account",
+ "scrobble_to_lastfm": "I-scrobble sa Last.fm",
+ "go_to_album": "Pumunta sa Album",
+ "discord_rich_presence": "Discord Rich Presence",
+ "browse_all": "I-browse Lahat",
+ "genres": "Mga Genre",
+ "explore_genres": "Tuklasin ang mga Genre",
+ "friends": "Mga Kaibigan",
+ "no_lyrics_available": "Paumanhin, hindi mahanap ang lyrics para sa track na ito",
+ "start_a_radio": "Magsimula ng Radio",
+ "how_to_start_radio": "Paano mo gustong simulan ang radio?",
+ "replace_queue_question": "Gusto mo bang palitan ang kasalukuyang pila o idagdag dito?",
+ "endless_playback": "Walang Hanggang Playback",
+ "delete_playlist": "Burahin ang Playlist",
+ "delete_playlist_confirmation": "Sigurado ka bang gusto mong burahin ang playlist na ito?",
+ "local_tracks": "Mga Lokal na Track",
+ "local_tab": "Lokal",
+ "song_link": "Link ng Kanta",
+ "skip_this_nonsense": "Laktawan ang kalokohan na ito",
+ "freedom_of_music": "\"Kalayaan ng Musika\"",
+ "freedom_of_music_palm": "\"Kalayaan ng Musika sa iyong palad\"",
+ "get_started": "Magsimula na tayo",
+ "youtube_source_description": "Inirerekomenda at pinakamahusay na gumagana.",
+ "piped_source_description": "Gusto ng kalayaan? Kapareho ng YouTube ngunit mas malaya.",
+ "jiosaavn_source_description": "Pinakamahusay para sa rehiyon ng South Asia.",
+ "invidious_source_description": "Katulad ng Piped ngunit may mas mataas na availability.",
+ "highest_quality": "Pinakamataas na Kalidad: {quality}",
+ "select_audio_source": "Pumili ng Pinagmulan ng Audio",
+ "endless_playback_description": "Awtomatikong magdagdag ng mga bagong kanta\nsa dulo ng pila",
+ "choose_your_region": "Piliin ang iyong rehiyon",
+ "choose_your_region_description": "Ito ay tutulong sa Spotube na ipakita sa iyo ang tamang content\npara sa iyong lokasyon.",
+ "choose_your_language": "Piliin ang iyong wika",
+ "help_project_grow": "Tulungan ang proyektong ito na lumago",
+ "help_project_grow_description": "Ang Spotube ay isang open-source na proyekto. Maaari mong tulungan ang proyektong ito na lumago sa pamamagitan ng pag-contribute sa proyekto, pag-ulat ng mga bug, o pagmungkahi ng mga bagong feature.",
+ "contribute_on_github": "Mag-contribute sa GitHub",
+ "donate_on_open_collective": "Mag-donate sa Open Collective",
+ "browse_anonymously": "Mag-browse nang Anonymous",
+ "enable_connect": "I-enable ang Connect",
+ "enable_connect_description": "Kontrolin ang Spotube mula sa ibang mga device",
+ "devices": "Mga Device",
+ "select": "Pumili",
+ "connect_client_alert": "Ikaw ay kontrolado ng {client}",
+ "this_device": "Ang Device na ito",
+ "remote": "Remote",
+ "stats": "Mga Stat",
+ "and_n_more": "at {count} pa",
+ "recently_played": "Kamakailan Lang na Ni-play",
+ "browse_more": "Mag-browse pa",
+ "no_title": "Walang Pamagat",
+ "not_playing": "Hindi tumutugtog",
+ "epic_failure": "Epic na pagkabigo!",
+ "added_num_tracks_to_queue": "Nagdagdag ng {tracks_length} na mga track sa pila",
+ "spotube_has_an_update": "Ang Spotube ay may update",
+ "download_now": "I-download Ngayon",
+ "nightly_version": "Ang Spotube Nightly {nightlyBuildNum} ay inilabas na",
+ "release_version": "Ang Spotube v{version} ay inilabas na",
+ "read_the_latest": "Basahin ang pinakabagong ",
+ "release_notes": "release notes",
+ "pick_color_scheme": "Pumili ng color scheme",
+ "save": "I-save",
+ "choose_the_device": "Piliin ang device:",
+ "multiple_device_connected": "Mayroong maraming device na nakakonekta.\nPiliin ang device kung saan mo gustong maganap ang aksyon na ito",
+ "nothing_found": "Walang nahanap",
+ "the_box_is_empty": "Ang kahon ay walang laman",
+ "top_artists": "Nangungunang mga Artista",
+ "top_albums": "Nangungunang mga Album",
+ "this_week": "Ngayong linggo",
+ "this_month": "Ngayong buwan",
+ "last_6_months": "Nakaraang 6 na buwan",
+ "this_year": "Ngayong taon",
+ "last_2_years": "Nakaraang 2 taon",
+ "all_time": "Lahat ng panahon",
+ "powered_by_provider": "Pinapagana ng {providerName}",
+ "email": "Email",
+ "profile_followers": "Mga Tagasunod",
+ "birthday": "Kaarawan",
+ "subscription": "Subscription",
+ "not_born": "Hindi pa ipinanganak",
+ "hacker": "Hacker",
+ "profile": "Profile",
+ "no_name": "Walang Pangalan",
+ "edit": "I-edit",
+ "user_profile": "Profile ng User",
+ "count_plays": "{count} na mga play",
+ "streaming_fees_hypothetical": "Mga bayarin sa streaming (hypothetical)",
+ "minutes_listened": "Mga minutong pinapakinggan",
+ "streamed_songs": "Mga na-stream na kanta",
+ "count_streams": "{count} na mga stream",
+ "owned_by_you": "Pag-aari mo",
+ "copied_shareurl_to_clipboard": "Na-kopya ang {shareUrl} sa clipboard",
+ "spotify_hipotetical_calculation": "*Ito ay kinalkula batay sa bawat stream\nna bayad ng Spotify na $0.003 hanggang $0.005. Ito ay isang hypothetical\nna pagkalkula para bigyan ang user ng ideya kung magkano\nang kanilang ibabayad sa mga artista kung sila ay nakikinig\nng kanilang kanta sa Spotify.",
+ "count_mins": "{minutes} minuto",
+ "summary_minutes": "minuto",
+ "summary_listened_to_music": "Nakinig sa musika",
+ "summary_songs": "mga kanta",
+ "summary_streamed_overall": "Na-stream sa kabuuan",
+ "summary_owed_to_artists": "Utang sa mga artista\nngayong buwan",
+ "summary_artists": "artista",
+ "summary_music_reached_you": "Umabot sa iyo ang musika",
+ "summary_full_albums": "buong album",
+ "summary_got_your_love": "Nakuha ang iyong pagmamahal",
+ "summary_playlists": "mga playlist",
+ "summary_were_on_repeat": "Pinu-playlst muli",
+ "total_money": "Kabuuang {money}",
+ "webview_not_found": "Hindi nahanap ang Webview",
+ "webview_not_found_description": "Walang webview runtime na naka-install sa iyong device.\nKung naka-install ito, siguraduhing nasa Environment PATH\n\nPagkatapos mag-install, i-restart ang app",
+ "unsupported_platform": "Hindi suportadong platform",
+ "cache_music": "I-cache ang musika",
+ "open": "Buksan",
+ "cache_folder": "Folder ng cache",
+ "export": "I-export",
+ "clear_cache": "Burahin ang cache",
+ "clear_cache_confirmation": "Gusto mo bang burahin ang cache?",
+ "export_cache_files": "I-export ang mga Naka-cache na File",
+ "found_n_files": "Nahanap ang {count} na mga file",
+ "export_cache_confirmation": "Gusto mo bang i-export ang mga file na ito sa",
+ "exported_n_out_of_m_files": "Na-export ang {filesExported} mula sa {files} na mga file",
+ "undo": "I-undo",
+ "download_all": "I-download lahat",
+ "add_all_to_playlist": "Idagdag lahat sa playlist",
+ "add_all_to_queue": "Idagdag lahat sa pila",
+ "play_all_next": "I-play lahat susunod",
+ "pause": "Pause",
+ "view_all": "Tingnan lahat",
+ "no_tracks_added_yet": "Mukhang wala ka pang idinaragdag na mga track",
+ "no_tracks": "Mukhang walang mga track dito",
+ "no_tracks_listened_yet": "Mukhang wala ka pang pinakikinggan",
+ "not_following_artists": "Hindi ka sumusunod sa anumang mga artista",
+ "no_favorite_albums_yet": "Mukhang wala ka pang idinagdag na anumang mga album sa iyong mga paborito",
+ "no_logs_found": "Walang nahanap na mga log",
+ "youtube_engine": "YouTube Engine",
+ "youtube_engine_not_installed_title": "Hindi naka-install ang {engine}",
+ "youtube_engine_not_installed_message": "Hindi naka-install ang {engine} sa iyong sistema.",
+ "youtube_engine_set_path": "Siguraduhing available ito sa PATH variable o\ni-set ang absolute path sa {engine} executable sa ibaba",
+ "youtube_engine_unix_issue_message": "Sa macOS/Linux/unix tulad ng OS, ang pag-set ng path sa .zshrc/.bashrc/.bash_profile atbp. ay hindi gagana.\nKailangan mong i-set ang path sa configuration file ng shell",
+ "download": "I-download",
+ "file_not_found": "Hindi nahanap ang file",
+ "custom": "Custom",
+ "add_custom_url": "Magdagdag ng custom URL",
+ "edit_port": "I-edit ang port",
+ "port_helper_msg": "Ang default ay -1 na nagpapahiwatig ng random na numero. Kung na-configure mo ang firewall, inirerekomenda na itakda ito.",
+ "connect_request": "Payagan ang {client} na kumonekta?",
+ "connection_request_denied": "Tanggihan ang koneksyon. Tinanggihan ng gumagamit ang pag-access."
+}
\ No newline at end of file
diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb
index 1e659cc5..7c3bc42f 100644
--- a/lib/l10n/app_tr.arb
+++ b/lib/l10n/app_tr.arb
@@ -426,5 +426,9 @@
"download": "İndir",
"file_not_found": "Dosya bulunamadı",
"custom": "Özel",
- "add_custom_url": "Özel URL ekle"
+ "add_custom_url": "Özel URL ekle",
+ "edit_port": "Portu düzenle",
+ "port_helper_msg": "Varsayılan -1'dir, bu da rastgele bir sayıyı gösterir. Bir güvenlik duvarınız varsa, bunu ayarlamanız önerilir.",
+ "connect_request": "{client} bağlantısına izin verilsin mi?",
+ "connection_request_denied": "Bağlantı reddedildi. Kullanıcı erişimi reddetti."
}
\ No newline at end of file
diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb
index bc731240..9cefc4a8 100644
--- a/lib/l10n/app_uk.arb
+++ b/lib/l10n/app_uk.arb
@@ -426,5 +426,9 @@
"download": "Завантажити",
"file_not_found": "Файл не знайдено",
"custom": "Користувацький",
- "add_custom_url": "Додати користувацький URL"
+ "add_custom_url": "Додати користувацький URL",
+ "edit_port": "Редагувати порт",
+ "port_helper_msg": "За замовчуванням -1, що означає випадкове число. Якщо у вас налаштований брандмауер, рекомендується це налаштувати.",
+ "connect_request": "Дозволити {client} підключення?",
+ "connection_request_denied": "Підключення відхилено. Користувач відмовив у доступі."
}
\ No newline at end of file
diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb
index 75f8e3f7..47e5cf27 100644
--- a/lib/l10n/app_vi.arb
+++ b/lib/l10n/app_vi.arb
@@ -426,5 +426,9 @@
"download": "Tải xuống",
"file_not_found": "Không tìm thấy tệp",
"custom": "Tùy chỉnh",
- "add_custom_url": "Thêm URL tùy chỉnh"
+ "add_custom_url": "Thêm URL tùy chỉnh",
+ "edit_port": "Chỉnh sửa cổng",
+ "port_helper_msg": "Mặc định là -1, có nghĩa là số ngẫu nhiên. Nếu bạn đã cấu hình tường lửa, nên đặt điều này.",
+ "connect_request": "Cho phép {client} kết nối?",
+ "connection_request_denied": "Kết nối bị từ chối. Người dùng đã từ chối quyền truy cập."
}
\ No newline at end of file
diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb
index 03ebae12..f68b30f5 100644
--- a/lib/l10n/app_zh.arb
+++ b/lib/l10n/app_zh.arb
@@ -426,5 +426,9 @@
"download": "下载",
"file_not_found": "文件未找到",
"custom": "自定义",
- "add_custom_url": "添加自定义 URL"
+ "add_custom_url": "添加自定义 URL",
+ "edit_port": "编辑端口",
+ "port_helper_msg": "默认值为-1,表示随机数。如果您已配置防火墙,建议设置此项。",
+ "connect_request": "允许 {client} 连接吗?",
+ "connection_request_denied": "连接被拒绝。用户拒绝访问。"
}
\ No newline at end of file
diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart
index 457e29b6..35cafab8 100644
--- a/lib/l10n/generated/app_localizations.dart
+++ b/lib/l10n/generated/app_localizations.dart
@@ -2704,6 +2704,30 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Add custom URL'**
String get add_custom_url;
+
+ /// No description provided for @edit_port.
+ ///
+ /// In en, this message translates to:
+ /// **'Edit port'**
+ String get edit_port;
+
+ /// No description provided for @port_helper_msg.
+ ///
+ /// In en, this message translates to:
+ /// **'Default is -1 which indicates random number. If you\'ve firewall configured, setting this is recommended.'**
+ String get port_helper_msg;
+
+ /// No description provided for @connect_request.
+ ///
+ /// In en, this message translates to:
+ /// **'Allow {client} to connect?'**
+ String connect_request(Object client);
+
+ /// No description provided for @connection_request_denied.
+ ///
+ /// In en, this message translates to:
+ /// **'Connection denied. User denied access.'**
+ String get connection_request_denied;
}
class _AppLocalizationsDelegate extends LocalizationsDelegate {
diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart
index 19f23d09..e713fe4e 100644
--- a/lib/l10n/generated/app_localizations_ar.dart
+++ b/lib/l10n/generated/app_localizations_ar.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsAr extends AppLocalizations {
@override
String get add_custom_url => 'إضافة URL مخصص';
+
+ @override
+ String get edit_port => 'تعديل المنفذ';
+
+ @override
+ String get port_helper_msg => 'القيمة الافتراضية هي -1 والتي تشير إلى رقم عشوائي. إذا كان لديك جدار ناري مُعد، يُوصى بتعيين هذا.';
+
+ @override
+ String connect_request(Object client) {
+ return 'السماح لـ $client بالاتصال؟';
+ }
+
+ @override
+ String get connection_request_denied => 'تم رفض الاتصال. المستخدم رفض الوصول.';
}
diff --git a/lib/l10n/generated/app_localizations_bn.dart b/lib/l10n/generated/app_localizations_bn.dart
index 4009f3dd..ae9c842a 100644
--- a/lib/l10n/generated/app_localizations_bn.dart
+++ b/lib/l10n/generated/app_localizations_bn.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsBn extends AppLocalizations {
@override
String get add_custom_url => 'কাস্টম URL যোগ করুন';
+
+ @override
+ String get edit_port => 'পোর্ট সম্পাদনা করুন';
+
+ @override
+ String get port_helper_msg => 'ডিফল্ট হল -1 যা এলোমেলো সংখ্যা নির্দেশ করে। যদি আপনার ফায়ারওয়াল কনফিগার করা থাকে, তবে এটি সেট করা সুপারিশ করা হয়।';
+
+ @override
+ String connect_request(Object client) {
+ return '$client কে সংযোগ করতে অনুমতি দেবেন?';
+ }
+
+ @override
+ String get connection_request_denied => 'সংযোগ অস্বীকৃত। ব্যবহারকারী প্রবেশাধিকার অস্বীকার করেছে।';
}
diff --git a/lib/l10n/generated/app_localizations_ca.dart b/lib/l10n/generated/app_localizations_ca.dart
index c9f80a5a..1e78b087 100644
--- a/lib/l10n/generated/app_localizations_ca.dart
+++ b/lib/l10n/generated/app_localizations_ca.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsCa extends AppLocalizations {
@override
String get add_custom_url => 'Afegir URL personalitzada';
+
+ @override
+ String get edit_port => 'Editar port';
+
+ @override
+ String get port_helper_msg => 'El valor per defecte és -1, que indica un número aleatori. Si teniu un tallafoc configurat, es recomana establir-ho.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Permetre que $client es connecti?';
+ }
+
+ @override
+ String get connection_request_denied => 'Connexió denegada. L\'usuari ha denegat l\'accés.';
}
diff --git a/lib/l10n/generated/app_localizations_cs.dart b/lib/l10n/generated/app_localizations_cs.dart
index 4bacb229..dcf39b70 100644
--- a/lib/l10n/generated/app_localizations_cs.dart
+++ b/lib/l10n/generated/app_localizations_cs.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsCs extends AppLocalizations {
@override
String get add_custom_url => 'Přidat vlastní URL';
+
+ @override
+ String get edit_port => 'Upravit port';
+
+ @override
+ String get port_helper_msg => 'Výchozí hodnota je -1, což znamená náhodné číslo. Pokud máte nakonfigurován firewall, doporučuje se to nastavit.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Povolit $client připojení?';
+ }
+
+ @override
+ String get connection_request_denied => 'Připojení bylo zamítnuto. Uživatel odmítl přístup.';
}
diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart
index a3b51c8a..17b9eac4 100644
--- a/lib/l10n/generated/app_localizations_de.dart
+++ b/lib/l10n/generated/app_localizations_de.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get add_custom_url => 'Benutzerdefinierte URL hinzufügen';
+
+ @override
+ String get edit_port => 'Port bearbeiten';
+
+ @override
+ String get port_helper_msg => 'Der Standardwert ist -1, was eine zufällige Zahl bedeutet. Wenn Sie eine Firewall konfiguriert haben, wird empfohlen, dies einzustellen.';
+
+ @override
+ String connect_request(Object client) {
+ return '$client die Verbindung erlauben?';
+ }
+
+ @override
+ String get connection_request_denied => 'Verbindung abgelehnt. Benutzer hat den Zugriff verweigert.';
}
diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart
index 8ad7ca57..91ac3586 100644
--- a/lib/l10n/generated/app_localizations_en.dart
+++ b/lib/l10n/generated/app_localizations_en.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get add_custom_url => 'Add custom URL';
+
+ @override
+ String get edit_port => 'Edit port';
+
+ @override
+ String get port_helper_msg => 'Default is -1 which indicates random number. If you\'ve firewall configured, setting this is recommended.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Allow $client to connect?';
+ }
+
+ @override
+ String get connection_request_denied => 'Connection denied. User denied access.';
}
diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart
index 7db6473a..5a05dc78 100644
--- a/lib/l10n/generated/app_localizations_es.dart
+++ b/lib/l10n/generated/app_localizations_es.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get add_custom_url => 'Agregar URL personalizada';
+
+ @override
+ String get edit_port => 'Editar puerto';
+
+ @override
+ String get port_helper_msg => 'El valor predeterminado es -1, lo que indica un número aleatorio. Si tienes un firewall configurado, se recomienda establecer esto.';
+
+ @override
+ String connect_request(Object client) {
+ return '¿Permitir que $client se conecte?';
+ }
+
+ @override
+ String get connection_request_denied => 'Conexión denegada. El usuario denegó el acceso.';
}
diff --git a/lib/l10n/generated/app_localizations_eu.dart b/lib/l10n/generated/app_localizations_eu.dart
index 96615c5b..6a5d81d7 100644
--- a/lib/l10n/generated/app_localizations_eu.dart
+++ b/lib/l10n/generated/app_localizations_eu.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsEu extends AppLocalizations {
@override
String get add_custom_url => 'Gehitu URL pertsonalizatua';
+
+ @override
+ String get edit_port => 'Editatu portua';
+
+ @override
+ String get port_helper_msg => 'Lehenetsitako balioa -1 da, zenbaki aleatorioa adierazten duena. Su firewall konfiguratu baduzu, gomendatzen da hau ezartzea.';
+
+ @override
+ String connect_request(Object client) {
+ return '$client konektatzea baimendu?';
+ }
+
+ @override
+ String get connection_request_denied => 'Konektatzea ukatu da. Erabiltzaileak sarbidea ukatu du.';
}
diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart
index 657d01e1..d3e13d97 100644
--- a/lib/l10n/generated/app_localizations_fa.dart
+++ b/lib/l10n/generated/app_localizations_fa.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsFa extends AppLocalizations {
@override
String get add_custom_url => 'اضافه کردن URL سفارشی';
+
+ @override
+ String get edit_port => 'ویرایش پورت';
+
+ @override
+ String get port_helper_msg => 'پیشفرض -1 است که نشاندهنده یک عدد تصادفی است. اگر فایروال شما پیکربندی شده است، توصیه میشود این را تنظیم کنید.';
+
+ @override
+ String connect_request(Object client) {
+ return 'آیا اجازه میدهید $client متصل شود؟';
+ }
+
+ @override
+ String get connection_request_denied => 'اتصال رد شد. کاربر دسترسی را رد کرد.';
}
diff --git a/lib/l10n/generated/app_localizations_fi.dart b/lib/l10n/generated/app_localizations_fi.dart
index a1c7579f..f31b6609 100644
--- a/lib/l10n/generated/app_localizations_fi.dart
+++ b/lib/l10n/generated/app_localizations_fi.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsFi extends AppLocalizations {
@override
String get add_custom_url => 'Lisää mukautettu URL';
+
+ @override
+ String get edit_port => 'Muokkaa porttia';
+
+ @override
+ String get port_helper_msg => 'Oletusarvo on -1, mikä tarkoittaa satunnaista numeroa. Jos sinulla on palomuuri määritetty, tämän asettamista suositellaan.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Salli $client yhdistää?';
+ }
+
+ @override
+ String get connection_request_denied => 'Yhteys evätty. Käyttäjä eväsi pääsyn.';
}
diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart
index 4e56d666..56caeae7 100644
--- a/lib/l10n/generated/app_localizations_fr.dart
+++ b/lib/l10n/generated/app_localizations_fr.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get add_custom_url => 'Ajouter une URL personnalisée';
+
+ @override
+ String get edit_port => 'Modifier le port';
+
+ @override
+ String get port_helper_msg => 'La valeur par défaut est -1, ce qui indique un nombre aléatoire. Si vous avez configuré un pare-feu, il est recommandé de le définir.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Autoriser $client à se connecter ?';
+ }
+
+ @override
+ String get connection_request_denied => 'Connection denied. User denied access.';
}
diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart
index fc9ceda4..440868f5 100644
--- a/lib/l10n/generated/app_localizations_hi.dart
+++ b/lib/l10n/generated/app_localizations_hi.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsHi extends AppLocalizations {
@override
String get add_custom_url => 'कस्टम URL जोड़ें';
+
+ @override
+ String get edit_port => 'पोर्ट संपादित करें';
+
+ @override
+ String get port_helper_msg => 'डिफ़ॉल्ट -1 है जो यादृच्छिक संख्या को दर्शाता है। यदि आपने फ़ायरवॉल कॉन्फ़िगर किया है, तो इसे सेट करना अनुशंसित है।';
+
+ @override
+ String connect_request(Object client) {
+ return '$client को कनेक्ट करने की अनुमति दें?';
+ }
+
+ @override
+ String get connection_request_denied => 'कनेक्शन अस्वीकृत। उपयोगकर्ता ने पहुंच अस्वीकृत कर दी।';
}
diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart
index 3e07ed0c..d76adc71 100644
--- a/lib/l10n/generated/app_localizations_id.dart
+++ b/lib/l10n/generated/app_localizations_id.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsId extends AppLocalizations {
@override
String get add_custom_url => 'Add custom URL';
+
+ @override
+ String get edit_port => 'Edit port';
+
+ @override
+ String get port_helper_msg => 'Default adalah -1 yang menunjukkan angka acak. Jika Anda telah mengonfigurasi firewall, disarankan untuk mengatur ini.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Izinkan $client untuk terhubung?';
+ }
+
+ @override
+ String get connection_request_denied => 'Koneksi ditolak. Pengguna menolak akses.';
}
diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart
index abfc0fb4..82574b07 100644
--- a/lib/l10n/generated/app_localizations_it.dart
+++ b/lib/l10n/generated/app_localizations_it.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get add_custom_url => 'Aggiungi URL personalizzato';
+
+ @override
+ String get edit_port => 'Modifica porta';
+
+ @override
+ String get port_helper_msg => 'Il valore predefinito è -1, che indica un numero casuale. Se hai configurato un firewall, si consiglia di impostarlo.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Consentire a $client di connettersi?';
+ }
+
+ @override
+ String get connection_request_denied => 'Connessione negata. L\'utente ha negato l\'accesso.';
}
diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart
index a8233a1d..b2f1a23d 100644
--- a/lib/l10n/generated/app_localizations_ja.dart
+++ b/lib/l10n/generated/app_localizations_ja.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get add_custom_url => 'カスタムURLを追加';
+
+ @override
+ String get edit_port => 'ポートを編集';
+
+ @override
+ String get port_helper_msg => 'デフォルトは-1で、ランダムな番号を示します。ファイアウォールを設定している場合は、これを設定することをお勧めします。';
+
+ @override
+ String connect_request(Object client) {
+ return '$clientの接続を許可しますか?';
+ }
+
+ @override
+ String get connection_request_denied => '接続が拒否されました。ユーザーがアクセスを拒否しました。';
}
diff --git a/lib/l10n/generated/app_localizations_ka.dart b/lib/l10n/generated/app_localizations_ka.dart
index cefdc73e..0044d144 100644
--- a/lib/l10n/generated/app_localizations_ka.dart
+++ b/lib/l10n/generated/app_localizations_ka.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsKa extends AppLocalizations {
@override
String get add_custom_url => 'დამატება პერსონალური URL';
+
+ @override
+ String get edit_port => 'პორტის რედაქტირება';
+
+ @override
+ String get port_helper_msg => 'ნაგულისხმევი არის -1, რაც შემთხვევითი ნომრის მითითებას ნიშნავს. თუ لديك firewall настроен, рекомендуется установить это.';
+
+ @override
+ String connect_request(Object client) {
+ return '$client-ის დაკავშირების ნებართვა?';
+ }
+
+ @override
+ String get connection_request_denied => 'კავშირი უარყოფილია. მომხმარებელმა უარყო წვდომა.';
}
diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart
index 14628194..a3f11040 100644
--- a/lib/l10n/generated/app_localizations_ko.dart
+++ b/lib/l10n/generated/app_localizations_ko.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsKo extends AppLocalizations {
@override
String get add_custom_url => '사용자 정의 URL 추가';
+
+ @override
+ String get edit_port => '포트 편집';
+
+ @override
+ String get port_helper_msg => '기본값은 -1로 무작위 숫자를 나타냅니다. 방화벽이 구성된 경우 이를 설정하는 것이 좋습니다.';
+
+ @override
+ String connect_request(Object client) {
+ return '$client의 연결을 허용하시겠습니까?';
+ }
+
+ @override
+ String get connection_request_denied => '연결이 거부되었습니다. 사용자가 액세스를 거부했습니다.';
}
diff --git a/lib/l10n/generated/app_localizations_ne.dart b/lib/l10n/generated/app_localizations_ne.dart
index 06fc54f9..f1d0f657 100644
--- a/lib/l10n/generated/app_localizations_ne.dart
+++ b/lib/l10n/generated/app_localizations_ne.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsNe extends AppLocalizations {
@override
String get add_custom_url => 'कस्टम URL जोड़ें';
+
+ @override
+ String get edit_port => 'पोर्ट सम्पादन गर्नुहोस्';
+
+ @override
+ String get port_helper_msg => 'डिफ़ॉल्ट -1 हो जुन यादृच्छिक संख्या जनाउँछ। यदि तपाईंले फायरवाल कन्फिगर गर्नुभएको छ भने, यसलाई सेट गर्न सिफारिस गरिन्छ।';
+
+ @override
+ String connect_request(Object client) {
+ return '$client लाई जडान गर्न अनुमति दिनुहोस्?';
+ }
+
+ @override
+ String get connection_request_denied => 'जडान अस्वीकृत। प्रयोगकर्ताले पहुँच अस्वीकृत गर्यो।';
}
diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart
index 3c17818f..338a664a 100644
--- a/lib/l10n/generated/app_localizations_nl.dart
+++ b/lib/l10n/generated/app_localizations_nl.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get add_custom_url => 'Voeg aangepaste URL toe';
+
+ @override
+ String get edit_port => 'Poort bewerken';
+
+ @override
+ String get port_helper_msg => 'Standaard is -1, wat een willekeurig nummer aangeeft. Als je een firewall hebt geconfigureerd, wordt aanbevolen dit in te stellen.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Toestaan dat $client verbinding maakt?';
+ }
+
+ @override
+ String get connection_request_denied => 'Verbinding geweigerd. Gebruiker heeft toegang geweigerd.';
}
diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart
index d4001f8f..00e8cb9c 100644
--- a/lib/l10n/generated/app_localizations_pl.dart
+++ b/lib/l10n/generated/app_localizations_pl.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get add_custom_url => 'Dodaj niestandardowy URL';
+
+ @override
+ String get edit_port => 'Edytuj port';
+
+ @override
+ String get port_helper_msg => 'Domyślna wartość to -1, co oznacza losową liczbę. Jeśli masz skonfigurowany zaporę, zaleca się jej ustawienie.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Zezwolić $client na połączenie?';
+ }
+
+ @override
+ String get connection_request_denied => 'Połączenie odrzucone. Użytkownik odmówił dostępu.';
}
diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart
index 87ac9bfa..87e065b6 100644
--- a/lib/l10n/generated/app_localizations_pt.dart
+++ b/lib/l10n/generated/app_localizations_pt.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get add_custom_url => 'Adicionar URL personalizada';
+
+ @override
+ String get edit_port => 'Editar porta';
+
+ @override
+ String get port_helper_msg => 'O padrão é -1, que indica um número aleatório. Se você tiver um firewall configurado, é recomendável definir isso.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Permitir que $client se conecte?';
+ }
+
+ @override
+ String get connection_request_denied => 'Conexão negada. O usuário negou o acesso .';
}
diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart
index 7f38bb57..baca93f3 100644
--- a/lib/l10n/generated/app_localizations_ru.dart
+++ b/lib/l10n/generated/app_localizations_ru.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get add_custom_url => 'Добавить пользовательский URL';
+
+ @override
+ String get edit_port => 'Редактировать порт';
+
+ @override
+ String get port_helper_msg => 'По умолчанию -1, что означает случайное число. Если у вас настроен брандмауэр, рекомендуется установить это.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Разрешить $client подключение?';
+ }
+
+ @override
+ String get connection_request_denied => 'Подключение отклонено. Пользователь отказал в доступе.';
}
diff --git a/lib/l10n/generated/app_localizations_ta.dart b/lib/l10n/generated/app_localizations_ta.dart
index be0826b6..ec29a427 100644
--- a/lib/l10n/generated/app_localizations_ta.dart
+++ b/lib/l10n/generated/app_localizations_ta.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsTa extends AppLocalizations {
@override
String get add_custom_url => 'தனிப்பயன் URL ஐச் சேர்க்கவும்';
+
+ @override
+ String get edit_port => 'போர்டு திருத்தவும்';
+
+ @override
+ String get port_helper_msg => 'இயல்புநிலை -1 ஆகும், இது சீரற்ற எண்ணை குறிக்கிறது. நீங்கள் தீயணைப்பு அமைக்கப்பட்டிருந்தால், இதை அமைப்பது பரிந்துரைக்கப்படுகிறது.';
+
+ @override
+ String connect_request(Object client) {
+ return '$client க்கு இணைக்க அனுமதிக்கவா?';
+ }
+
+ @override
+ String get connection_request_denied => 'இணைப்பு மறுக்கப்பட்டது. பயனர் அணுகலை மறுத்தார்.';
}
diff --git a/lib/l10n/generated/app_localizations_th.dart b/lib/l10n/generated/app_localizations_th.dart
index 679a12da..d421fa81 100644
--- a/lib/l10n/generated/app_localizations_th.dart
+++ b/lib/l10n/generated/app_localizations_th.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsTh extends AppLocalizations {
@override
String get add_custom_url => 'เพิ่ม URL แบบกำหนดเอง';
+
+ @override
+ String get edit_port => 'แก้ไขพอร์ต';
+
+ @override
+ String get port_helper_msg => 'ค่าเริ่มต้นคือ -1 ซึ่งหมายถึงหมายเลขสุ่ม หากคุณได้กำหนดค่าไฟร์วอลล์แล้ว แนะนำให้ตั้งค่านี้';
+
+ @override
+ String connect_request(Object client) {
+ return 'อนุญาตให้ $client เชื่อมต่อหรือไม่?';
+ }
+
+ @override
+ String get connection_request_denied => 'การเชื่อมต่อล้มเหลว ผู้ใช้ปฏิเสธการเข้าถึง';
}
diff --git a/lib/l10n/generated/app_localizations_tl.dart b/lib/l10n/generated/app_localizations_tl.dart
index 49452c3b..30a4cdf9 100644
--- a/lib/l10n/generated/app_localizations_tl.dart
+++ b/lib/l10n/generated/app_localizations_tl.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsTl extends AppLocalizations {
@override
String get add_custom_url => 'Magdagdag ng custom URL';
+
+ @override
+ String get edit_port => 'I-edit ang port';
+
+ @override
+ String get port_helper_msg => 'Ang default ay -1 na nagpapahiwatig ng random na numero. Kung na-configure mo ang firewall, inirerekomenda na itakda ito.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Payagan ang $client na kumonekta?';
+ }
+
+ @override
+ String get connection_request_denied => 'Tanggihan ang koneksyon. Tinanggihan ng gumagamit ang pag-access.';
}
diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart
index 11a78620..1df5a965 100644
--- a/lib/l10n/generated/app_localizations_tr.dart
+++ b/lib/l10n/generated/app_localizations_tr.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsTr extends AppLocalizations {
@override
String get add_custom_url => 'Özel URL ekle';
+
+ @override
+ String get edit_port => 'Portu düzenle';
+
+ @override
+ String get port_helper_msg => 'Varsayılan -1\'dir, bu da rastgele bir sayıyı gösterir. Bir güvenlik duvarınız varsa, bunu ayarlamanız önerilir.';
+
+ @override
+ String connect_request(Object client) {
+ return '$client bağlantısına izin verilsin mi?';
+ }
+
+ @override
+ String get connection_request_denied => 'Bağlantı reddedildi. Kullanıcı erişimi reddetti.';
}
diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart
index 2511b2c2..21ffca26 100644
--- a/lib/l10n/generated/app_localizations_uk.dart
+++ b/lib/l10n/generated/app_localizations_uk.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsUk extends AppLocalizations {
@override
String get add_custom_url => 'Додати користувацький URL';
+
+ @override
+ String get edit_port => 'Редагувати порт';
+
+ @override
+ String get port_helper_msg => 'За замовчуванням -1, що означає випадкове число. Якщо у вас налаштований брандмауер, рекомендується це налаштувати.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Дозволити $client підключення?';
+ }
+
+ @override
+ String get connection_request_denied => 'Підключення відхилено. Користувач відмовив у доступі.';
}
diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart
index 0f773578..53e5aa7a 100644
--- a/lib/l10n/generated/app_localizations_vi.dart
+++ b/lib/l10n/generated/app_localizations_vi.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsVi extends AppLocalizations {
@override
String get add_custom_url => 'Thêm URL tùy chỉnh';
+
+ @override
+ String get edit_port => 'Chỉnh sửa cổng';
+
+ @override
+ String get port_helper_msg => 'Mặc định là -1, có nghĩa là số ngẫu nhiên. Nếu bạn đã cấu hình tường lửa, nên đặt điều này.';
+
+ @override
+ String connect_request(Object client) {
+ return 'Cho phép $client kết nối?';
+ }
+
+ @override
+ String get connection_request_denied => 'Kết nối bị từ chối. Người dùng đã từ chối quyền truy cập.';
}
diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart
index 58f7a37e..eb97a506 100644
--- a/lib/l10n/generated/app_localizations_zh.dart
+++ b/lib/l10n/generated/app_localizations_zh.dart
@@ -1371,4 +1371,18 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get add_custom_url => '添加自定义 URL';
+
+ @override
+ String get edit_port => '编辑端口';
+
+ @override
+ String get port_helper_msg => '默认值为-1,表示随机数。如果您已配置防火墙,建议设置此项。';
+
+ @override
+ String connect_request(Object client) {
+ return '允许 $client 连接吗?';
+ }
+
+ @override
+ String get connection_request_denied => '连接被拒绝。用户拒绝访问。';
}
diff --git a/lib/models/database/database.dart b/lib/models/database/database.dart
index 199e7147..151bbc78 100644
--- a/lib/models/database/database.dart
+++ b/lib/models/database/database.dart
@@ -62,7 +62,7 @@ class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection());
@override
- int get schemaVersion => 4;
+ int get schemaVersion => 6;
@override
MigrationStrategy get migration {
@@ -87,6 +87,40 @@ class AppDatabase extends _$AppDatabase {
schema.preferencesTable.youtubeClientEngine,
);
},
+ from4To5: (m, schema) async {
+ final columnName = schema.preferencesTable.accentColorScheme
+ .escapedNameFor(SqlDialect.sqlite);
+ final columnNameOld =
+ '"${schema.preferencesTable.accentColorScheme.name}_old"';
+ final tableName = schema.preferencesTable.actualTableName;
+ await customStatement(
+ "ALTER TABLE $tableName "
+ "RENAME COLUMN $columnName to $columnNameOld",
+ );
+ await customStatement(
+ "ALTER TABLE $tableName "
+ "ADD COLUMN $columnName TEXT NOT NULL DEFAULT 'Orange:0xFFf97315'",
+ );
+ await customStatement(
+ "UPDATE $tableName "
+ "SET $columnName = $columnNameOld",
+ );
+ await customStatement(
+ "ALTER TABLE $tableName "
+ "DROP COLUMN $columnNameOld",
+ );
+ await customStatement(
+ "UPDATE $tableName "
+ "SET $columnName = 'Orange:0xFFf97315' WHERE $columnName = 'Blue:0xFF2196F3'",
+ );
+ },
+ from5To6: (m, schema) async {
+ // Add new column to preferences table
+ await m.addColumn(
+ schema.preferencesTable,
+ schema.preferencesTable.connectPort,
+ );
+ },
),
);
}
diff --git a/lib/models/database/database.g.dart b/lib/models/database/database.g.dart
index cd004d69..5dfe8db8 100644
--- a/lib/models/database/database.g.dart
+++ b/lib/models/database/database.g.dart
@@ -666,7 +666,7 @@ class $PreferencesTableTable extends PreferencesTable
'accent_color_scheme', aliasedName, false,
type: DriftSqlType.string,
requiredDuringInsert: false,
- defaultValue: const Constant("Blue:0xFF2196F3"))
+ defaultValue: const Constant("Orange:0xFFf97315"))
.withConverter(
$PreferencesTableTable.$converteraccentColorScheme);
static const VerificationMeta _layoutModeMeta =
@@ -823,6 +823,14 @@ class $PreferencesTableTable extends PreferencesTable
defaultConstraints: GeneratedColumn.constraintIsAlways(
'CHECK ("enable_connect" IN (0, 1))'),
defaultValue: const Constant(false));
+ static const VerificationMeta _connectPortMeta =
+ const VerificationMeta('connectPort');
+ @override
+ late final GeneratedColumn connectPort = GeneratedColumn(
+ 'connect_port', aliasedName, false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ defaultValue: const Constant(-1));
static const VerificationMeta _cacheMusicMeta =
const VerificationMeta('cacheMusic');
@override
@@ -862,6 +870,7 @@ class $PreferencesTableTable extends PreferencesTable
discordPresence,
endlessPlayback,
enableConnect,
+ connectPort,
cacheMusic
];
@override
@@ -971,6 +980,12 @@ class $PreferencesTableTable extends PreferencesTable
enableConnect.isAcceptableOrUnknown(
data['enable_connect']!, _enableConnectMeta));
}
+ if (data.containsKey('connect_port')) {
+ context.handle(
+ _connectPortMeta,
+ connectPort.isAcceptableOrUnknown(
+ data['connect_port']!, _connectPortMeta));
+ }
if (data.containsKey('cache_music')) {
context.handle(
_cacheMusicMeta,
@@ -1054,6 +1069,8 @@ class $PreferencesTableTable extends PreferencesTable
.read(DriftSqlType.bool, data['${effectivePrefix}endless_playback'])!,
enableConnect: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}enable_connect'])!,
+ connectPort: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}connect_port'])!,
cacheMusic: attachedDatabase.typeMapping
.read(DriftSqlType.bool, data['${effectivePrefix}cache_music'])!,
);
@@ -1126,6 +1143,7 @@ class PreferencesTableData extends DataClass
final bool discordPresence;
final bool endlessPlayback;
final bool enableConnect;
+ final int connectPort;
final bool cacheMusic;
const PreferencesTableData(
{required this.id,
@@ -1155,6 +1173,7 @@ class PreferencesTableData extends DataClass
required this.discordPresence,
required this.endlessPlayback,
required this.enableConnect,
+ required this.connectPort,
required this.cacheMusic});
@override
Map toColumns(bool nullToAbsent) {
@@ -1230,6 +1249,7 @@ class PreferencesTableData extends DataClass
map['discord_presence'] = Variable(discordPresence);
map['endless_playback'] = Variable(endlessPlayback);
map['enable_connect'] = Variable(enableConnect);
+ map['connect_port'] = Variable(connectPort);
map['cache_music'] = Variable(cacheMusic);
return map;
}
@@ -1263,6 +1283,7 @@ class PreferencesTableData extends DataClass
discordPresence: Value(discordPresence),
endlessPlayback: Value(endlessPlayback),
enableConnect: Value(enableConnect),
+ connectPort: Value(connectPort),
cacheMusic: Value(cacheMusic),
);
}
@@ -1310,6 +1331,7 @@ class PreferencesTableData extends DataClass
discordPresence: serializer.fromJson(json['discordPresence']),
endlessPlayback: serializer.fromJson(json['endlessPlayback']),
enableConnect: serializer.fromJson(json['enableConnect']),
+ connectPort: serializer.fromJson(json['connectPort']),
cacheMusic: serializer.fromJson(json['cacheMusic']),
);
}
@@ -1358,6 +1380,7 @@ class PreferencesTableData extends DataClass
'discordPresence': serializer.toJson(discordPresence),
'endlessPlayback': serializer.toJson(endlessPlayback),
'enableConnect': serializer.toJson(enableConnect),
+ 'connectPort': serializer.toJson(connectPort),
'cacheMusic': serializer.toJson(cacheMusic),
};
}
@@ -1390,6 +1413,7 @@ class PreferencesTableData extends DataClass
bool? discordPresence,
bool? endlessPlayback,
bool? enableConnect,
+ int? connectPort,
bool? cacheMusic}) =>
PreferencesTableData(
id: id ?? this.id,
@@ -1419,6 +1443,7 @@ class PreferencesTableData extends DataClass
discordPresence: discordPresence ?? this.discordPresence,
endlessPlayback: endlessPlayback ?? this.endlessPlayback,
enableConnect: enableConnect ?? this.enableConnect,
+ connectPort: connectPort ?? this.connectPort,
cacheMusic: cacheMusic ?? this.cacheMusic,
);
PreferencesTableData copyWithCompanion(PreferencesTableCompanion data) {
@@ -1492,6 +1517,8 @@ class PreferencesTableData extends DataClass
enableConnect: data.enableConnect.present
? data.enableConnect.value
: this.enableConnect,
+ connectPort:
+ data.connectPort.present ? data.connectPort.value : this.connectPort,
cacheMusic:
data.cacheMusic.present ? data.cacheMusic.value : this.cacheMusic,
);
@@ -1527,6 +1554,7 @@ class PreferencesTableData extends DataClass
..write('discordPresence: $discordPresence, ')
..write('endlessPlayback: $endlessPlayback, ')
..write('enableConnect: $enableConnect, ')
+ ..write('connectPort: $connectPort, ')
..write('cacheMusic: $cacheMusic')
..write(')'))
.toString();
@@ -1561,6 +1589,7 @@ class PreferencesTableData extends DataClass
discordPresence,
endlessPlayback,
enableConnect,
+ connectPort,
cacheMusic
]);
@override
@@ -1594,6 +1623,7 @@ class PreferencesTableData extends DataClass
other.discordPresence == this.discordPresence &&
other.endlessPlayback == this.endlessPlayback &&
other.enableConnect == this.enableConnect &&
+ other.connectPort == this.connectPort &&
other.cacheMusic == this.cacheMusic);
}
@@ -1625,6 +1655,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
final Value discordPresence;
final Value endlessPlayback;
final Value enableConnect;
+ final Value connectPort;
final Value cacheMusic;
const PreferencesTableCompanion({
this.id = const Value.absent(),
@@ -1654,6 +1685,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
this.discordPresence = const Value.absent(),
this.endlessPlayback = const Value.absent(),
this.enableConnect = const Value.absent(),
+ this.connectPort = const Value.absent(),
this.cacheMusic = const Value.absent(),
});
PreferencesTableCompanion.insert({
@@ -1684,6 +1716,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
this.discordPresence = const Value.absent(),
this.endlessPlayback = const Value.absent(),
this.enableConnect = const Value.absent(),
+ this.connectPort = const Value.absent(),
this.cacheMusic = const Value.absent(),
});
static Insertable custom({
@@ -1714,6 +1747,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
Expression? discordPresence,
Expression? endlessPlayback,
Expression? enableConnect,
+ Expression? connectPort,
Expression? cacheMusic,
}) {
return RawValuesInsertable({
@@ -1748,6 +1782,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
if (discordPresence != null) 'discord_presence': discordPresence,
if (endlessPlayback != null) 'endless_playback': endlessPlayback,
if (enableConnect != null) 'enable_connect': enableConnect,
+ if (connectPort != null) 'connect_port': connectPort,
if (cacheMusic != null) 'cache_music': cacheMusic,
});
}
@@ -1780,6 +1815,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
Value? discordPresence,
Value? endlessPlayback,
Value? enableConnect,
+ Value? connectPort,
Value? cacheMusic}) {
return PreferencesTableCompanion(
id: id ?? this.id,
@@ -1809,6 +1845,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
discordPresence: discordPresence ?? this.discordPresence,
endlessPlayback: endlessPlayback ?? this.endlessPlayback,
enableConnect: enableConnect ?? this.enableConnect,
+ connectPort: connectPort ?? this.connectPort,
cacheMusic: cacheMusic ?? this.cacheMusic,
);
}
@@ -1918,6 +1955,9 @@ class PreferencesTableCompanion extends UpdateCompanion {
if (enableConnect.present) {
map['enable_connect'] = Variable(enableConnect.value);
}
+ if (connectPort.present) {
+ map['connect_port'] = Variable(connectPort.value);
+ }
if (cacheMusic.present) {
map['cache_music'] = Variable(cacheMusic.value);
}
@@ -1954,6 +1994,7 @@ class PreferencesTableCompanion extends UpdateCompanion {
..write('discordPresence: $discordPresence, ')
..write('endlessPlayback: $endlessPlayback, ')
..write('enableConnect: $enableConnect, ')
+ ..write('connectPort: $connectPort, ')
..write('cacheMusic: $cacheMusic')
..write(')'))
.toString();
@@ -4626,6 +4667,7 @@ typedef $$PreferencesTableTableCreateCompanionBuilder
Value discordPresence,
Value endlessPlayback,
Value enableConnect,
+ Value connectPort,
Value cacheMusic,
});
typedef $$PreferencesTableTableUpdateCompanionBuilder
@@ -4657,6 +4699,7 @@ typedef $$PreferencesTableTableUpdateCompanionBuilder
Value discordPresence,
Value endlessPlayback,
Value enableConnect,
+ Value connectPort,
Value cacheMusic,
});
@@ -4786,6 +4829,9 @@ class $$PreferencesTableTableFilterComposer
ColumnFilters get enableConnect => $composableBuilder(
column: $table.enableConnect, builder: (column) => ColumnFilters(column));
+ ColumnFilters get connectPort => $composableBuilder(
+ column: $table.connectPort, builder: (column) => ColumnFilters(column));
+
ColumnFilters get cacheMusic => $composableBuilder(
column: $table.cacheMusic, builder: (column) => ColumnFilters(column));
}
@@ -4899,6 +4945,9 @@ class $$PreferencesTableTableOrderingComposer
column: $table.enableConnect,
builder: (column) => ColumnOrderings(column));
+ ColumnOrderings get connectPort => $composableBuilder(
+ column: $table.connectPort, builder: (column) => ColumnOrderings(column));
+
ColumnOrderings get cacheMusic => $composableBuilder(
column: $table.cacheMusic, builder: (column) => ColumnOrderings(column));
}
@@ -5003,6 +5052,9 @@ class $$PreferencesTableTableAnnotationComposer
GeneratedColumn get enableConnect => $composableBuilder(
column: $table.enableConnect, builder: (column) => column);
+ GeneratedColumn get connectPort => $composableBuilder(
+ column: $table.connectPort, builder: (column) => column);
+
GeneratedColumn get cacheMusic => $composableBuilder(
column: $table.cacheMusic, builder: (column) => column);
}
@@ -5063,6 +5115,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
Value discordPresence = const Value.absent(),
Value endlessPlayback = const Value.absent(),
Value enableConnect = const Value.absent(),
+ Value connectPort = const Value.absent(),
Value cacheMusic = const Value.absent(),
}) =>
PreferencesTableCompanion(
@@ -5093,6 +5146,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
discordPresence: discordPresence,
endlessPlayback: endlessPlayback,
enableConnect: enableConnect,
+ connectPort: connectPort,
cacheMusic: cacheMusic,
),
createCompanionCallback: ({
@@ -5124,6 +5178,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
Value discordPresence = const Value.absent(),
Value endlessPlayback = const Value.absent(),
Value enableConnect = const Value.absent(),
+ Value connectPort = const Value.absent(),
Value cacheMusic = const Value.absent(),
}) =>
PreferencesTableCompanion.insert(
@@ -5154,6 +5209,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
discordPresence: discordPresence,
endlessPlayback: endlessPlayback,
enableConnect: enableConnect,
+ connectPort: connectPort,
cacheMusic: cacheMusic,
),
withReferenceMapper: (p0) => p0
diff --git a/lib/models/database/database.steps.dart b/lib/models/database/database.steps.dart
index 8e0f8e3f..3e416ea5 100644
--- a/lib/models/database/database.steps.dart
+++ b/lib/models/database/database.steps.dart
@@ -1,11 +1,11 @@
// dart format width=80
import 'package:drift/internal/versioned_schema.dart' as i0;
import 'package:drift/drift.dart' as i1;
-import 'package:drift/drift.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import
+import 'package:flutter/material.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/models/database/database.dart';
-import 'package:spotube/services/sourced_track/enums.dart'; // ignore_for_file: type=lint,unused_import
+import 'package:spotube/services/sourced_track/enums.dart';
// GENERATED BY drift_dev, DO NOT MODIFY.
final class Schema2 extends i0.VersionedSchema {
@@ -1188,10 +1188,516 @@ i1.GeneratedColumn _column_54(String aliasedName) =>
i1.GeneratedColumn('youtube_client_engine', aliasedName, false,
type: i1.DriftSqlType.string,
defaultValue: Constant(YoutubeClientEngine.youtubeExplode.name));
+
+final class Schema5 extends i0.VersionedSchema {
+ Schema5({required super.database}) : super(version: 5);
+ @override
+ late final List entities = [
+ authenticationTable,
+ blacklistTable,
+ preferencesTable,
+ scrobblerTable,
+ skipSegmentTable,
+ sourceMatchTable,
+ audioPlayerStateTable,
+ playlistTable,
+ playlistMediaTable,
+ historyTable,
+ lyricsTable,
+ uniqueBlacklist,
+ uniqTrackMatch,
+ ];
+ late final Shape0 authenticationTable = Shape0(
+ source: i0.VersionedTable(
+ entityName: 'authentication_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_1,
+ _column_2,
+ _column_3,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape1 blacklistTable = Shape1(
+ source: i0.VersionedTable(
+ entityName: 'blacklist_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_4,
+ _column_5,
+ _column_6,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape12 preferencesTable = Shape12(
+ source: i0.VersionedTable(
+ entityName: 'preferences_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_7,
+ _column_8,
+ _column_9,
+ _column_10,
+ _column_11,
+ _column_12,
+ _column_13,
+ _column_14,
+ _column_15,
+ _column_55,
+ _column_17,
+ _column_18,
+ _column_19,
+ _column_20,
+ _column_21,
+ _column_22,
+ _column_23,
+ _column_24,
+ _column_25,
+ _column_26,
+ _column_54,
+ _column_27,
+ _column_28,
+ _column_29,
+ _column_30,
+ _column_31,
+ _column_53,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape3 scrobblerTable = Shape3(
+ source: i0.VersionedTable(
+ entityName: 'scrobbler_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_32,
+ _column_33,
+ _column_34,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape4 skipSegmentTable = Shape4(
+ source: i0.VersionedTable(
+ entityName: 'skip_segment_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_35,
+ _column_36,
+ _column_37,
+ _column_32,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape5 sourceMatchTable = Shape5(
+ source: i0.VersionedTable(
+ entityName: 'source_match_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_37,
+ _column_38,
+ _column_39,
+ _column_32,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape6 audioPlayerStateTable = Shape6(
+ source: i0.VersionedTable(
+ entityName: 'audio_player_state_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_40,
+ _column_41,
+ _column_42,
+ _column_43,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape7 playlistTable = Shape7(
+ source: i0.VersionedTable(
+ entityName: 'playlist_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_44,
+ _column_45,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape8 playlistMediaTable = Shape8(
+ source: i0.VersionedTable(
+ entityName: 'playlist_media_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_46,
+ _column_47,
+ _column_48,
+ _column_49,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape9 historyTable = Shape9(
+ source: i0.VersionedTable(
+ entityName: 'history_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_32,
+ _column_50,
+ _column_51,
+ _column_52,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape10 lyricsTable = Shape10(
+ source: i0.VersionedTable(
+ entityName: 'lyrics_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_37,
+ _column_52,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ final i1.Index uniqueBlacklist = i1.Index('unique_blacklist',
+ 'CREATE UNIQUE INDEX unique_blacklist ON blacklist_table (element_type, element_id)');
+ final i1.Index uniqTrackMatch = i1.Index('uniq_track_match',
+ 'CREATE UNIQUE INDEX uniq_track_match ON source_match_table (track_id, source_id, source_type)');
+}
+
+i1.GeneratedColumn _column_55(String aliasedName) =>
+ i1.GeneratedColumn('accent_color_scheme', aliasedName, false,
+ type: i1.DriftSqlType.string,
+ defaultValue: const Constant("Orange:0xFFf97315"));
+
+final class Schema6 extends i0.VersionedSchema {
+ Schema6({required super.database}) : super(version: 6);
+ @override
+ late final List entities = [
+ authenticationTable,
+ blacklistTable,
+ preferencesTable,
+ scrobblerTable,
+ skipSegmentTable,
+ sourceMatchTable,
+ audioPlayerStateTable,
+ playlistTable,
+ playlistMediaTable,
+ historyTable,
+ lyricsTable,
+ uniqueBlacklist,
+ uniqTrackMatch,
+ ];
+ late final Shape0 authenticationTable = Shape0(
+ source: i0.VersionedTable(
+ entityName: 'authentication_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_1,
+ _column_2,
+ _column_3,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape1 blacklistTable = Shape1(
+ source: i0.VersionedTable(
+ entityName: 'blacklist_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_4,
+ _column_5,
+ _column_6,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape13 preferencesTable = Shape13(
+ source: i0.VersionedTable(
+ entityName: 'preferences_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_7,
+ _column_8,
+ _column_9,
+ _column_10,
+ _column_11,
+ _column_12,
+ _column_13,
+ _column_14,
+ _column_15,
+ _column_55,
+ _column_17,
+ _column_18,
+ _column_19,
+ _column_20,
+ _column_21,
+ _column_22,
+ _column_23,
+ _column_24,
+ _column_25,
+ _column_26,
+ _column_54,
+ _column_27,
+ _column_28,
+ _column_29,
+ _column_30,
+ _column_31,
+ _column_56,
+ _column_53,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape3 scrobblerTable = Shape3(
+ source: i0.VersionedTable(
+ entityName: 'scrobbler_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_32,
+ _column_33,
+ _column_34,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape4 skipSegmentTable = Shape4(
+ source: i0.VersionedTable(
+ entityName: 'skip_segment_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_35,
+ _column_36,
+ _column_37,
+ _column_32,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape5 sourceMatchTable = Shape5(
+ source: i0.VersionedTable(
+ entityName: 'source_match_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_37,
+ _column_38,
+ _column_39,
+ _column_32,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape6 audioPlayerStateTable = Shape6(
+ source: i0.VersionedTable(
+ entityName: 'audio_player_state_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_40,
+ _column_41,
+ _column_42,
+ _column_43,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape7 playlistTable = Shape7(
+ source: i0.VersionedTable(
+ entityName: 'playlist_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_44,
+ _column_45,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape8 playlistMediaTable = Shape8(
+ source: i0.VersionedTable(
+ entityName: 'playlist_media_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_46,
+ _column_47,
+ _column_48,
+ _column_49,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape9 historyTable = Shape9(
+ source: i0.VersionedTable(
+ entityName: 'history_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_32,
+ _column_50,
+ _column_51,
+ _column_52,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ late final Shape10 lyricsTable = Shape10(
+ source: i0.VersionedTable(
+ entityName: 'lyrics_table',
+ withoutRowId: false,
+ isStrict: false,
+ tableConstraints: [],
+ columns: [
+ _column_0,
+ _column_37,
+ _column_52,
+ ],
+ attachedDatabase: database,
+ ),
+ alias: null);
+ final i1.Index uniqueBlacklist = i1.Index('unique_blacklist',
+ 'CREATE UNIQUE INDEX unique_blacklist ON blacklist_table (element_type, element_id)');
+ final i1.Index uniqTrackMatch = i1.Index('uniq_track_match',
+ 'CREATE UNIQUE INDEX uniq_track_match ON source_match_table (track_id, source_id, source_type)');
+}
+
+class Shape13 extends i0.VersionedTable {
+ Shape13({required super.source, required super.alias}) : super.aliased();
+ i1.GeneratedColumn get id =>
+ columnsByName['id']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get audioQuality =>
+ columnsByName['audio_quality']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get albumColorSync =>
+ columnsByName['album_color_sync']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get amoledDarkTheme =>
+ columnsByName['amoled_dark_theme']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get checkUpdate =>
+ columnsByName['check_update']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get normalizeAudio =>
+ columnsByName['normalize_audio']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get showSystemTrayIcon =>
+ columnsByName['show_system_tray_icon']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get systemTitleBar =>
+ columnsByName['system_title_bar']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get skipNonMusic =>
+ columnsByName['skip_non_music']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get closeBehavior =>
+ columnsByName['close_behavior']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get accentColorScheme =>
+ columnsByName['accent_color_scheme']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get layoutMode =>
+ columnsByName['layout_mode']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get locale =>
+ columnsByName['locale']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get market =>
+ columnsByName['market']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get searchMode =>
+ columnsByName['search_mode']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get downloadLocation =>
+ columnsByName['download_location']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get localLibraryLocation =>
+ columnsByName['local_library_location']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get pipedInstance =>
+ columnsByName['piped_instance']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get invidiousInstance =>
+ columnsByName['invidious_instance']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get themeMode =>
+ columnsByName['theme_mode']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get audioSource =>
+ columnsByName['audio_source']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get youtubeClientEngine =>
+ columnsByName['youtube_client_engine']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get streamMusicCodec =>
+ columnsByName['stream_music_codec']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get downloadMusicCodec =>
+ columnsByName['download_music_codec']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get discordPresence =>
+ columnsByName['discord_presence']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get endlessPlayback =>
+ columnsByName['endless_playback']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get enableConnect =>
+ columnsByName['enable_connect']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get connectPort =>
+ columnsByName['connect_port']! as i1.GeneratedColumn;
+ i1.GeneratedColumn get cacheMusic =>
+ columnsByName['cache_music']! as i1.GeneratedColumn;
+}
+
+i1.GeneratedColumn _column_56(String aliasedName) =>
+ i1.GeneratedColumn('connect_port', aliasedName, false,
+ type: i1.DriftSqlType.int, defaultValue: const Constant(-1));
i0.MigrationStepWithVersion migrationSteps({
required Future Function(i1.Migrator m, Schema2 schema) from1To2,
required Future Function(i1.Migrator m, Schema3 schema) from2To3,
required Future Function(i1.Migrator m, Schema4 schema) from3To4,
+ required Future Function(i1.Migrator m, Schema5 schema) from4To5,
+ required Future Function(i1.Migrator m, Schema6 schema) from5To6,
}) {
return (currentVersion, database) async {
switch (currentVersion) {
@@ -1210,6 +1716,16 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema);
await from3To4(migrator, schema);
return 4;
+ case 4:
+ final schema = Schema5(database: database);
+ final migrator = i1.Migrator(database, schema);
+ await from4To5(migrator, schema);
+ return 5;
+ case 5:
+ final schema = Schema6(database: database);
+ final migrator = i1.Migrator(database, schema);
+ await from5To6(migrator, schema);
+ return 6;
default:
throw ArgumentError.value('Unknown migration from $currentVersion');
}
@@ -1220,10 +1736,14 @@ i1.OnUpgrade stepByStep({
required Future Function(i1.Migrator m, Schema2 schema) from1To2,
required Future Function(i1.Migrator m, Schema3 schema) from2To3,
required Future Function(i1.Migrator m, Schema4 schema) from3To4,
+ required Future Function(i1.Migrator m, Schema5 schema) from4To5,
+ required Future Function(i1.Migrator m, Schema6 schema) from5To6,
}) =>
i0.VersionedSchema.stepByStepHelper(
step: migrationSteps(
from1To2: from1To2,
from2To3: from2To3,
from3To4: from3To4,
+ from4To5: from4To5,
+ from5To6: from5To6,
));
diff --git a/lib/models/database/tables/preferences.dart b/lib/models/database/tables/preferences.dart
index 492ac1f9..377f288d 100644
--- a/lib/models/database/tables/preferences.dart
+++ b/lib/models/database/tables/preferences.dart
@@ -79,7 +79,7 @@ class PreferencesTable extends Table {
TextColumn get closeBehavior => textEnum()
.withDefault(Constant(CloseBehavior.close.name))();
TextColumn get accentColorScheme => text()
- .withDefault(const Constant("Blue:0xFF2196F3"))
+ .withDefault(const Constant("Orange:0xFFf97315"))
.map(const SpotubeColorConverter())();
TextColumn get layoutMode =>
textEnum().withDefault(Constant(LayoutMode.adaptive.name))();
@@ -115,6 +115,7 @@ class PreferencesTable extends Table {
boolean().withDefault(const Constant(true))();
BoolColumn get enableConnect =>
boolean().withDefault(const Constant(false))();
+ IntColumn get connectPort => integer().withDefault(const Constant(-1))();
BoolColumn get cacheMusic => boolean().withDefault(const Constant(true))();
// Default values as PreferencesTableData
@@ -130,7 +131,7 @@ class PreferencesTable extends Table {
systemTitleBar: false,
skipNonMusic: false,
closeBehavior: CloseBehavior.close,
- accentColorScheme: SpotubeColor(Colors.blue.value, name: "Blue"),
+ accentColorScheme: SpotubeColor(Colors.orange.value, name: "Orange"),
layoutMode: LayoutMode.adaptive,
locale: const Locale("system", "system"),
market: Market.US,
@@ -148,6 +149,7 @@ class PreferencesTable extends Table {
endlessPlayback: true,
enableConnect: false,
cacheMusic: true,
+ connectPort: -1,
);
}
}
diff --git a/lib/models/database/typeconverters/color.dart b/lib/models/database/typeconverters/color.dart
index 70c27374..513921a2 100644
--- a/lib/models/database/typeconverters/color.dart
+++ b/lib/models/database/typeconverters/color.dart
@@ -10,7 +10,7 @@ class ColorConverter extends TypeConverter {
@override
int toSql(Color value) {
- return value.value;
+ return value.toARGB32();
}
}
diff --git a/lib/modules/album/album_card.dart b/lib/modules/album/album_card.dart
index 84106594..5fee9cc4 100644
--- a/lib/modules/album/album_card.dart
+++ b/lib/modules/album/album_card.dart
@@ -54,7 +54,7 @@ class AlbumCard extends HookConsumerWidget {
Future> fetchAllTrack() async {
if (album.tracks != null && album.tracks!.isNotEmpty) {
- return album.tracks!.map((track) => track.asTrack(album)).toList();
+ return album.tracks!.asTracks(album, ref);
}
await ref.read(albumTracksProvider(album).future);
return ref.read(albumTracksProvider(album).notifier).fetchAll();
diff --git a/lib/modules/home/sections/feed.dart b/lib/modules/home/sections/feed.dart
index d3e363cc..216dc491 100644
--- a/lib/modules/home/sections/feed.dart
+++ b/lib/modules/home/sections/feed.dart
@@ -12,7 +12,7 @@ class HomePageFeedSection extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final homeFeed = ref.watch(homeViewProvider);
- final nonShortSections = homeFeed.asData?.value?.sections
+ final nonShortSections = homeFeed.asData?.value.sections
.where((s) => s.typename == "HomeGenericSectionData")
.toList() ??
[];
diff --git a/lib/modules/home/sections/genres/genre_card_playlist_card.dart b/lib/modules/home/sections/genres/genre_card_playlist_card.dart
index 1e1b3b76..328507cc 100644
--- a/lib/modules/home/sections/genres/genre_card_playlist_card.dart
+++ b/lib/modules/home/sections/genres/genre_card_playlist_card.dart
@@ -1,6 +1,6 @@
import 'package:auto_route/auto_route.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:spotify/spotify.dart' hide Image;
import 'package:spotube/collections/env.dart';
import 'package:spotube/collections/routes.gr.dart';
diff --git a/lib/modules/library/playlist_generate/multi_select_field.dart b/lib/modules/library/playlist_generate/multi_select_field.dart
index 7118d57d..00a09c95 100644
--- a/lib/modules/library/playlist_generate/multi_select_field.dart
+++ b/lib/modules/library/playlist_generate/multi_select_field.dart
@@ -68,7 +68,7 @@ class MultiSelectField extends HookWidget {
side: BorderSide(
color: enabled
? theme.colorScheme.onSurface
- : theme.colorScheme.onSurface.withOpacity(0.1),
+ : theme.colorScheme.onSurface.withValues(alpha: 0.1),
),
),
mouseCursor: WidgetStateMouseCursor.textable,
diff --git a/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart b/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart
index da1288f5..812d9367 100644
--- a/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart
+++ b/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart
@@ -119,8 +119,10 @@ class SeedsMultiAutocomplete extends HookWidget {
focusNode: focusNode,
onSubmitted: (_) => onFieldSubmitted(),
enabled: enabled,
- leading: leading,
- trailing: trailing,
+ features: [
+ if (leading != null) InputFeature.leading(leading!),
+ if (trailing != null) InputFeature.trailing(trailing!),
+ ],
placeholder: placeholder,
);
},
diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart
index aa5171d5..b02910e9 100644
--- a/lib/modules/player/player.dart
+++ b/lib/modules/player/player.dart
@@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:sliding_up_panel/sliding_up_panel.dart';
import 'package:spotube/collections/assets.gen.dart';
@@ -132,7 +132,7 @@ class PlayerView extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.details),
- ),
+ ).call,
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.info, size: 18),
onPressed: currentTrack == null
diff --git a/lib/modules/player/player_actions.dart b/lib/modules/player/player_actions.dart
index 0ed56ed2..53023a10 100644
--- a/lib/modules/player/player_actions.dart
+++ b/lib/modules/player/player_actions.dart
@@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/routes.gr.dart';
@@ -82,7 +82,7 @@ class PlayerActions extends HookConsumerWidget {
children: [
if (showQueue)
Tooltip(
- tooltip: TooltipContainer(child: Text(context.l10n.queue)),
+ tooltip: TooltipContainer(child: Text(context.l10n.queue)).call,
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.queue),
enabled: playlist.activeTrack != null,
@@ -119,7 +119,8 @@ class PlayerActions extends HookConsumerWidget {
if (!isLocalTrack)
Tooltip(
tooltip: TooltipContainer(
- child: Text(context.l10n.alternative_track_sources)),
+ child: Text(context.l10n.alternative_track_sources),
+ ).call,
child: IconButton.ghost(
enabled: playlist.activeTrack != null,
icon: const Icon(SpotubeIcons.alternativeRoute),
@@ -160,7 +161,8 @@ class PlayerActions extends HookConsumerWidget {
else
Tooltip(
tooltip:
- TooltipContainer(child: Text(context.l10n.download_track)),
+ TooltipContainer(child: Text(context.l10n.download_track))
+ .call,
child: IconButton.ghost(
icon: Icon(
isDownloaded ? SpotubeIcons.done : SpotubeIcons.download,
diff --git a/lib/modules/player/player_controls.dart b/lib/modules/player/player_controls.dart
index 4d5d6deb..14b9cf43 100644
--- a/lib/modules/player/player_controls.dart
+++ b/lib/modules/player/player_controls.dart
@@ -3,7 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:media_kit/media_kit.dart';
import 'package:palette_generator/palette_generator.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/collections/intents.dart';
@@ -89,7 +89,7 @@ class PlayerControls extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.slide_to_seek),
- ),
+ ).call,
child: SizedBox(
width: mediaQuery.xlAndUp ? 600 : 500,
child: Slider(
@@ -147,7 +147,7 @@ class PlayerControls extends HookConsumerWidget {
? context.l10n.unshuffle_playlist
: context.l10n.shuffle_playlist,
),
- ),
+ ).call,
child: IconButton(
icon: Icon(
SpotubeIcons.shuffle,
@@ -170,7 +170,7 @@ class PlayerControls extends HookConsumerWidget {
}),
Tooltip(
tooltip: TooltipContainer(
- child: Text(context.l10n.previous_track)),
+ child: Text(context.l10n.previous_track)).call,
child: IconButton.ghost(
enabled: !isFetchingActiveTrack,
icon: const Icon(SpotubeIcons.skipBack),
@@ -184,7 +184,7 @@ class PlayerControls extends HookConsumerWidget {
? context.l10n.pause_playback
: context.l10n.resume_playback,
),
- ),
+ ).call,
child: IconButton.primary(
shape: ButtonShape.circle,
icon: isFetchingActiveTrack
@@ -206,7 +206,7 @@ class PlayerControls extends HookConsumerWidget {
),
Tooltip(
tooltip:
- TooltipContainer(child: Text(context.l10n.next_track)),
+ TooltipContainer(child: Text(context.l10n.next_track)).call,
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.skipForward),
onPressed:
@@ -226,7 +226,7 @@ class PlayerControls extends HookConsumerWidget {
? context.l10n.repeat_playlist
: "",
),
- ),
+ ).call,
child: IconButton(
icon: Icon(
loopMode == PlaylistMode.single
diff --git a/lib/modules/player/player_overlay_collapsed.dart b/lib/modules/player/player_overlay_collapsed.dart
index d0961ade..aa5a3b38 100644
--- a/lib/modules/player/player_overlay_collapsed.dart
+++ b/lib/modules/player/player_overlay_collapsed.dart
@@ -1,6 +1,6 @@
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:sliding_up_panel/sliding_up_panel.dart';
import 'package:spotube/collections/intents.dart';
import 'package:spotube/collections/spotube_icons.dart';
diff --git a/lib/modules/player/player_queue.dart b/lib/modules/player/player_queue.dart
index 0ef86111..06d7e3c7 100644
--- a/lib/modules/player/player_queue.dart
+++ b/lib/modules/player/player_queue.dart
@@ -161,7 +161,7 @@ class PlayerQueue extends HookConsumerWidget {
const SizedBox(width: 10),
Tooltip(
tooltip: TooltipContainer(
- child: Text(context.l10n.clear_all)),
+ child: Text(context.l10n.clear_all)).call,
child: IconButton.outline(
icon: const Icon(SpotubeIcons.playlistRemove),
onPressed: () {
diff --git a/lib/modules/playlist/playlist_card.dart b/lib/modules/playlist/playlist_card.dart
index 1e2ba1bf..c4ffffa7 100644
--- a/lib/modules/playlist/playlist_card.dart
+++ b/lib/modules/playlist/playlist_card.dart
@@ -1,7 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:spotify/spotify.dart' hide Offset, Image;
import 'package:spotube/collections/env.dart';
import 'package:spotube/collections/routes.gr.dart';
diff --git a/lib/modules/root/bottom_player.dart b/lib/modules/root/bottom_player.dart
index 18b4c221..c2e6369d 100644
--- a/lib/modules/root/bottom_player.dart
+++ b/lib/modules/root/bottom_player.dart
@@ -1,7 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/assets.gen.dart';
@@ -76,7 +76,7 @@ class BottomPlayer extends HookConsumerWidget {
extraActions: [
Tooltip(
tooltip:
- TooltipContainer(child: Text(context.l10n.mini_player)),
+ TooltipContainer(child: Text(context.l10n.mini_player)).call,
child: IconButton(
variance: ButtonVariance.ghost,
icon: const Icon(SpotubeIcons.miniPlayer),
diff --git a/lib/modules/root/sidebar/sidebar.dart b/lib/modules/root/sidebar/sidebar.dart
index 743b339b..6b61c70b 100644
--- a/lib/modules/root/sidebar/sidebar.dart
+++ b/lib/modules/root/sidebar/sidebar.dart
@@ -20,13 +20,16 @@ class Sidebar extends HookConsumerWidget {
super.key,
});
- static Widget brandLogo() {
+ static Widget brandLogo(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(50),
),
- child: Assets.spotubeLogoPng.image(height: 50),
+ child: Assets.spotubeLogoPng.image(
+ height: 50,
+ cacheHeight: (100 * MediaQuery.devicePixelRatioOf(context)).toInt(),
+ ),
);
}
@@ -62,13 +65,22 @@ class Sidebar extends HookConsumerWidget {
final navigationButtons = [
NavigationLabel(
- child: mediaQuery.lgAndUp ? const Text("Spotube") : const Text(""),
+ child: mediaQuery.lgAndUp
+ ? const DefaultTextStyle(
+ style: TextStyle(
+ fontFamily: "Cookie",
+ fontSize: 30,
+ letterSpacing: 1.8,
+ ),
+ child: Text("Spotube"),
+ )
+ : const Text(""),
),
for (final tile in sidebarTileList)
NavigationButton(
label: mediaQuery.lgAndUp ? Text(tile.title) : null,
child: Tooltip(
- tooltip: TooltipContainer(child: Text(tile.title)),
+ tooltip: TooltipContainer(child: Text(tile.title)).call,
child: Icon(tile.icon),
),
onPressed: () {
@@ -85,7 +97,7 @@ class Sidebar extends HookConsumerWidget {
context.navigateTo(tile.route);
},
child: Tooltip(
- tooltip: TooltipContainer(child: Text(tile.title)),
+ tooltip: TooltipContainer(child: Text(tile.title)).call,
child: Icon(tile.icon),
),
),
diff --git a/lib/modules/settings/color_scheme_picker_dialog.dart b/lib/modules/settings/color_scheme_picker_dialog.dart
index 8092f825..3fb05e72 100644
--- a/lib/modules/settings/color_scheme_picker_dialog.dart
+++ b/lib/modules/settings/color_scheme_picker_dialog.dart
@@ -21,7 +21,7 @@ class SpotubeColor extends Color {
@override
String toString() {
- return "$name:$value";
+ return "$name:${toARGB32()}";
}
}
diff --git a/lib/modules/settings/playback/edit_connect_port_dialog.dart b/lib/modules/settings/playback/edit_connect_port_dialog.dart
new file mode 100644
index 00000000..587f4388
--- /dev/null
+++ b/lib/modules/settings/playback/edit_connect_port_dialog.dart
@@ -0,0 +1,97 @@
+import 'package:flutter/services.dart';
+import 'package:flutter_form_builder/flutter_form_builder.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:form_builder_validators/form_builder_validators.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:spotube/components/form/text_form_field.dart';
+import 'package:spotube/extensions/context.dart';
+import 'package:spotube/hooks/controllers/use_shadcn_text_editing_controller.dart';
+import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
+
+class SettingsPlaybackEditConnectPortDialog extends HookConsumerWidget {
+ const SettingsPlaybackEditConnectPortDialog({super.key});
+
+ @override
+ Widget build(BuildContext context, ref) {
+ final connectPort = ref.watch(
+ userPreferencesProvider.select((s) => s.connectPort),
+ );
+ final controller = useShadcnTextEditingController(
+ text: connectPort.toString(),
+ );
+ final formKey = useMemoized(() => GlobalKey(), []);
+
+ return ConstrainedBox(
+ constraints: const BoxConstraints(maxWidth: 400),
+ child: Alert(
+ title: Text(context.l10n.edit_port).h4(),
+ content: FormBuilder(
+ key: formKey,
+ child: Column(
+ children: [
+ const Gap(10),
+ TextFormBuilderField(
+ name: "port",
+ controller: controller,
+ placeholder: const Text("3000"),
+ validator: FormBuilderValidators.integer(radix: 10),
+ keyboardType: TextInputType.number,
+ inputFormatters: [
+ // Allow only signed integers
+ TextInputFormatter.withFunction(
+ (oldValue, newValue) {
+ if (newValue.text.isEmpty) {
+ return const TextEditingValue();
+ }
+ if (newValue.text.length == 1 && newValue.text == "-") {
+ return newValue;
+ }
+
+ final intValue = int.tryParse(newValue.text);
+ if (intValue == null) {
+ return oldValue;
+ }
+ return newValue;
+ },
+ ),
+ ],
+ ),
+ const Gap(5),
+ Text(context.l10n.port_helper_msg).small.muted,
+ const Gap(20),
+ Row(
+ children: [
+ Expanded(
+ child: Button.secondary(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ child: Text(context.l10n.cancel),
+ ),
+ ),
+ const Gap(10),
+ Expanded(
+ child: Button.primary(
+ onPressed: () {
+ if (!formKey.currentState!.saveAndValidate()) {
+ return;
+ }
+ final port = int.parse(controller.text);
+ ref
+ .read(userPreferencesProvider.notifier)
+ .setConnectPort(port);
+ Navigator.of(context).pop();
+ },
+ child: Text(context.l10n.save),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/modules/settings/playback/edit_instance_url_dialog.dart b/lib/modules/settings/playback/edit_instance_url_dialog.dart
new file mode 100644
index 00000000..b2dda411
--- /dev/null
+++ b/lib/modules/settings/playback/edit_instance_url_dialog.dart
@@ -0,0 +1,75 @@
+import 'package:flutter_form_builder/flutter_form_builder.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:form_builder_validators/form_builder_validators.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:spotube/components/form/text_form_field.dart';
+import 'package:spotube/extensions/context.dart';
+import 'package:spotube/hooks/controllers/use_shadcn_text_editing_controller.dart';
+
+class SettingsPlaybackEditInstanceUrlDialog extends HookConsumerWidget {
+ final String title;
+ final String? initialValue;
+ final ValueChanged onSave;
+
+ const SettingsPlaybackEditInstanceUrlDialog({
+ super.key,
+ required this.title,
+ required this.onSave,
+ this.initialValue,
+ });
+
+ @override
+ Widget build(BuildContext context, ref) {
+ final controller = useShadcnTextEditingController(
+ text: initialValue,
+ );
+ final formKey = useMemoized(() => GlobalKey(), []);
+
+ return Alert(
+ title: Text(title).h4(),
+ content: FormBuilder(
+ key: formKey,
+ child: Column(
+ children: [
+ const Gap(10),
+ TextFormBuilderField(
+ name: "url",
+ controller: controller,
+ placeholder: Text(title),
+ validator: FormBuilderValidators.url(),
+ ),
+ const Gap(10),
+ Row(
+ children: [
+ Expanded(
+ child: Button.secondary(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ child: Text(context.l10n.cancel),
+ ),
+ ),
+ const Gap(10),
+ Expanded(
+ child: Button.primary(
+ onPressed: () {
+ if (!formKey.currentState!.saveAndValidate()) {
+ return;
+ }
+ onSave(
+ controller.text,
+ );
+ Navigator.of(context).pop();
+ },
+ child: Text(context.l10n.save),
+ ),
+ ),
+ ],
+ )
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/modules/stats/top/artists.dart b/lib/modules/stats/top/artists.dart
index c53c34fd..cb2a152f 100644
--- a/lib/modules/stats/top/artists.dart
+++ b/lib/modules/stats/top/artists.dart
@@ -25,7 +25,13 @@ class TopArtists extends HookConsumerWidget {
ref.watch(historyTopTracksProvider(historyDuration).notifier);
final artistsData = useMemoized(
- () => topTracks.asData?.value.artists ?? [], [topTracks.asData?.value]);
+ () => topTracks.asData?.value.artists ?? [],
+ [topTracks.asData?.value],
+ );
+
+ for (final artist in artistsData) {
+ print("${artist.artist.name} has ${artist.artist.images?.length} images");
+ }
return Skeletonizer.sliver(
enabled: topTracks.isLoading && !topTracks.isLoadingNextPage,
diff --git a/lib/pages/artist/section/footer.dart b/lib/pages/artist/section/footer.dart
index 0fe2ab68..9a1423b5 100644
--- a/lib/pages/artist/section/footer.dart
+++ b/lib/pages/artist/section/footer.dart
@@ -35,7 +35,7 @@ class ArtistPageFooter extends ConsumerWidget {
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
colorFilter: ColorFilter.mode(
- Colors.black.withOpacity(0.5),
+ Colors.black.withValues(alpha: 0.5),
BlendMode.darken,
),
image: UniversalImage.imageProvider(
diff --git a/lib/pages/artist/section/header.dart b/lib/pages/artist/section/header.dart
index b6224428..62e66edc 100644
--- a/lib/pages/artist/section/header.dart
+++ b/lib/pages/artist/section/header.dart
@@ -1,7 +1,7 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:skeletonizer/skeletonizer.dart';
import 'package:spotube/collections/fake.dart';
import 'package:spotube/collections/spotube_icons.dart';
@@ -84,7 +84,7 @@ class ArtistPageHeader extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.add_artist_to_blacklist),
- ),
+ ).call,
child: IconButton(
icon: Icon(
SpotubeIcons.userRemove,
diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart
index 2511809c..e28566fd 100644
--- a/lib/pages/connect/control/control.dart
+++ b/lib/pages/connect/control/control.dart
@@ -1,9 +1,13 @@
+import 'dart:convert';
+
import 'package:auto_route/auto_route.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/collections/spotube_icons.dart';
+import 'package:spotube/models/connect/connect.dart';
import 'package:spotube/modules/player/player_queue.dart';
import 'package:spotube/modules/player/volume_slider.dart';
import 'package:spotube/components/image/universal_image.dart';
@@ -57,6 +61,7 @@ class ConnectControlPage extends HookConsumerWidget {
final resolvedService =
ref.watch(connectClientsProvider).asData?.value.resolvedService;
+ final connect = ref.watch(connectProvider);
final connectNotifier = ref.read(connectProvider.notifier);
final playlist = ref.watch(queueProvider);
final playing = ref.watch(playingProvider);
@@ -69,12 +74,32 @@ class ConnectControlPage extends HookConsumerWidget {
}
});
+ useEffect(() {
+ if (connect.asData?.value == null) return null;
+
+ final subscription = connect.asData?.value?.stream.listen((message) {
+ final event = WebSocketEvent.fromJson(
+ jsonDecode(message),
+ (data) => data,
+ );
+ event.onError((event) {
+ if (event.data != "Connection denied") return;
+ if (!context.mounted) return;
+ context.back();
+ });
+ });
+
+ return () {
+ subscription?.cancel();
+ };
+ }, [connect.asData?.value]);
+
return SafeArea(
bottom: false,
child: Scaffold(
headers: [
TitleBar(
- title: Text(resolvedService!.name),
+ title: Text(resolvedService?.name ?? ""),
)
],
child: LayoutBuilder(builder: (context, constrains) {
@@ -188,7 +213,7 @@ class ConnectControlPage extends HookConsumerWidget {
? context.l10n.unshuffle_playlist
: context.l10n.shuffle_playlist,
),
- ),
+ ).call,
child: IconButton(
icon: const Icon(SpotubeIcons.shuffle),
variance: shuffled
@@ -204,7 +229,7 @@ class ConnectControlPage extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.previous_track),
- ),
+ ).call,
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.skipBack),
onPressed: playlist.activeTrack == null
@@ -219,7 +244,7 @@ class ConnectControlPage extends HookConsumerWidget {
? context.l10n.pause_playback
: context.l10n.resume_playback,
),
- ),
+ ).call,
child: IconButton.primary(
shape: ButtonShape.circle,
icon: playlist.activeTrack == null
@@ -247,7 +272,8 @@ class ConnectControlPage extends HookConsumerWidget {
),
Tooltip(
tooltip: TooltipContainer(
- child: Text(context.l10n.next_track)),
+ child: Text(context.l10n.next_track))
+ .call,
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.skipForward),
onPressed: playlist.activeTrack == null
@@ -264,7 +290,7 @@ class ConnectControlPage extends HookConsumerWidget {
? context.l10n.repeat_playlist
: context.l10n.no_loop,
),
- ),
+ ).call,
child: IconButton(
icon: Icon(
loopMode == PlaylistMode.single
diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart
index 9ca71c04..1ef81027 100644
--- a/lib/pages/home/home.dart
+++ b/lib/pages/home/home.dart
@@ -1,3 +1,5 @@
+import 'dart:ui';
+
import 'package:auto_route/auto_route.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -28,6 +30,7 @@ class HomePage extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
+ final theme = Theme.of(context);
final controller = useScrollController();
final mediaQuery = MediaQuery.of(context);
final layoutMode =
@@ -45,7 +48,17 @@ class HomePage extends HookConsumerWidget {
if (mediaQuery.smAndDown || layoutMode == LayoutMode.compact)
SliverAppBar(
floating: true,
- title: Assets.spotubeLogoPng.image(height: 45),
+ title: Image.asset(
+ theme.brightness == Brightness.dark
+ ? Assets.spotubeLogoPng.path
+ : Assets.spotubeLogoLight.path,
+ height: 45,
+ width: 45,
+ color: theme.colorScheme.background,
+ colorBlendMode: BlendMode.saturation,
+ cacheHeight:
+ (100 * MediaQuery.devicePixelRatioOf(context)).toInt(),
+ ),
backgroundColor: context.theme.colorScheme.background,
foregroundColor: context.theme.colorScheme.foreground,
actions: [
diff --git a/lib/pages/lastfm_login/lastfm_login.dart b/lib/pages/lastfm_login/lastfm_login.dart
index ca0f5693..164b9b0d 100644
--- a/lib/pages/lastfm_login/lastfm_login.dart
+++ b/lib/pages/lastfm_login/lastfm_login.dart
@@ -119,15 +119,19 @@ class LastFMLoginPage extends HookConsumerWidget {
],
obscureText: !passwordVisible.value,
placeholder: Text(context.l10n.password),
- trailing: IconButton.ghost(
- icon: Icon(
- passwordVisible.value
- ? SpotubeIcons.eye
- : SpotubeIcons.noEye,
+ features: [
+ InputFeature.trailing(
+ IconButton.ghost(
+ icon: Icon(
+ passwordVisible.value
+ ? SpotubeIcons.eye
+ : SpotubeIcons.noEye,
+ ),
+ onPressed: () => passwordVisible.value =
+ !passwordVisible.value,
+ ),
),
- onPressed: () => passwordVisible.value =
- !passwordVisible.value,
- ),
+ ],
),
),
],
diff --git a/lib/pages/library/user_albums.dart b/lib/pages/library/user_albums.dart
index 60ba7319..beaa779f 100644
--- a/lib/pages/library/user_albums.dart
+++ b/lib/pages/library/user_albums.dart
@@ -75,7 +75,9 @@ class UserAlbumsPage extends HookConsumerWidget {
height: 48,
child: TextField(
onChanged: (value) => searchText.value = value,
- leading: const Icon(SpotubeIcons.filter),
+ features: const [
+ InputFeature.leading(Icon(SpotubeIcons.filter))
+ ],
placeholder: Text(context.l10n.filter_artist),
),
),
diff --git a/lib/pages/library/user_artists.dart b/lib/pages/library/user_artists.dart
index 5f304f5e..35577cd7 100644
--- a/lib/pages/library/user_artists.dart
+++ b/lib/pages/library/user_artists.dart
@@ -80,7 +80,9 @@ class UserArtistsPage extends HookConsumerWidget {
height: 48,
child: TextField(
onChanged: (value) => searchText.value = value,
- leading: const Icon(SpotubeIcons.filter),
+ features: const [
+ InputFeature.leading(Icon(SpotubeIcons.filter)),
+ ],
placeholder: Text(context.l10n.filter_artist),
),
),
diff --git a/lib/pages/library/user_playlists.dart b/lib/pages/library/user_playlists.dart
index 8249726d..8b9e0dc3 100644
--- a/lib/pages/library/user_playlists.dart
+++ b/lib/pages/library/user_playlists.dart
@@ -99,7 +99,9 @@ class UserPlaylistsPage extends HookConsumerWidget {
child: TextField(
onChanged: (value) => searchText.value = value,
placeholder: Text(context.l10n.filter_playlists),
- leading: const Icon(SpotubeIcons.filter),
+ features: const [
+ InputFeature.leading(Icon(SpotubeIcons.filter)),
+ ],
),
),
),
diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart
index d3e77bf0..1bd58d61 100644
--- a/lib/pages/lyrics/lyrics.dart
+++ b/lib/pages/lyrics/lyrics.dart
@@ -1,6 +1,6 @@
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/components/titlebar/titlebar.dart';
@@ -101,7 +101,7 @@ class LyricsPage extends HookConsumerWidget {
borderRadius: BorderRadius.zero,
borderWidth: 0,
child: ColoredBox(
- color: palette.color.withOpacity(.7),
+ color: palette.color.withValues(alpha: .7),
child: SafeArea(
child: IndexedStack(
index: selectedIndex.value,
diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart
index 3e50987d..4c28eddd 100644
--- a/lib/pages/lyrics/mini_lyrics.dart
+++ b/lib/pages/lyrics/mini_lyrics.dart
@@ -2,7 +2,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:palette_generator/palette_generator.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/collections/spotube_icons.dart';
@@ -59,7 +59,7 @@ class MiniLyricsPage extends HookConsumerWidget {
areaActive.value = false;
},
child: Scaffold(
- backgroundColor: theme.colorScheme.background.withOpacity(0.4),
+ backgroundColor: theme.colorScheme.background.withValues(alpha: 0.4),
headers: [
Padding(
padding: const EdgeInsets.all(8.0),
@@ -89,7 +89,8 @@ class MiniLyricsPage extends HookConsumerWidget {
const Spacer(),
Tooltip(
tooltip:
- TooltipContainer(child: Text(context.l10n.lyrics)),
+ TooltipContainer(child: Text(context.l10n.lyrics))
+ .call,
child: IconButton(
variance: showLyrics.value
? ButtonVariance.secondary
@@ -115,7 +116,7 @@ class MiniLyricsPage extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.show_hide_ui_on_hover),
- ),
+ ).call,
child: IconButton(
variance: hoverMode.value
? ButtonVariance.secondary
@@ -136,7 +137,7 @@ class MiniLyricsPage extends HookConsumerWidget {
return Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.always_on_top),
- ),
+ ).call,
child: IconButton(
variance: snapshot.data == true
? ButtonVariance.secondary
@@ -199,7 +200,7 @@ class MiniLyricsPage extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.queue),
- ),
+ ).call,
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.queue),
onPressed: playlistQueue.activeTrack != null
@@ -245,7 +246,8 @@ class MiniLyricsPage extends HookConsumerWidget {
const Flexible(child: PlayerControls(compact: true)),
Tooltip(
tooltip: TooltipContainer(
- child: Text(context.l10n.exit_mini_player)),
+ child: Text(context.l10n.exit_mini_player))
+ .call,
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.maximize),
onPressed: () async {
@@ -268,7 +270,7 @@ class MiniLyricsPage extends HookConsumerWidget {
const Duration(milliseconds: 200));
} finally {
if (context.mounted) {
- context.navigateTo(LyricsRoute());
+ context.navigateTo(const LyricsRoute());
}
}
},
diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart
index 3826a0b6..25fb046a 100644
--- a/lib/pages/search/search.dart
+++ b/lib/pages/search/search.dart
@@ -121,32 +121,47 @@ class SearchPage extends HookConsumerWidget {
}
},
child: AutoComplete(
- suggestions: suggestions,
+ suggestions: suggestions.length <= 2
+ ? [
+ ...suggestions,
+ "Twenty One Pilots",
+ "Linkin Park",
+ "d4vd"
+ ]
+ : suggestions,
+ completer: (suggestion) => suggestion,
+ mode: AutoCompleteMode.replaceAll,
child: TextField(
autofocus: true,
controller: controller,
- leading:
- const Icon(SpotubeIcons.search),
- textInputAction: TextInputAction.search,
- placeholder: Text(context.l10n.search),
- trailing: AnimatedCrossFade(
- duration:
- const Duration(milliseconds: 300),
- crossFadeState:
- controller.text.isNotEmpty
+ features: [
+ const InputFeature.leading(
+ Icon(SpotubeIcons.search),
+ ),
+ InputFeature.trailing(
+ AnimatedCrossFade(
+ duration: const Duration(
+ milliseconds: 300),
+ crossFadeState: controller
+ .text.isNotEmpty
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
- firstChild: IconButton.ghost(
- size: ButtonSize.small,
- icon:
- const Icon(SpotubeIcons.close),
- onPressed: () {
- controller.clear();
- },
- ),
- secondChild: const SizedBox.square(
- dimension: 28),
- ),
+ firstChild: IconButton.ghost(
+ size: ButtonSize.small,
+ icon: const Icon(
+ SpotubeIcons.close),
+ onPressed: () {
+ controller.clear();
+ },
+ ),
+ secondChild:
+ const SizedBox.square(
+ dimension: 28),
+ ),
+ )
+ ],
+ textInputAction: TextInputAction.search,
+ placeholder: Text(context.l10n.search),
onSubmitted: onSubmitted,
),
),
@@ -194,7 +209,7 @@ class SearchPage extends HookConsumerWidget {
fontSize: 20,
fontWeight: FontWeight.w900,
color: theme.colorScheme.foreground
- .withOpacity(0.7),
+ .withValues(alpha: 0.7),
),
),
const SizedBox(height: 20),
diff --git a/lib/pages/settings/sections/accounts.dart b/lib/pages/settings/sections/accounts.dart
index 5e40b9ec..a381dc23 100644
--- a/lib/pages/settings/sections/accounts.dart
+++ b/lib/pages/settings/sections/accounts.dart
@@ -49,7 +49,7 @@ class SettingsAccountSection extends HookConsumerWidget {
),
),
onTap: () {
- context.navigateTo(ProfileRoute());
+ context.navigateTo(const ProfileRoute());
},
),
if (auth.asData?.value == null)
diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart
index f3b7d131..6acc70b1 100644
--- a/lib/pages/settings/sections/playback.dart
+++ b/lib/pages/settings/sections/playback.dart
@@ -4,19 +4,16 @@ import 'package:auto_route/auto_route.dart';
import 'package:collection/collection.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart' show ListTile;
-import 'package:flutter_form_builder/flutter_form_builder.dart';
-import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:piped_client/piped_client.dart';
-import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/collections/spotube_icons.dart';
-import 'package:spotube/components/form/text_form_field.dart';
-import 'package:spotube/hooks/controllers/use_shadcn_text_editing_controller.dart';
import 'package:spotube/models/database/database.dart';
+import 'package:spotube/modules/settings/playback/edit_connect_port_dialog.dart';
+import 'package:spotube/modules/settings/playback/edit_instance_url_dialog.dart';
import 'package:spotube/modules/settings/section_card_with_heading.dart';
import 'package:spotube/components/adaptive/adaptive_select_tile.dart';
import 'package:spotube/extensions/context.dart';
@@ -106,7 +103,7 @@ class SettingsPlaybackSection extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.add_custom_url),
- ),
+ ).call,
child: IconButton.outline(
icon: const Icon(SpotubeIcons.edit),
size: ButtonSize.small,
@@ -114,67 +111,12 @@ class SettingsPlaybackSection extends HookConsumerWidget {
showDialog(
context: context,
barrierColor: Colors.black.withValues(alpha: 0.5),
- builder: (context) => HookBuilder(
- builder: (context) {
- final controller =
- useShadcnTextEditingController(
- text: preferences.pipedInstance,
- );
- final formKey = useMemoized(
- () => GlobalKey(), []);
-
- return Alert(
- title:
- Text(context.l10n.piped_instance).h4(),
- content: FormBuilder(
- key: formKey,
- child: Column(
- children: [
- const Gap(10),
- TextFormBuilderField(
- name: "url",
- controller: controller,
- placeholder: Text(
- context.l10n.piped_instance),
- validator:
- FormBuilderValidators.url(),
- ),
- const Gap(10),
- Row(
- children: [
- Expanded(
- child: Button.secondary(
- onPressed: () {
- Navigator.of(context).pop();
- },
- child:
- Text(context.l10n.cancel),
- ),
- ),
- const Gap(10),
- Expanded(
- child: Button.primary(
- onPressed: () {
- if (!formKey.currentState!
- .saveAndValidate()) {
- return;
- }
- preferencesNotifier
- .setPipedInstance(
- controller.text,
- );
- Navigator.of(context).pop();
- },
- child:
- Text(context.l10n.save),
- ),
- ),
- ],
- )
- ],
- ),
- ),
- );
+ builder: (context) =>
+ SettingsPlaybackEditInstanceUrlDialog(
+ title: context.l10n.piped_instance,
+ initialValue: preferences.pipedInstance,
+ onSave: (value) {
+ preferencesNotifier.setPipedInstance(value);
},
),
);
@@ -261,7 +203,7 @@ class SettingsPlaybackSection extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.add_custom_url),
- ),
+ ).call,
child: IconButton.outline(
icon: const Icon(SpotubeIcons.edit),
size: ButtonSize.small,
@@ -269,67 +211,13 @@ class SettingsPlaybackSection extends HookConsumerWidget {
showDialog(
context: context,
barrierColor: Colors.black.withValues(alpha: 0.5),
- builder: (context) => HookBuilder(
- builder: (context) {
- final controller =
- useShadcnTextEditingController(
- text: preferences.invidiousInstance,
- );
- final formKey = useMemoized(
- () => GlobalKey(), []);
-
- return Alert(
- title: Text(context.l10n.invidious_instance)
- .h4(),
- content: FormBuilder(
- key: formKey,
- child: Column(
- children: [
- const Gap(10),
- TextFormBuilderField(
- name: "url",
- controller: controller,
- placeholder: Text(context
- .l10n.invidious_instance),
- validator:
- FormBuilderValidators.url(),
- ),
- const Gap(10),
- Row(
- children: [
- Expanded(
- child: Button.secondary(
- onPressed: () {
- Navigator.of(context).pop();
- },
- child:
- Text(context.l10n.cancel),
- ),
- ),
- const Gap(10),
- Expanded(
- child: Button.primary(
- onPressed: () {
- if (!formKey.currentState!
- .saveAndValidate()) {
- return;
- }
- preferencesNotifier
- .setInvidiousInstance(
- controller.text,
- );
- Navigator.of(context).pop();
- },
- child:
- Text(context.l10n.save),
- ),
- ),
- ],
- )
- ],
- ),
- ),
- );
+ builder: (context) =>
+ SettingsPlaybackEditInstanceUrlDialog(
+ title: context.l10n.invidious_instance,
+ initialValue: preferences.invidiousInstance,
+ onSave: (value) {
+ preferencesNotifier
+ .setInvidiousInstance(value);
},
),
);
@@ -561,9 +449,32 @@ class SettingsPlaybackSection extends HookConsumerWidget {
title: Text(context.l10n.enable_connect),
subtitle: Text(context.l10n.enable_connect_description),
leading: const Icon(SpotubeIcons.connect),
- trailing: Switch(
- value: preferences.enableConnect,
- onChanged: preferencesNotifier.setEnableConnect,
+ trailing: Row(
+ mainAxisSize: MainAxisSize.min,
+ spacing: 10,
+ children: [
+ Tooltip(
+ tooltip: TooltipContainer(
+ child: Text(context.l10n.edit_port),
+ ).call,
+ child: IconButton.outline(
+ icon: const Icon(SpotubeIcons.edit),
+ size: ButtonSize.small,
+ onPressed: () {
+ showDialog(
+ context: context,
+ barrierColor: Colors.black.withValues(alpha: 0.5),
+ builder: (context) =>
+ const SettingsPlaybackEditConnectPortDialog(),
+ );
+ },
+ ),
+ ),
+ Switch(
+ value: preferences.enableConnect,
+ onChanged: preferencesNotifier.setEnableConnect,
+ ),
+ ],
),
),
],
diff --git a/lib/pages/track/track.dart b/lib/pages/track/track.dart
index 2918d1d7..8e6df748 100644
--- a/lib/pages/track/track.dart
+++ b/lib/pages/track/track.dart
@@ -77,7 +77,7 @@ class TrackPage extends HookConsumerWidget {
),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
- colorScheme.background.withOpacity(0.5),
+ colorScheme.background.withValues(alpha: 0.5),
BlendMode.srcOver,
),
alignment: Alignment.topCenter,
@@ -196,7 +196,7 @@ class TrackPage extends HookConsumerWidget {
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.play_next),
- ),
+ ).call,
child: IconButton.outline(
icon: const Icon(
SpotubeIcons.lightning),
@@ -214,7 +214,7 @@ class TrackPage extends HookConsumerWidget {
? context.l10n.pause_playback
: context.l10n.play,
),
- ),
+ ).call,
child: IconButton.primary(
shape: ButtonShape.circle,
icon: Icon(
diff --git a/lib/provider/audio_player/audio_player_streams.dart b/lib/provider/audio_player/audio_player_streams.dart
index 54c6d7cd..c221a2b0 100644
--- a/lib/provider/audio_player/audio_player_streams.dart
+++ b/lib/provider/audio_player/audio_player_streams.dart
@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:math';
import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:spotify/spotify.dart';
import 'package:spotube/models/local_track.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/audio_player/state.dart';
@@ -10,6 +11,7 @@ import 'package:spotube/provider/history/history.dart';
import 'package:spotube/provider/skip_segments/skip_segments.dart';
import 'package:spotube/provider/scrobbler/scrobbler.dart';
import 'package:spotube/provider/server/sourced_track.dart';
+import 'package:spotube/provider/spotify/spotify.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/audio_services/audio_services.dart';
@@ -63,7 +65,9 @@ class AudioPlayerStreamListeners {
final currentSegments = await ref.read(segmentProvider.future);
if (currentSegments?.segments.isNotEmpty != true ||
- position < const Duration(seconds: 3)) return;
+ position < const Duration(seconds: 3)) {
+ return;
+ }
for (final segment in currentSegments!.segments) {
final seconds = position.inSeconds;
@@ -80,7 +84,7 @@ class AudioPlayerStreamListeners {
StreamSubscription subscribeToScrobbleChanged() {
String? lastScrobbled;
- return audioPlayer.positionStream.listen((position) {
+ return audioPlayer.positionStream.listen((position) async {
try {
final uid = audioPlayerState.activeTrack is LocalTrack
? (audioPlayerState.activeTrack as LocalTrack).path
@@ -93,8 +97,23 @@ class AudioPlayerStreamListeners {
}
scrobbler.scrobble(audioPlayerState.activeTrack!);
- history.addTrack(audioPlayerState.activeTrack!);
lastScrobbled = uid;
+
+ /// The [Track] from Playlist.getTracks doesn't contain artist images
+ /// so we need to fetch them from the API
+ final activeTrack =
+ Track.fromJson(audioPlayerState.activeTrack!.toJson());
+ if (audioPlayerState.activeTrack!.artists
+ ?.any((a) => a.images == null) ??
+ false) {
+ activeTrack.artists =
+ await ref.read(spotifyProvider).api.artists.list([
+ for (final artist in audioPlayerState.activeTrack!.artists!)
+ artist.id!,
+ ]).then((value) => value.toList());
+ }
+
+ await history.addTrack(activeTrack);
} catch (e, stack) {
AppLogger.reportError(e, stack);
}
diff --git a/lib/provider/authentication/authentication.dart b/lib/provider/authentication/authentication.dart
index 583955b0..497ccf79 100644
--- a/lib/provider/authentication/authentication.dart
+++ b/lib/provider/authentication/authentication.dart
@@ -61,7 +61,7 @@ class AuthenticationNotifier extends AsyncNotifier {
Timer? refreshTimer;
- ref.listenSelf((prevData, newData) async {
+ listenSelf((prevData, newData) async {
if (newData.asData?.value == null) return;
if (newData.asData!.value!.isExpired) {
diff --git a/lib/provider/connect/connect.dart b/lib/provider/connect/connect.dart
index 000a28af..93d2fb88 100644
--- a/lib/provider/connect/connect.dart
+++ b/lib/provider/connect/connect.dart
@@ -1,6 +1,10 @@
import 'dart:convert';
import 'package:media_kit/media_kit.dart' hide Track;
+import 'package:shadcn_flutter/shadcn_flutter.dart';
+import 'package:spotube/collections/routes.dart';
+import 'package:spotube/collections/spotube_icons.dart';
+import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/audio_player/state.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/logger/logger.dart';
@@ -46,15 +50,17 @@ final volumeProvider = StateProvider(
(ref) => 1.0,
);
-class ConnectNotifier extends AsyncNotifier {
+typedef ConnectState = ({WebSocketChannel channel, Stream stream});
+
+class ConnectNotifier extends AsyncNotifier {
@override
build() async {
try {
- final connectClients = ref.watch(connectClientsProvider);
+ final connectClients = await ref.watch(connectClientsProvider.future);
- if (connectClients.asData?.value.resolvedService == null) return null;
+ if (connectClients.resolvedService == null) return null;
- final service = connectClients.asData!.value.resolvedService!;
+ final service = connectClients.resolvedService!;
AppLogger.log.t(
'♾️ Connecting to ${service.name}: ws://${service.host}:${service.port}/ws',
@@ -70,7 +76,9 @@ class ConnectNotifier extends AsyncNotifier {
'✅ Connected to ${service.name}: ws://${service.host}:${service.port}/ws',
);
- final subscription = channel.stream.listen(
+ final stream = channel.stream.asBroadcastStream();
+
+ final subscription = stream.listen(
(message) {
final event =
WebSocketEvent.fromJson(jsonDecode(message), (data) => data);
@@ -102,6 +110,38 @@ class ConnectNotifier extends AsyncNotifier {
event.onVolume((event) {
ref.read(volumeProvider.notifier).state = event.data;
});
+
+ event.onError((event) {
+ if (event.data == "Connection denied") {
+ ref.read(connectClientsProvider.notifier).clearResolvedService();
+
+ if (rootNavigatorKey.currentContext?.mounted == true) {
+ final theme = Theme.of(rootNavigatorKey.currentContext!);
+
+ showToast(
+ context: rootNavigatorKey.currentContext!,
+ location: ToastLocation.topRight,
+ dismissible: true,
+ builder: (context, overlay) {
+ return SurfaceCard(
+ fillColor: theme.colorScheme.destructive,
+ filled: true,
+ child: Basic(
+ leading: const Icon(SpotubeIcons.error),
+ title: Text(
+ context.l10n.connection_request_denied,
+ style: theme.typography.normal.copyWith(
+ color: theme.colorScheme.destructiveForeground,
+ ),
+ ),
+ leadingAlignment: Alignment.center,
+ ),
+ );
+ },
+ );
+ }
+ }
+ });
},
onError: (error) {
AppLogger.reportError(error, StackTrace.current);
@@ -113,7 +153,7 @@ class ConnectNotifier extends AsyncNotifier {
channel.sink.close(status.goingAway);
});
- return channel;
+ return (channel: channel, stream: stream);
} catch (e, stack) {
AppLogger.reportError(e, stack);
rethrow;
@@ -122,7 +162,7 @@ class ConnectNotifier extends AsyncNotifier {
Future emit(Object message) async {
if (state.value == null) return;
- state.value?.sink.add(
+ state.value?.channel.sink.add(
message is String ? message : (message as dynamic).toJson(),
);
}
@@ -184,7 +224,6 @@ class ConnectNotifier extends AsyncNotifier {
}
}
-final connectProvider =
- AsyncNotifierProvider(
+final connectProvider = AsyncNotifierProvider(
() => ConnectNotifier(),
);
diff --git a/lib/provider/download_manager_provider.dart b/lib/provider/download_manager_provider.dart
index 5e9eda20..1b588399 100644
--- a/lib/provider/download_manager_provider.dart
+++ b/lib/provider/download_manager_provider.dart
@@ -46,7 +46,9 @@ class DownloadManagerProvider extends ChangeNotifier {
//? WebA audiotagging is not supported yet
//? Although in future by converting weba to opus & then tagging it
//? is possible using vorbis comments
- downloadCodec == SourceCodecs.weba) return;
+ downloadCodec == SourceCodecs.weba) {
+ return;
+ }
final file = File(request.path);
diff --git a/lib/provider/history/history.dart b/lib/provider/history/history.dart
index 0c20a9e5..25b722ff 100644
--- a/lib/provider/history/history.dart
+++ b/lib/provider/history/history.dart
@@ -39,6 +39,11 @@ class PlaybackHistoryActions {
}
Future addTracks(List tracks) async {
+ assert(
+ tracks.every((t) => t.artists?.every((a) => a.images != null) ?? false),
+ 'Track artists must have images',
+ );
+
await _batchInsertHistoryEntries([
for (final track in tracks)
HistoryTableCompanion.insert(
@@ -50,6 +55,11 @@ class PlaybackHistoryActions {
}
Future addTrack(Track track) async {
+ assert(
+ track.artists?.every((a) => a.images != null) ?? false,
+ 'Track artists must have images',
+ );
+
await _db.into(_db.historyTable).insert(
HistoryTableCompanion.insert(
type: HistoryEntryType.track,
diff --git a/lib/provider/history/top/tracks.dart b/lib/provider/history/top/tracks.dart
index b737d148..3c057e56 100644
--- a/lib/provider/history/top/tracks.dart
+++ b/lib/provider/history/top/tracks.dart
@@ -28,7 +28,15 @@ class HistoryTopTracksState extends PaginatedState {
return groupBy(artists, (artist) => artist.id!)
.entries
.map((entry) {
- return (count: entry.value.length, artist: entry.value.first);
+ return (
+ count: entry.value.length,
+
+ /// Previously, due to a bug, artist images were not being saved.
+ /// Now it's fixed, but we need to handle the case where images are null.
+ /// So we take the first artist with images if available, otherwise the first one.
+ artist: entry.value.firstWhereOrNull((a) => a.images != null) ??
+ entry.value.first,
+ );
})
.sorted((a, b) => b.count.compareTo(a.count))
.toList();
@@ -85,11 +93,58 @@ class HistoryTopTracksNotifier extends FamilyPaginatedAsyncNotifier<
);
}
+ Future fixImageNotLoadingForArtistIssue(
+ List entries,
+ ) async {
+ final nonImageArtistTracks =
+ entries.where((e) => e.track!.artists!.any((a) => a.images == null));
+
+ if (nonImageArtistTracks.isEmpty) return;
+
+ final artistIds = nonImageArtistTracks
+ .map((e) => e.track!.artists!.map((a) => a.id!))
+ .expand((e) => e)
+ .toSet()
+ .toList();
+
+ if (artistIds.isEmpty) return;
+
+ final artists = await ref.read(spotifyProvider).api.artists.list(artistIds);
+
+ final imagedArtistTracks = nonImageArtistTracks.map((e) {
+ final track = e.track!;
+ final includedArtists = track.artists!
+ .map((a) => artists.firstWhereOrNull((artist) => artist.id == a.id))
+ .nonNulls
+ .toList();
+
+ track.artists = includedArtists;
+
+ return e.copyWith(data: track.toJson());
+ });
+
+ assert(
+ imagedArtistTracks
+ .every((e) => e.track!.artists!.every((a) => a.images != null)),
+ 'Tracks artists should have images',
+ );
+
+ final database = ref.read(databaseProvider);
+ await database.batch((batch) {
+ batch.insertAllOnConflictUpdate(
+ database.historyTable,
+ imagedArtistTracks,
+ );
+ });
+ }
+
@override
fetch(arg, offset, limit) async {
final tracksQuery = createTracksQuery()..limit(limit, offset: offset);
- final items = getTracksWithCount(await tracksQuery.get());
+ final entries = await tracksQuery.get();
+
+ final items = getTracksWithCount(entries);
return (
items: items,
@@ -123,13 +178,26 @@ class HistoryTopTracksNotifier extends FamilyPaginatedAsyncNotifier<
}
List getTracksWithCount(List