mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
commit
723b6b1f38
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"flutterSdkVersion": "3.29.0"
|
"flutterSdkVersion": "3.29.2"
|
||||||
}
|
}
|
2
.fvmrc
2
.fvmrc
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"flutter": "3.29.0",
|
"flutter": "3.29.2",
|
||||||
"flavors": {}
|
"flavors": {}
|
||||||
}
|
}
|
2
.github/workflows/pr-lint.yml
vendored
2
.github/workflows/pr-lint.yml
vendored
@ -4,7 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FLUTTER_VERSION: 3.29.0
|
FLUTTER_VERSION: 3.29.2
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
2
.github/workflows/spotube-release-binary.yml
vendored
2
.github/workflows/spotube-release-binary.yml
vendored
@ -20,7 +20,7 @@ on:
|
|||||||
description: Dry run without uploading to release
|
description: Dry run without uploading to release
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FLUTTER_VERSION: 3.29.0
|
FLUTTER_VERSION: 3.29.2
|
||||||
FLUTTER_CHANNEL: master
|
FLUTTER_CHANNEL: master
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -28,5 +28,5 @@
|
|||||||
"README.md": "LICENSE,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md,CONTRIBUTION.md,CHANGELOG.md,PRIVACY_POLICY.md",
|
"README.md": "LICENSE,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md,CONTRIBUTION.md,CHANGELOG.md,PRIVACY_POLICY.md",
|
||||||
"*.dart": "${capture}.g.dart,${capture}.freezed.dart"
|
"*.dart": "${capture}.g.dart,${capture}.freezed.dart"
|
||||||
},
|
},
|
||||||
"dart.flutterSdkPath": ".fvm/versions/3.29.0"
|
"dart.flutterSdkPath": ".fvm/versions/3.29.2"
|
||||||
}
|
}
|
19
CHANGELOG.md
19
CHANGELOG.md
@ -2,6 +2,25 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
## [4.0.1](https://github.com/krtirtho/spotube/compare/v4.0.0...v4.0.1) (2025-03-15)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **android**: navigation overlaying in app navigation
|
||||||
|
- add to playlist not working in smaller screen devices
|
||||||
|
- language picker search broken
|
||||||
|
- **generate_playlist**: create playlist not adding tracks nor navigating to playlist page
|
||||||
|
- **desktop**: double titlebar in local library folders and massive space in overlay player
|
||||||
|
- lastfm form broken in other locales #2447
|
||||||
|
- spotify login broken due to new totp requirement #2494
|
||||||
|
- spotify authentication 429 errors
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- **local_library**: add support for x-flac, opus and x-wav
|
||||||
|
- **translation**: add tagalog language support #2504
|
||||||
|
- **translation**: add tamil translation for spotube #2501
|
||||||
|
|
||||||
## [4.0.0](https://github.com/krtirtho/spotube/compare/v3.9.0...v4.0.0) (2025-03-07)
|
## [4.0.0](https://github.com/krtirtho/spotube/compare/v3.9.0...v4.0.0) (2025-03-07)
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
@ -325,8 +325,9 @@ If you are concerned, you can [read the reason of choosing this license](https:/
|
|||||||
1. [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) - A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key.
|
1. [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) - A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key.
|
||||||
1. [http_parser](https://pub.dev/packages/http_parser) - A platform-independent package for parsing and serializing HTTP formats.
|
1. [http_parser](https://pub.dev/packages/http_parser) - A platform-independent package for parsing and serializing HTTP formats.
|
||||||
1. [collection](https://pub.dev/packages/collection) - Collections and utilities functions and classes related to collections.
|
1. [collection](https://pub.dev/packages/collection) - Collections and utilities functions and classes related to collections.
|
||||||
|
1. [otp_util](https://github.com/dushiling) - otp_util is a dart package to generate and verify one-time passwords,it It provides two methods TOPT and HOTP.They are Time-based OTPs and Counter-based OTPs.
|
||||||
|
1. [dio_http2_adapter](https://github.com/cfug/dio) - An adapter that combines HTTP/2 and dio. Supports reusing connections, header compression, etc.
|
||||||
1. [build_runner](https://pub.dev/packages/build_runner) - A build system for Dart code generation and modular compilation.
|
1. [build_runner](https://pub.dev/packages/build_runner) - A build system for Dart code generation and modular compilation.
|
||||||
1. [crypto](https://pub.dev/packages/crypto) - Implementations of SHA, MD5, and HMAC cryptographic functions.
|
|
||||||
1. [envied_generator](https://github.com/petercinibulk/envied) - Generator for the Envied package. See https://pub.dev/packages/envied.
|
1. [envied_generator](https://github.com/petercinibulk/envied) - Generator for the Envied package. See https://pub.dev/packages/envied.
|
||||||
1. [flutter_gen_runner](https://github.com/FlutterGen/flutter_gen) - The Flutter code generator for your assets, fonts, colors, … — Get rid of all String-based APIs.
|
1. [flutter_gen_runner](https://github.com/FlutterGen/flutter_gen) - The Flutter code generator for your assets, fonts, colors, … — Get rid of all String-based APIs.
|
||||||
1. [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) - A package which simplifies the task of updating your Flutter app's launcher icon.
|
1. [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) - A package which simplifies the task of updating your Flutter app's launcher icon.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
arb-dir: lib/l10n
|
arb-dir: lib/l10n
|
||||||
template-arb-file: app_en.arb
|
template-arb-file: app_en.arb
|
||||||
output-localization-file: app_localizations.dart
|
output-dir: lib/l10n/generated
|
||||||
untranslated-messages-file: untranslated_messages.json
|
untranslated-messages-file: untranslated_messages.json
|
||||||
|
synthetic-package: false
|
||||||
|
@ -13,12 +13,6 @@ class FontFamily {
|
|||||||
/// Font family: BootstrapIcons
|
/// Font family: BootstrapIcons
|
||||||
static const String bootstrapIcons = 'BootstrapIcons';
|
static const String bootstrapIcons = 'BootstrapIcons';
|
||||||
|
|
||||||
/// Font family: GeistMono
|
|
||||||
static const String geistMono = 'GeistMono';
|
|
||||||
|
|
||||||
/// Font family: GeistSans
|
|
||||||
static const String geistSans = 'GeistSans';
|
|
||||||
|
|
||||||
/// Font family: RadixIcons
|
/// Font family: RadixIcons
|
||||||
static const String radixIcons = 'RadixIcons';
|
static const String radixIcons = 'RadixIcons';
|
||||||
}
|
}
|
||||||
|
@ -625,10 +625,10 @@ abstract class LanguageLocals {
|
|||||||
// name: "Swedish",
|
// name: "Swedish",
|
||||||
// nativeName: "svenska",
|
// nativeName: "svenska",
|
||||||
// ),
|
// ),
|
||||||
// "ta": const ISOLanguageName(
|
"ta": const ISOLanguageName(
|
||||||
// name: "Tamil",
|
name: "Tamil",
|
||||||
// nativeName: "தமிழ்",
|
nativeName: "தமிழ்",
|
||||||
// ),
|
),
|
||||||
// "te": const ISOLanguageName(
|
// "te": const ISOLanguageName(
|
||||||
// name: "Telugu",
|
// name: "Telugu",
|
||||||
// nativeName: "తెలుగు",
|
// nativeName: "తెలుగు",
|
||||||
@ -653,10 +653,10 @@ abstract class LanguageLocals {
|
|||||||
// name: "Turkmen",
|
// name: "Turkmen",
|
||||||
// nativeName: "Türkmen, Түркмен",
|
// nativeName: "Türkmen, Түркмен",
|
||||||
// ),
|
// ),
|
||||||
// "tl": const ISOLanguageName(
|
"tl": const ISOLanguageName(
|
||||||
// name: "Tagalog",
|
name: "Tagalog",
|
||||||
// nativeName: "Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔",
|
nativeName: "Wikang Tagalog",
|
||||||
// ),
|
),
|
||||||
// "tn": const ISOLanguageName(
|
// "tn": const ISOLanguageName(
|
||||||
// name: "Tswana",
|
// name: "Tswana",
|
||||||
// nativeName: "Setswana",
|
// nativeName: "Setswana",
|
||||||
|
@ -75,17 +75,17 @@ class AppRouter extends RootStackRouter {
|
|||||||
path: "local",
|
path: "local",
|
||||||
page: UserLocalLibraryRoute.page,
|
page: UserLocalLibraryRoute.page,
|
||||||
),
|
),
|
||||||
AutoRoute(
|
|
||||||
path: "local/folder",
|
|
||||||
page: LocalLibraryRoute.page,
|
|
||||||
// parentNavigatorKey: shellRouteNavigatorKey,
|
|
||||||
),
|
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
path: "downloads",
|
path: "downloads",
|
||||||
page: UserDownloadsRoute.page,
|
page: UserDownloadsRoute.page,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
AutoRoute(
|
||||||
|
path: "local/folder",
|
||||||
|
page: LocalLibraryRoute.page,
|
||||||
|
// parentNavigatorKey: shellRouteNavigatorKey,
|
||||||
|
),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
path: "library/generate",
|
path: "library/generate",
|
||||||
page: PlaylistGeneratorRoute.page,
|
page: PlaylistGeneratorRoute.page,
|
||||||
|
@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:spotube/collections/routes.gr.dart';
|
import 'package:spotube/collections/routes.gr.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:spotube/l10n/l10n.dart';
|
||||||
|
|
||||||
class SideBarTiles {
|
class SideBarTiles {
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
|
@ -28,7 +28,7 @@ class AdaptiveMenuButton<T> extends MenuButton {
|
|||||||
/// or equal to 640px
|
/// or equal to 640px
|
||||||
/// In smaller screen, a [IconButton] with a [showModalBottomSheet] is shown
|
/// In smaller screen, a [IconButton] with a [showModalBottomSheet] is shown
|
||||||
class AdaptivePopSheetList<T> extends StatelessWidget {
|
class AdaptivePopSheetList<T> extends StatelessWidget {
|
||||||
final List<AdaptiveMenuButton<T>> children;
|
final List<AdaptiveMenuButton<T>> Function(BuildContext context) items;
|
||||||
final Widget? icon;
|
final Widget? icon;
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
final bool useRootNavigator;
|
final bool useRootNavigator;
|
||||||
@ -43,7 +43,7 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
|||||||
|
|
||||||
const AdaptivePopSheetList({
|
const AdaptivePopSheetList({
|
||||||
super.key,
|
super.key,
|
||||||
required this.children,
|
required this.items,
|
||||||
this.icon,
|
this.icon,
|
||||||
this.child,
|
this.child,
|
||||||
this.useRootNavigator = true,
|
this.useRootNavigator = true,
|
||||||
@ -59,27 +59,28 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
|||||||
|
|
||||||
Future<void> showDropdownMenu(BuildContext context, Offset position) async {
|
Future<void> showDropdownMenu(BuildContext context, Offset position) async {
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
final childrenModified = children.map((s) {
|
List<MenuButton> childrenModified(BuildContext context) =>
|
||||||
if (s.onPressed == null) {
|
items(context).map((s) {
|
||||||
return MenuButton(
|
if (s.onPressed == null) {
|
||||||
key: s.key,
|
return MenuButton(
|
||||||
autoClose: s.autoClose,
|
key: s.key,
|
||||||
enabled: s.enabled,
|
autoClose: s.autoClose,
|
||||||
leading: s.leading,
|
enabled: s.enabled,
|
||||||
focusNode: s.focusNode,
|
leading: s.leading,
|
||||||
onPressed: (context) {
|
focusNode: s.focusNode,
|
||||||
if (s.value != null) {
|
onPressed: (context) {
|
||||||
onSelected?.call(s.value as T);
|
if (s.value != null) {
|
||||||
}
|
onSelected?.call(s.value as T);
|
||||||
},
|
}
|
||||||
popoverController: s.popoverController,
|
},
|
||||||
subMenu: s.subMenu,
|
popoverController: s.popoverController,
|
||||||
trailing: s.trailing,
|
subMenu: s.subMenu,
|
||||||
child: s.child,
|
trailing: s.trailing,
|
||||||
);
|
child: s.child,
|
||||||
}
|
);
|
||||||
return s;
|
}
|
||||||
}).toList();
|
return s;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
if (mediaQuery.mdAndUp) {
|
if (mediaQuery.mdAndUp) {
|
||||||
await showDropdown<T?>(
|
await showDropdown<T?>(
|
||||||
@ -92,7 +93,7 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
|||||||
position: position,
|
position: position,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return DropdownMenu(
|
return DropdownMenu(
|
||||||
children: childrenModified,
|
children: childrenModified(context),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).future;
|
).future;
|
||||||
@ -109,11 +110,12 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
backgroundColor: context.theme.colorScheme.card,
|
backgroundColor: context.theme.colorScheme.card,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
|
final children = childrenModified(context);
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: childrenModified.length,
|
itemCount: children.length,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final data = childrenModified[index];
|
final data = children[index];
|
||||||
|
|
||||||
return Button(
|
return Button(
|
||||||
enabled: data.enabled,
|
enabled: data.enabled,
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
|
|
||||||
class AnimateGradient extends HookWidget {
|
|
||||||
const AnimateGradient({
|
|
||||||
super.key,
|
|
||||||
required this.primaryColors,
|
|
||||||
required this.secondaryColors,
|
|
||||||
this.child,
|
|
||||||
this.primaryBegin,
|
|
||||||
this.primaryEnd,
|
|
||||||
this.secondaryBegin,
|
|
||||||
this.secondaryEnd,
|
|
||||||
AnimationController? controller,
|
|
||||||
this.duration = const Duration(seconds: 4),
|
|
||||||
this.animateAlignments = true,
|
|
||||||
this.reverse = true,
|
|
||||||
}) : assert(primaryColors.length >= 2),
|
|
||||||
assert(primaryColors.length == secondaryColors.length),
|
|
||||||
_controller = controller;
|
|
||||||
|
|
||||||
/// [controller]: pass this to have a fine control over the [Animation]
|
|
||||||
final AnimationController? _controller;
|
|
||||||
|
|
||||||
/// [duration]: Time to switch between [Gradient].
|
|
||||||
/// By default its value is [Duration(seconds:4)]
|
|
||||||
final Duration duration;
|
|
||||||
|
|
||||||
/// [primaryColors]: These will be the starting colors of the [Animation].
|
|
||||||
final List<Color> primaryColors;
|
|
||||||
|
|
||||||
/// [secondaryColors]: These Colors are those in which the [primaryColors] will transition into.
|
|
||||||
final List<Color> secondaryColors;
|
|
||||||
|
|
||||||
/// [primaryBegin]: This is begin [Alignment] for [primaryColors].
|
|
||||||
/// By default its value is [Alignment.topLeft]
|
|
||||||
final Alignment? primaryBegin;
|
|
||||||
|
|
||||||
/// [primaryBegin]: This is end [Alignment] for [primaryColors].
|
|
||||||
/// By default its value is [Alignment.topRight]
|
|
||||||
final Alignment? primaryEnd;
|
|
||||||
|
|
||||||
/// [secondaryBegin]: This is begin [Alignment] for [secondaryColors].
|
|
||||||
/// By default its value is [Alignment.bottomLeft]
|
|
||||||
final Alignment? secondaryBegin;
|
|
||||||
|
|
||||||
/// [secondaryEnd]: This is end [Alignment] for [secondaryColors].
|
|
||||||
/// By default its value is [Alignment.bottomRight]
|
|
||||||
final Alignment? secondaryEnd;
|
|
||||||
|
|
||||||
/// [animateAlignments]: set to false if you don't want to animate the alignments.
|
|
||||||
/// This can provide you way cooler animations
|
|
||||||
final bool animateAlignments;
|
|
||||||
|
|
||||||
/// [reverse]: set it to false if you don't want to reverse the animation.
|
|
||||||
/// using that it will go into one direction only
|
|
||||||
final bool reverse;
|
|
||||||
|
|
||||||
final Widget? child;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// ignore: no_leading_underscores_for_local_identifiers
|
|
||||||
final __controller = useAnimationController(
|
|
||||||
duration: duration,
|
|
||||||
)..repeat(reverse: reverse);
|
|
||||||
|
|
||||||
final controller = _controller ?? __controller;
|
|
||||||
|
|
||||||
final animation = useMemoized(
|
|
||||||
() => CurvedAnimation(
|
|
||||||
parent: controller,
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
),
|
|
||||||
[controller]);
|
|
||||||
|
|
||||||
final colorTween = useMemoized(
|
|
||||||
() => primaryColors.map((color) {
|
|
||||||
return ColorTween(
|
|
||||||
begin: color,
|
|
||||||
end: color,
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
[primaryColors]);
|
|
||||||
final colors = useMemoized(
|
|
||||||
() => colorTween.map((color) {
|
|
||||||
return color.evaluate(animation)!;
|
|
||||||
}).toList(),
|
|
||||||
[colorTween, animation]);
|
|
||||||
|
|
||||||
final begin = useMemoized(
|
|
||||||
() => AlignmentTween(
|
|
||||||
begin: primaryBegin ?? Alignment.topLeft,
|
|
||||||
end: primaryEnd ?? Alignment.topRight,
|
|
||||||
),
|
|
||||||
[primaryBegin, primaryEnd]);
|
|
||||||
|
|
||||||
final end = useMemoized(
|
|
||||||
() => AlignmentTween(
|
|
||||||
begin: secondaryBegin ?? Alignment.bottomLeft,
|
|
||||||
end: secondaryEnd ?? Alignment.bottomRight,
|
|
||||||
),
|
|
||||||
[secondaryBegin, secondaryEnd]);
|
|
||||||
|
|
||||||
return AnimatedBuilder(
|
|
||||||
animation: animation,
|
|
||||||
child: useMemoized(() => child, [child]),
|
|
||||||
builder: (BuildContext context, Widget? child) {
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: animateAlignments
|
|
||||||
? begin.evaluate(animation)
|
|
||||||
: (primaryBegin as Alignment),
|
|
||||||
end: animateAlignments
|
|
||||||
? end.evaluate(animation)
|
|
||||||
: primaryEnd as Alignment,
|
|
||||||
colors: colors,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
|
||||||
|
|
||||||
class SpotubePage<T> extends MaterialPage<T> {
|
|
||||||
const SpotubePage({required super.child});
|
|
||||||
}
|
|
||||||
|
|
||||||
// class SpotubeSlidePage extends CustomTransitionPage {
|
|
||||||
// SpotubeSlidePage({
|
|
||||||
// required super.child,
|
|
||||||
// super.key,
|
|
||||||
// }) : super(
|
|
||||||
// reverseTransitionDuration: const Duration(milliseconds: 150),
|
|
||||||
// transitionDuration: const Duration(milliseconds: 150),
|
|
||||||
// transitionsBuilder: (context, animation, secondaryAnimation, child) {
|
|
||||||
// return SlideTransition(
|
|
||||||
// position: Tween<Offset>(
|
|
||||||
// begin: const Offset(1, 0),
|
|
||||||
// end: Offset.zero,
|
|
||||||
// ).animate(animation),
|
|
||||||
// child: child,
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// }
|
|
@ -166,7 +166,7 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
icon: const Icon(SpotubeIcons.moreVertical),
|
icon: const Icon(SpotubeIcons.moreVertical),
|
||||||
variance: ButtonVariance.outline,
|
variance: ButtonVariance.outline,
|
||||||
children: [
|
items: (context) => [
|
||||||
AdaptiveMenuButton(
|
AdaptiveMenuButton(
|
||||||
value: "download",
|
value: "download",
|
||||||
leading: const Icon(SpotubeIcons.download),
|
leading: const Icon(SpotubeIcons.download),
|
||||||
|
@ -23,7 +23,7 @@ class SortTracksDropdown extends StatelessWidget {
|
|||||||
onSelected: onChanged,
|
onSelected: onChanged,
|
||||||
tooltip: context.l10n.sort_tracks,
|
tooltip: context.l10n.sort_tracks,
|
||||||
icon: const Icon(SpotubeIcons.sort),
|
icon: const Icon(SpotubeIcons.sort),
|
||||||
children: [
|
items: (context) => [
|
||||||
AdaptiveMenuButton(
|
AdaptiveMenuButton(
|
||||||
value: SortBy.none,
|
value: SortBy.none,
|
||||||
enabled: value != SortBy.none,
|
enabled: value != SortBy.none,
|
||||||
|
@ -90,11 +90,25 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
Track track,
|
Track track,
|
||||||
) {
|
) {
|
||||||
showDialog(
|
/// showDialog doesn't work for some reason. So we have to
|
||||||
context: context,
|
/// manually push a Dialog Route in the Navigator to get it working
|
||||||
builder: (context) => PlaylistAddTrackDialog(
|
Navigator.push(
|
||||||
tracks: [track],
|
context,
|
||||||
openFromPlaylist: playlistId,
|
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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -352,7 +366,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
children: [
|
items: (context) => [
|
||||||
if (isLocalTrack)
|
if (isLocalTrack)
|
||||||
AdaptiveMenuButton(
|
AdaptiveMenuButton(
|
||||||
value: TrackOptionValue.delete,
|
value: TrackOptionValue.delete,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:spotube/l10n/l10n.dart';
|
||||||
|
|
||||||
extension AppLocale on BuildContext {
|
extension AppLocale on BuildContext {
|
||||||
AppLocalizations get l10n => AppLocalizations.of(this)!;
|
AppLocalizations get l10n => AppLocalizations.of(this)!;
|
||||||
|
428
lib/l10n/app_ta.arb
Normal file
428
lib/l10n/app_ta.arb
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
{
|
||||||
|
"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 ஐச் சேர்க்கவும்"
|
||||||
|
}
|
428
lib/l10n/app_tl.arb
Normal file
428
lib/l10n/app_tl.arb
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
2766
lib/l10n/generated/app_localizations.dart
Normal file
2766
lib/l10n/generated/app_localizations.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ar.dart
Normal file
1374
lib/l10n/generated/app_localizations_ar.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_bn.dart
Normal file
1374
lib/l10n/generated/app_localizations_bn.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ca.dart
Normal file
1374
lib/l10n/generated/app_localizations_ca.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_cs.dart
Normal file
1374
lib/l10n/generated/app_localizations_cs.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_de.dart
Normal file
1374
lib/l10n/generated/app_localizations_de.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_en.dart
Normal file
1374
lib/l10n/generated/app_localizations_en.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_es.dart
Normal file
1374
lib/l10n/generated/app_localizations_es.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_eu.dart
Normal file
1374
lib/l10n/generated/app_localizations_eu.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_fa.dart
Normal file
1374
lib/l10n/generated/app_localizations_fa.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_fi.dart
Normal file
1374
lib/l10n/generated/app_localizations_fi.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_fr.dart
Normal file
1374
lib/l10n/generated/app_localizations_fr.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_hi.dart
Normal file
1374
lib/l10n/generated/app_localizations_hi.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_id.dart
Normal file
1374
lib/l10n/generated/app_localizations_id.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_it.dart
Normal file
1374
lib/l10n/generated/app_localizations_it.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ja.dart
Normal file
1374
lib/l10n/generated/app_localizations_ja.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ka.dart
Normal file
1374
lib/l10n/generated/app_localizations_ka.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ko.dart
Normal file
1374
lib/l10n/generated/app_localizations_ko.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ne.dart
Normal file
1374
lib/l10n/generated/app_localizations_ne.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_nl.dart
Normal file
1374
lib/l10n/generated/app_localizations_nl.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_pl.dart
Normal file
1374
lib/l10n/generated/app_localizations_pl.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_pt.dart
Normal file
1374
lib/l10n/generated/app_localizations_pt.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ru.dart
Normal file
1374
lib/l10n/generated/app_localizations_ru.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_ta.dart
Normal file
1374
lib/l10n/generated/app_localizations_ta.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_th.dart
Normal file
1374
lib/l10n/generated/app_localizations_th.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_tl.dart
Normal file
1374
lib/l10n/generated/app_localizations_tl.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_tr.dart
Normal file
1374
lib/l10n/generated/app_localizations_tr.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_uk.dart
Normal file
1374
lib/l10n/generated/app_localizations_uk.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_vi.dart
Normal file
1374
lib/l10n/generated/app_localizations_vi.dart
Normal file
File diff suppressed because it is too large
Load Diff
1374
lib/l10n/generated/app_localizations_zh.dart
Normal file
1374
lib/l10n/generated/app_localizations_zh.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -12,11 +12,13 @@
|
|||||||
/// doannc2212@github => Vietnamese
|
/// doannc2212@github => Vietnamese
|
||||||
/// sappho192@github => Korean
|
/// sappho192@github => Korean
|
||||||
/// watchakorn-18k@github => Thai
|
/// watchakorn-18k@github => Thai
|
||||||
|
/// llama3, vishnumur777@github => Tamil
|
||||||
/// Microsoft Copilot, Tutislav@github => Czech
|
/// Microsoft Copilot, Tutislav@github => Czech
|
||||||
|
|
||||||
library l10n;
|
library l10n;
|
||||||
|
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
|
export 'package:spotube/l10n/generated/app_localizations.dart';
|
||||||
|
|
||||||
class L10n {
|
class L10n {
|
||||||
static final all = [
|
static final all = [
|
||||||
@ -41,8 +43,10 @@ class L10n {
|
|||||||
const Locale('pl', 'PL'),
|
const Locale('pl', 'PL'),
|
||||||
const Locale('pt', 'PT'),
|
const Locale('pt', 'PT'),
|
||||||
const Locale('ru', 'RU'),
|
const Locale('ru', 'RU'),
|
||||||
|
const Locale('tl', 'PH'),
|
||||||
const Locale('uk', 'UA'),
|
const Locale('uk', 'UA'),
|
||||||
const Locale('th', 'TH'),
|
const Locale('th', 'TH'),
|
||||||
|
const Locale('ta', 'IN'),
|
||||||
const Locale('tr', 'TR'),
|
const Locale('tr', 'TR'),
|
||||||
const Locale('zh', 'CN'),
|
const Locale('zh', 'CN'),
|
||||||
const Locale('vi', 'VN'),
|
const Locale('vi', 'VN'),
|
||||||
|
@ -44,7 +44,6 @@ import 'package:spotube/services/logger/logger.dart';
|
|||||||
import 'package:spotube/services/wm_tools/wm_tools.dart';
|
import 'package:spotube/services/wm_tools/wm_tools.dart';
|
||||||
import 'package:spotube/utils/migrations/sandbox.dart';
|
import 'package:spotube/utils/migrations/sandbox.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
||||||
import 'package:timezone/data/latest.dart' as tz;
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
|
@ -27,6 +27,7 @@ import 'package:spotube/provider/audio_player/audio_player.dart';
|
|||||||
import 'package:spotube/provider/server/active_sourced_track.dart';
|
import 'package:spotube/provider/server/active_sourced_track.dart';
|
||||||
import 'package:spotube/provider/volume_provider.dart';
|
import 'package:spotube/provider/volume_provider.dart';
|
||||||
import 'package:spotube/services/sourced_track/sources/youtube.dart';
|
import 'package:spotube/services/sourced_track/sources/youtube.dart';
|
||||||
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
ref.watch(audioPlayerProvider.select((s) => s.activeTrack));
|
ref.watch(audioPlayerProvider.select((s) => s.activeTrack));
|
||||||
final currentTrack = sourcedCurrentTrack ?? currentActiveTrack;
|
final currentTrack = sourcedCurrentTrack ?? currentActiveTrack;
|
||||||
final isLocalTrack = currentTrack is LocalTrack;
|
final isLocalTrack = currentTrack is LocalTrack;
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.sizeOf(context);
|
||||||
|
|
||||||
final shouldHide = useState(true);
|
final shouldHide = useState(true);
|
||||||
|
|
||||||
@ -101,6 +102,9 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
headers: [
|
headers: [
|
||||||
SafeArea(
|
SafeArea(
|
||||||
|
minimum:
|
||||||
|
kIsMobile ? const EdgeInsets.only(top: 80) : EdgeInsets.zero,
|
||||||
|
bottom: false,
|
||||||
child: TitleBar(
|
child: TitleBar(
|
||||||
surfaceOpacity: 0,
|
surfaceOpacity: 0,
|
||||||
surfaceBlur: 0,
|
surfaceBlur: 0,
|
||||||
|
@ -191,7 +191,7 @@ class PlayerActions extends HookConsumerWidget {
|
|||||||
sleepTimerNotifier.setSleepTimer(value);
|
sleepTimerNotifier.setSleepTimer(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
children: [
|
items: (context) => [
|
||||||
for (final entry in sleepTimerEntries.entries)
|
for (final entry in sleepTimerEntries.entries)
|
||||||
AdaptiveMenuButton(
|
AdaptiveMenuButton(
|
||||||
value: entry.value,
|
value: entry.value,
|
||||||
|
@ -101,11 +101,17 @@ class PlaylistCreateDialog extends HookConsumerWidget {
|
|||||||
} else {
|
} else {
|
||||||
await playlistNotifier.create(payload, onError);
|
await playlistNotifier.create(payload, onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trackIds.isNotEmpty) {
|
||||||
|
await playlistNotifier.addTracks(trackIds, onError);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
isSubmitting.value = false;
|
isSubmitting.value = false;
|
||||||
if (context.mounted &&
|
if (context.mounted &&
|
||||||
!ref.read(playlistProvider(playlistId ?? "")).hasError) {
|
!ref.read(playlistProvider(playlistId ?? "")).hasError) {
|
||||||
context.router.maybePop();
|
context.router.maybePop<Playlist>(
|
||||||
|
await ref.read(playlistProvider(playlistId ?? "").future),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,37 +133,38 @@ class GettingStartedPageLanguageRegionSection extends HookConsumerWidget {
|
|||||||
popup: SelectPopup.builder(
|
popup: SelectPopup.builder(
|
||||||
searchPlaceholder: Text(context.l10n.search),
|
searchPlaceholder: Text(context.l10n.search),
|
||||||
builder: (context, searchQuery) {
|
builder: (context, searchQuery) {
|
||||||
final filteredLocale = searchQuery?.isNotEmpty != true
|
final hasNotQueried =
|
||||||
? L10n.all
|
searchQuery == null || searchQuery.trim().isEmpty;
|
||||||
|
final filteredLocale = hasNotQueried
|
||||||
|
? [
|
||||||
|
const Locale("system", "system"),
|
||||||
|
...L10n.all,
|
||||||
|
]
|
||||||
: L10n.all
|
: L10n.all
|
||||||
.where(
|
.where(
|
||||||
(element) =>
|
(element) => filterLocale(
|
||||||
filterLocale(element, searchQuery!),
|
element,
|
||||||
|
searchQuery.trim(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return SelectItemBuilder(
|
return SelectItemBuilder(
|
||||||
childCount: filteredLocale.length + 1,
|
childCount: filteredLocale.length,
|
||||||
builder: (context, index) {
|
builder: (context, index) {
|
||||||
if (index == 0 &&
|
final locale = filteredLocale[index];
|
||||||
searchQuery?.isNotEmpty != true) {
|
if (locale == const Locale("system", "system")) {
|
||||||
return SelectItemButton(
|
return SelectItemButton(
|
||||||
value: const Locale("system", "system"),
|
value: locale,
|
||||||
child: Text(context.l10n.system_default),
|
child: Text(context.l10n.system_default),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final indexThen = searchQuery?.isNotEmpty != true
|
|
||||||
? index
|
|
||||||
: index - 1;
|
|
||||||
|
|
||||||
final locale = filteredLocale[indexThen];
|
|
||||||
return SelectItemButton(
|
return SelectItemButton(
|
||||||
value: locale,
|
value: locale,
|
||||||
child: Text(
|
child: Text(
|
||||||
LanguageLocals.getDisplayLanguage(
|
LanguageLocals.getDisplayLanguage(
|
||||||
locale.languageCode)
|
locale.languageCode,
|
||||||
.toString(),
|
).toString(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -96,7 +96,9 @@ class LastFMLoginPage extends HookConsumerWidget {
|
|||||||
FormField(
|
FormField(
|
||||||
label: Text(context.l10n.username),
|
label: Text(context.l10n.username),
|
||||||
key: usernameKey,
|
key: usernameKey,
|
||||||
validator: const NotEmptyValidator(),
|
validator: const NotEmptyValidator(
|
||||||
|
message: "Username is required",
|
||||||
|
),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
autofillHints: const [
|
autofillHints: const [
|
||||||
AutofillHints.username,
|
AutofillHints.username,
|
||||||
@ -107,7 +109,9 @@ class LastFMLoginPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
FormField(
|
FormField(
|
||||||
key: passwordKey,
|
key: passwordKey,
|
||||||
validator: const NotEmptyValidator(),
|
validator: const NotEmptyValidator(
|
||||||
|
message: "Password is required",
|
||||||
|
),
|
||||||
label: Text(context.l10n.password),
|
label: Text(context.l10n.password),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
autofillHints: const [
|
autofillHints: const [
|
||||||
|
@ -81,6 +81,7 @@ class LyricsPage extends HookConsumerWidget {
|
|||||||
title: tabbar,
|
title: tabbar,
|
||||||
height: 58 * context.theme.scaling,
|
height: 58 * context.theme.scaling,
|
||||||
surfaceBlur: 0,
|
surfaceBlur: 0,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
)
|
)
|
||||||
: tabbar
|
: tabbar
|
||||||
],
|
],
|
||||||
|
@ -43,13 +43,16 @@ class RootAppPage extends HookConsumerWidget {
|
|||||||
final scaffold = MediaQuery.removeViewInsets(
|
final scaffold = MediaQuery.removeViewInsets(
|
||||||
context: context,
|
context: context,
|
||||||
removeBottom: true,
|
removeBottom: true,
|
||||||
child: const Scaffold(
|
child: const SafeArea(
|
||||||
footers: [
|
top: false,
|
||||||
BottomPlayer(),
|
child: Scaffold(
|
||||||
SpotubeNavigationBar(),
|
footers: [
|
||||||
],
|
BottomPlayer(),
|
||||||
floatingFooter: true,
|
SpotubeNavigationBar(),
|
||||||
child: Sidebar(child: AutoRouter()),
|
],
|
||||||
|
floatingFooter: true,
|
||||||
|
child: Sidebar(child: AutoRouter()),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
@ -11,6 +12,14 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/l10n/l10n.dart';
|
import 'package:spotube/l10n/l10n.dart';
|
||||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||||
|
|
||||||
|
final localWithName = L10n.all.map((e) {
|
||||||
|
final isoCodeName = LanguageLocals.getDisplayLanguage(e.languageCode);
|
||||||
|
return (
|
||||||
|
locale: e,
|
||||||
|
name: "${isoCodeName.name} (${isoCodeName.nativeName})",
|
||||||
|
);
|
||||||
|
}).sortedBy((e) => e.name);
|
||||||
|
|
||||||
class SettingsLanguageRegionSection extends HookConsumerWidget {
|
class SettingsLanguageRegionSection extends HookConsumerWidget {
|
||||||
const SettingsLanguageRegionSection({super.key});
|
const SettingsLanguageRegionSection({super.key});
|
||||||
|
|
||||||
@ -36,18 +45,8 @@ class SettingsLanguageRegionSection extends HookConsumerWidget {
|
|||||||
value: const Locale("system", "system"),
|
value: const Locale("system", "system"),
|
||||||
child: Text(context.l10n.system_default),
|
child: Text(context.l10n.system_default),
|
||||||
),
|
),
|
||||||
for (final locale in L10n.all)
|
for (final (:locale, :name) in localWithName)
|
||||||
SelectItemButton(
|
SelectItemButton(value: locale, child: Text(name)),
|
||||||
value: locale,
|
|
||||||
child: Builder(builder: (context) {
|
|
||||||
final isoCodeName = LanguageLocals.getDisplayLanguage(
|
|
||||||
locale.languageCode,
|
|
||||||
);
|
|
||||||
return Text(
|
|
||||||
"${isoCodeName.name} (${isoCodeName.nativeName})",
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
AdaptiveSelectTile<Market>(
|
AdaptiveSelectTile<Market>(
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dio/io.dart';
|
import 'package:dio_http2_adapter/dio_http2_adapter.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart'
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart'
|
||||||
hide X509Certificate;
|
hide X509Certificate;
|
||||||
@ -15,6 +16,10 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/models/database/database.dart';
|
import 'package:spotube/models/database/database.dart';
|
||||||
import 'package:spotube/provider/database/database.dart';
|
import 'package:spotube/provider/database/database.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
import 'package:otp_util/otp_util.dart';
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:otp_util/src/utils/generic_util.dart';
|
||||||
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
extension ExpirationAuthenticationTableData on AuthenticationTableData {
|
extension ExpirationAuthenticationTableData on AuthenticationTableData {
|
||||||
bool get isExpired => DateTime.now().isAfter(expiration);
|
bool get isExpired => DateTime.now().isAfter(expiration);
|
||||||
@ -30,13 +35,17 @@ extension ExpirationAuthenticationTableData on AuthenticationTableData {
|
|||||||
|
|
||||||
class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
|
class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
|
||||||
static final Dio dio = () {
|
static final Dio dio = () {
|
||||||
final dio = Dio();
|
final dio = Dio()
|
||||||
|
..httpClientAdapter = Http2Adapter(
|
||||||
(dio.httpClientAdapter as IOHttpClientAdapter)
|
ConnectionManager(
|
||||||
.createHttpClient = () => HttpClient()
|
idleTimeout: const Duration(seconds: 10),
|
||||||
..badCertificateCallback = (X509Certificate cert, String host, int port) {
|
onClientCreate: (uri, clientSettings) {
|
||||||
return host.endsWith("spotify.com") && port == 443;
|
clientSettings.onBadCertificate = (X509Certificate cert) {
|
||||||
};
|
return uri.host.endsWith("spotify.com");
|
||||||
|
};
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return dio;
|
return dio;
|
||||||
}();
|
}();
|
||||||
@ -100,6 +109,94 @@ class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
|
|||||||
.insert(refreshedCredentials, mode: InsertMode.replace);
|
.insert(refreshedCredentials, mode: InsertMode.replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String base32FromBytes(Uint8List e, String secretSauce) {
|
||||||
|
var t = 0;
|
||||||
|
var n = 0;
|
||||||
|
var r = "";
|
||||||
|
for (int i = 0; i < e.length; i++) {
|
||||||
|
n = n << 8 | e[i];
|
||||||
|
t += 8;
|
||||||
|
while (t >= 5) {
|
||||||
|
r += secretSauce[n >>> t - 5 & 31];
|
||||||
|
t -= 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (t > 0) {
|
||||||
|
r += secretSauce[n << 5 - t & 31];
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint8List cleanBuffer(String e) {
|
||||||
|
e = e.replaceAll(" ", "");
|
||||||
|
final t = List.filled(e.length ~/ 2, 0);
|
||||||
|
final n = Uint8List.fromList(t);
|
||||||
|
for (int r = 0; r < e.length; r += 2) {
|
||||||
|
n[r ~/ 2] = int.parse(e.substring(r, r + 2), radix: 16);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> generateTotp() async {
|
||||||
|
const secretSauce = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
final secretCipherBytes = const [
|
||||||
|
12,
|
||||||
|
56,
|
||||||
|
76,
|
||||||
|
33,
|
||||||
|
88,
|
||||||
|
44,
|
||||||
|
88,
|
||||||
|
33,
|
||||||
|
78,
|
||||||
|
78,
|
||||||
|
11,
|
||||||
|
66,
|
||||||
|
22,
|
||||||
|
22,
|
||||||
|
55,
|
||||||
|
69,
|
||||||
|
54
|
||||||
|
].mapIndexed((t, e) => e ^ t % 33 + 9).toList();
|
||||||
|
|
||||||
|
final secretBytes = cleanBuffer(
|
||||||
|
utf8
|
||||||
|
.encode(secretCipherBytes.join(""))
|
||||||
|
.map((e) => e.toRadixString(16))
|
||||||
|
.join(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final secret = base32FromBytes(secretBytes, secretSauce);
|
||||||
|
|
||||||
|
final res = await dio.get(
|
||||||
|
"https://open.spotify.com/server-time",
|
||||||
|
options: Options(
|
||||||
|
headers: {
|
||||||
|
"Host": "open.spotify.com",
|
||||||
|
"User-Agent": ServiceUtils.randomUserAgent(
|
||||||
|
kIsDesktop ? UserAgentDevice.desktop : UserAgentDevice.mobile,
|
||||||
|
),
|
||||||
|
"accept": "*/*",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final serverTimeSeconds = res.data["serverTime"] as int;
|
||||||
|
|
||||||
|
final totp = TOTP(
|
||||||
|
secret: secret,
|
||||||
|
algorithm: OTPAlgorithm.SHA1,
|
||||||
|
digits: 6,
|
||||||
|
interval: 30,
|
||||||
|
);
|
||||||
|
|
||||||
|
return totp.generateOTP(
|
||||||
|
input: Util.timeFormat(
|
||||||
|
time: DateTime.fromMillisecondsSinceEpoch(serverTimeSeconds * 1000),
|
||||||
|
interval: 30,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<AuthenticationTableCompanion> credentialsFromCookie(
|
Future<AuthenticationTableCompanion> credentialsFromCookie(
|
||||||
String cookie,
|
String cookie,
|
||||||
) async {
|
) async {
|
||||||
@ -108,10 +205,17 @@ class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
|
|||||||
.split("; ")
|
.split("; ")
|
||||||
.firstWhereOrNull((c) => c.trim().startsWith("sp_dc="))
|
.firstWhereOrNull((c) => c.trim().startsWith("sp_dc="))
|
||||||
?.trim();
|
?.trim();
|
||||||
|
|
||||||
|
final totp = await generateTotp();
|
||||||
|
final timestamp = (DateTime.now().millisecondsSinceEpoch / 1000).floor();
|
||||||
|
|
||||||
|
final accessTokenUrl = Uri.parse(
|
||||||
|
"https://open.spotify.com/get_access_token?reason=transport&productType=web_player"
|
||||||
|
"&totp=$totp&totpVer=5&ts=$timestamp",
|
||||||
|
);
|
||||||
|
|
||||||
final res = await dio.getUri(
|
final res = await dio.getUri(
|
||||||
Uri.parse(
|
accessTokenUrl,
|
||||||
"https://open.spotify.com/get_access_token?reason=transport&productType=web_player",
|
|
||||||
),
|
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: {
|
headers: {
|
||||||
"Cookie": spDc ?? "",
|
"Cookie": spDc ?? "",
|
||||||
|
@ -24,6 +24,9 @@ const supportedAudioTypes = [
|
|||||||
"audio/opus",
|
"audio/opus",
|
||||||
"audio/wav",
|
"audio/wav",
|
||||||
"audio/aac",
|
"audio/aac",
|
||||||
|
"audio/flac",
|
||||||
|
"audio/x-flac",
|
||||||
|
"audio/x-wav",
|
||||||
];
|
];
|
||||||
|
|
||||||
const imgMimeToExt = {
|
const imgMimeToExt = {
|
||||||
@ -68,13 +71,16 @@ final localTracksProvider =
|
|||||||
await Directory(location).list(recursive: true).toList();
|
await Directory(location).list(recursive: true).toList();
|
||||||
|
|
||||||
entities.addAll(
|
entities.addAll(
|
||||||
dirEntities
|
dirEntities.where(
|
||||||
.where(
|
(e) {
|
||||||
(e) =>
|
final mime = lookupMimeType(e.path) ??
|
||||||
e is File &&
|
(extension(e.path) == ".opus" ? "audio/opus" : null);
|
||||||
supportedAudioTypes.contains(lookupMimeType(e.path)),
|
|
||||||
)
|
print("${basename(e.path)}: $mime");
|
||||||
.cast<File>(),
|
|
||||||
|
return e is File && supportedAudioTypes.contains(mime);
|
||||||
|
},
|
||||||
|
).cast<File>(),
|
||||||
);
|
);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
AppLogger.reportError(e, stack);
|
AppLogger.reportError(e, stack);
|
||||||
|
@ -98,6 +98,23 @@ class PlaylistNotifier extends FamilyAsyncNotifier<Playlist, String> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> addTracks(List<String> trackIds, [ValueChanged? onError]) async {
|
||||||
|
try {
|
||||||
|
if (state.value == null) return;
|
||||||
|
|
||||||
|
final spotify = ref.read(spotifyProvider);
|
||||||
|
|
||||||
|
await spotify.playlists.addTracks(
|
||||||
|
trackIds.map((id) => "spotify:track:$id").toList(),
|
||||||
|
state.value!.id!,
|
||||||
|
);
|
||||||
|
} catch (e, stack) {
|
||||||
|
onError?.call(e);
|
||||||
|
AppLogger.reportError(e, stack);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final playlistProvider =
|
final playlistProvider =
|
||||||
|
@ -11,8 +11,6 @@ final homeViewProvider = FutureProvider((ref) async {
|
|||||||
authenticationProvider.select((s) => s.asData?.value?.getCookie("sp_t")),
|
authenticationProvider.select((s) => s.asData?.value?.getCookie("sp_t")),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (spTCookie == null) return null;
|
|
||||||
|
|
||||||
final spotify = ref.watch(customSpotifyEndpointProvider);
|
final spotify = ref.watch(customSpotifyEndpointProvider);
|
||||||
|
|
||||||
return spotify.getHomeFeed(
|
return spotify.getHomeFeed(
|
||||||
|
@ -5,7 +5,7 @@ import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
|
|||||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||||
|
|
||||||
final homeSectionViewProvider =
|
final homeSectionViewProvider =
|
||||||
FutureProvider.family<SpotifyHomeFeedSection?, String>(
|
FutureProvider.family<SpotifyHomeFeedSection, String>(
|
||||||
(ref, sectionUri) async {
|
(ref, sectionUri) async {
|
||||||
final country = ref.watch(
|
final country = ref.watch(
|
||||||
userPreferencesProvider.select((s) => s.market),
|
userPreferencesProvider.select((s) => s.market),
|
||||||
@ -14,8 +14,6 @@ final homeSectionViewProvider =
|
|||||||
authenticationProvider.select((s) => s.asData?.value?.getCookie("sp_t")),
|
authenticationProvider.select((s) => s.asData?.value?.getCookie("sp_t")),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (spTCookie == null) return null;
|
|
||||||
|
|
||||||
final spotify = ref.watch(customSpotifyEndpointProvider);
|
final spotify = ref.watch(customSpotifyEndpointProvider);
|
||||||
|
|
||||||
return spotify.getHomeFeedSection(
|
return spotify.getHomeFeedSection(
|
||||||
|
@ -117,8 +117,8 @@ class CustomSpotifyEndpoints {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<SpotifyHomeFeed> getHomeFeed({
|
Future<SpotifyHomeFeed> getHomeFeed({
|
||||||
required String spTCookie,
|
|
||||||
required Market country,
|
required Market country,
|
||||||
|
String? spTCookie,
|
||||||
}) async {
|
}) async {
|
||||||
final headers = {
|
final headers = {
|
||||||
'app-platform': 'WebPlayer',
|
'app-platform': 'WebPlayer',
|
||||||
@ -137,7 +137,7 @@ class CustomSpotifyEndpoints {
|
|||||||
"operationName": "home",
|
"operationName": "home",
|
||||||
"variables": jsonEncode({
|
"variables": jsonEncode({
|
||||||
"timeZone": tz.local.name,
|
"timeZone": tz.local.name,
|
||||||
"sp_t": spTCookie,
|
"sp_t": spTCookie ?? "",
|
||||||
"country": country.name,
|
"country": country.name,
|
||||||
"facet": null,
|
"facet": null,
|
||||||
"sectionItemsLimit": 10
|
"sectionItemsLimit": 10
|
||||||
@ -169,7 +169,7 @@ class CustomSpotifyEndpoints {
|
|||||||
|
|
||||||
Future<SpotifyHomeFeedSection> getHomeFeedSection(
|
Future<SpotifyHomeFeedSection> getHomeFeedSection(
|
||||||
String sectionUri, {
|
String sectionUri, {
|
||||||
required String spTCookie,
|
String? spTCookie,
|
||||||
required Market country,
|
required Market country,
|
||||||
}) async {
|
}) async {
|
||||||
final headers = {
|
final headers = {
|
||||||
@ -189,7 +189,7 @@ class CustomSpotifyEndpoints {
|
|||||||
"operationName": "homeSection",
|
"operationName": "homeSection",
|
||||||
"variables": jsonEncode({
|
"variables": jsonEncode({
|
||||||
"timeZone": tz.local.name,
|
"timeZone": tz.local.name,
|
||||||
"sp_t": spTCookie,
|
"sp_t": spTCookie ?? "",
|
||||||
"country": country.name,
|
"country": country.name,
|
||||||
"uri": sectionUri
|
"uri": sectionUri
|
||||||
}),
|
}),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import 'dart:math';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
|
|
||||||
@ -28,6 +28,11 @@ import 'package:spotube/collections/env.dart';
|
|||||||
|
|
||||||
import 'package:version/version.dart';
|
import 'package:version/version.dart';
|
||||||
|
|
||||||
|
enum UserAgentDevice {
|
||||||
|
desktop,
|
||||||
|
mobile,
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ServiceUtils {
|
abstract class ServiceUtils {
|
||||||
static final _englishMatcherRegex = RegExp(
|
static final _englishMatcherRegex = RegExp(
|
||||||
"^[a-zA-Z0-9\\s!\"#\$%&\\'()*+,-.\\/:;<=>?@\\[\\]^_`{|}~]*\$",
|
"^[a-zA-Z0-9\\s!\"#\$%&\\'()*+,-.\\/:;<=>?@\\[\\]^_`{|}~]*\$",
|
||||||
@ -417,4 +422,16 @@ abstract class ServiceUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int randomNumber(int min, int max) {
|
||||||
|
return min + Random().nextInt(max - min);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String randomUserAgent(UserAgentDevice type) {
|
||||||
|
if (type == UserAgentDevice.desktop) {
|
||||||
|
return "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_${randomNumber(11, 15)}_${randomNumber(4, 9)}) AppleWebKit/${randomNumber(530, 537)}.${randomNumber(30, 37)} (KHTML, like Gecko) Chrome/${randomNumber(80, 105)}.0.${randomNumber(3000, 4500)}.${randomNumber(60, 125)} Safari/${randomNumber(530, 537)}.${randomNumber(30, 36)}";
|
||||||
|
} else {
|
||||||
|
return "Mozilla/5.0 (Linux; Android ${randomNumber(8, 13)}) AppleWebKit/${randomNumber(530, 537)}.${randomNumber(30, 36)} (KHTML, like Gecko) Chrome/${randomNumber(101, 116)}.0.${randomNumber(3000, 6000)}.${randomNumber(60, 125)} Mobile Safari/${randomNumber(530, 537)}.${randomNumber(30, 36)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
38
pubspec.lock
38
pubspec.lock
@ -166,6 +166,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
base32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: base32
|
||||||
|
sha256: ddad4ebfedf93d4500818ed8e61443b734ffe7cf8a45c668c9b34ef6adde02e2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
bonsoir:
|
bonsoir:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -440,7 +448,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.4+2"
|
version: "0.3.4+2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: "direct dev"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||||
@ -536,6 +544,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.7.0"
|
version: "5.7.0"
|
||||||
|
dio_http2_adapter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dio_http2_adapter
|
||||||
|
sha256: b8bd5d587fd228a461711f8b82f378ccd4bf1fbf7802e7663ca60d7b5ce0e3aa
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.0"
|
||||||
dio_web_adapter:
|
dio_web_adapter:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1178,6 +1194,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.2"
|
version: "1.2.2"
|
||||||
|
http2:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http2
|
||||||
|
sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
http_methods:
|
http_methods:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1539,10 +1563,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.6"
|
version: "2.0.0"
|
||||||
nm:
|
nm:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1639,6 +1663,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.3"
|
version: "0.0.3"
|
||||||
|
otp_util:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: otp_util
|
||||||
|
sha256: dd8956c6472bacc3ffabe62c03f8a9782d1e5a5a3f2674420970f549d642b1cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
47
pubspec.yaml
47
pubspec.yaml
@ -3,7 +3,7 @@ description: Open source Spotify client that doesn't require Premium nor uses El
|
|||||||
|
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
|
|
||||||
version: 4.0.0+39
|
version: 4.0.1+40
|
||||||
|
|
||||||
homepage: https://spotube.krtirtho.dev
|
homepage: https://spotube.krtirtho.dev
|
||||||
repository: https://github.com/KRTirtho/spotube
|
repository: https://github.com/KRTirtho/spotube
|
||||||
@ -88,7 +88,7 @@ dependencies:
|
|||||||
media_kit: ^1.1.10+1
|
media_kit: ^1.1.10+1
|
||||||
media_kit_libs_audio: ^1.0.4
|
media_kit_libs_audio: ^1.0.4
|
||||||
metadata_god: ^1.0.0
|
metadata_god: ^1.0.0
|
||||||
mime: ^1.0.2
|
mime: ^2.0.0
|
||||||
open_file: ^3.5.10
|
open_file: ^3.5.10
|
||||||
package_info_plus: ^6.0.0
|
package_info_plus: ^6.0.0
|
||||||
palette_generator: ^0.3.3
|
palette_generator: ^0.3.3
|
||||||
@ -140,10 +140,11 @@ dependencies:
|
|||||||
url: https://github.com/KRTirtho/flutter_new_pipe_extractor.git
|
url: https://github.com/KRTirtho/flutter_new_pipe_extractor.git
|
||||||
http_parser: ^4.1.2
|
http_parser: ^4.1.2
|
||||||
collection: any
|
collection: any
|
||||||
|
otp_util: ^1.0.2
|
||||||
|
dio_http2_adapter: ^2.6.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.13
|
build_runner: ^2.4.13
|
||||||
crypto: ^3.0.3
|
|
||||||
envied_generator: ^1.0.0
|
envied_generator: ^1.0.0
|
||||||
flutter_gen_runner: ^5.4.0
|
flutter_gen_runner: ^5.4.0
|
||||||
flutter_launcher_icons: ^0.14.2
|
flutter_launcher_icons: ^0.14.2
|
||||||
@ -193,46 +194,6 @@ flutter:
|
|||||||
- packages/flutter_undraw/assets/undraw/empty.svg
|
- packages/flutter_undraw/assets/undraw/empty.svg
|
||||||
- packages/flutter_undraw/assets/undraw/no_data.svg
|
- packages/flutter_undraw/assets/undraw/no_data.svg
|
||||||
fonts:
|
fonts:
|
||||||
- family: GeistSans
|
|
||||||
fonts:
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-Black.otf
|
|
||||||
weight: 800
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-Bold.otf
|
|
||||||
weight: 700
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-Light.otf
|
|
||||||
weight: 300
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-Medium.otf
|
|
||||||
weight: 500
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-SemiBold.otf
|
|
||||||
weight: 600
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-Thin.otf
|
|
||||||
weight: 100
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-UltraBlack.otf
|
|
||||||
weight: 900
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-UltraLight.otf
|
|
||||||
weight: 200
|
|
||||||
- asset: packages/shadcn_flutter/fonts/Geist-Regular.otf
|
|
||||||
weight: 400
|
|
||||||
- family: GeistMono
|
|
||||||
fonts:
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-Black.otf
|
|
||||||
weight: 800
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-Bold.otf
|
|
||||||
weight: 700
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-Light.otf
|
|
||||||
weight: 300
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-Medium.otf
|
|
||||||
weight: 500
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-Regular.otf
|
|
||||||
weight: 400
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-SemiBold.otf
|
|
||||||
weight: 600
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-Thin.otf
|
|
||||||
weight: 100
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-UltraBlack.otf
|
|
||||||
weight: 900
|
|
||||||
- asset: packages/shadcn_flutter/fonts/GeistMono-UltraLight.otf
|
|
||||||
weight: 200
|
|
||||||
- family: RadixIcons
|
- family: RadixIcons
|
||||||
fonts:
|
fonts:
|
||||||
- asset: packages/shadcn_flutter/icons/RadixIcons.otf
|
- asset: packages/shadcn_flutter/icons/RadixIcons.otf
|
||||||
|
Loading…
Reference in New Issue
Block a user