Fixed crash when trying to open a downloaded file without a player

This commit is contained in:
Somethingweirdhere 2018-04-17 19:19:12 +02:00 committed by GitHub
parent 696c94050d
commit 15b4a7d055
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 852 additions and 0 deletions

381
MissionAdapter.java Normal file
View File

@ -0,0 +1,381 @@
package us.shandian.giga.ui.adapter;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.support.v4.content.FileProvider;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.MimeTypeMap;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.R;
import java.io.File;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import us.shandian.giga.get.DownloadManager;
import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.ui.common.ProgressDrawable;
import us.shandian.giga.util.Utility;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHolder> {
private static final Map<Integer, String> ALGORITHMS = new HashMap<>();
private static final String TAG = "MissionAdapter";
static {
ALGORITHMS.put(R.id.md5, "MD5");
ALGORITHMS.put(R.id.sha1, "SHA1");
}
private Context mContext;
private LayoutInflater mInflater;
private DownloadManager mManager;
private DownloadManagerService.DMBinder mBinder;
private int mLayout;
public MissionAdapter(Context context, DownloadManagerService.DMBinder binder, DownloadManager manager, boolean isLinear) {
mContext = context;
mManager = manager;
mBinder = binder;
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mLayout = isLinear ? R.layout.mission_item_linear : R.layout.mission_item;
}
@Override
public MissionAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ViewHolder h = new ViewHolder(mInflater.inflate(mLayout, parent, false));
h.menu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buildPopup(h);
}
});
/*h.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDetail(h);
}
});*/
return h;
}
@Override
public void onViewRecycled(MissionAdapter.ViewHolder h) {
super.onViewRecycled(h);
h.mission.removeListener(h.observer);
h.mission = null;
h.observer = null;
h.progress = null;
h.position = -1;
h.lastTimeStamp = -1;
h.lastDone = -1;
h.colorId = 0;
}
@Override
public void onBindViewHolder(MissionAdapter.ViewHolder h, int pos) {
DownloadMission ms = mManager.getMission(pos);
h.mission = ms;
h.position = pos;
Utility.FileType type = Utility.getFileType(ms.name);
h.icon.setImageResource(Utility.getIconForFileType(type));
h.name.setText(ms.name);
h.size.setText(Utility.formatBytes(ms.length));
h.progress = new ProgressDrawable(mContext, Utility.getBackgroundForFileType(type), Utility.getForegroundForFileType(type));
ViewCompat.setBackground(h.bkg, h.progress);
h.observer = new MissionObserver(this, h);
ms.addListener(h.observer);
updateProgress(h);
}
@Override
public int getItemCount() {
return mManager.getCount();
}
@Override
public long getItemId(int position) {
return position;
}
private void updateProgress(ViewHolder h) {
updateProgress(h, false);
}
private void updateProgress(ViewHolder h, boolean finished) {
if (h.mission == null) return;
long now = System.currentTimeMillis();
if (h.lastTimeStamp == -1) {
h.lastTimeStamp = now;
}
if (h.lastDone == -1) {
h.lastDone = h.mission.done;
}
long deltaTime = now - h.lastTimeStamp;
long deltaDone = h.mission.done - h.lastDone;
if (deltaTime == 0 || deltaTime > 1000 || finished) {
if (h.mission.errCode > 0) {
h.status.setText(R.string.msg_error);
} else {
float progress = (float) h.mission.done / h.mission.length;
h.status.setText(String.format(Locale.US, "%.2f%%", progress * 100));
h.progress.setProgress(progress);
}
}
if (deltaTime > 1000 && deltaDone > 0) {
float speed = (float) deltaDone / deltaTime;
String speedStr = Utility.formatSpeed(speed * 1000);
String sizeStr = Utility.formatBytes(h.mission.length);
h.size.setText(sizeStr + " " + speedStr);
h.lastTimeStamp = now;
h.lastDone = h.mission.done;
}
}
private void buildPopup(final ViewHolder h) {
PopupMenu popup = new PopupMenu(mContext, h.menu);
popup.inflate(R.menu.mission);
Menu menu = popup.getMenu();
MenuItem start = menu.findItem(R.id.start);
MenuItem pause = menu.findItem(R.id.pause);
MenuItem view = menu.findItem(R.id.view);
MenuItem delete = menu.findItem(R.id.delete);
MenuItem checksum = menu.findItem(R.id.checksum);
// Set to false first
start.setVisible(false);
pause.setVisible(false);
view.setVisible(false);
delete.setVisible(false);
checksum.setVisible(false);
if (!h.mission.finished) {
if (!h.mission.running) {
if (h.mission.errCode == -1) {
start.setVisible(true);
}
delete.setVisible(true);
} else {
pause.setVisible(true);
}
} else {
view.setVisible(true);
delete.setVisible(true);
checksum.setVisible(true);
}
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.start:
mManager.resumeMission(h.position);
mBinder.onMissionAdded(mManager.getMission(h.position));
return true;
case R.id.pause:
mManager.pauseMission(h.position);
mBinder.onMissionRemoved(mManager.getMission(h.position));
h.lastTimeStamp = -1;
h.lastDone = -1;
return true;
case R.id.view:
File f = new File(h.mission.location, h.mission.name);
String ext = Utility.getFileExt(h.mission.name);
Log.d(TAG, "Viewing file: " + f.getAbsolutePath() + " ext: " + ext);
if (ext == null) {
Log.w(TAG, "Can't view file because it has no extension: " +
h.mission.name);
return false;
}
String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1));
Log.v(TAG, "Mime: " + mime + " package: " + mContext.getApplicationContext().getPackageName() + ".provider");
if (f.exists()) {
viewFileWithFileProvider(f, mime);
} else {
Log.w(TAG, "File doesn't exist");
}
return true;
case R.id.delete:
mManager.deleteMission(h.position);
notifyDataSetChanged();
return true;
case R.id.md5:
case R.id.sha1:
DownloadMission mission = mManager.getMission(h.position);
new ChecksumTask().execute(mission.location + "/" + mission.name, ALGORITHMS.get(id));
return true;
default:
return false;
}
}
});
popup.show();
}
private void viewFile(File file, String mimetype) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), mimetype);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION);
}
//mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.v(TAG, "Starting intent: " + intent);
mContext.startActivity(intent);
}
private void viewFileWithFileProvider(File file, String mimetype) {
String ourPackage = mContext.getApplicationContext().getPackageName();
Uri uri = FileProvider.getUriForFile(mContext, ourPackage + ".provider", file);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(uri, mimetype);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION);
}
//mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.v(TAG, "Starting intent: " + intent);
if (intent.resolveActivity(mContext.getPackageManager()) != null) {
mContext.startActivity(intent);
} else {
Toast noPlayerToast = Toast.makeText(mContext, R.string.toast_no_player, Toast.LENGTH_LONG);
noPlayerToast.show();
}
}
static class ViewHolder extends RecyclerView.ViewHolder {
public DownloadMission mission;
public int position;
public TextView status;
public ImageView icon;
public TextView name;
public TextView size;
public View bkg;
public ImageView menu;
public ProgressDrawable progress;
public MissionObserver observer;
public long lastTimeStamp = -1;
public long lastDone = -1;
public int colorId;
public ViewHolder(View v) {
super(v);
status = v.findViewById(R.id.item_status);
icon = v.findViewById(R.id.item_icon);
name = v.findViewById(R.id.item_name);
size = v.findViewById(R.id.item_size);
bkg = v.findViewById(R.id.item_bkg);
menu = v.findViewById(R.id.item_more);
}
}
static class MissionObserver implements DownloadMission.MissionListener {
private MissionAdapter mAdapter;
private ViewHolder mHolder;
public MissionObserver(MissionAdapter adapter, ViewHolder holder) {
mAdapter = adapter;
mHolder = holder;
}
@Override
public void onProgressUpdate(DownloadMission downloadMission, long done, long total) {
mAdapter.updateProgress(mHolder);
}
@Override
public void onFinish(DownloadMission downloadMission) {
//mAdapter.mManager.deleteMission(mHolder.position);
// TODO Notification
//mAdapter.notifyDataSetChanged();
if (mHolder.mission != null) {
mHolder.size.setText(Utility.formatBytes(mHolder.mission.length));
mAdapter.updateProgress(mHolder, true);
}
}
@Override
public void onError(DownloadMission downloadMission, int errCode) {
mAdapter.updateProgress(mHolder);
}
}
private class ChecksumTask extends AsyncTask<String, Void, String> {
ProgressDialog prog;
@Override
protected void onPreExecute() {
super.onPreExecute();
// Create dialog
prog = new ProgressDialog(mContext);
prog.setCancelable(false);
prog.setMessage(mContext.getString(R.string.msg_wait));
prog.show();
}
@Override
protected String doInBackground(String... params) {
return Utility.checksum(params[0], params[1]);
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
prog.dismiss();
Utility.copyToClipboard(mContext, result);
}
}
}

