Compare commits

...

23 Commits

Author SHA1 Message Date
plum7x
441dabde8a
Merge f8892c7267 into 723b6b1f38 2025-03-16 01:23:26 +00:00
Kingkor Roy Tirtho
723b6b1f38
Merge pull request #2524 from KRTirtho/dev
Release 4.0.1
2025-03-15 17:21:27 +06:00
Kingkor Roy Tirtho
764950b286 Revert "chore: spotify home feed recommendations now showing up"
This reverts commit 290affd435.
2025-03-15 17:15:29 +06:00
Kingkor Roy Tirtho
290affd435 chore: spotify home feed recommendations now showing up 2025-03-15 17:00:57 +06:00
Kingkor Roy Tirtho
c59b5c651e chore: reenable impeller 2025-03-15 16:48:24 +06:00
Kingkor Roy Tirtho
e4ac7cacc9 chore: generate changelogs and migrate to non synthetic l10n 2025-03-15 16:44:57 +06:00
Kingkor Roy Tirtho
26b1c31f8f chore: flutter 3.29.2 and bump of to 4.0.1 2025-03-15 16:31:20 +06:00
VARUN M
4bfe334419
feat(translation): add tamil translation for spotube (#2501)
* feat: add tamil language for spotube

* fix: syntax error lib/l10n/app_ta.arb

---------

Co-authored-by: Kingkor Roy Tirtho <krtirtho@gmail.com>
2025-03-15 16:28:27 +06:00
Justin May
48fcfbc928
feat(translation): add tagalog language support
Added Tagalog translation
2025-03-15 16:26:49 +06:00
Kingkor Roy Tirtho
95e09ffc94 chore: remove certificate check for dio 2025-03-15 14:23:38 +06:00
Kingkor Roy Tirtho
968fd09eb3 chore: add random user agent 2025-03-15 10:48:34 +06:00
Kingkor Roy Tirtho
1a32264bc7 fix: spotify authentication 429 errors 2025-03-15 10:37:29 +06:00
Kingkor Roy Tirtho
59f298a935 fix: spotify login broken due to new totp requirement #2494 2025-03-15 01:41:51 +06:00
Kingkor Roy Tirtho
bbe3394e9e fix: lastfm form broken in other locales #2447 2025-03-12 15:05:32 +06:00
Kingkor Roy Tirtho
7cde803bee feat(local_library): add support for x-flac, opus and x-wav 2025-03-12 14:20:19 +06:00
Kingkor Roy Tirtho
cd475e93d0 chore: upgrade action flutter to 3.29.1 2025-03-12 13:48:07 +06:00
Kingkor Roy Tirtho
3d334d96fd fix(desktop): double titlebar in local library folders and massive space in overlay player 2025-03-11 21:28:57 +06:00
Kingkor Roy Tirtho
bd4cd22e4e fix(generate_playlist): create playlist not adding tracks nor navigating to playlist page 2025-03-11 00:16:53 +06:00
Kingkor Roy Tirtho
c709de6bf1 fix: language picker search broken 2025-03-10 20:44:52 +06:00
Kingkor Roy Tirtho
ccbac85171 chore: remove GeistMono 2025-03-10 20:15:28 +06:00
Kingkor Roy Tirtho
50123b235c fix: add to playlist not working in smaller screen devices 2025-03-10 20:07:51 +06:00
Kingkor Roy Tirtho
4072531c62 fix(android): navigation overlaying in app navigation 2025-03-09 10:05:02 +06:00
plum7x
f8892c7267
Create app_zh_TW.arb 2025-02-07 15:59:08 +08:00
71 changed files with 44235 additions and 327 deletions

View File

@ -1,3 +1,3 @@
{
"flutterSdkVersion": "3.29.0"
"flutterSdkVersion": "3.29.2"
}

2
.fvmrc
View File

@ -1,4 +1,4 @@
{
"flutter": "3.29.0",
"flutter": "3.29.2",
"flavors": {}
}

View File

@ -4,7 +4,7 @@ on:
pull_request:
env:
FLUTTER_VERSION: 3.29.0
FLUTTER_VERSION: 3.29.2
jobs:
lint:

View File

@ -20,7 +20,7 @@ on:
description: Dry run without uploading to release
env:
FLUTTER_VERSION: 3.29.0
FLUTTER_VERSION: 3.29.2
FLUTTER_CHANNEL: master
permissions:

View File

@ -28,5 +28,5 @@
"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.flutterSdkPath": ".fvm/versions/3.29.0"
"dart.flutterSdkPath": ".fvm/versions/3.29.2"
}

