feat: custom piped & invidious instance support

This commit is contained in:
Kingkor Roy Tirtho 2025-03-07 11:50:39 +06:00
parent c3bbc129ad
commit 91871d0d26
4 changed files with 764 additions and 500 deletions

View File

@ -8,6 +8,7 @@ class AdaptiveSelectTile<T> extends HookWidget {
final Widget title; final Widget title;
final Widget? subtitle; final Widget? subtitle;
final Widget? secondary; final Widget? secondary;
final List<Widget>? trailing;
final ListTileControlAffinity? controlAffinity; final ListTileControlAffinity? controlAffinity;
final T value; final T value;
final ValueChanged<T?>? onChanged; final ValueChanged<T?>? onChanged;
@ -34,6 +35,7 @@ class AdaptiveSelectTile<T> extends HookWidget {
this.controlAffinity = ListTileControlAffinity.trailing, this.controlAffinity = ListTileControlAffinity.trailing,
this.subtitle, this.subtitle,
this.secondary, this.secondary,
this.trailing,
this.breakLayout, this.breakLayout,
this.showValueWhenUnfolded = true, this.showValueWhenUnfolded = true,
super.key, super.key,
@ -54,8 +56,10 @@ class AdaptiveSelectTile<T> extends HookWidget {
onChanged: onChanged, onChanged: onChanged,
popupConstraints: popupConstraints ?? const BoxConstraints(maxWidth: 200), popupConstraints: popupConstraints ?? const BoxConstraints(maxWidth: 200),
popupWidthConstraint: popupWidthConstraint ?? PopoverConstraint.flexible, popupWidthConstraint: popupWidthConstraint ?? PopoverConstraint.flexible,
autoClosePopover: true,
popup: (context) { popup: (context) {
return SelectPopup( return SelectPopup(
autoClose: true,
items: SelectItemBuilder( items: SelectItemBuilder(
childCount: options.length, childCount: options.length,
builder: (context, index) { builder: (context, index) {
@ -82,9 +86,20 @@ class AdaptiveSelectTile<T> extends HookWidget {
leading: controlAffinity != ListTileControlAffinity.leading leading: controlAffinity != ListTileControlAffinity.leading
? secondary ? secondary
: control, : control,
trailing: controlAffinity == ListTileControlAffinity.leading trailing: Row(
? secondary mainAxisSize: MainAxisSize.min,
: control, mainAxisAlignment: MainAxisAlignment.end,
spacing: 5,
children: [
...?trailing,
if (controlAffinity == ListTileControlAffinity.leading &&
secondary != null)
secondary!
else if (controlAffinity == ListTileControlAffinity.trailing &&
control != null)
control,
],
),
onTap: breakLayout ?? mediaQuery.mdAndUp onTap: breakLayout ?? mediaQuery.mdAndUp
? null ? null
: () { : () {

View File

@ -1,426 +1,428 @@
{ {
"guest": "Guest", "guest": "Guest",
"browse": "Browse", "browse": "Browse",
"search": "Search", "search": "Search",
"library": "Library", "library": "Library",
"lyrics": "Lyrics", "lyrics": "Lyrics",
"settings": "Settings", "settings": "Settings",
"genre_categories_filter": "Filter categories or genres...", "genre_categories_filter": "Filter categories or genres...",
"genre": "Genre", "genre": "Genre",
"personalized": "Personalized", "personalized": "Personalized",
"featured": "Featured", "featured": "Featured",
"new_releases": "New Releases", "new_releases": "New Releases",
"songs": "Songs", "songs": "Songs",
"playing_track": "Playing {track}", "playing_track": "Playing {track}",
"queue_clear_alert": "This will clear the current queue. {track_length} tracks will be removed\nDo you want to continue?", "queue_clear_alert": "This will clear the current queue. {track_length} tracks will be removed\nDo you want to continue?",
"load_more": "Load more", "load_more": "Load more",
"playlists": "Playlists", "playlists": "Playlists",
"artists": "Artists", "artists": "Artists",
"albums": "Albums", "albums": "Albums",
"tracks": "Tracks", "tracks": "Tracks",
"downloads": "Downloads", "downloads": "Downloads",
"filter_playlists": "Filter your playlists...", "filter_playlists": "Filter your playlists...",
"liked_tracks": "Liked Tracks", "liked_tracks": "Liked Tracks",
"liked_tracks_description": "All your liked tracks", "liked_tracks_description": "All your liked tracks",
"playlist": "Playlist", "playlist": "Playlist",
"create_a_playlist": "Create a playlist", "create_a_playlist": "Create a playlist",
"update_playlist": "Update playlist", "update_playlist": "Update playlist",
"create": "Create", "create": "Create",
"cancel": "Cancel", "cancel": "Cancel",
"update": "Update", "update": "Update",
"playlist_name": "Playlist Name", "playlist_name": "Playlist Name",
"name_of_playlist": "Name of the playlist", "name_of_playlist": "Name of the playlist",
"description": "Description", "description": "Description",
"public": "Public", "public": "Public",
"collaborative": "Collaborative", "collaborative": "Collaborative",
"search_local_tracks": "Search local tracks...", "search_local_tracks": "Search local tracks...",
"play": "Play", "play": "Play",
"delete": "Delete", "delete": "Delete",
"none": "None", "none": "None",
"sort_a_z": "Sort by A-Z", "sort_a_z": "Sort by A-Z",
"sort_z_a": "Sort by Z-A", "sort_z_a": "Sort by Z-A",
"sort_artist": "Sort by Artist", "sort_artist": "Sort by Artist",
"sort_album": "Sort by Album", "sort_album": "Sort by Album",
"sort_duration": "Sort by Duration", "sort_duration": "Sort by Duration",
"sort_tracks": "Sort Tracks", "sort_tracks": "Sort Tracks",
"currently_downloading": "Currently Downloading ({tracks_length})", "currently_downloading": "Currently Downloading ({tracks_length})",
"cancel_all": "Cancel All", "cancel_all": "Cancel All",
"filter_artist": "Filter artists...", "filter_artist": "Filter artists...",
"followers": "{followers} Followers", "followers": "{followers} Followers",
"add_artist_to_blacklist": "Add artist to blacklist", "add_artist_to_blacklist": "Add artist to blacklist",
"top_tracks": "Top Tracks", "top_tracks": "Top Tracks",
"fans_also_like": "Fans also like", "fans_also_like": "Fans also like",
"loading": "Loading...", "loading": "Loading...",
"artist": "Artist", "artist": "Artist",
"blacklisted": "Blacklisted", "blacklisted": "Blacklisted",
"following": "Following", "following": "Following",
"follow": "Follow", "follow": "Follow",
"artist_url_copied": "Artist URL copied to clipboard", "artist_url_copied": "Artist URL copied to clipboard",
"added_to_queue": "Added {tracks} tracks to queue", "added_to_queue": "Added {tracks} tracks to queue",
"filter_albums": "Filter albums...", "filter_albums": "Filter albums...",
"synced": "Synced", "synced": "Synced",
"plain": "Plain", "plain": "Plain",
"shuffle": "Shuffle", "shuffle": "Shuffle",
"search_tracks": "Search tracks...", "search_tracks": "Search tracks...",
"released": "Released", "released": "Released",
"error": "Error {error}", "error": "Error {error}",
"title": "Title", "title": "Title",
"time": "Time", "time": "Time",
"more_actions": "More actions", "more_actions": "More actions",
"download_count": "Download ({count})", "download_count": "Download ({count})",
"add_count_to_playlist": "Add ({count}) to Playlist", "add_count_to_playlist": "Add ({count}) to Playlist",
"add_count_to_queue": "Add ({count}) to Queue", "add_count_to_queue": "Add ({count}) to Queue",
"play_count_next": "Play ({count}) next", "play_count_next": "Play ({count}) next",
"album": "Album", "album": "Album",
"copied_to_clipboard": "Copied {data} to clipboard", "copied_to_clipboard": "Copied {data} to clipboard",
"add_to_following_playlists": "Add {track} to following Playlists", "add_to_following_playlists": "Add {track} to following Playlists",
"add": "Add", "add": "Add",
"added_track_to_queue": "Added {track} to queue", "added_track_to_queue": "Added {track} to queue",
"add_to_queue": "Add to queue", "add_to_queue": "Add to queue",
"track_will_play_next": "{track} will play next", "track_will_play_next": "{track} will play next",
"play_next": "Play next", "play_next": "Play next",
"removed_track_from_queue": "Removed {track} from queue", "removed_track_from_queue": "Removed {track} from queue",
"remove_from_queue": "Remove from queue", "remove_from_queue": "Remove from queue",
"remove_from_favorites": "Remove from favorites", "remove_from_favorites": "Remove from favorites",
"save_as_favorite": "Save as favorite", "save_as_favorite": "Save as favorite",
"add_to_playlist": "Add to playlist", "add_to_playlist": "Add to playlist",
"remove_from_playlist": "Remove from playlist", "remove_from_playlist": "Remove from playlist",
"add_to_blacklist": "Add to blacklist", "add_to_blacklist": "Add to blacklist",
"remove_from_blacklist": "Remove from blacklist", "remove_from_blacklist": "Remove from blacklist",
"share": "Share", "share": "Share",
"mini_player": "Mini Player", "mini_player": "Mini Player",
"slide_to_seek": "Slide to seek forward or backward", "slide_to_seek": "Slide to seek forward or backward",
"shuffle_playlist": "Shuffle playlist", "shuffle_playlist": "Shuffle playlist",
"unshuffle_playlist": "Unshuffle playlist", "unshuffle_playlist": "Unshuffle playlist",
"previous_track": "Previous track", "previous_track": "Previous track",
"next_track": "Next track", "next_track": "Next track",
"pause_playback": "Pause Playback", "pause_playback": "Pause Playback",
"resume_playback": "Resume Playback", "resume_playback": "Resume Playback",
"loop_track": "Loop track", "loop_track": "Loop track",
"no_loop": "No loop", "no_loop": "No loop",
"repeat_playlist": "Repeat playlist", "repeat_playlist": "Repeat playlist",
"queue": "Queue", "queue": "Queue",
"alternative_track_sources": "Alternative track sources", "alternative_track_sources": "Alternative track sources",
"download_track": "Download track", "download_track": "Download track",
"tracks_in_queue": "{tracks} tracks in queue", "tracks_in_queue": "{tracks} tracks in queue",
"clear_all": "Clear all", "clear_all": "Clear all",
"show_hide_ui_on_hover": "Show/Hide UI on hover", "show_hide_ui_on_hover": "Show/Hide UI on hover",
"always_on_top": "Always on top", "always_on_top": "Always on top",
"exit_mini_player": "Exit Mini player", "exit_mini_player": "Exit Mini player",
"download_location": "Download location", "download_location": "Download location",
"local_library": "Local library", "local_library": "Local library",
"add_library_location": "Add to library", "add_library_location": "Add to library",
"remove_library_location": "Remove from library", "remove_library_location": "Remove from library",
"account": "Account", "account": "Account",
"login_with_spotify": "Login with your Spotify account", "login_with_spotify": "Login with your Spotify account",
"connect_with_spotify": "Connect with Spotify", "connect_with_spotify": "Connect with Spotify",
"logout": "Logout", "logout": "Logout",
"logout_of_this_account": "Logout of this account", "logout_of_this_account": "Logout of this account",
"language_region": "Language & Region", "language_region": "Language & Region",
"language": "Language", "language": "Language",
"system_default": "System Default", "system_default": "System Default",
"market_place_region": "Marketplace Region", "market_place_region": "Marketplace Region",
"recommendation_country": "Recommendation Country", "recommendation_country": "Recommendation Country",
"appearance": "Appearance", "appearance": "Appearance",
"layout_mode": "Layout Mode", "layout_mode": "Layout Mode",
"override_layout_settings": "Override responsive layout mode settings", "override_layout_settings": "Override responsive layout mode settings",
"adaptive": "Adaptive", "adaptive": "Adaptive",
"compact": "Compact", "compact": "Compact",
"extended": "Extended", "extended": "Extended",
"theme": "Theme", "theme": "Theme",
"dark": "Dark", "dark": "Dark",
"light": "Light", "light": "Light",
"system": "System", "system": "System",
"accent_color": "Accent Color", "accent_color": "Accent Color",
"sync_album_color": "Sync album color", "sync_album_color": "Sync album color",
"sync_album_color_description": "Uses the dominant color of the album art as the accent color", "sync_album_color_description": "Uses the dominant color of the album art as the accent color",
"playback": "Playback", "playback": "Playback",
"audio_quality": "Audio Quality", "audio_quality": "Audio Quality",
"high": "High", "high": "High",
"low": "Low", "low": "Low",
"pre_download_play": "Pre-download and play", "pre_download_play": "Pre-download and play",
"pre_download_play_description": "Instead of streaming audio, download bytes and play instead (Recommended for higher bandwidth users)", "pre_download_play_description": "Instead of streaming audio, download bytes and play instead (Recommended for higher bandwidth users)",
"skip_non_music": "Skip non-music segments (SponsorBlock)", "skip_non_music": "Skip non-music segments (SponsorBlock)",
"blacklist_description": "Blacklisted tracks and artists", "blacklist_description": "Blacklisted tracks and artists",
"wait_for_download_to_finish": "Please wait for the current download to finish", "wait_for_download_to_finish": "Please wait for the current download to finish",
"desktop": "Desktop", "desktop": "Desktop",
"close_behavior": "Close Behavior", "close_behavior": "Close Behavior",
"close": "Close", "close": "Close",
"minimize_to_tray": "Minimize to tray", "minimize_to_tray": "Minimize to tray",
"show_tray_icon": "Show System tray icon", "show_tray_icon": "Show System tray icon",
"about": "About", "about": "About",
"u_love_spotube": "We know you love Spotube", "u_love_spotube": "We know you love Spotube",
"check_for_updates": "Check for updates", "check_for_updates": "Check for updates",
"about_spotube": "About Spotube", "about_spotube": "About Spotube",
"blacklist": "Blacklist", "blacklist": "Blacklist",
"please_sponsor": "Please Sponsor/Donate", "please_sponsor": "Please Sponsor/Donate",
"spotube_description": "Spotube, a lightweight, cross-platform, free-for-all spotify client", "spotube_description": "Spotube, a lightweight, cross-platform, free-for-all spotify client",
"version": "Version", "version": "Version",
"build_number": "Build Number", "build_number": "Build Number",
"founder": "Founder", "founder": "Founder",
"repository": "Repository", "repository": "Repository",
"bug_issues": "Bug+Issues", "bug_issues": "Bug+Issues",
"made_with": "Made with ❤️ in Bangladesh🇧🇩", "made_with": "Made with ❤️ in Bangladesh🇧🇩",
"kingkor_roy_tirtho": "Kingkor Roy Tirtho", "kingkor_roy_tirtho": "Kingkor Roy Tirtho",
"copyright": "© 2021-{current_year} Kingkor Roy Tirtho", "copyright": "© 2021-{current_year} Kingkor Roy Tirtho",
"license": "License", "license": "License",
"add_spotify_credentials": "Add your spotify credentials to get started", "add_spotify_credentials": "Add your spotify credentials to get started",
"credentials_will_not_be_shared_disclaimer": "Don't worry, any of your credentials won't be collected or shared with anyone", "credentials_will_not_be_shared_disclaimer": "Don't worry, any of your credentials won't be collected or shared with anyone",
"know_how_to_login": "Don't know how to do this?", "know_how_to_login": "Don't know how to do this?",
"follow_step_by_step_guide": "Follow along the Step by Step guide", "follow_step_by_step_guide": "Follow along the Step by Step guide",
"spotify_cookie": "Spotify {name} Cookie", "spotify_cookie": "Spotify {name} Cookie",
"cookie_name_cookie": "{name} Cookie", "cookie_name_cookie": "{name} Cookie",
"fill_in_all_fields": "Please fill in all the fields", "fill_in_all_fields": "Please fill in all the fields",
"submit": "Submit", "submit": "Submit",
"exit": "Exit", "exit": "Exit",
"previous": "Previous", "previous": "Previous",
"next": "Next", "next": "Next",
"done": "Done", "done": "Done",
"step_1": "Step 1", "step_1": "Step 1",
"first_go_to": "First, Go to", "first_go_to": "First, Go to",
"login_if_not_logged_in": "and Login/Signup if you are not logged in", "login_if_not_logged_in": "and Login/Signup if you are not logged in",
"step_2": "Step 2", "step_2": "Step 2",
"step_2_steps": "1. Once you're logged in, press F12 or Mouse Right Click > Inspect to Open the Browser devtools.\n2. Then go the \"Application\" Tab (Chrome, Edge, Brave etc..) or \"Storage\" Tab (Firefox, Palemoon etc..)\n3. Go to the \"Cookies\" section then the \"https://accounts.spotify.com\" subsection", "step_2_steps": "1. Once you're logged in, press F12 or Mouse Right Click > Inspect to Open the Browser devtools.\n2. Then go the \"Application\" Tab (Chrome, Edge, Brave etc..) or \"Storage\" Tab (Firefox, Palemoon etc..)\n3. Go to the \"Cookies\" section then the \"https://accounts.spotify.com\" subsection",
"step_3": "Step 3", "step_3": "Step 3",
"step_3_steps": "Copy the value of \"sp_dc\" Cookie", "step_3_steps": "Copy the value of \"sp_dc\" Cookie",
"success_emoji": "Success🥳", "success_emoji": "Success🥳",
"success_message": "Now you've successfully Logged in with your Spotify account. Good Job, mate!", "success_message": "Now you've successfully Logged in with your Spotify account. Good Job, mate!",
"step_4": "Step 4", "step_4": "Step 4",
"step_4_steps": "Paste the copied \"sp_dc\" value", "step_4_steps": "Paste the copied \"sp_dc\" value",
"something_went_wrong": "Something went wrong", "something_went_wrong": "Something went wrong",
"piped_instance": "Piped Server Instance", "piped_instance": "Piped Server Instance",
"piped_description": "The Piped server instance to use for track matching", "piped_description": "The Piped server instance to use for track matching",
"piped_warning": "Some of them might not work well. So use at your own risk", "piped_warning": "Some of them might not work well. So use at your own risk",
"invidious_instance": "Invidious Server Instance", "invidious_instance": "Invidious Server Instance",
"invidious_description": "The Invidious server instance to use for track matching", "invidious_description": "The Invidious server instance to use for track matching",
"invidious_warning": "Some of them might not work well. So use at your own risk", "invidious_warning": "Some of them might not work well. So use at your own risk",
"generate": "Generate", "generate": "Generate",
"track_exists": "Track {track} already exists", "track_exists": "Track {track} already exists",
"replace_downloaded_tracks": "Replace all downloaded tracks", "replace_downloaded_tracks": "Replace all downloaded tracks",
"skip_download_tracks": "Skip downloading all downloaded tracks", "skip_download_tracks": "Skip downloading all downloaded tracks",
"do_you_want_to_replace": "Do you want to replace the existing track??", "do_you_want_to_replace": "Do you want to replace the existing track??",
"replace": "Replace", "replace": "Replace",
"skip": "Skip", "skip": "Skip",
"select_up_to_count_type": "Select up to {count} {type}", "select_up_to_count_type": "Select up to {count} {type}",
"select_genres": "Select Genres", "select_genres": "Select Genres",
"add_genres": "Add Genres", "add_genres": "Add Genres",
"country": "Country", "country": "Country",
"number_of_tracks_generate": "Number of tracks to generate", "number_of_tracks_generate": "Number of tracks to generate",
"acousticness": "Acousticness", "acousticness": "Acousticness",
"danceability": "Danceability", "danceability": "Danceability",
"energy": "Energy", "energy": "Energy",
"instrumentalness": "Instrumentalness", "instrumentalness": "Instrumentalness",
"liveness": "Liveness", "liveness": "Liveness",
"loudness": "Loudness", "loudness": "Loudness",
"speechiness": "Speechiness", "speechiness": "Speechiness",
"valence": "Valence", "valence": "Valence",
"popularity": "Popularity", "popularity": "Popularity",
"key": "Key", "key": "Key",
"duration": "Duration (s)", "duration": "Duration (s)",
"tempo": "Tempo (BPM)", "tempo": "Tempo (BPM)",
"mode": "Mode", "mode": "Mode",
"time_signature": "Time Signature", "time_signature": "Time Signature",
"short": "Short", "short": "Short",
"medium": "Medium", "medium": "Medium",
"long": "Long", "long": "Long",
"min": "Min", "min": "Min",
"max": "Max", "max": "Max",
"target": "Target", "target": "Target",
"moderate": "Moderate", "moderate": "Moderate",
"deselect_all": "Deselect All", "deselect_all": "Deselect All",
"select_all": "Select All", "select_all": "Select All",
"are_you_sure": "Are you sure?", "are_you_sure": "Are you sure?",
"generating_playlist": "Generating your custom playlist...", "generating_playlist": "Generating your custom playlist...",
"selected_count_tracks": "Selected {count} tracks", "selected_count_tracks": "Selected {count} tracks",
"download_warning": "If you download all Tracks at bulk you're clearly pirating Music & causing damage to the creative society of Music. I hope you are aware of this. Always, try respecting & supporting Artist's hard work", "download_warning": "If you download all Tracks at bulk you're clearly pirating Music & causing damage to the creative society of Music. I hope you are aware of this. Always, try respecting & supporting Artist's hard work",
"download_ip_ban_warning": "BTW, your IP can get blocked on YouTube due excessive download requests than usual. IP block means you can't use YouTube (even if you're logged in) for at least 2-3 months from that IP device. And Spotube doesn't hold any responsibility if this ever happens", "download_ip_ban_warning": "BTW, your IP can get blocked on YouTube due excessive download requests than usual. IP block means you can't use YouTube (even if you're logged in) for at least 2-3 months from that IP device. And Spotube doesn't hold any responsibility if this ever happens",
"by_clicking_accept_terms": "By clicking 'accept' you agree to following terms:", "by_clicking_accept_terms": "By clicking 'accept' you agree to following terms:",
"download_agreement_1": "I know I'm pirating Music. I'm bad", "download_agreement_1": "I know I'm pirating Music. I'm bad",
"download_agreement_2": "I'll support the Artist wherever I can and I'm only doing this because I don't have money to buy their art", "download_agreement_2": "I'll support the Artist wherever I can and I'm only doing this because I don't have money to buy their art",
"download_agreement_3": "I'm completely aware that my IP can get blocked on YouTube & I don't hold Spotube or his owners/contributors responsible for any accidents caused by my current action", "download_agreement_3": "I'm completely aware that my IP can get blocked on YouTube & I don't hold Spotube or his owners/contributors responsible for any accidents caused by my current action",
"decline": "Decline", "decline": "Decline",
"accept": "Accept", "accept": "Accept",
"details": "Details", "details": "Details",
"youtube": "YouTube", "youtube": "YouTube",
"channel": "Channel", "channel": "Channel",
"likes": "Likes", "likes": "Likes",
"dislikes": "Dislikes", "dislikes": "Dislikes",
"views": "Views", "views": "Views",
"streamUrl": "Stream URL", "streamUrl": "Stream URL",
"stop": "Stop", "stop": "Stop",
"sort_newest": "Sort by newest added", "sort_newest": "Sort by newest added",
"sort_oldest": "Sort by oldest added", "sort_oldest": "Sort by oldest added",
"sleep_timer": "Sleep Timer", "sleep_timer": "Sleep Timer",
"mins": "{minutes} Minutes", "mins": "{minutes} Minutes",
"hours": "{hours} Hours", "hours": "{hours} Hours",
"hour": "{hours} Hour", "hour": "{hours} Hour",
"custom_hours": "Custom Hours", "custom_hours": "Custom Hours",
"logs": "Logs", "logs": "Logs",
"developers": "Developers", "developers": "Developers",
"not_logged_in": "You're not logged in", "not_logged_in": "You're not logged in",
"search_mode": "Search Mode", "search_mode": "Search Mode",
"audio_source": "Audio Source", "audio_source": "Audio Source",
"ok": "Ok", "ok": "Ok",
"failed_to_encrypt": "Failed to encrypt", "failed_to_encrypt": "Failed to encrypt",
"encryption_failed_warning": "Spotube uses encryption to securely store your data. But failed to do so. So it'll fallback to insecure storage\nIf you're using linux, please make sure you've any secret-service (gnome-keyring, kde-wallet, keepassxc etc) installed", "encryption_failed_warning": "Spotube uses encryption to securely store your data. But failed to do so. So it'll fallback to insecure storage\nIf you're using linux, please make sure you've any secret-service (gnome-keyring, kde-wallet, keepassxc etc) installed",
"querying_info": "Querying info...", "querying_info": "Querying info...",
"piped_api_down": "Piped API is down", "piped_api_down": "Piped API is down",
"piped_down_error_instructions": "The Piped instance {pipedInstance} is currently down\n\nEither change the instance or change the 'API type' to official YouTube API\n\nMake sure to restart the app after change", "piped_down_error_instructions": "The Piped instance {pipedInstance} is currently down\n\nEither change the instance or change the 'API type' to official YouTube API\n\nMake sure to restart the app after change",
"you_are_offline": "You are currently offline", "you_are_offline": "You are currently offline",
"connection_restored": "Your internet connection was restored", "connection_restored": "Your internet connection was restored",
"use_system_title_bar": "Use system title bar", "use_system_title_bar": "Use system title bar",
"crunching_results": "Crunching results...", "crunching_results": "Crunching results...",
"search_to_get_results": "Search to get results", "search_to_get_results": "Search to get results",
"use_amoled_mode": "Pitch black dark theme", "use_amoled_mode": "Pitch black dark theme",
"pitch_dark_theme": "AMOLED Mode", "pitch_dark_theme": "AMOLED Mode",
"normalize_audio": "Normalize audio", "normalize_audio": "Normalize audio",
"change_cover": "Change cover", "change_cover": "Change cover",
"add_cover": "Add cover", "add_cover": "Add cover",
"restore_defaults": "Restore defaults", "restore_defaults": "Restore defaults",
"download_music_codec": "Download music codec", "download_music_codec": "Download music codec",
"streaming_music_codec": "Streaming music codec", "streaming_music_codec": "Streaming music codec",
"login_with_lastfm": "Login with Last.fm", "login_with_lastfm": "Login with Last.fm",
"connect": "Connect", "connect": "Connect",
"disconnect_lastfm": "Disconnect Last.fm", "disconnect_lastfm": "Disconnect Last.fm",
"disconnect": "Disconnect", "disconnect": "Disconnect",
"username": "Username", "username": "Username",
"password": "Password", "password": "Password",
"login": "Login", "login": "Login",
"login_with_your_lastfm": "Login with your Last.fm account", "login_with_your_lastfm": "Login with your Last.fm account",
"scrobble_to_lastfm": "Scrobble to Last.fm", "scrobble_to_lastfm": "Scrobble to Last.fm",
"go_to_album": "Go to Album", "go_to_album": "Go to Album",
"discord_rich_presence": "Discord Rich Presence", "discord_rich_presence": "Discord Rich Presence",
"browse_all": "Browse All", "browse_all": "Browse All",
"genres": "Genres", "genres": "Genres",
"explore_genres": "Explore Genres", "explore_genres": "Explore Genres",
"friends": "Friends", "friends": "Friends",
"no_lyrics_available": "Sorry, unable find lyrics for this track", "no_lyrics_available": "Sorry, unable find lyrics for this track",
"start_a_radio": "Start a Radio", "start_a_radio": "Start a Radio",
"how_to_start_radio": "How do you want to start the radio?", "how_to_start_radio": "How do you want to start the radio?",
"replace_queue_question": "Do you want to replace the current queue or append to it?", "replace_queue_question": "Do you want to replace the current queue or append to it?",
"endless_playback": "Endless Playback", "endless_playback": "Endless Playback",
"delete_playlist": "Delete Playlist", "delete_playlist": "Delete Playlist",
"delete_playlist_confirmation": "Are you sure you want to delete this playlist?", "delete_playlist_confirmation": "Are you sure you want to delete this playlist?",
"local_tracks": "Local Tracks", "local_tracks": "Local Tracks",
"local_tab": "Local", "local_tab": "Local",
"song_link": "Song Link", "song_link": "Song Link",
"skip_this_nonsense": "Skip this nonsense", "skip_this_nonsense": "Skip this nonsense",
"freedom_of_music": "“Freedom of Music”", "freedom_of_music": "“Freedom of Music”",
"freedom_of_music_palm": "“Freedom of Music in the palm of your hand”", "freedom_of_music_palm": "“Freedom of Music in the palm of your hand”",
"get_started": "Let's get started", "get_started": "Let's get started",
"youtube_source_description": "Recommended and works best.", "youtube_source_description": "Recommended and works best.",
"piped_source_description": "Feeling free? Same as YouTube but a lot free.", "piped_source_description": "Feeling free? Same as YouTube but a lot free.",
"jiosaavn_source_description": "Best for South Asian region.", "jiosaavn_source_description": "Best for South Asian region.",
"invidious_source_description": "Similar to Piped but with higher availability.", "invidious_source_description": "Similar to Piped but with higher availability.",
"highest_quality": "Highest Quality: {quality}", "highest_quality": "Highest Quality: {quality}",
"select_audio_source": "Select Audio Source", "select_audio_source": "Select Audio Source",
"endless_playback_description": "Automatically append new songs\nto the end of the queue", "endless_playback_description": "Automatically append new songs\nto the end of the queue",
"choose_your_region": "Choose your region", "choose_your_region": "Choose your region",
"choose_your_region_description": "This will help Spotube show you the right content\nfor your location.", "choose_your_region_description": "This will help Spotube show you the right content\nfor your location.",
"choose_your_language": "Choose your language", "choose_your_language": "Choose your language",
"help_project_grow": "Help this project grow", "help_project_grow": "Help this project grow",
"help_project_grow_description": "Spotube is an open-source project. You can help this project grow by contributing to the project, reporting bugs, or suggesting new features.", "help_project_grow_description": "Spotube is an open-source project. You can help this project grow by contributing to the project, reporting bugs, or suggesting new features.",
"contribute_on_github": "Contribute on GitHub", "contribute_on_github": "Contribute on GitHub",
"donate_on_open_collective": "Donate on Open Collective", "donate_on_open_collective": "Donate on Open Collective",
"browse_anonymously": "Browse Anonymously", "browse_anonymously": "Browse Anonymously",
"enable_connect": "Enable Connect", "enable_connect": "Enable Connect",
"enable_connect_description": "Control Spotube from other devices", "enable_connect_description": "Control Spotube from other devices",
"devices": "Devices", "devices": "Devices",
"select": "Select", "select": "Select",
"connect_client_alert": "You're being controlled by {client}", "connect_client_alert": "You're being controlled by {client}",
"this_device": "This Device", "this_device": "This Device",
"remote": "Remote", "remote": "Remote",
"stats": "Stats", "stats": "Stats",
"and_n_more": "and {count} more", "and_n_more": "and {count} more",
"recently_played": "Recently Played", "recently_played": "Recently Played",
"browse_more": "Browse More", "browse_more": "Browse More",
"no_title": "No Title", "no_title": "No Title",
"not_playing": "Not playing", "not_playing": "Not playing",
"epic_failure": "Epic failure!", "epic_failure": "Epic failure!",
"added_num_tracks_to_queue": "Added {tracks_length} tracks to queue", "added_num_tracks_to_queue": "Added {tracks_length} tracks to queue",
"spotube_has_an_update": "Spotube has an update", "spotube_has_an_update": "Spotube has an update",
"download_now": "Download Now", "download_now": "Download Now",
"nightly_version": "Spotube Nightly {nightlyBuildNum} has been released", "nightly_version": "Spotube Nightly {nightlyBuildNum} has been released",
"release_version": "Spotube v{version} has been released", "release_version": "Spotube v{version} has been released",
"read_the_latest": "Read the latest ", "read_the_latest": "Read the latest ",
"release_notes": "release notes", "release_notes": "release notes",
"pick_color_scheme": "Pick color scheme", "pick_color_scheme": "Pick color scheme",
"save": "Save", "save": "Save",
"choose_the_device": "Choose the device:", "choose_the_device": "Choose the device:",
"multiple_device_connected": "There are multiple device connected.\nChoose the device you want this action to take place", "multiple_device_connected": "There are multiple device connected.\nChoose the device you want this action to take place",
"nothing_found": "Nothing found", "nothing_found": "Nothing found",
"the_box_is_empty": "The box is empty", "the_box_is_empty": "The box is empty",
"top_artists": "Top Artists", "top_artists": "Top Artists",
"top_albums": "Top Albums", "top_albums": "Top Albums",
"this_week": "This week", "this_week": "This week",
"this_month": "This month", "this_month": "This month",
"last_6_months": "Last 6 months", "last_6_months": "Last 6 months",
"this_year": "This year", "this_year": "This year",
"last_2_years": "Last 2 years", "last_2_years": "Last 2 years",
"all_time": "All time", "all_time": "All time",
"powered_by_provider": "Powered by {providerName}", "powered_by_provider": "Powered by {providerName}",
"email": "Email", "email": "Email",
"profile_followers": "Followers", "profile_followers": "Followers",
"birthday": "Birthday", "birthday": "Birthday",
"subscription": "Subscription", "subscription": "Subscription",
"not_born": "Not born", "not_born": "Not born",
"hacker": "Hacker", "hacker": "Hacker",
"profile": "Profile", "profile": "Profile",
"no_name": "No Name", "no_name": "No Name",
"edit": "Edit", "edit": "Edit",
"user_profile": "User Profile", "user_profile": "User Profile",
"count_plays": "{count} plays", "count_plays": "{count} plays",
"streaming_fees_hypothetical": "Streaming fees (hypothetical)", "streaming_fees_hypothetical": "Streaming fees (hypothetical)",
"minutes_listened": "Minutes listened", "minutes_listened": "Minutes listened",
"streamed_songs": "Streamed songs", "streamed_songs": "Streamed songs",
"count_streams": "{count} streams", "count_streams": "{count} streams",
"owned_by_you": "Owned by you", "owned_by_you": "Owned by you",
"copied_shareurl_to_clipboard": "Copied {shareUrl} to clipboard", "copied_shareurl_to_clipboard": "Copied {shareUrl} to clipboard",
"spotify_hipotetical_calculation": "*This is calculated based on Spotify's per stream\npayout of $0.003 to $0.005. This is a hypothetical\ncalculation to give user insight about how much they\nwould have paid to the artists if they were to listen\ntheir song in Spotify.", "spotify_hipotetical_calculation": "*This is calculated based on Spotify's per stream\npayout of $0.003 to $0.005. This is a hypothetical\ncalculation to give user insight about how much they\nwould have paid to the artists if they were to listen\ntheir song in Spotify.",
"count_mins": "{minutes} mins", "count_mins": "{minutes} mins",
"summary_minutes": "minutes", "summary_minutes": "minutes",
"summary_listened_to_music": "Listened to music", "summary_listened_to_music": "Listened to music",
"summary_songs": "songs", "summary_songs": "songs",
"summary_streamed_overall": "Streamed overall", "summary_streamed_overall": "Streamed overall",
"summary_owed_to_artists": "Owed to artists\nthis month", "summary_owed_to_artists": "Owed to artists\nthis month",
"summary_artists": "artist's", "summary_artists": "artist's",
"summary_music_reached_you": "Music reached you", "summary_music_reached_you": "Music reached you",
"summary_full_albums": "full albums", "summary_full_albums": "full albums",
"summary_got_your_love": "Got your love", "summary_got_your_love": "Got your love",
"summary_playlists": "playlists", "summary_playlists": "playlists",
"summary_were_on_repeat": "Were on repeat", "summary_were_on_repeat": "Were on repeat",
"total_money": "Total {money}", "total_money": "Total {money}",
"webview_not_found": "Webview not found", "webview_not_found": "Webview not found",
"webview_not_found_description": "No webview runtime is installed in your device.\nIf it's installed make sure it's in the Environment PATH\n\nAfter installing, restart the app", "webview_not_found_description": "No webview runtime is installed in your device.\nIf it's installed make sure it's in the Environment PATH\n\nAfter installing, restart the app",
"unsupported_platform": "Unsupported platform", "unsupported_platform": "Unsupported platform",
"cache_music": "Cache music", "cache_music": "Cache music",
"open": "Open", "open": "Open",
"cache_folder": "Cache folder", "cache_folder": "Cache folder",
"export": "Export", "export": "Export",
"clear_cache": "Clear cache", "clear_cache": "Clear cache",
"clear_cache_confirmation": "Do you want to clear the cache?", "clear_cache_confirmation": "Do you want to clear the cache?",
"export_cache_files": "Export Cached Files", "export_cache_files": "Export Cached Files",
"found_n_files": "Found {count} files", "found_n_files": "Found {count} files",
"export_cache_confirmation": "Do you want to export these files to", "export_cache_confirmation": "Do you want to export these files to",
"exported_n_out_of_m_files": "Exported {filesExported} out of {files} files", "exported_n_out_of_m_files": "Exported {filesExported} out of {files} files",
"undo": "Undo", "undo": "Undo",
"download_all": "Download all", "download_all": "Download all",
"add_all_to_playlist": "Add all to playlist", "add_all_to_playlist": "Add all to playlist",
"add_all_to_queue": "Add all to queue", "add_all_to_queue": "Add all to queue",
"play_all_next": "Play all next", "play_all_next": "Play all next",
"pause": "Pause", "pause": "Pause",
"view_all": "View all", "view_all": "View all",
"no_tracks_added_yet": "Looks like you haven't added any tracks yet", "no_tracks_added_yet": "Looks like you haven't added any tracks yet",
"no_tracks": "Looks like there are no tracks here", "no_tracks": "Looks like there are no tracks here",
"no_tracks_listened_yet": "Looks like you haven't listened to anything yet", "no_tracks_listened_yet": "Looks like you haven't listened to anything yet",
"not_following_artists": "You're not following any artists", "not_following_artists": "You're not following any artists",
"no_favorite_albums_yet": "Looks like you haven't added any albums to your favorites yet", "no_favorite_albums_yet": "Looks like you haven't added any albums to your favorites yet",
"no_logs_found": "No logs found", "no_logs_found": "No logs found",
"youtube_engine": "YouTube Engine", "youtube_engine": "YouTube Engine",
"youtube_engine_not_installed_title": "{engine} is not installed", "youtube_engine_not_installed_title": "{engine} is not installed",
"youtube_engine_not_installed_message": "{engine} is not installed in your system.", "youtube_engine_not_installed_message": "{engine} is not installed in your system.",
"youtube_engine_set_path": "Make sure it's available in the PATH variable or\nset the absolute path to the {engine} executable below", "youtube_engine_set_path": "Make sure it's available in the PATH variable or\nset the absolute path to the {engine} executable below",
"youtube_engine_unix_issue_message": "In macOS/Linux/unix like OS's, setting path on .zshrc/.bashrc/.bash_profile etc. won't work.\nYou need to set the path in the shell configuration file", "youtube_engine_unix_issue_message": "In macOS/Linux/unix like OS's, setting path on .zshrc/.bashrc/.bash_profile etc. won't work.\nYou need to set the path in the shell configuration file",
"download": "Download", "download": "Download",
"file_not_found": "File not found" "file_not_found": "File not found",
"custom": "Custom",
"add_custom_url": "Add custom URL"
} }

View File

@ -4,6 +4,9 @@ import 'package:auto_route/auto_route.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart' show ListTile; import 'package:flutter/material.dart' show ListTile;
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@ -11,6 +14,8 @@ import 'package:piped_client/piped_client.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/form/text_form_field.dart';
import 'package:spotube/hooks/controllers/use_shadcn_text_editing_controller.dart';
import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/database/database.dart';
import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart';
import 'package:spotube/components/adaptive/adaptive_select_tile.dart'; import 'package:spotube/components/adaptive/adaptive_select_tile.dart';
@ -97,32 +102,127 @@ class SettingsPlaybackSection extends HookConsumerWidget {
), ),
value: preferences.pipedInstance, value: preferences.pipedInstance,
showValueWhenUnfolded: false, showValueWhenUnfolded: false,
options: data trailing: [
.sortedBy((e) => e.name) Tooltip(
.map( tooltip: TooltipContainer(
(e) => SelectItemButton( child: Text(context.l10n.add_custom_url),
value: e.apiUrl, ),
child: RichText( child: IconButton.outline(
text: TextSpan( icon: const Icon(SpotubeIcons.edit),
style: theme.typography.normal.copyWith( size: ButtonSize.small,
color: theme.colorScheme.foreground, onPressed: () {
), showDialog(
children: [ context: context,
TextSpan( barrierColor: Colors.black.withValues(alpha: 0.5),
text: "${e.name.trim()}\n", builder: (context) => HookBuilder(
), builder: (context) {
TextSpan( final controller =
text: e.locations useShadcnTextEditingController(
.map(countryCodeToEmoji) text: preferences.pipedInstance,
.join(""), );
style: GoogleFonts.notoColorEmoji(), final formKey = useMemoized(
), () => GlobalKey<FormBuilderState>(), []);
],
return Alert(
title:
Text(context.l10n.piped_instance).h4(),
content: FormBuilder(
key: formKey,
child: Column(
children: [
const Gap(10),
TextFormBuilderField(
name: "url",
controller: controller,
placeholder: Text(
context.l10n.piped_instance),
validator:
FormBuilderValidators.url(),
),
const Gap(10),
Row(
children: [
Expanded(
child: Button.secondary(
onPressed: () {
Navigator.of(context).pop();
},
child:
Text(context.l10n.cancel),
),
),
const Gap(10),
Expanded(
child: Button.primary(
onPressed: () {
if (!formKey.currentState!
.saveAndValidate()) {
return;
}
preferencesNotifier
.setPipedInstance(
controller.text,
);
Navigator.of(context).pop();
},
child:
Text(context.l10n.save),
),
),
],
)
],
),
),
);
},
), ),
);
},
),
)
],
options: [
if (data
.none((e) => e.apiUrl == preferences.pipedInstance))
SelectItemButton(
value: preferences.pipedInstance,
child: Text.rich(
TextSpan(
style: theme.typography.xSmall.copyWith(
color: theme.colorScheme.foreground,
),
children: [
TextSpan(text: context.l10n.custom),
const TextSpan(text: "\n"),
TextSpan(text: preferences.pipedInstance),
],
), ),
), ),
) ),
.toList(), for (final e in data.sortedBy((e) => e.name))
SelectItemButton(
value: e.apiUrl,
child: RichText(
text: TextSpan(
style: theme.typography.normal.copyWith(
color: theme.colorScheme.foreground,
),
children: [
TextSpan(
text: "${e.name.trim()}\n",
),
TextSpan(
text: e.locations
.map(countryCodeToEmoji)
.join(""),
style: GoogleFonts.notoColorEmoji(),
),
],
),
),
),
],
onChanged: (value) { onChanged: (value) {
if (value != null) { if (value != null) {
preferencesNotifier.setPipedInstance(value); preferencesNotifier.setPipedInstance(value);
@ -157,34 +257,129 @@ class SettingsPlaybackSection extends HookConsumerWidget {
"${context.l10n.invidious_description}\n" "${context.l10n.invidious_description}\n"
"${context.l10n.invidious_warning}", "${context.l10n.invidious_warning}",
), ),
trailing: [
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.add_custom_url),
),
child: IconButton.outline(
icon: const Icon(SpotubeIcons.edit),
size: ButtonSize.small,
onPressed: () {
showDialog(
context: context,
barrierColor: Colors.black.withValues(alpha: 0.5),
builder: (context) => HookBuilder(
builder: (context) {
final controller =
useShadcnTextEditingController(
text: preferences.invidiousInstance,
);
final formKey = useMemoized(
() => GlobalKey<FormBuilderState>(), []);
return Alert(
title: Text(context.l10n.invidious_instance)
.h4(),
content: FormBuilder(
key: formKey,
child: Column(
children: [
const Gap(10),
TextFormBuilderField(
name: "url",
controller: controller,
placeholder: Text(context
.l10n.invidious_instance),
validator:
FormBuilderValidators.url(),
),
const Gap(10),
Row(
children: [
Expanded(
child: Button.secondary(
onPressed: () {
Navigator.of(context).pop();
},
child:
Text(context.l10n.cancel),
),
),
const Gap(10),
Expanded(
child: Button.primary(
onPressed: () {
if (!formKey.currentState!
.saveAndValidate()) {
return;
}
preferencesNotifier
.setInvidiousInstance(
controller.text,
);
Navigator.of(context).pop();
},
child:
Text(context.l10n.save),
),
),
],
)
],
),
),
);
},
),
);
},
),
)
],
value: preferences.invidiousInstance, value: preferences.invidiousInstance,
showValueWhenUnfolded: false, showValueWhenUnfolded: false,
options: data options: [
.sortedBy((e) => e.name) if (data.none((e) =>
.map( e.details.uri == preferences.invidiousInstance))
(e) => SelectItemButton( SelectItemButton(
value: e.details.uri, value: preferences.invidiousInstance,
child: RichText( child: Text.rich(
text: TextSpan( TextSpan(
style: theme.typography.normal.copyWith( style: theme.typography.xSmall.copyWith(
color: theme.colorScheme.foreground, color: theme.colorScheme.foreground,
),
children: [
TextSpan(
text: "${e.name.trim()}\n",
),
TextSpan(
text: countryCodeToEmoji(
e.details.region,
),
style: GoogleFonts.notoColorEmoji(),
),
],
), ),
children: [
TextSpan(text: context.l10n.custom),
const TextSpan(text: "\n"),
TextSpan(text: preferences.invidiousInstance),
],
), ),
), ),
) ),
.toList(), for (final e in data.sortedBy((e) => e.name))
SelectItemButton(
value: e.details.uri,
child: RichText(
text: TextSpan(
style: theme.typography.normal.copyWith(
color: theme.colorScheme.foreground,
),
children: [
TextSpan(
text: "${e.name.trim()}\n",
),
TextSpan(
text: countryCodeToEmoji(
e.details.region,
),
style: GoogleFonts.notoColorEmoji(),
),
],
),
),
),
],
onChanged: (value) { onChanged: (value) {
if (value != null) { if (value != null) {
preferencesNotifier.setInvidiousInstance(value); preferencesNotifier.setInvidiousInstance(value);

View File

@ -22,7 +22,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"bn": [ "bn": [
@ -48,7 +50,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"ca": [ "ca": [
@ -74,7 +78,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"cs": [ "cs": [
@ -100,7 +106,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"de": [ "de": [
@ -126,7 +134,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"es": [ "es": [
@ -152,7 +162,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"eu": [ "eu": [
@ -178,7 +190,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"fa": [ "fa": [
@ -204,7 +218,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"fi": [ "fi": [
@ -230,7 +246,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"fr": [ "fr": [
@ -256,7 +274,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"hi": [ "hi": [
@ -282,7 +302,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"id": [ "id": [
@ -308,7 +330,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"it": [ "it": [
@ -334,7 +358,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"ja": [ "ja": [
@ -360,7 +386,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"ka": [ "ka": [
@ -386,7 +414,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"ko": [ "ko": [
@ -412,7 +442,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"ne": [ "ne": [
@ -438,7 +470,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"nl": [ "nl": [
@ -464,7 +498,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"pl": [ "pl": [
@ -490,7 +526,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"pt": [ "pt": [
@ -516,7 +554,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"ru": [ "ru": [
@ -542,7 +582,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"th": [ "th": [
@ -568,7 +610,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"tr": [ "tr": [
@ -594,7 +638,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"uk": [ "uk": [
@ -620,7 +666,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"vi": [ "vi": [
@ -646,7 +694,9 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
], ],
"zh": [ "zh": [
@ -672,6 +722,8 @@
"youtube_engine_set_path", "youtube_engine_set_path",
"youtube_engine_unix_issue_message", "youtube_engine_unix_issue_message",
"download", "download",
"file_not_found" "file_not_found",
"custom",
"add_custom_url"
] ]
} }