471
strings.xml Normal file
View File

@ -0,0 +1,471 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name" translatable="false">NewPipe</string>
<string name="main_bg_subtitle">Tap search to get started</string>
<string name="view_count_text">%1$s views</string>
<string name="upload_date_text">Published on %1$s</string>
<string name="no_player_found">No stream player found. Do you want to install VLC?</string>
<string name="no_player_found_toast">No stream player found (you can install VLC to play it)</string>
<string name="install">Install</string>
<string name="cancel">Cancel</string>
<string name="fdroid_vlc_url" translatable="false">https://f-droid.org/repository/browse/?fdfilter=vlc&amp;fdid=org.videolan.vlc</string>
<string name="open_in_browser">Open in browser</string>
<string name="open_in_popup_mode">Open in popup mode</string>
<string name="share">Share</string>
<string name="download">Download</string>
<string name="controls_download_desc">Download stream file.</string>
<string name="search">Search</string>
<string name="settings">Settings</string>
<string name="did_you_mean">Did you mean: %1$s ?</string>
<string name="share_dialog_title">Share with</string>
<string name="choose_browser">Choose browser</string>
<string name="screen_rotation">rotation</string>
<string name="use_external_video_player_title">Use external video player</string>
<string name="use_external_video_player_summary">Some resolutions will NOT have audio when this option is enabled</string>
<string name="use_external_audio_player_title">Use external audio player</string>
<string name="popup_mode_share_menu_title">NewPipe popup mode</string>
<string name="rss_button_title" translatable="false">RSS</string>
<string name="subscribe_button_title">Subscribe</string>
<string name="subscribed_button_title">Subscribed</string>
<string name="channel_unsubscribed">Channel unsubscribed</string>
<string name="subscription_change_failed">Unable to change subscription</string>
<string name="subscription_update_failed">Unable to update subscription</string>
<string name="show_info">Show info</string>
<string name="tab_main">Main</string>
<string name="tab_subscriptions">Subscriptions</string>
<string name="tab_bookmarks">Bookmarks</string>
<string name="fragment_whats_new">What\'s New</string>
<string name="controls_background_title">Background</string>
<string name="controls_popup_title">Popup</string>
<string name="controls_add_to_playlist_title">Add To</string>
<string name="download_path_title">Video download path</string>
<string name="download_path_summary">Path to store downloaded videos in</string>
<string name="download_path_dialog_title">Enter download path for videos</string>
<string name="download_path_audio_title">Audio download path</string>
<string name="download_path_audio_summary">Path to store downloaded audio in</string>
<string name="download_path_audio_dialog_title">Enter download path for audio files</string>
<string name="autoplay_by_calling_app_title">Autoplay</string>
<string name="autoplay_by_calling_app_summary">Automatically plays a video when NewPipe is called from another app</string>
<string name="default_resolution_title">Default resolution</string>
<string name="default_popup_resolution_title">Default popup resolution</string>
<string name="show_higher_resolutions_title">Show higher resolutions</string>
<string name="show_higher_resolutions_summary">Only some devices support playing 2K/4K videos</string>
<string name="play_with_kodi_title">Play with Kodi</string>
<string name="kore_not_found">Kore app not found. Install it?</string>
<string name="kore_package" translatable="false">org.xbmc.kore</string>
<string name="show_play_with_kodi_title">Show \"Play with Kodi\" option</string>
<string name="show_play_with_kodi_summary">Display an option to play a video via Kodi media center</string>
<string name="play_audio">Audio</string>
<string name="default_audio_format_title">Default audio format</string>
<string name="default_video_format_title">Default video format</string>
<string name="webm_description">WebM — free format</string>
<string name="m4a_description">M4A — better quality</string>
<string name="theme_title">Theme</string>
<string name="light_theme_title">Light</string>
<string name="dark_theme_title">Dark</string>
<string name="black_theme_title">Black</string>
<string name="popup_remember_size_pos_title">Remember popup size and position</string>
<string name="popup_remember_size_pos_summary">Remember last size and position of popup</string>
<string name="use_inexact_seek_title">Use fast inexact seek</string>
<string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision</string>
<string name="download_thumbnail_title">Load thumbnails</string>
<string name="download_thumbnail_summary">Disable to stop all thumbnails from loading and save on data and memory usage. Changing this will clear both in-memory and on-disk image cache.</string>
<string name="thumbnail_cache_wipe_complete_notice">Image cache wiped</string>
<string name="metadata_cache_wipe_title">Wipe cached metadata</string>
<string name="metadata_cache_wipe_summary">Remove all cached webpage data</string>
<string name="metadata_cache_wipe_complete_notice">Metadata cache wiped</string>
<string name="auto_queue_title">Auto-queue next stream</string>
<string name="auto_queue_summary">Automatically append a related stream when playback starts on the last stream in a non-repeating play queue.</string>
<string name="player_gesture_controls_title">Player gesture controls</string>
<string name="player_gesture_controls_summary">Use gestures to control the brightness and volume of the player</string>
<string name="show_search_suggestions_title">Search suggestions</string>
<string name="show_search_suggestions_summary">Show suggestions when searching</string>
<string name="enable_search_history_title">Search history</string>
<string name="enable_search_history_summary">Store search queries locally</string>
<string name="enable_watch_history_title">History</string>
<string name="enable_watch_history_summary">Keep track of watched videos</string>
<string name="resume_on_audio_focus_gain_title">Resume on focus gain</string>
<string name="resume_on_audio_focus_gain_summary">Continue playing after interruptions (e.g. phone calls)</string>
<string name="download_dialog_title">Download</string>
<string name="next_video_title">Next video</string>
<string name="show_next_and_similar_title">Show next and similar videos</string>
<string name="show_hold_to_append_title">Show hold to append tip</string>
<string name="show_hold_to_append_summary">Show tip when background or popup button is pressed on video details page</string>
<string name="url_not_supported_toast">URL not supported</string>
<string name="default_content_country_title">Default content country</string>
<string name="service_title">Service</string>
<string name="search_language_title">Default content language</string>
<string name="settings_category_player_title">Player</string>
<string name="settings_category_player_behavior_title">Behavior</string>
<string name="settings_category_video_audio_title">Video &amp; Audio</string>
<string name="settings_category_history_title">History &amp; Cache</string>
<string name="settings_category_popup_title">Popup</string>
<string name="settings_category_appearance_title">Appearance</string>
<string name="settings_category_other_title">Other</string>
<string name="settings_category_debug_title">Debug</string>
<string name="background_player_playing_toast">Playing in background</string>
<string name="popup_playing_toast">Playing in popup mode</string>
<string name="background_player_append">Queued on background player</string>
<string name="popup_playing_append">Queued on popup player</string>
<string name="c3s_url" translatable="false">https://www.c3s.cc/</string>
<string name="play_btn_text">Play</string>
<string name="content">Content</string>
<string name="show_age_restricted_content_title">Show age restricted content</string>
<string name="video_is_age_restricted">Age Restricted Video. Allowing such material is possible from Settings.</string>
<string name="duration_live">live</string>
<string name="duration_live_button" translatable="false">LIVE</string>
<string name="downloads">Downloads</string>
<string name="downloads_title">Downloads</string>
<string name="error_report_title">Error report</string>
<string name="all">All</string>
<string name="channel">Channel</string>
<string name="playlist">Playlist</string>
<string name="yes">Yes</string>
<string name="later">Later</string>
<string name="disabled">Disabled</string>
<string name="filter">Filter</string>
<string name="refresh">Refresh</string>
<string name="clear">Clear</string>
<string name="popup_resizing_indicator_title">Resizing</string>
<string name="best_resolution">Best resolution</string>
<string name="undo">Undo</string>
<string name="play_all">Play All</string>
<string name="always">Always</string>
<string name="just_once">Just Once</string>
<string name="file">File</string>
<string name="notification_channel_id" translatable="false">newpipe</string>
<string name="notification_channel_name">NewPipe Notification</string>
<string name="notification_channel_description">Notifications for NewPipe Background and Popup Players</string>
<string name="unknown_content">[Unknown]</string>
<string name="toggle_orientation">Toggle Orientation</string>
<string name="switch_to_background">Switch to Background</string>
<string name="switch_to_popup">Switch to Popup</string>
<string name="switch_to_main">Switch to Main</string>
<string name="import_data_title">Import database</string>
<string name="export_data_title">Export database</string>
<string name="import_data_summary">Will override your current history and subscriptions</string>
<string name="export_data_summary">Export history, subscriptions and playlists.</string>
<!-- error strings -->
<string name="general_error">Error</string>
<string name="network_error">Network error</string>
<string name="could_not_load_thumbnails">Could not load all thumbnails</string>
<string name="youtube_signature_decryption_error">Could not decrypt video URL signature</string>
<string name="parsing_error">Could not parse website</string>
<string name="light_parsing_error">Could not parse website completely</string>
<string name="content_not_available">Content not available</string>
<string name="blocked_by_gema">Blocked by GEMA</string>
<string name="could_not_setup_download_menu">Could not set up download menu</string>
<string name="live_streams_not_supported">This is a LIVE STREAM, which is not yet supported.</string>
<string name="could_not_get_stream">Could not get any stream</string>
<string name="could_not_load_image">Could not load image</string>
<string name="app_ui_crash">App/UI crashed</string>
<string name="player_stream_failure">Failed to play this stream</string>
<string name="player_unrecoverable_failure">Unrecoverable player error occurred</string>
<string name="player_recoverable_failure">Recovering from player error</string>
<string name="external_player_unsupported_link_type">External players don\'t support these types of links</string>
<string name="invalid_url_toast">Invalid URL</string>
<string name="video_streams_empty">No video streams found</string>
<string name="audio_streams_empty">No audio streams found</string>
<string name="invalid_directory">Invalid directory</string>
<string name="invalid_source">Invalid file/content source</string>
<string name="invalid_file">File doesn\'t exist or insufficient permission to read or write to it</string>
<string name="file_name_empty_error">File name cannot be empty</string>
<string name="error_occurred_detail">An error occurred: %1$s</string>
<string name="no_streams_available_download">No streams available to download</string>
<!-- error activity -->
<string name="sorry_string">Sorry, that should not have happened.</string>
<string name="guru_meditation" translatable="false">Guru Meditation.</string>
<string name="error_report_button_text">Report error via e-mail</string>
<string name="error_snackbar_message">Sorry, some errors occurred.</string>
<string name="error_snackbar_action">REPORT</string>
<string name="what_device_headline">Info:</string>
<string name="what_happened_headline">What happened:</string>
<string name="info_labels">What:\\nRequest:\\nContent Lang:\\nService:\\nGMT Time:\\nPackage:\\nVersion:\\nOS version:</string>
<string name="your_comment">Your comment (in English):</string>
<string name="error_details_headline">Details:</string>
<!-- Content descriptions (for better accessibility) -->
<string name="list_thumbnail_view_description">Video preview thumbnail</string>
<string name="detail_thumbnail_view_description">Video preview thumbnail</string>
<string name="detail_uploader_thumbnail_view_description">Uploader\'s avatar thumbnail</string>
<string name="detail_likes_img_view_description">Likes</string>
<string name="detail_dislikes_img_view_description">Dislikes</string>
<string name="use_tor_title">Use Tor</string>
<string name="use_tor_summary">(Experimental) Force download traffic through Tor for increased privacy (streaming videos not yet supported).</string>
<string name="report_error">Report an Error</string>
<string name="user_report">User report</string>
<string name="search_no_results">No results</string>
<string name="empty_view_no_videos" translatable="false">@string/no_videos</string>
<string name="empty_subscription_feed_subtitle">Nothing Here But Crickets</string>
<string name="detail_drag_description">Drag to reorder</string>
<string name="err_dir_create">Cannot create download directory \'%1$s\'</string>
<string name="info_dir_created">Created download directory \'%1$s\'</string>
<string name="video">Video</string>
<string name="audio">Audio</string>
<string name="retry">Retry</string>
<string name="storage_permission_denied">Storage access permission denied</string>
<string name="use_old_player_title">Use old player</string>
<string name="use_old_player_summary">Old built-in Mediaframework player</string>
<string name="short_thousand">K</string>
<string name="short_million">M</string>
<string name="short_billion">B</string>
<!--Zero don't get selected (in some languages) as it is not a "special case" for android-->
<string name="no_subscribers">No subscribers</string>
<plurals name="subscribers">
<item quantity="one">%s subscriber</item>
<item quantity="other">%s subscribers</item>
</plurals>
<string name="no_views">No views</string>
<plurals name="views">
<item quantity="one">%s view</item>
<item quantity="other">%s views</item>
</plurals>
<string name="no_videos">No videos</string>
<plurals name="videos">
<item quantity="one">%s video</item>
<item quantity="other">%s videos</item>
</plurals>
<!-- Missions -->
<string name="start">Start</string>
<string name="pause">Pause</string>
<string name="view">Play</string>
<string name="create">Create</string>
<string name="delete">Delete</string>
<string name="delete_one">Delete One</string>
<string name="delete_all">Delete All</string>
<string name="checksum">Checksum</string>
<string name="dismiss">Dismiss</string>
<string name="rename">Rename</string>
<!-- Fragment -->
<string name="add">New mission</string>
<string name="finish">OK</string>
<!-- Msg -->
<string name="msg_name">Filename</string>
<string name="msg_threads">Threads</string>
<string name="msg_error">Error</string>
<string name="msg_server_unsupported">Server unsupported</string>
<string name="msg_exists">File already exists</string>
<string name="msg_url_malform">Malformed URL or Internet not available</string>
<string name="msg_running">NewPipe Downloading</string>
<string name="msg_running_detail">Tap for details</string>
<string name="msg_wait">Please wait…</string>
<string name="msg_copied">Copied to clipboard</string>
<string name="no_available_dir">Please select an available download folder</string>
<string name="msg_popup_permission">This permission is needed to\nopen in popup mode</string>
<!-- Checksum types -->
<string name="md5" translatable="false">MD5</string>
<string name="sha1" translatable="false">SHA-1</string>
<string name="reCaptchaActivity">reCAPTCHA</string>
<string name="reCaptcha_title">reCAPTCHA Challenge</string>
<string name="recaptcha_request_toast">reCAPTCHA Challenge requested</string>
<!-- End of GigaGet's Strings -->
<!-- Downloads -->
<string name="settings_category_downloads_title">Download</string>
<string name="settings_file_charset_title">Allowed characters in filenames</string>
<string name="settings_file_replacement_character_summary">Invalid characters are replaced with this value</string>
<string name="settings_file_replacement_character_title">Replacement character</string>
<string name="charset_letters_and_digits_value" translatable="false">[^\\w\\d]+</string>
<string name="charset_most_special_characters_value" translatable="false">[\\n\\r|\\?*&lt;":&gt;/']+</string>
<string name="charset_letters_and_digits">Letters and digits</string>
<string name="charset_most_special_characters">Most special characters</string>
<string name="toast_no_player">No player has been found for this file</string>
<!-- About -->
<string name="title_activity_about">About NewPipe</string>
<string name="action_settings">Settings</string>
<string name="action_about">About</string>
<string name="title_licenses">Third-party Licenses</string>
<string name="copyright" formatted="true">© %1$s by %2$s under %3$s</string>
<string name="error_unable_to_load_license">Could not load license</string>
<string name="action_open_website">Open website</string>
<string name="tab_about">About</string>
<string name="tab_contributors">Contributors</string>
<string name="tab_licenses">Licenses</string>
<string name="app_description">A free lightweight YouTube frontend for Android.</string>
<string name="contribution_title">Contribute</string>
<string name="contribution_encouragement">Whether you have ideas of; translation, design changes, code cleaning, or real heavy code changes—help is always welcome. The more is done the better it gets!</string>
<string name="github_url" translatable="false">https://github.com/TeamNewPipe/NewPipe</string>
<string name="view_on_github">View on GitHub</string>
<string name="donation_title">Donate</string>
<string name="donation_encouragement">NewPipe gets developed by volunteers which spend their free time to bring the best experience to you. Now it is time to give back to make sure our developers can make NewPipe even more better while enjoying a cup of java!</string>
<string name="donation_url" translatable="false">https://newpipe.schabi.org/donate</string>
<string name="give_back">Give back</string>
<string name="website_title">Website</string>
<string name="website_encouragement">To get more information and the latest news about NewPipe visit our website.</string>
<string name="website_url" translatable="false">https://newpipe.schabi.org/</string>
<string name="app_license_title">NewPipe\'s License</string>
<string name="app_license" translatable="false">NewPipe is Free Software: You can use, study share and improve it at your will. Specifically you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</string>
<string name="read_full_license">Read license</string>
<!-- History -->
<string name="title_activity_history">History</string>
<string name="title_history_search">Searched</string>
<string name="title_history_view">Watched</string>
<string name="history_disabled">History is disabled</string>
<string name="action_history">History</string>
<string name="history_empty">The history is empty</string>
<string name="history_cleared">History cleared</string>
<string name="item_deleted">Item deleted</string>
<string name="delete_item_search_history">Do you want to delete this item from search history?</string>
<string name="delete_stream_history_prompt">Do you want to delete this item from watch history?</string>
<string name="delete_all_history_prompt">Are you sure you want to delete all items from history?</string>
<string name="title_last_played">Last Played</string>
<string name="title_most_played">Most Played</string>
<!-- Content -->
<string name="main_page_content">Content of main page</string>
<string name="blank_page_summary">Blank Page</string>
<string name="kiosk_page_summary">Kiosk Page</string>
<string name="subscription_page_summary">Subscription Page</string>
<string name="feed_page_summary">Feed Page</string>
<string name="channel_page_summary">Channel Page</string>
<string-array name="main_page_content_names">
<item>@string/blank_page_summary</item>
<item>@string/kiosk_page_summary</item>
<item>@string/feed_page_summary</item>
<item>@string/subscription_page_summary</item>
<item>@string/channel_page_summary</item>
</string-array>
<string name="select_a_channel">Select a channel</string>
<string name="no_channel_subscribed_yet">No channel subscribed yet</string>
<string name="select_a_kiosk">Select a kiosk</string>
<string name="export_complete_toast">Export complete</string>
<string name="import_complete_toast">Import complete</string>
<string name="no_valid_zip_file">No valid ZIP file</string>
<string name="could_not_import_all_files">Warning: Could not import all files.</string>
<string name="override_current_data">This will override your current setup.</string>
<!-- Kiosk Names -->
<string name="kiosk">Kiosk</string>
<string name="trending">Trending</string>
<string name="top_50">Top 50</string>
<string name="new_and_hot">New &amp; hot</string>
<string name="service_kiosk_string" translatable="false">%1$s/%2$s</string>
<!-- Play Queue -->
<string name="title_activity_background_player">Background Player</string>
<string name="title_activity_popup_player">Popup Player</string>
<string name="play_queue_remove">Remove</string>
<string name="play_queue_stream_detail">Details</string>
<string name="play_queue_audio_settings">Audio Settings</string>
<string name="hold_to_append">Hold To Enqueue</string>
<string name="enqueue_on_background">Enqueue on Background</string>
<string name="enqueue_on_popup">Enqueue on Popup</string>
<string name="start_here_on_main">Start Playing Here</string>
<string name="start_here_on_background">Start Here on Background</string>
<string name="start_here_on_popup">Start Here on Popup</string>
<!-- Drawer -->
<string name="drawer_open">Open Drawer</string>
<string name="drawer_close">Close Drawer</string>
<string name="youtube" translatable="false">YouTube</string>
<string name="soundcloud" translatable="false">SoundCloud</string>
<string name="drawer_header_action_paceholder_text">Something will come here soon ;D</string>
<!-- Preferred player -->
<string name="preferred_open_action_share_menu_title" translatable="false">NewPipe</string>
<string name="preferred_open_action_settings_title">Preferred open action</string>
<string name="preferred_open_action_settings_summary">Default action when opening content — %s</string>
<string name="video_player">Video player</string>
<string name="background_player">Background player</string>
<string name="popup_player">Popup player</string>
<string name="always_ask_open_action">Always ask</string>
<string name="preferred_player_fetcher_notification_title">Getting info…</string>
<string name="preferred_player_fetcher_notification_message">"The requested content is loading"</string>
<!-- Local Playlist -->
<string name="create_playlist">Create New Playlist</string>
<string name="delete_playlist">Delete Playlist</string>
<string name="rename_playlist">Rename Playlist</string>
<string name="playlist_name_input">Name</string>
<string name="append_playlist">Add To Playlist</string>
<string name="set_as_playlist_thumbnail">Set as Playlist Thumbnail</string>
<string name="bookmark_playlist">Bookmark Playlist</string>
<string name="unbookmark_playlist">Remove Bookmark</string>
<string name="delete_playlist_prompt">Do you want to delete this playlist?</string>
<string name="playlist_creation_success">Playlist successfully created</string>
<string name="playlist_add_stream_success">Added to playlist</string>
<string name="playlist_thumbnail_change_success">Playlist thumbnail changed</string>
<string name="playlist_delete_failure">Failed to delete playlist</string>
<!-- Players -->
<string name="caption_none">No Caption</string>
<string name="resize_fit">FIT</string>
<string name="resize_fill">FILL</string>
<string name="resize_zoom">ZOOM</string>
<string name="caption_auto_generated">Auto-generated</string>
<!-- Caption Settings -->
<string name="caption_setting_title">Caption</string>
<string name="caption_setting_description">Modify player caption text scale and background styles. Require player restart to take effect.</string>
<!-- Debug Settings -->
<string name="enable_leak_canary_title">Enable LeakCanary</string>
<string name="enable_leak_canary_summary">Memory leak monitoring may cause app to become unresponsive when heap dumping</string>
<string name="enable_disposed_exceptions_title">Report Out-of-lifecycle errors</string>
<string name="enable_disposed_exceptions_summary">Force reporting of undeliverable Rx exceptions occurring outside of fragment or activity lifecycle after dispose</string>
<!-- Subscriptions import/export -->
<string name="import_export_title">Import/Export</string>
<string name="import_title">Import</string>
<string name="import_from">Import from</string>
<string name="export_to">Export to</string>
<string name="import_ongoing">Importing…</string>
<string name="export_ongoing">Exporting…</string>
<string name="import_file_title">Import file</string>
<string name="previous_export">Previous export</string>
<string name="subscriptions_import_unsuccessful">Subscriptions import failed</string>
<string name="subscriptions_export_unsuccessful">Subscriptions export failed</string>
<string name="import_youtube_instructions">To import your YouTube subscriptions you will need the export file, which can be downloaded following these instructions:\n\n1. Go to this url: %1$s\n2. Log in to your account when asked\n3. A download should start (that\'s the export file) </string>
<string name="import_soundcloud_instructions">To import your SoundCloud followings you have to know your profile url or id. If you do, just type either of them in the input below and you\'re ready to go.\n\nIf you don\'t, you can follow these steps:\n\n1. Enable \"desktop mode\" in some browser (the site is not available for mobile devices)\n2. Go to this url: %1$s\n3. Log in to your account when asked\n4. Copy the url that you were redirected to (that\'s your profile url)</string>
<string name="import_soundcloud_instructions_hint">yourid, soundcloud.com/yourid</string>
<string name="import_network_expensive_warning">Keep in mind that this operation can be network expensive.\n\nDo you want to continue?</string>
<!-- Playback Parameters -->
<string name="playback_speed_control">Playback Speed Control</string>
<string name="playback_tempo">Tempo</string>
<string name="playback_pitch">Pitch</string>
<string name="unhook_checkbox">Unhook (may cause distortion)</string>
<string name="playback_nightcore">Nightcore</string>
<string name="playback_default">Default</string>
</resources>