View File

@ -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.
## [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)
## Changes

View File

@ -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. [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. [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. [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. [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.

View File

@ -1,4 +1,5 @@
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-dir: lib/l10n/generated
untranslated-messages-file: untranslated_messages.json
synthetic-package: false

View File

@ -13,12 +13,6 @@ class FontFamily {
/// Font family: 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
static const String radixIcons = 'RadixIcons';
}

View File

@ -625,10 +625,10 @@ abstract class LanguageLocals {
// name: "Swedish",
// nativeName: "svenska",
// ),
// "ta": const ISOLanguageName(
// name: "Tamil",
// nativeName: "தமிழ்",
// ),
"ta": const ISOLanguageName(
name: "Tamil",
nativeName: "தமிழ்",
),
// "te": const ISOLanguageName(
// name: "Telugu",
// nativeName: "తెలుగు",
@ -653,10 +653,10 @@ abstract class LanguageLocals {
// name: "Turkmen",
// nativeName: "Türkmen, Түркмен",
// ),
// "tl": const ISOLanguageName(
// name: "Tagalog",
// nativeName: "Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔",
// ),
"tl": const ISOLanguageName(
name: "Tagalog",
nativeName: "Wikang Tagalog",
),
// "tn": const ISOLanguageName(
// name: "Tswana",
// nativeName: "Setswana",

View File

@ -75,17 +75,17 @@ class AppRouter extends RootStackRouter {
path: "local",
page: UserLocalLibraryRoute.page,
),
AutoRoute(
path: "local/folder",
page: LocalLibraryRoute.page,
// parentNavigatorKey: shellRouteNavigatorKey,
),
AutoRoute(
path: "downloads",
page: UserDownloadsRoute.page,
),
],
),
AutoRoute(
path: "local/folder",
page: LocalLibraryRoute.page,
// parentNavigatorKey: shellRouteNavigatorKey,
),
AutoRoute(
path: "library/generate",
page: PlaylistGeneratorRoute.page,

View File

@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:spotube/collections/routes.gr.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 {
final IconData icon;

View File

@ -28,7 +28,7 @@ class AdaptiveMenuButton<T> extends MenuButton {
/// or equal to 640px
/// In smaller screen, a [IconButton] with a [showModalBottomSheet] is shown
class AdaptivePopSheetList<T> extends StatelessWidget {
final List<AdaptiveMenuButton<T>> children;
final List<AdaptiveMenuButton<T>> Function(BuildContext context) items;
final Widget? icon;
final Widget? child;
final bool useRootNavigator;
@ -43,7 +43,7 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
const AdaptivePopSheetList({
super.key,
required this.children,
required this.items,
this.icon,
this.child,
this.useRootNavigator = true,
@ -59,27 +59,28 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
Future<void> showDropdownMenu(BuildContext context, Offset position) async {
final mediaQuery = MediaQuery.of(context);
final childrenModified = children.map((s) {
if (s.onPressed == null) {
return MenuButton(
key: s.key,
autoClose: s.autoClose,
enabled: s.enabled,
leading: s.leading,
focusNode: s.focusNode,
onPressed: (context) {
if (s.value != null) {
onSelected?.call(s.value as T);
}
},
popoverController: s.popoverController,
subMenu: s.subMenu,
trailing: s.trailing,
child: s.child,
);
}
return s;
}).toList();
List<MenuButton> childrenModified(BuildContext context) =>
items(context).map((s) {
if (s.onPressed == null) {
return MenuButton(
key: s.key,
autoClose: s.autoClose,
enabled: s.enabled,
leading: s.leading,
focusNode: s.focusNode,
onPressed: (context) {
if (s.value != null) {
onSelected?.call(s.value as T);
}
},
popoverController: s.popoverController,
subMenu: s.subMenu,
trailing: s.trailing,
child: s.child,
);
}
return s;
}).toList();
if (mediaQuery.mdAndUp) {
await showDropdown<T?>(
@ -92,7 +93,7 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
position: position,
builder: (context) {
return DropdownMenu(
children: childrenModified,
children: childrenModified(context),
);
},
).future;
@ -109,11 +110,12 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
),
backgroundColor: context.theme.colorScheme.card,
builder: (context) {
final children = childrenModified(context);
return ListView.builder(
itemCount: childrenModified.length,
itemCount: children.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final data = childrenModified[index];
final data = children[index];
return Button(
enabled: data.enabled,

View File

@ -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,
);
},
);
}
}

View File

@ -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,
// );
// },
// );
// }

View File

@ -166,7 +166,7 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
},
icon: const Icon(SpotubeIcons.moreVertical),
variance: ButtonVariance.outline,
children: [
items: (context) => [
AdaptiveMenuButton(
value: "download",
leading: const Icon(SpotubeIcons.download),

View File

@ -23,7 +23,7 @@ class SortTracksDropdown extends StatelessWidget {
onSelected: onChanged,
tooltip: context.l10n.sort_tracks,
icon: const Icon(SpotubeIcons.sort),
children: [
items: (context) => [
AdaptiveMenuButton(
value: SortBy.none,
enabled: value != SortBy.none,

View File

@ -90,11 +90,25 @@ class TrackOptions extends HookConsumerWidget {
BuildContext context,
Track track,
) {
showDialog(
context: context,
builder: (context) => PlaylistAddTrackDialog(
tracks: [track],
openFromPlaylist: playlistId,
/// showDialog doesn't work for some reason. So we have to
/// manually push a Dialog Route in the Navigator to get it working
Navigator.push(
context,
DialogRoute(
alignment: Alignment.bottomCenter,
transitionBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(opacity: animation, child: child);
},
context: context,
barrierColor: Colors.black.withValues(alpha: 0.5),
builder: (context) {
return Center(
child: PlaylistAddTrackDialog(
tracks: [track],
openFromPlaylist: playlistId,
),
);
},
),
);
}
@ -352,7 +366,7 @@ class TrackOptions extends HookConsumerWidget {
),
),
],
children: [
items: (context) => [
if (isLocalTrack)
AdaptiveMenuButton(
value: TrackOptionValue.delete,

View File

@ -1,5 +1,5 @@
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 {
AppLocalizations get l10n => AppLocalizations.of(this)!;

428
lib/l10n/app_ta.arb Normal file
View 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
View 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"
}

405
lib/l10n/app_zh_TW.arb Normal file
View File

@ -0,0 +1,405 @@
{
"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": "您點贊過的所有歌曲",
"create_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": "藝人的分享連結已複製至剪貼簿",
"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": "單曲循環",
"repeat_playlist": "播放清單循環",
"queue": "播放隊列",
"alternative_track_sources": "其它音訊來源",
"download_track": "下載歌曲",
"tracks_in_queue": "{tracks} 首歌曲在播放隊列中",
"clear_all": "清除全部",
"show_hide_ui_on_hover": "懸停時顯示/隱藏控制列",
"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": "略過非音樂片段(贊助商阻擋)",
"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": "Kingkor Roy Tirtho",
"copyright": "© 2021-{current_year} Kingkor Roy Tirtho",
"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",
"cookie_name_cookie": "{name} Cookie",
"fill_in_all_fields": "請填寫所有欄位",
"submit": "提交",
"exit": "退出",
"previous": "上一步",
"next": "下一步",
"done": "完成",
"step_1": "步驟 1",
"first_go_to": "首先,前往",
"login_if_not_logged_in": "如果尚未登入,請登入或者註冊一個帳戶",
"step_2": "步驟 2",
"step_2_steps": "1. 一旦您已經完成登入, 按 F12 鍵或者滑鼠右擊網頁空白區域 > 選擇「檢查」以打開瀏覽器開發者工具DevTools\n2. 然後選擇 \"應用Application\" 標籤頁Chrome、Edge、Brave 等基於 Chromium 的瀏覽器) 或 \"存儲Storage\" 標籤頁 Firefox、Palemoon 等基於 Firefox 的瀏覽器))\n3. 選擇 \"Cookies\" 欄位然後選擇 \"https://accounts.spotify.com\" 子欄位",
"step_3": "步驟 3",
"step_3_steps": "複製 \"sp_dc\" Cookie 的值",
"success_emoji": "成功🥳",
"success_message": "您已經成功使用 Spotify 登入。幹得漂亮!",
"step_4": "步驟 4",
"step_4_steps": "貼上複製的 \"sp_dc\" 值",
"something_went_wrong": "某些地方出現了問題",
"piped_instance": "管線伺服器實例",
"piped_description": "管線伺服器實例用於匹配歌曲",
"piped_warning": "它們中的一部分可能並不能正常工作。使用時請自行承擔風險",
"invidious_instance": "Invidious 伺服器實例",
"invidious_description": "用於音軌匹配的 Invidious 伺服器實例",
"invidious_warning": "有些可能無法正常工作。請自行承擔風險",
"generate_playlist": "產生播放清單",
"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": "歌曲時長 (s)",
"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 封鎖,這意味著您的裝置將在長達 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如果您使用 Linux請確保已安裝 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": "使用 AMOLED 模式",
"pitch_dark_theme": "深色主題",
"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": "自動將新歌曲新增到隊列的末尾",
"choose_your_region": "選擇您的地區",
"choose_your_region_description": "這將幫助 Spotube 為您的位置顯示正確的內容。",
"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": "*基於 Spotify 每次播放的支付金額\n從 $0.003 到 $0.005 計算。這是一個假設性的\n計算旨在讓使用者瞭解如果他們在 Spotify 上收聽\n這些歌曲可能會付給藝人的金額。",
"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計算用於給使用者瞭解他們如果在 Spotify 上\n收聽歌曲會支付給藝人的金額。",
"count_mins": "{minutes} 分鐘",
"summary_minutes": "分鐘",
"summary_listened_to_music": "聽音樂",
"summary_songs": "歌曲",
"summary_streamed_overall": "總體串流媒體",
"summary_owed_to_artists": "本月欠藝人的",
"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",
"webview_not_found_description": "您的裝置中未安裝 Webview 運行時。\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} 個檔案"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,13 @@
/// doannc2212@github => Vietnamese
/// sappho192@github => Korean
/// watchakorn-18k@github => Thai
/// llama3, vishnumur777@github => Tamil
/// Microsoft Copilot, Tutislav@github => Czech
library l10n;
import 'package:shadcn_flutter/shadcn_flutter.dart';
export 'package:spotube/l10n/generated/app_localizations.dart';
class L10n {
static final all = [
@ -41,8 +43,10 @@ class L10n {
const Locale('pl', 'PL'),
const Locale('pt', 'PT'),
const Locale('ru', 'RU'),
const Locale('tl', 'PH'),
const Locale('uk', 'UA'),
const Locale('th', 'TH'),
const Locale('ta', 'IN'),
const Locale('tr', 'TR'),
const Locale('zh', 'CN'),
const Locale('vi', 'VN'),

View File

@ -44,7 +44,6 @@ import 'package:spotube/services/logger/logger.dart';
import 'package:spotube/services/wm_tools/wm_tools.dart';
import 'package:spotube/utils/migrations/sandbox.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_displaymode/flutter_displaymode.dart';
import 'package:timezone/data/latest.dart' as tz;

View File

@ -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/volume_provider.dart';
import 'package:spotube/services/sourced_track/sources/youtube.dart';
import 'package:spotube/utils/platform.dart';
import 'package:url_launcher/url_launcher_string.dart';
@ -48,7 +49,7 @@ class PlayerView extends HookConsumerWidget {
ref.watch(audioPlayerProvider.select((s) => s.activeTrack));
final currentTrack = sourcedCurrentTrack ?? currentActiveTrack;
final isLocalTrack = currentTrack is LocalTrack;
final mediaQuery = MediaQuery.of(context);
final mediaQuery = MediaQuery.sizeOf(context);
final shouldHide = useState(true);
@ -101,6 +102,9 @@ class PlayerView extends HookConsumerWidget {
backgroundColor: Colors.transparent,
headers: [
SafeArea(
minimum:
kIsMobile ? const EdgeInsets.only(top: 80) : EdgeInsets.zero,
bottom: false,
child: TitleBar(
surfaceOpacity: 0,
surfaceBlur: 0,

View File

@ -191,7 +191,7 @@ class PlayerActions extends HookConsumerWidget {
sleepTimerNotifier.setSleepTimer(value);
}
},
children: [
items: (context) => [
for (final entry in sleepTimerEntries.entries)
AdaptiveMenuButton(
value: entry.value,

View File

@ -101,11 +101,17 @@ class PlaylistCreateDialog extends HookConsumerWidget {
} else {
await playlistNotifier.create(payload, onError);
}
if (trackIds.isNotEmpty) {
await playlistNotifier.addTracks(trackIds, onError);
}
} finally {
isSubmitting.value = false;
if (context.mounted &&
!ref.read(playlistProvider(playlistId ?? "")).hasError) {
context.router.maybePop();
context.router.maybePop<Playlist>(
await ref.read(playlistProvider(playlistId ?? "").future),
);
}
}
}

View File

@ -133,37 +133,38 @@ class GettingStartedPageLanguageRegionSection extends HookConsumerWidget {
popup: SelectPopup.builder(
searchPlaceholder: Text(context.l10n.search),
builder: (context, searchQuery) {
final filteredLocale = searchQuery?.isNotEmpty != true
? L10n.all
final hasNotQueried =
searchQuery == null || searchQuery.trim().isEmpty;
final filteredLocale = hasNotQueried
? [
const Locale("system", "system"),
...L10n.all,
]
: L10n.all
.where(
(element) =>
filterLocale(element, searchQuery!),
(element) => filterLocale(
element,
searchQuery.trim(),
),
)
.toList();
return SelectItemBuilder(
childCount: filteredLocale.length + 1,
childCount: filteredLocale.length,
builder: (context, index) {
if (index == 0 &&
searchQuery?.isNotEmpty != true) {
final locale = filteredLocale[index];
if (locale == const Locale("system", "system")) {
return SelectItemButton(
value: const Locale("system", "system"),
value: locale,
child: Text(context.l10n.system_default),
);
}
final indexThen = searchQuery?.isNotEmpty != true
? index
: index - 1;
final locale = filteredLocale[indexThen];
return SelectItemButton(
value: locale,
child: Text(
LanguageLocals.getDisplayLanguage(
locale.languageCode)
.toString(),
locale.languageCode,
).toString(),
),
);
},

View File

@ -96,7 +96,9 @@ class LastFMLoginPage extends HookConsumerWidget {
FormField(
label: Text(context.l10n.username),
key: usernameKey,
validator: const NotEmptyValidator(),
validator: const NotEmptyValidator(
message: "Username is required",
),
child: TextField(
autofillHints: const [
AutofillHints.username,
@ -107,7 +109,9 @@ class LastFMLoginPage extends HookConsumerWidget {
),
FormField(
key: passwordKey,
validator: const NotEmptyValidator(),
validator: const NotEmptyValidator(
message: "Password is required",
),
label: Text(context.l10n.password),
child: TextField(
autofillHints: const [

View File

@ -81,6 +81,7 @@ class LyricsPage extends HookConsumerWidget {
title: tabbar,
height: 58 * context.theme.scaling,
surfaceBlur: 0,
automaticallyImplyLeading: false,
)
: tabbar
],

View File

@ -43,13 +43,16 @@ class RootAppPage extends HookConsumerWidget {
final scaffold = MediaQuery.removeViewInsets(
context: context,
removeBottom: true,
child: const Scaffold(
footers: [
BottomPlayer(),
SpotubeNavigationBar(),
],
floatingFooter: true,
child: Sidebar(child: AutoRouter()),
child: const SafeArea(
top: false,
child: Scaffold(
footers: [
BottomPlayer(),
SpotubeNavigationBar(),
],
floatingFooter: true,
child: Sidebar(child: AutoRouter()),
),
),
);

View File

@ -1,3 +1,4 @@
import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.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/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 {
const SettingsLanguageRegionSection({super.key});
@ -36,18 +45,8 @@ class SettingsLanguageRegionSection extends HookConsumerWidget {
value: const Locale("system", "system"),
child: Text(context.l10n.system_default),
),
for (final locale in L10n.all)
SelectItemButton(
value: locale,
child: Builder(builder: (context) {
final isoCodeName = LanguageLocals.getDisplayLanguage(
locale.languageCode,
);
return Text(
"${isoCodeName.name} (${isoCodeName.nativeName})",
);
}),
),
for (final (:locale, :name) in localWithName)
SelectItemButton(value: locale, child: Text(name)),
],
),
AdaptiveSelectTile<Market>(

View File

@ -1,10 +1,11 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:collection/collection.dart';
import 'package:desktop_webview_window/desktop_webview_window.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:flutter_inappwebview/flutter_inappwebview.dart'
hide X509Certificate;
@ -15,6 +16,10 @@ import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/database/database.dart';
import 'package:spotube/provider/database/database.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 {
bool get isExpired => DateTime.now().isAfter(expiration);
@ -30,13 +35,17 @@ extension ExpirationAuthenticationTableData on AuthenticationTableData {
class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
static final Dio dio = () {
final dio = Dio();
(dio.httpClientAdapter as IOHttpClientAdapter)
.createHttpClient = () => HttpClient()
..badCertificateCallback = (X509Certificate cert, String host, int port) {
return host.endsWith("spotify.com") && port == 443;
};
final dio = Dio()
..httpClientAdapter = Http2Adapter(
ConnectionManager(
idleTimeout: const Duration(seconds: 10),
onClientCreate: (uri, clientSettings) {
clientSettings.onBadCertificate = (X509Certificate cert) {
return uri.host.endsWith("spotify.com");
};
},
),
);
return dio;
}();
@ -100,6 +109,94 @@ class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
.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(
String cookie,
) async {
@ -108,10 +205,17 @@ class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
.split("; ")
.firstWhereOrNull((c) => c.trim().startsWith("sp_dc="))
?.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(
Uri.parse(
"https://open.spotify.com/get_access_token?reason=transport&productType=web_player",
),
accessTokenUrl,
options: Options(
headers: {
"Cookie": spDc ?? "",

View File

@ -24,6 +24,9 @@ const supportedAudioTypes = [
"audio/opus",
"audio/wav",
"audio/aac",
"audio/flac",
"audio/x-flac",
"audio/x-wav",
];
const imgMimeToExt = {
@ -68,13 +71,16 @@ final localTracksProvider =
await Directory(location).list(recursive: true).toList();
entities.addAll(
dirEntities
.where(
(e) =>
e is File &&
supportedAudioTypes.contains(lookupMimeType(e.path)),
)
.cast<File>(),
dirEntities.where(
(e) {
final mime = lookupMimeType(e.path) ??
(extension(e.path) == ".opus" ? "audio/opus" : null);
print("${basename(e.path)}: $mime");
return e is File && supportedAudioTypes.contains(mime);
},
).cast<File>(),
);
} catch (e, stack) {
AppLogger.reportError(e, stack);

View File

@ -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 =

View File

@ -11,8 +11,6 @@ final homeViewProvider = FutureProvider((ref) async {
authenticationProvider.select((s) => s.asData?.value?.getCookie("sp_t")),
);
if (spTCookie == null) return null;
final spotify = ref.watch(customSpotifyEndpointProvider);
return spotify.getHomeFeed(

View File

@ -5,7 +5,7 @@ import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
final homeSectionViewProvider =
FutureProvider.family<SpotifyHomeFeedSection?, String>(
FutureProvider.family<SpotifyHomeFeedSection, String>(
(ref, sectionUri) async {
final country = ref.watch(
userPreferencesProvider.select((s) => s.market),
@ -14,8 +14,6 @@ final homeSectionViewProvider =
authenticationProvider.select((s) => s.asData?.value?.getCookie("sp_t")),
);
if (spTCookie == null) return null;
final spotify = ref.watch(customSpotifyEndpointProvider);
return spotify.getHomeFeedSection(

View File

@ -117,8 +117,8 @@ class CustomSpotifyEndpoints {
}
Future<SpotifyHomeFeed> getHomeFeed({
required String spTCookie,
required Market country,
String? spTCookie,
}) async {
final headers = {
'app-platform': 'WebPlayer',
@ -137,7 +137,7 @@ class CustomSpotifyEndpoints {
"operationName": "home",
"variables": jsonEncode({
"timeZone": tz.local.name,
"sp_t": spTCookie,
"sp_t": spTCookie ?? "",
"country": country.name,
"facet": null,
"sectionItemsLimit": 10
@ -169,7 +169,7 @@ class CustomSpotifyEndpoints {
Future<SpotifyHomeFeedSection> getHomeFeedSection(
String sectionUri, {
required String spTCookie,
String? spTCookie,
required Market country,
}) async {
final headers = {
@ -189,7 +189,7 @@ class CustomSpotifyEndpoints {
"operationName": "homeSection",
"variables": jsonEncode({
"timeZone": tz.local.name,
"sp_t": spTCookie,
"sp_t": spTCookie ?? "",
"country": country.name,
"uri": sectionUri
}),

View File

@ -1,6 +1,6 @@
import 'dart:math';
import 'dart:typed_data';
import 'package:auto_route/auto_route.dart';
import 'package:dio/dio.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';
enum UserAgentDevice {
desktop,
mobile,
}
abstract class ServiceUtils {
static final _englishMatcherRegex = RegExp(
"^[a-zA-Z0-9\\s!\"#\$%&\\'()*+,-.\\/:;<=>?@\\[\\]^_`{|}~]*\$",
@ -417,4 +422,16 @@ abstract class ServiceUtils {
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)}";
}
}
}

View File

@ -166,6 +166,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.0"
base32:
dependency: transitive
description:
name: base32
sha256: ddad4ebfedf93d4500818ed8e61443b734ffe7cf8a45c668c9b34ef6adde02e2
url: "https://pub.dev"
source: hosted
version: "2.1.3"
bonsoir:
dependency: "direct main"
description:
@ -440,7 +448,7 @@ packages:
source: hosted
version: "0.3.4+2"
crypto:
dependency: "direct dev"
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
@ -536,6 +544,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -1178,6 +1194,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.2"
http2:
dependency: transitive
description:
name: http2
sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
http_methods:
dependency: transitive
description:
@ -1539,10 +1563,10 @@ packages:
dependency: "direct main"
description:
name: mime
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "1.0.6"
version: "2.0.0"
nm:
dependency: transitive
description:
@ -1639,6 +1663,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:

View File

@ -3,7 +3,7 @@ description: Open source Spotify client that doesn't require Premium nor uses El
publish_to: "none"
version: 4.0.0+39
version: 4.0.1+40
homepage: https://spotube.krtirtho.dev
repository: https://github.com/KRTirtho/spotube
@ -88,7 +88,7 @@ dependencies:
media_kit: ^1.1.10+1
media_kit_libs_audio: ^1.0.4
metadata_god: ^1.0.0
mime: ^1.0.2
mime: ^2.0.0
open_file: ^3.5.10
package_info_plus: ^6.0.0
palette_generator: ^0.3.3
@ -140,10 +140,11 @@ dependencies:
url: https://github.com/KRTirtho/flutter_new_pipe_extractor.git
http_parser: ^4.1.2
collection: any
otp_util: ^1.0.2
dio_http2_adapter: ^2.6.0
dev_dependencies:
build_runner: ^2.4.13
crypto: ^3.0.3
envied_generator: ^1.0.0
flutter_gen_runner: ^5.4.0
flutter_launcher_icons: ^0.14.2
@ -193,46 +194,6 @@ flutter:
- packages/flutter_undraw/assets/undraw/empty.svg
- packages/flutter_undraw/assets/undraw/no_data.svg
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
fonts:
- asset: packages/shadcn_flutter/icons/RadixIcons.otf