Merge branch 'dev' into playback_state_list
11
README.md
|
@ -66,15 +66,22 @@ NewPipe does not use any Google framework libraries, nor the YouTube API. Websit
|
|||
* Enqueue videos
|
||||
* Local playlists
|
||||
* Subtitles
|
||||
* Multi-service support (e.g. SoundCloud \[beta\])
|
||||
* Livestream support
|
||||
* Show comments
|
||||
|
||||
### Coming Features
|
||||
|
||||
* Cast to UPnP and Cast
|
||||
* Show comments
|
||||
* … and many more
|
||||
|
||||
### Supported Services
|
||||
|
||||
NewPipe supports multiple services. Our [docs](https://teamnewpipe.github.io/documentation/) provide more info on how a new service can be added to the app and the extractor. Please get in touch with us if you intend to add a new one. Currently supported services are:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[beta\]
|
||||
* media.ccc.de \[beta\]
|
||||
|
||||
## Updates
|
||||
When a change to the NewPipe code occurs (due to either adding features or bug fixing), eventually a release will occur. These are in the format x.xx.x . In order to get this new version, you can:
|
||||
* Build a debug APK yourself. This is the fastest way to get new features on your device, but is much more complicated, so we recommend using one of the other methods.
|
||||
|
|
|
@ -8,8 +8,8 @@ android {
|
|||
applicationId "org.schabi.newpipe"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
versionCode 720
|
||||
versionName "0.16.0"
|
||||
versionCode 740
|
||||
versionName "0.16.2"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
@ -57,7 +57,7 @@ dependencies {
|
|||
exclude module: 'support-annotations'
|
||||
})
|
||||
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:aa4f03a'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:c64c90a'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:2.23.0'
|
||||
|
|
|
@ -55,7 +55,7 @@ public class DownloadActivity extends AppCompatActivity {
|
|||
private void updateFragments() {
|
||||
MissionsFragment fragment = new MissionsFragment();
|
||||
|
||||
getFragmentManager().beginTransaction()
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.frame, fragment, MISSIONS_FRAGMENT_TAG)
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
.commit();
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
package org.schabi.newpipe.download;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.view.menu.ActionMenuItemView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
@ -34,7 +43,8 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
|
|||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.extractor.utils.Localization;
|
||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.FilenameUtils;
|
||||
import org.schabi.newpipe.util.ListHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
|
@ -43,19 +53,27 @@ import org.schabi.newpipe.util.StreamItemAdapter;
|
|||
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import icepick.Icepick;
|
||||
import icepick.State;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
import us.shandian.giga.postprocessing.Postprocessing;
|
||||
import us.shandian.giga.service.DownloadManager;
|
||||
import us.shandian.giga.service.DownloadManagerService;
|
||||
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
|
||||
import us.shandian.giga.service.MissionState;
|
||||
|
||||
public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
||||
private static final String TAG = "DialogFragment";
|
||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||
private static final int REQUEST_DOWNLOAD_PATH_SAF = 0x1230;
|
||||
|
||||
@State
|
||||
protected StreamInfo currentInfo;
|
||||
|
@ -80,7 +98,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
|
||||
private EditText nameEditText;
|
||||
private Spinner streamsSpinner;
|
||||
private RadioGroup radioVideoAudioGroup;
|
||||
private RadioGroup radioStreamsGroup;
|
||||
private TextView threadsCountTextView;
|
||||
private SeekBar threadsSeekBar;
|
||||
|
||||
|
@ -160,7 +178,9 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
return;
|
||||
}
|
||||
|
||||
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(getContext()));
|
||||
context = getContext();
|
||||
|
||||
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
|
||||
Icepick.restoreInstanceState(this, savedInstanceState);
|
||||
|
||||
SparseArray<SecondaryStreamHelper<AudioStream>> secondaryStreams = new SparseArray<>(4);
|
||||
|
@ -177,9 +197,59 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
}
|
||||
}
|
||||
|
||||
this.videoStreamsAdapter = new StreamItemAdapter<>(getContext(), wrappedVideoStreams, secondaryStreams);
|
||||
this.audioStreamsAdapter = new StreamItemAdapter<>(getContext(), wrappedAudioStreams);
|
||||
this.subtitleStreamsAdapter = new StreamItemAdapter<>(getContext(), wrappedSubtitleStreams);
|
||||
this.videoStreamsAdapter = new StreamItemAdapter<>(context, wrappedVideoStreams, secondaryStreams);
|
||||
this.audioStreamsAdapter = new StreamItemAdapter<>(context, wrappedAudioStreams);
|
||||
this.subtitleStreamsAdapter = new StreamItemAdapter<>(context, wrappedSubtitleStreams);
|
||||
|
||||
Intent intent = new Intent(context, DownloadManagerService.class);
|
||||
context.startService(intent);
|
||||
|
||||
context.bindService(intent, new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName cname, IBinder service) {
|
||||
DownloadManagerBinder mgr = (DownloadManagerBinder) service;
|
||||
|
||||
mainStorageAudio = mgr.getMainStorageAudio();
|
||||
mainStorageVideo = mgr.getMainStorageVideo();
|
||||
downloadManager = mgr.getDownloadManager();
|
||||
askForSavePath = mgr.askForSavePath();
|
||||
|
||||
okButton.setEnabled(true);
|
||||
|
||||
context.unbindService(this);
|
||||
|
||||
// check of download paths are defined
|
||||
if (!askForSavePath) {
|
||||
String msg = "";
|
||||
if (mainStorageVideo == null) msg += getString(R.string.download_path_title);
|
||||
if (mainStorageAudio == null)
|
||||
msg += getString(R.string.download_path_audio_title);
|
||||
|
||||
if (!msg.isEmpty()) {
|
||||
String title;
|
||||
if (mainStorageVideo == null && mainStorageAudio == null) {
|
||||
title = getString(R.string.general_error);
|
||||
msg = getString(R.string.no_available_dir) + ":\n" + msg;
|
||||
} else {
|
||||
title = msg;
|
||||
msg = getString(R.string.no_available_dir);
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setTitle(title)
|
||||
.setMessage(msg)
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
// nothing to do
|
||||
}
|
||||
}, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -204,8 +274,8 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
threadsCountTextView = view.findViewById(R.id.threads_count);
|
||||
threadsSeekBar = view.findViewById(R.id.threads);
|
||||
|
||||
radioVideoAudioGroup = view.findViewById(R.id.video_audio_group);
|
||||
radioVideoAudioGroup.setOnCheckedChangeListener(this);
|
||||
radioStreamsGroup = view.findViewById(R.id.video_audio_group);
|
||||
radioStreamsGroup.setOnCheckedChangeListener(this);
|
||||
|
||||
initToolbar(view.findViewById(R.id.toolbar));
|
||||
setupDownloadOptions();
|
||||
|
@ -240,17 +310,17 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
disposables.clear();
|
||||
|
||||
disposables.add(StreamSizeWrapper.fetchSizeForWrapper(wrappedVideoStreams).subscribe(result -> {
|
||||
if (radioVideoAudioGroup.getCheckedRadioButtonId() == R.id.video_button) {
|
||||
if (radioStreamsGroup.getCheckedRadioButtonId() == R.id.video_button) {
|
||||
setupVideoSpinner();
|
||||
}
|
||||
}));
|
||||
disposables.add(StreamSizeWrapper.fetchSizeForWrapper(wrappedAudioStreams).subscribe(result -> {
|
||||
if (radioVideoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button) {
|
||||
if (radioStreamsGroup.getCheckedRadioButtonId() == R.id.audio_button) {
|
||||
setupAudioSpinner();
|
||||
}
|
||||
}));
|
||||
disposables.add(StreamSizeWrapper.fetchSizeForWrapper(wrappedSubtitleStreams).subscribe(result -> {
|
||||
if (radioVideoAudioGroup.getCheckedRadioButtonId() == R.id.subtitle_button) {
|
||||
if (radioStreamsGroup.getCheckedRadioButtonId() == R.id.subtitle_button) {
|
||||
setupSubtitleSpinner();
|
||||
}
|
||||
}));
|
||||
|
@ -263,22 +333,49 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
Icepick.saveInstanceState(this, outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == REQUEST_DOWNLOAD_PATH_SAF && resultCode == Activity.RESULT_OK) {
|
||||
if (data.getData() == null) {
|
||||
showFailedDialog(R.string.general_error);
|
||||
return;
|
||||
}
|
||||
|
||||
DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
||||
if (docFile == null) {
|
||||
showFailedDialog(R.string.general_error);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the selected file was previously used
|
||||
checkSelectedDownload(null, data.getData(), docFile.getName(), docFile.getType());
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Inits
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void initToolbar(Toolbar toolbar) {
|
||||
if (DEBUG) Log.d(TAG, "initToolbar() called with: toolbar = [" + toolbar + "]");
|
||||
|
||||
boolean isLight = ThemeHelper.isLightThemeSelected(getActivity());
|
||||
|
||||
toolbar.setTitle(R.string.download_dialog_title);
|
||||
toolbar.setNavigationIcon(ThemeHelper.isLightThemeSelected(getActivity()) ? R.drawable.ic_arrow_back_black_24dp : R.drawable.ic_arrow_back_white_24dp);
|
||||
toolbar.setNavigationIcon(isLight ? R.drawable.ic_arrow_back_black_24dp : R.drawable.ic_arrow_back_white_24dp);
|
||||
toolbar.inflateMenu(R.menu.dialog_url);
|
||||
toolbar.setNavigationOnClickListener(v -> getDialog().dismiss());
|
||||
|
||||
okButton = toolbar.findViewById(R.id.okay);
|
||||
okButton.setEnabled(false);// disable until the download service connection is done
|
||||
|
||||
toolbar.setOnMenuItemClickListener(item -> {
|
||||
if (item.getItemId() == R.id.okay) {
|
||||
prepareSelectedDownload();
|
||||
|
@ -346,7 +443,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "onItemSelected() called with: parent = [" + parent + "], view = [" + view + "], position = [" + position + "], id = [" + id + "]");
|
||||
switch (radioVideoAudioGroup.getCheckedRadioButtonId()) {
|
||||
switch (radioStreamsGroup.getCheckedRadioButtonId()) {
|
||||
case R.id.audio_button:
|
||||
selectedAudioIndex = position;
|
||||
break;
|
||||
|
@ -370,9 +467,9 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
protected void setupDownloadOptions() {
|
||||
setRadioButtonsState(false);
|
||||
|
||||
final RadioButton audioButton = radioVideoAudioGroup.findViewById(R.id.audio_button);
|
||||
final RadioButton videoButton = radioVideoAudioGroup.findViewById(R.id.video_button);
|
||||
final RadioButton subtitleButton = radioVideoAudioGroup.findViewById(R.id.subtitle_button);
|
||||
final RadioButton audioButton = radioStreamsGroup.findViewById(R.id.audio_button);
|
||||
final RadioButton videoButton = radioStreamsGroup.findViewById(R.id.video_button);
|
||||
final RadioButton subtitleButton = radioStreamsGroup.findViewById(R.id.subtitle_button);
|
||||
final boolean isVideoStreamsAvailable = videoStreamsAdapter.getCount() > 0;
|
||||
final boolean isAudioStreamsAvailable = audioStreamsAdapter.getCount() > 0;
|
||||
final boolean isSubtitleStreamsAvailable = subtitleStreamsAdapter.getCount() > 0;
|
||||
|
@ -397,9 +494,9 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
}
|
||||
|
||||
private void setRadioButtonsState(boolean enabled) {
|
||||
radioVideoAudioGroup.findViewById(R.id.audio_button).setEnabled(enabled);
|
||||
radioVideoAudioGroup.findViewById(R.id.video_button).setEnabled(enabled);
|
||||
radioVideoAudioGroup.findViewById(R.id.subtitle_button).setEnabled(enabled);
|
||||
radioStreamsGroup.findViewById(R.id.audio_button).setEnabled(enabled);
|
||||
radioStreamsGroup.findViewById(R.id.video_button).setEnabled(enabled);
|
||||
radioStreamsGroup.findViewById(R.id.subtitle_button).setEnabled(enabled);
|
||||
}
|
||||
|
||||
private int getSubtitleIndexBy(List<SubtitlesStream> streams) {
|
||||
|
@ -434,98 +531,297 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
return 0;
|
||||
}
|
||||
|
||||
StoredDirectoryHelper mainStorageAudio = null;
|
||||
StoredDirectoryHelper mainStorageVideo = null;
|
||||
DownloadManager downloadManager = null;
|
||||
ActionMenuItemView okButton = null;
|
||||
Context context;
|
||||
boolean askForSavePath;
|
||||
|
||||
private String getNameEditText() {
|
||||
String str = nameEditText.getText().toString().trim();
|
||||
|
||||
return FilenameUtils.createFilename(context, str.isEmpty() ? currentInfo.getName() : str);
|
||||
}
|
||||
|
||||
private void showFailedDialog(@StringRes int msg) {
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.general_error)
|
||||
.setMessage(msg)
|
||||
.setNegativeButton(android.R.string.ok, null)
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showErrorActivity(Exception e) {
|
||||
ErrorActivity.reportError(
|
||||
context,
|
||||
Collections.singletonList(e),
|
||||
null,
|
||||
null,
|
||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "-", "-", R.string.general_error)
|
||||
);
|
||||
}
|
||||
|
||||
private void prepareSelectedDownload() {
|
||||
final Context context = getContext();
|
||||
Stream stream;
|
||||
String location;
|
||||
char kind;
|
||||
StoredDirectoryHelper mainStorage;
|
||||
MediaFormat format;
|
||||
String mime;
|
||||
|
||||
String fileName = nameEditText.getText().toString().trim();
|
||||
if (fileName.isEmpty())
|
||||
fileName = FilenameUtils.createFilename(context, currentInfo.getName());
|
||||
// first, build the filename and get the output folder (if possible)
|
||||
// later, run a very very very large file checking logic
|
||||
|
||||
switch (radioVideoAudioGroup.getCheckedRadioButtonId()) {
|
||||
String filename = getNameEditText().concat(".");
|
||||
|
||||
switch (radioStreamsGroup.getCheckedRadioButtonId()) {
|
||||
case R.id.audio_button:
|
||||
stream = audioStreamsAdapter.getItem(selectedAudioIndex);
|
||||
location = NewPipeSettings.getAudioDownloadPath(context);
|
||||
kind = 'a';
|
||||
mainStorage = mainStorageAudio;
|
||||
format = audioStreamsAdapter.getItem(selectedAudioIndex).getFormat();
|
||||
mime = format.mimeType;
|
||||
filename += format.suffix;
|
||||
break;
|
||||
case R.id.video_button:
|
||||
stream = videoStreamsAdapter.getItem(selectedVideoIndex);
|
||||
location = NewPipeSettings.getVideoDownloadPath(context);
|
||||
kind = 'v';
|
||||
mainStorage = mainStorageVideo;
|
||||
format = videoStreamsAdapter.getItem(selectedVideoIndex).getFormat();
|
||||
mime = format.mimeType;
|
||||
filename += format.suffix;
|
||||
break;
|
||||
case R.id.subtitle_button:
|
||||
stream = subtitleStreamsAdapter.getItem(selectedSubtitleIndex);
|
||||
location = NewPipeSettings.getVideoDownloadPath(context);// assume that subtitle & video files go together
|
||||
kind = 's';
|
||||
mainStorage = mainStorageVideo;// subtitle & video files go together
|
||||
format = subtitleStreamsAdapter.getItem(selectedSubtitleIndex).getFormat();
|
||||
mime = format.mimeType;
|
||||
filename += format == MediaFormat.TTML ? MediaFormat.SRT.suffix : format.suffix;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("No stream selected");
|
||||
}
|
||||
|
||||
if (mainStorage == null || askForSavePath) {
|
||||
// This part is called if with SAF preferred:
|
||||
// * older android version running
|
||||
// * save path not defined (via download settings)
|
||||
// * the user as checked the "ask where to download" option
|
||||
|
||||
StoredFileHelper.requestSafWithFileCreation(this, REQUEST_DOWNLOAD_PATH_SAF, filename, mime);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for existing file with the same name
|
||||
checkSelectedDownload(mainStorage, mainStorage.findFile(filename), filename, mime);
|
||||
}
|
||||
|
||||
private void checkSelectedDownload(StoredDirectoryHelper mainStorage, Uri targetFile, String filename, String mime) {
|
||||
StoredFileHelper storage;
|
||||
|
||||
try {
|
||||
if (mainStorage == null) {
|
||||
// using SAF on older android version
|
||||
storage = new StoredFileHelper(context, null, targetFile, "");
|
||||
} else if (targetFile == null) {
|
||||
// the file does not exist, but it is probably used in a pending download
|
||||
storage = new StoredFileHelper(mainStorage.getUri(), filename, mime, mainStorage.getTag());
|
||||
} else {
|
||||
// the target filename is already use, attempt to use it
|
||||
storage = new StoredFileHelper(context, mainStorage.getUri(), targetFile, mainStorage.getTag());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
showErrorActivity(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if is our file
|
||||
MissionState state = downloadManager.checkForExistingMission(storage);
|
||||
@StringRes int msgBtn;
|
||||
@StringRes int msgBody;
|
||||
|
||||
switch (state) {
|
||||
case Finished:
|
||||
msgBtn = R.string.overwrite;
|
||||
msgBody = R.string.overwrite_finished_warning;
|
||||
break;
|
||||
case Pending:
|
||||
msgBtn = R.string.overwrite;
|
||||
msgBody = R.string.download_already_pending;
|
||||
break;
|
||||
case PendingRunning:
|
||||
msgBtn = R.string.generate_unique_name;
|
||||
msgBody = R.string.download_already_running;
|
||||
break;
|
||||
case None:
|
||||
if (mainStorage == null) {
|
||||
// This part is called if:
|
||||
// * using SAF on older android version
|
||||
// * save path not defined
|
||||
continueSelectedDownload(storage);
|
||||
return;
|
||||
} else if (targetFile == null) {
|
||||
// This part is called if:
|
||||
// * the filename is not used in a pending/finished download
|
||||
// * the file does not exists, create
|
||||
|
||||
if (!mainStorage.mkdirs()) {
|
||||
showFailedDialog(R.string.error_path_creation);
|
||||
return;
|
||||
}
|
||||
|
||||
storage = mainStorage.createFile(filename, mime);
|
||||
if (storage == null || !storage.canWrite()) {
|
||||
showFailedDialog(R.string.error_file_creation);
|
||||
return;
|
||||
}
|
||||
|
||||
continueSelectedDownload(storage);
|
||||
return;
|
||||
}
|
||||
msgBtn = R.string.overwrite;
|
||||
msgBody = R.string.overwrite_unrelated_warning;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
int threads;
|
||||
|
||||
if (radioVideoAudioGroup.getCheckedRadioButtonId() == R.id.subtitle_button) {
|
||||
threads = 1;// use unique thread for subtitles due small file size
|
||||
fileName += ".srt";// final subtitle format
|
||||
} else {
|
||||
threads = threadsSeekBar.getProgress() + 1;
|
||||
fileName += "." + stream.getFormat().getSuffix();
|
||||
AlertDialog.Builder askDialog = new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.download_dialog_title)
|
||||
.setMessage(msgBody)
|
||||
.setNegativeButton(android.R.string.cancel, null);
|
||||
final StoredFileHelper finalStorage = storage;
|
||||
|
||||
|
||||
if (mainStorage == null) {
|
||||
// This part is called if:
|
||||
// * using SAF on older android version
|
||||
// * save path not defined
|
||||
switch (state) {
|
||||
case Pending:
|
||||
case Finished:
|
||||
askDialog.setPositiveButton(msgBtn, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
downloadManager.forgetMission(finalStorage);
|
||||
continueSelectedDownload(finalStorage);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
askDialog.create().show();
|
||||
return;
|
||||
}
|
||||
|
||||
final String finalFileName = fileName;
|
||||
askDialog.setPositiveButton(msgBtn, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
|
||||
DownloadManagerService.checkForRunningMission(context, location, fileName, (listed, finished) -> {
|
||||
if (listed) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.download_dialog_title)
|
||||
.setMessage(finished ? R.string.overwrite_warning : R.string.download_already_running)
|
||||
.setPositiveButton(
|
||||
finished ? R.string.overwrite : R.string.generate_unique_name,
|
||||
(dialog, which) -> downloadSelected(context, stream, location, finalFileName, kind, threads)
|
||||
)
|
||||
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
})
|
||||
.create()
|
||||
.show();
|
||||
} else {
|
||||
downloadSelected(context, stream, location, finalFileName, kind, threads);
|
||||
StoredFileHelper storageNew;
|
||||
switch (state) {
|
||||
case Finished:
|
||||
case Pending:
|
||||
downloadManager.forgetMission(finalStorage);
|
||||
case None:
|
||||
if (targetFile == null) {
|
||||
storageNew = mainStorage.createFile(filename, mime);
|
||||
} else {
|
||||
try {
|
||||
// try take (or steal) the file
|
||||
storageNew = new StoredFileHelper(context, mainStorage.getUri(), targetFile, mainStorage.getTag());
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to take (or steal) the file in " + targetFile.toString());
|
||||
storageNew = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (storageNew != null && storageNew.canWrite())
|
||||
continueSelectedDownload(storageNew);
|
||||
else
|
||||
showFailedDialog(R.string.error_file_creation);
|
||||
break;
|
||||
case PendingRunning:
|
||||
storageNew = mainStorage.createUniqueFile(filename, mime);
|
||||
if (storageNew == null)
|
||||
showFailedDialog(R.string.error_file_creation);
|
||||
else
|
||||
continueSelectedDownload(storageNew);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
askDialog.create().show();
|
||||
}
|
||||
|
||||
private void downloadSelected(Context context, Stream selectedStream, String location, String fileName, char kind, int threads) {
|
||||
private void continueSelectedDownload(@NonNull StoredFileHelper storage) {
|
||||
if (!storage.canWrite()) {
|
||||
showFailedDialog(R.string.permission_denied);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the selected file has to be overwritten, by simply checking its length
|
||||
try {
|
||||
if (storage.length() > 0) storage.truncate();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed to overwrite the file: " + storage.getUri().toString(), e);
|
||||
showFailedDialog(R.string.overwrite_failed);
|
||||
return;
|
||||
}
|
||||
|
||||
Stream selectedStream;
|
||||
char kind;
|
||||
int threads = threadsSeekBar.getProgress() + 1;
|
||||
String[] urls;
|
||||
String psName = null;
|
||||
String[] psArgs = null;
|
||||
String secondaryStreamUrl = null;
|
||||
long nearLength = 0;
|
||||
|
||||
if (selectedStream instanceof VideoStream) {
|
||||
SecondaryStreamHelper<AudioStream> secondaryStream = videoStreamsAdapter
|
||||
.getAllSecondary()
|
||||
.get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream));
|
||||
// more download logic: select muxer, subtitle converter, etc.
|
||||
switch (radioStreamsGroup.getCheckedRadioButtonId()) {
|
||||
case R.id.audio_button:
|
||||
threads = 1;// use unique thread for subtitles due small file size
|
||||
kind = 'a';
|
||||
selectedStream = audioStreamsAdapter.getItem(selectedAudioIndex);
|
||||
|
||||
if (secondaryStream != null) {
|
||||
secondaryStreamUrl = secondaryStream.getStream().getUrl();
|
||||
psName = selectedStream.getFormat() == MediaFormat.MPEG_4 ? Postprocessing.ALGORITHM_MP4_MUXER : Postprocessing.ALGORITHM_WEBM_MUXER;
|
||||
psArgs = null;
|
||||
long videoSize = wrappedVideoStreams.getSizeInBytes((VideoStream) selectedStream);
|
||||
|
||||
// set nearLength, only, if both sizes are fetched or known. this probably does not work on slow networks
|
||||
if (secondaryStream.getSizeInBytes() > 0 && videoSize > 0) {
|
||||
nearLength = secondaryStream.getSizeInBytes() + videoSize;
|
||||
if (selectedStream.getFormat() == MediaFormat.M4A) {
|
||||
psName = Postprocessing.ALGORITHM_M4A_NO_DASH;
|
||||
}
|
||||
}
|
||||
} else if ((selectedStream instanceof SubtitlesStream) && selectedStream.getFormat() == MediaFormat.TTML) {
|
||||
psName = Postprocessing.ALGORITHM_TTML_CONVERTER;
|
||||
psArgs = new String[]{
|
||||
selectedStream.getFormat().getSuffix(),
|
||||
"false",// ignore empty frames
|
||||
"false",// detect youtube duplicate lines
|
||||
};
|
||||
break;
|
||||
case R.id.video_button:
|
||||
kind = 'v';
|
||||
selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex);
|
||||
|
||||
SecondaryStreamHelper<AudioStream> secondaryStream = videoStreamsAdapter
|
||||
.getAllSecondary()
|
||||
.get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream));
|
||||
|
||||
if (secondaryStream != null) {
|
||||
secondaryStreamUrl = secondaryStream.getStream().getUrl();
|
||||
|
||||
if (selectedStream.getFormat() == MediaFormat.MPEG_4)
|
||||
psName = Postprocessing.ALGORITHM_MP4_FROM_DASH_MUXER;
|
||||
else
|
||||
psName = Postprocessing.ALGORITHM_WEBM_MUXER;
|
||||
|
||||
psArgs = null;
|
||||
long videoSize = wrappedVideoStreams.getSizeInBytes((VideoStream) selectedStream);
|
||||
|
||||
// set nearLength, only, if both sizes are fetched or known. This probably
|
||||
// does not work on slow networks but is later updated in the downloader
|
||||
if (secondaryStream.getSizeInBytes() > 0 && videoSize > 0) {
|
||||
nearLength = secondaryStream.getSizeInBytes() + videoSize;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R.id.subtitle_button:
|
||||
kind = 's';
|
||||
selectedStream = subtitleStreamsAdapter.getItem(selectedSubtitleIndex);
|
||||
|
||||
if (selectedStream.getFormat() == MediaFormat.TTML) {
|
||||
psName = Postprocessing.ALGORITHM_TTML_CONVERTER;
|
||||
psArgs = new String[]{
|
||||
selectedStream.getFormat().getSuffix(),
|
||||
"false",// ignore empty frames
|
||||
"false",// detect youtube duplicate lines
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (secondaryStreamUrl == null) {
|
||||
|
@ -534,8 +830,8 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
urls = new String[]{selectedStream.getUrl(), secondaryStreamUrl};
|
||||
}
|
||||
|
||||
DownloadManagerService.startMission(context, urls, location, fileName, kind, threads, currentInfo.getUrl(), psName, psArgs, nearLength);
|
||||
DownloadManagerService.startMission(context, urls, storage, kind, threads, currentInfo.getUrl(), psName, psArgs, nearLength);
|
||||
|
||||
getDialog().dismiss();
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1210,7 +1210,7 @@ public class VideoDetailFragment
|
|||
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
||||
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
|
||||
|
||||
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
||||
downloadDialog.show(getActivity().getSupportFragmentManager(), "downloadDialog");
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.ErrorInfo info = ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||
ServiceList.all()
|
||||
|
|
|
@ -21,8 +21,8 @@ import org.schabi.newpipe.extractor.NewPipe;
|
|||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.local.subscription.SubscriptionService;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -262,7 +262,7 @@ public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Voi
|
|||
* If chosen feed already displayed, then we request another feed from another
|
||||
* subscription, until the subscription table runs out of new items.
|
||||
* <p>
|
||||
* This Observer is self-contained and will dispose itself when complete. However, this
|
||||
* This Observer is self-contained and will close itself when complete. However, this
|
||||
* does not obey the fragment lifecycle and may continue running in the background
|
||||
* until it is complete. This is done due to RxJava2 no longer propagate errors once
|
||||
* an observer is unsubscribed while the thread process is still running.
|
||||
|
|
|
@ -46,7 +46,6 @@ import com.google.android.exoplayer2.Timeline;
|
|||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
|
@ -66,6 +65,7 @@ import org.schabi.newpipe.player.helper.PlayerDataSource;
|
|||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||
import org.schabi.newpipe.player.mediasource.FailedMediaSource;
|
||||
import org.schabi.newpipe.player.playback.BasePlayerMediaSession;
|
||||
import org.schabi.newpipe.player.playback.CustomTrackSelector;
|
||||
import org.schabi.newpipe.player.playback.MediaSourceManager;
|
||||
import org.schabi.newpipe.player.playback.PlaybackListener;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
|
@ -115,7 +115,7 @@ public abstract class BasePlayer implements
|
|||
final protected HistoryRecordManager recordManager;
|
||||
|
||||
@NonNull
|
||||
final protected DefaultTrackSelector trackSelector;
|
||||
final protected CustomTrackSelector trackSelector;
|
||||
@NonNull
|
||||
final protected PlayerDataSource dataSource;
|
||||
|
||||
|
@ -212,7 +212,7 @@ public abstract class BasePlayer implements
|
|||
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
|
||||
|
||||
final TrackSelection.Factory trackSelectionFactory = PlayerHelper.getQualitySelector(context);
|
||||
this.trackSelector = new DefaultTrackSelector(trackSelectionFactory);
|
||||
this.trackSelector = new CustomTrackSelector(trackSelectionFactory);
|
||||
|
||||
this.loadControl = new LoadController(context);
|
||||
this.renderFactory = new DefaultRenderersFactory(context);
|
||||
|
|
|
@ -305,9 +305,9 @@ public abstract class VideoPlayer extends BasePlayer
|
|||
captionItem.setOnMenuItemClickListener(menuItem -> {
|
||||
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||
trackSelector.setPreferredTextLanguage(captionLanguage);
|
||||
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||
.setRendererDisabled(textRendererIndex, false)
|
||||
.setPreferredTextLanguage(captionLanguage));
|
||||
.setRendererDisabled(textRendererIndex, false));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
@ -315,7 +315,6 @@ public abstract class VideoPlayer extends BasePlayer
|
|||
captionPopupMenu.setOnDismissListener(this);
|
||||
}
|
||||
|
||||
|
||||
private void updateStreamRelatedViews() {
|
||||
if (getCurrentMetadata() == null) return;
|
||||
|
||||
|
@ -508,7 +507,7 @@ public abstract class VideoPlayer extends BasePlayer
|
|||
}
|
||||
|
||||
// Normalize mismatching language strings
|
||||
final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage;
|
||||
final String preferredLanguage = trackSelector.getPreferredTextLanguage();
|
||||
// Build UI
|
||||
buildCaptionMenu(availableLanguages);
|
||||
if (trackSelector.getParameters().getRendererDisabled(textRenderer) ||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package org.schabi.newpipe.player.playback;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* This class allows irregular text language labels for use when selecting text captions and
|
||||
* is mostly a copy-paste from {@link DefaultTrackSelector}.
|
||||
*
|
||||
* This is a hack and should be removed once ExoPlayer fixes language normalization to accept
|
||||
* a broader set of languages.
|
||||
* */
|
||||
public class CustomTrackSelector extends DefaultTrackSelector {
|
||||
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
|
||||
|
||||
private String preferredTextLanguage;
|
||||
|
||||
public CustomTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) {
|
||||
super(adaptiveTrackSelectionFactory);
|
||||
}
|
||||
|
||||
public String getPreferredTextLanguage() {
|
||||
return preferredTextLanguage;
|
||||
}
|
||||
|
||||
public void setPreferredTextLanguage(@NonNull final String label) {
|
||||
Assertions.checkNotNull(label);
|
||||
if (!label.equals(preferredTextLanguage)) {
|
||||
preferredTextLanguage = label;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/** @see DefaultTrackSelector#formatHasLanguage(Format, String)*/
|
||||
protected static boolean formatHasLanguage(Format format, String language) {
|
||||
return language != null && TextUtils.equals(language, format.language);
|
||||
}
|
||||
|
||||
/** @see DefaultTrackSelector#formatHasNoLanguage(Format)*/
|
||||
protected static boolean formatHasNoLanguage(Format format) {
|
||||
return TextUtils.isEmpty(format.language) || formatHasLanguage(format, C.LANGUAGE_UNDETERMINED);
|
||||
}
|
||||
|
||||
/** @see DefaultTrackSelector#selectTextTrack(TrackGroupArray, int[][], Parameters) */
|
||||
@Override
|
||||
protected Pair<TrackSelection, Integer> selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
|
||||
Parameters params) {
|
||||
TrackGroup selectedGroup = null;
|
||||
int selectedTrackIndex = 0;
|
||||
int selectedTrackScore = 0;
|
||||
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
||||
TrackGroup trackGroup = groups.get(groupIndex);
|
||||
int[] trackFormatSupport = formatSupport[groupIndex];
|
||||
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
||||
if (isSupported(trackFormatSupport[trackIndex],
|
||||
params.exceedRendererCapabilitiesIfNecessary)) {
|
||||
Format format = trackGroup.getFormat(trackIndex);
|
||||
int maskedSelectionFlags =
|
||||
format.selectionFlags & ~params.disabledTextTrackSelectionFlags;
|
||||
boolean isDefault = (maskedSelectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
|
||||
boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0;
|
||||
int trackScore;
|
||||
boolean preferredLanguageFound = formatHasLanguage(format, preferredTextLanguage);
|
||||
if (preferredLanguageFound
|
||||
|| (params.selectUndeterminedTextLanguage && formatHasNoLanguage(format))) {
|
||||
if (isDefault) {
|
||||
trackScore = 8;
|
||||
} else if (!isForced) {
|
||||
// Prefer non-forced to forced if a preferred text language has been specified. Where
|
||||
// both are provided the non-forced track will usually contain the forced subtitles as
|
||||
// a subset.
|
||||
trackScore = 6;
|
||||
} else {
|
||||
trackScore = 4;
|
||||
}
|
||||
trackScore += preferredLanguageFound ? 1 : 0;
|
||||
} else if (isDefault) {
|
||||
trackScore = 3;
|
||||
} else if (isForced) {
|
||||
if (formatHasLanguage(format, params.preferredAudioLanguage)) {
|
||||
trackScore = 2;
|
||||
} else {
|
||||
trackScore = 1;
|
||||
}
|
||||
} else {
|
||||
// Track should not be selected.
|
||||
continue;
|
||||
}
|
||||
if (isSupported(trackFormatSupport[trackIndex], false)) {
|
||||
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
|
||||
}
|
||||
if (trackScore > selectedTrackScore) {
|
||||
selectedGroup = trackGroup;
|
||||
selectedTrackIndex = trackIndex;
|
||||
selectedTrackScore = trackScore;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return selectedGroup == null
|
||||
? null
|
||||
: Pair.create(
|
||||
new FixedTrackSelection(selectedGroup, selectedTrackIndex), selectedTrackScore);
|
||||
}
|
||||
}
|
|
@ -158,7 +158,7 @@ public class MediaSourceManager {
|
|||
* Dispose the manager and releases all message buses and loaders.
|
||||
* */
|
||||
public void dispose() {
|
||||
if (DEBUG) Log.d(TAG, "dispose() called.");
|
||||
if (DEBUG) Log.d(TAG, "close() called.");
|
||||
|
||||
debouncedSignal.onComplete();
|
||||
debouncedLoader.dispose();
|
||||
|
|
|
@ -17,7 +17,9 @@ public enum UserAction {
|
|||
REQUESTED_KIOSK("requested kiosk"),
|
||||
REQUESTED_COMMENTS("requested comments"),
|
||||
DELETE_FROM_HISTORY("delete from history"),
|
||||
PLAY_STREAM("Play stream");
|
||||
PLAY_STREAM("Play stream"),
|
||||
DOWNLOAD_POSTPROCESSING("download post-processing"),
|
||||
DOWNLOAD_FAILED("download failed");
|
||||
|
||||
|
||||
private final String message;
|
||||
|
|
|
@ -1,30 +1,77 @@
|
|||
package org.schabi.newpipe.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nononsenseapps.filepicker.Utils;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||
|
||||
public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||
private static final int REQUEST_DOWNLOAD_PATH = 0x1235;
|
||||
private static final int REQUEST_DOWNLOAD_AUDIO_PATH = 0x1236;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
private String DOWNLOAD_PATH_PREFERENCE;
|
||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
||||
|
||||
public class DownloadSettingsFragment extends BasePreferenceFragment {
|
||||
private static final int REQUEST_DOWNLOAD_VIDEO_PATH = 0x1235;
|
||||
private static final int REQUEST_DOWNLOAD_AUDIO_PATH = 0x1236;
|
||||
public static final boolean IGNORE_RELEASE_ON_OLD_PATH = true;
|
||||
|
||||
private String DOWNLOAD_PATH_VIDEO_PREFERENCE;
|
||||
private String DOWNLOAD_PATH_AUDIO_PREFERENCE;
|
||||
|
||||
private String DOWNLOAD_STORAGE_ASK;
|
||||
|
||||
private Preference prefPathVideo;
|
||||
private Preference prefPathAudio;
|
||||
private Preference prefStorageAsk;
|
||||
|
||||
private Context ctx;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
initKeys();
|
||||
DOWNLOAD_PATH_VIDEO_PREFERENCE = getString(R.string.download_path_video_key);
|
||||
DOWNLOAD_PATH_AUDIO_PREFERENCE = getString(R.string.download_path_audio_key);
|
||||
DOWNLOAD_STORAGE_ASK = getString(R.string.downloads_storage_ask);
|
||||
|
||||
prefPathVideo = findPreference(DOWNLOAD_PATH_VIDEO_PREFERENCE);
|
||||
prefPathAudio = findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE);
|
||||
prefStorageAsk = findPreference(DOWNLOAD_STORAGE_ASK);
|
||||
|
||||
updatePreferencesSummary();
|
||||
updatePathPickers(!defaultPreferences.getBoolean(DOWNLOAD_STORAGE_ASK, false));
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
prefStorageAsk.setSummary(R.string.downloads_storage_ask_summary);
|
||||
}
|
||||
|
||||
if (hasInvalidPath(DOWNLOAD_PATH_VIDEO_PREFERENCE) || hasInvalidPath(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
|
||||
Toast.makeText(ctx, R.string.download_pick_path, Toast.LENGTH_SHORT).show();
|
||||
updatePreferencesSummary();
|
||||
}
|
||||
|
||||
prefStorageAsk.setOnPreferenceChangeListener((preference, value) -> {
|
||||
updatePathPickers(!(boolean) value);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -32,52 +79,183 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||
addPreferencesFromResource(R.xml.download_settings);
|
||||
}
|
||||
|
||||
private void initKeys() {
|
||||
DOWNLOAD_PATH_PREFERENCE = getString(R.string.download_path_key);
|
||||
DOWNLOAD_PATH_AUDIO_PREFERENCE = getString(R.string.download_path_audio_key);
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
ctx = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
ctx = null;
|
||||
prefStorageAsk.setOnPreferenceChangeListener(null);
|
||||
}
|
||||
|
||||
private void updatePreferencesSummary() {
|
||||
findPreference(DOWNLOAD_PATH_PREFERENCE).setSummary(defaultPreferences.getString(DOWNLOAD_PATH_PREFERENCE, getString(R.string.download_path_summary)));
|
||||
findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE).setSummary(defaultPreferences.getString(DOWNLOAD_PATH_AUDIO_PREFERENCE, getString(R.string.download_path_audio_summary)));
|
||||
showPathInSummary(DOWNLOAD_PATH_VIDEO_PREFERENCE, R.string.download_path_summary, prefPathVideo);
|
||||
showPathInSummary(DOWNLOAD_PATH_AUDIO_PREFERENCE, R.string.download_path_audio_summary, prefPathAudio);
|
||||
}
|
||||
|
||||
private void showPathInSummary(String prefKey, @StringRes int defaultString, Preference target) {
|
||||
String rawUri = defaultPreferences.getString(prefKey, null);
|
||||
if (rawUri == null || rawUri.isEmpty()) {
|
||||
target.setSummary(getString(defaultString));
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawUri.charAt(0) == File.separatorChar) {
|
||||
target.setSummary(rawUri);
|
||||
return;
|
||||
}
|
||||
if (rawUri.startsWith(ContentResolver.SCHEME_FILE)) {
|
||||
target.setSummary(new File(URI.create(rawUri)).getPath());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
rawUri = URLDecoder.decode(rawUri, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
target.setSummary(rawUri);
|
||||
}
|
||||
|
||||
private boolean isFileUri(String path) {
|
||||
return path.charAt(0) == File.separatorChar || path.startsWith(ContentResolver.SCHEME_FILE);
|
||||
}
|
||||
|
||||
private boolean hasInvalidPath(String prefKey) {
|
||||
String value = defaultPreferences.getString(prefKey, null);
|
||||
return value == null || value.isEmpty();
|
||||
}
|
||||
|
||||
private void updatePathPickers(boolean enabled) {
|
||||
prefPathVideo.setEnabled(enabled);
|
||||
prefPathAudio.setEnabled(enabled);
|
||||
}
|
||||
|
||||
// FIXME: after releasing the old path, all downloads created on the folder becomes inaccessible
|
||||
private void forgetSAFTree(Context ctx, String oldPath) {
|
||||
if (IGNORE_RELEASE_ON_OLD_PATH) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldPath == null || oldPath.isEmpty() || isFileUri(oldPath)) return;
|
||||
|
||||
try {
|
||||
Uri uri = Uri.parse(oldPath);
|
||||
|
||||
ctx.getContentResolver().releasePersistableUriPermission(uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||
ctx.revokeUriPermission(uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||
|
||||
Log.i(TAG, "Revoke old path permissions success on " + oldPath);
|
||||
} catch (Exception err) {
|
||||
Log.e(TAG, "Error revoking old path permissions on " + oldPath, err);
|
||||
}
|
||||
}
|
||||
|
||||
private void showMessageDialog(@StringRes int title, @StringRes int message) {
|
||||
AlertDialog.Builder msg = new AlertDialog.Builder(ctx);
|
||||
msg.setTitle(title);
|
||||
msg.setMessage(message);
|
||||
msg.setPositiveButton(android.R.string.ok, null);
|
||||
msg.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(Preference preference) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onPreferenceTreeClick() called with: preference = [" + preference + "]");
|
||||
Log.d(TAG, "onPreferenceTreeClick() called with: preference = [" + preference + "]");
|
||||
}
|
||||
|
||||
if (preference.getKey().equals(DOWNLOAD_PATH_PREFERENCE)
|
||||
|| preference.getKey().equals(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
|
||||
Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||
String key = preference.getKey();
|
||||
int request;
|
||||
|
||||
if (key.equals(DOWNLOAD_PATH_VIDEO_PREFERENCE)) {
|
||||
request = REQUEST_DOWNLOAD_VIDEO_PATH;
|
||||
} else if (key.equals(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
|
||||
request = REQUEST_DOWNLOAD_AUDIO_PATH;
|
||||
} else {
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
Intent i;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
.putExtra("android.content.extra.SHOW_ADVANCED", true)
|
||||
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||
} else {
|
||||
i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_MODE, FilePickerActivityHelper.MODE_DIR);
|
||||
if (preference.getKey().equals(DOWNLOAD_PATH_PREFERENCE)) {
|
||||
startActivityForResult(i, REQUEST_DOWNLOAD_PATH);
|
||||
} else if (preference.getKey().equals(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
|
||||
startActivityForResult(i, REQUEST_DOWNLOAD_AUDIO_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
startActivityForResult(i, request);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");
|
||||
Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], " +
|
||||
"resultCode = [" + resultCode + "], data = [" + data + "]"
|
||||
);
|
||||
}
|
||||
|
||||
if ((requestCode == REQUEST_DOWNLOAD_PATH || requestCode == REQUEST_DOWNLOAD_AUDIO_PATH)
|
||||
&& resultCode == Activity.RESULT_OK && data.getData() != null) {
|
||||
String key = getString(requestCode == REQUEST_DOWNLOAD_PATH ? R.string.download_path_key : R.string.download_path_audio_key);
|
||||
String path = Utils.getFileForUri(data.getData()).getAbsolutePath();
|
||||
if (resultCode != Activity.RESULT_OK) return;
|
||||
|
||||
defaultPreferences.edit().putString(key, path).apply();
|
||||
updatePreferencesSummary();
|
||||
String key;
|
||||
if (requestCode == REQUEST_DOWNLOAD_VIDEO_PATH)
|
||||
key = DOWNLOAD_PATH_VIDEO_PREFERENCE;
|
||||
else if (requestCode == REQUEST_DOWNLOAD_AUDIO_PATH)
|
||||
key = DOWNLOAD_PATH_AUDIO_PREFERENCE;
|
||||
else
|
||||
return;
|
||||
|
||||
Uri uri = data.getData();
|
||||
if (uri == null) {
|
||||
showMessageDialog(R.string.general_error, R.string.invalid_directory);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// steps:
|
||||
// 1. revoke permissions on the old save path
|
||||
// 2. acquire permissions on the new save path
|
||||
// 3. save the new path, if step(2) was successful
|
||||
final Context ctx = getContext();
|
||||
if (ctx == null) throw new NullPointerException("getContext()");
|
||||
|
||||
forgetSAFTree(ctx, defaultPreferences.getString(key, ""));
|
||||
|
||||
try {
|
||||
ctx.grantUriPermission(ctx.getPackageName(), uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||
|
||||
StoredDirectoryHelper mainStorage = new StoredDirectoryHelper(ctx, uri, null);
|
||||
Log.i(TAG, "Acquiring tree success from " + uri.toString());
|
||||
|
||||
if (!mainStorage.canWrite())
|
||||
throw new IOException("No write permissions on " + uri.toString());
|
||||
} catch (IOException err) {
|
||||
Log.e(TAG, "Error acquiring tree from " + uri.toString(), err);
|
||||
showMessageDialog(R.string.general_error, R.string.no_available_dir);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
File target = Utils.getFileForUri(data.getData());
|
||||
if (!target.canWrite()) {
|
||||
showMessageDialog(R.string.download_to_sdcard_error_title, R.string.download_to_sdcard_error_message);
|
||||
return;
|
||||
}
|
||||
uri = Uri.fromFile(target);
|
||||
}
|
||||
|
||||
defaultPreferences.edit().putString(key, uri.toString()).apply();
|
||||
updatePreferencesSummary();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,37 +70,23 @@ public class NewPipeSettings {
|
|||
getAudioDownloadFolder(context);
|
||||
}
|
||||
|
||||
public static File getVideoDownloadFolder(Context context) {
|
||||
return getDir(context, R.string.download_path_key, Environment.DIRECTORY_MOVIES);
|
||||
private static void getVideoDownloadFolder(Context context) {
|
||||
getDir(context, R.string.download_path_video_key, Environment.DIRECTORY_MOVIES);
|
||||
}
|
||||
|
||||
public static String getVideoDownloadPath(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final String key = context.getString(R.string.download_path_key);
|
||||
return prefs.getString(key, Environment.DIRECTORY_MOVIES);
|
||||
private static void getAudioDownloadFolder(Context context) {
|
||||
getDir(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC);
|
||||
}
|
||||
|
||||
public static File getAudioDownloadFolder(Context context) {
|
||||
return getDir(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC);
|
||||
}
|
||||
|
||||
public static String getAudioDownloadPath(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final String key = context.getString(R.string.download_path_audio_key);
|
||||
return prefs.getString(key, Environment.DIRECTORY_MUSIC);
|
||||
}
|
||||
|
||||
private static File getDir(Context context, int keyID, String defaultDirectoryName) {
|
||||
private static void getDir(Context context, int keyID, String defaultDirectoryName) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final String key = context.getString(keyID);
|
||||
String downloadPath = prefs.getString(key, null);
|
||||
if ((downloadPath != null) && (!downloadPath.isEmpty())) return new File(downloadPath.trim());
|
||||
if ((downloadPath != null) && (!downloadPath.isEmpty())) return;
|
||||
|
||||
final File dir = getDir(defaultDirectoryName);
|
||||
SharedPreferences.Editor spEditor = prefs.edit();
|
||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(dir));
|
||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName)));
|
||||
spEditor.apply();
|
||||
return dir;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -108,19 +94,7 @@ public class NewPipeSettings {
|
|||
return new File(Environment.getExternalStorageDirectory(), defaultDirectoryName);
|
||||
}
|
||||
|
||||
public static void resetDownloadFolders(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
resetDownloadFolder(prefs, context.getString(R.string.download_path_audio_key), Environment.DIRECTORY_MUSIC);
|
||||
resetDownloadFolder(prefs, context.getString(R.string.download_path_key), Environment.DIRECTORY_MOVIES);
|
||||
}
|
||||
|
||||
private static void resetDownloadFolder(SharedPreferences prefs, String key, String defaultDirectoryName) {
|
||||
SharedPreferences.Editor spEditor = prefs.edit();
|
||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName)));
|
||||
spEditor.apply();
|
||||
}
|
||||
|
||||
private static String getNewPipeChildFolderPathForDir(File dir) {
|
||||
return new File(dir, "NewPipe").getAbsolutePath();
|
||||
return new File(dir, "NewPipe").toURI().toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
|
@ -15,89 +16,239 @@ public class DataReader {
|
|||
public final static int INTEGER_SIZE = 4;
|
||||
public final static int FLOAT_SIZE = 4;
|
||||
|
||||
private long pos;
|
||||
public final SharpStream stream;
|
||||
private final boolean rewind;
|
||||
private final static int BUFFER_SIZE = 128 * 1024;// 128 KiB
|
||||
|
||||
private long position = 0;
|
||||
private final SharpStream stream;
|
||||
|
||||
private InputStream view;
|
||||
private int viewSize;
|
||||
|
||||
public DataReader(SharpStream stream) {
|
||||
this.rewind = stream.canRewind();
|
||||
this.stream = stream;
|
||||
this.pos = 0L;
|
||||
this.readOffset = this.readBuffer.length;
|
||||
}
|
||||
|
||||
public long position() {
|
||||
return pos;
|
||||
return position;
|
||||
}
|
||||
|
||||
public final int readInt() throws IOException {
|
||||
public int read() throws IOException {
|
||||
if (fillBuffer()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
position++;
|
||||
readCount--;
|
||||
|
||||
return readBuffer[readOffset++] & 0xFF;
|
||||
}
|
||||
|
||||
public long skipBytes(long amount) throws IOException {
|
||||
if (readCount < 0) {
|
||||
return 0;
|
||||
} else if (readCount == 0) {
|
||||
amount = stream.skip(amount);
|
||||
} else {
|
||||
if (readCount > amount) {
|
||||
readCount -= (int) amount;
|
||||
readOffset += (int) amount;
|
||||
} else {
|
||||
amount = readCount + stream.skip(amount - readCount);
|
||||
readCount = 0;
|
||||
readOffset = readBuffer.length;
|
||||
}
|
||||
}
|
||||
|
||||
position += amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
public int readInt() throws IOException {
|
||||
primitiveRead(INTEGER_SIZE);
|
||||
return primitive[0] << 24 | primitive[1] << 16 | primitive[2] << 8 | primitive[3];
|
||||
}
|
||||
|
||||
public final int read() throws IOException {
|
||||
int value = stream.read();
|
||||
if (value == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
pos++;
|
||||
return value;
|
||||
public short readShort() throws IOException {
|
||||
primitiveRead(SHORT_SIZE);
|
||||
return (short) (primitive[0] << 8 | primitive[1]);
|
||||
}
|
||||
|
||||
public final long skipBytes(long amount) throws IOException {
|
||||
amount = stream.skip(amount);
|
||||
pos += amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
public final long readLong() throws IOException {
|
||||
public long readLong() throws IOException {
|
||||
primitiveRead(LONG_SIZE);
|
||||
long high = primitive[0] << 24 | primitive[1] << 16 | primitive[2] << 8 | primitive[3];
|
||||
long low = primitive[4] << 24 | primitive[5] << 16 | primitive[6] << 8 | primitive[7];
|
||||
return high << 32 | low;
|
||||
}
|
||||
|
||||
public final short readShort() throws IOException {
|
||||
primitiveRead(SHORT_SIZE);
|
||||
return (short) (primitive[0] << 8 | primitive[1]);
|
||||
}
|
||||
|
||||
public final int read(byte[] buffer) throws IOException {
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
return read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
public final int read(byte[] buffer, int offset, int count) throws IOException {
|
||||
int res = stream.read(buffer, offset, count);
|
||||
pos += res;
|
||||
public int read(byte[] buffer, int offset, int count) throws IOException {
|
||||
if (readCount < 0) {
|
||||
return -1;
|
||||
}
|
||||
int total = 0;
|
||||
|
||||
return res;
|
||||
if (count >= readBuffer.length) {
|
||||
if (readCount > 0) {
|
||||
System.arraycopy(readBuffer, readOffset, buffer, offset, readCount);
|
||||
readOffset += readCount;
|
||||
|
||||
offset += readCount;
|
||||
count -= readCount;
|
||||
|
||||
total = readCount;
|
||||
readCount = 0;
|
||||
}
|
||||
total += Math.max(stream.read(buffer, offset, count), 0);
|
||||
} else {
|
||||
while (count > 0 && !fillBuffer()) {
|
||||
int read = Math.min(readCount, count);
|
||||
System.arraycopy(readBuffer, readOffset, buffer, offset, read);
|
||||
|
||||
readOffset += read;
|
||||
readCount -= read;
|
||||
|
||||
offset += read;
|
||||
count -= read;
|
||||
|
||||
total += read;
|
||||
}
|
||||
}
|
||||
|
||||
position += total;
|
||||
return total;
|
||||
}
|
||||
|
||||
public final boolean available() {
|
||||
return stream.available() > 0;
|
||||
public boolean available() {
|
||||
return readCount > 0 || stream.available() > 0;
|
||||
}
|
||||
|
||||
public void rewind() throws IOException {
|
||||
stream.rewind();
|
||||
pos = 0;
|
||||
|
||||
if ((position - viewSize) > 0) {
|
||||
viewSize = 0;// drop view
|
||||
} else {
|
||||
viewSize += position;
|
||||
}
|
||||
|
||||
position = 0;
|
||||
readOffset = readBuffer.length;
|
||||
}
|
||||
|
||||
public boolean canRewind() {
|
||||
return rewind;
|
||||
return stream.canRewind();
|
||||
}
|
||||
|
||||
private short[] primitive = new short[LONG_SIZE];
|
||||
/**
|
||||
* Wraps this instance of {@code DataReader} into {@code InputStream}
|
||||
* object. Note: Any read in the {@code DataReader} will not modify
|
||||
* (decrease) the view size
|
||||
*
|
||||
* @param size the size of the view
|
||||
* @return the view
|
||||
*/
|
||||
public InputStream getView(int size) {
|
||||
if (view == null) {
|
||||
view = new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (viewSize < 1) {
|
||||
return -1;
|
||||
}
|
||||
int res = DataReader.this.read();
|
||||
if (res > 0) {
|
||||
viewSize--;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
return read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int count) throws IOException {
|
||||
if (viewSize < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = DataReader.this.read(buffer, offset, Math.min(viewSize, count));
|
||||
viewSize -= res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long amount) throws IOException {
|
||||
if (viewSize < 1) {
|
||||
return 0;
|
||||
}
|
||||
int res = (int) DataReader.this.skipBytes(Math.min(amount, viewSize));
|
||||
viewSize -= res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return viewSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
viewSize = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
viewSize = size;
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private final short[] primitive = new short[LONG_SIZE];
|
||||
|
||||
private void primitiveRead(int amount) throws IOException {
|
||||
byte[] buffer = new byte[amount];
|
||||
int read = stream.read(buffer, 0, amount);
|
||||
pos += read;
|
||||
int read = read(buffer, 0, amount);
|
||||
|
||||
if (read != amount) {
|
||||
throw new EOFException("Truncated data, missing " + String.valueOf(amount - read) + " bytes");
|
||||
throw new EOFException("Truncated stream, missing " + String.valueOf(amount - read) + " bytes");
|
||||
}
|
||||
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
primitive[i] = (short) (buffer[i] & 0xFF);// the "byte" datatype is signed and is very annoying
|
||||
for (int i = 0; i < amount; i++) {
|
||||
primitive[i] = (short) (buffer[i] & 0xFF);// the "byte" data type in java is signed and is very annoying
|
||||
}
|
||||
}
|
||||
|
||||
private final byte[] readBuffer = new byte[BUFFER_SIZE];
|
||||
private int readOffset;
|
||||
private int readCount;
|
||||
|
||||
private boolean fillBuffer() throws IOException {
|
||||
if (readCount < 0) {
|
||||
return true;
|
||||
}
|
||||
if (readOffset >= readBuffer.length) {
|
||||
readCount = stream.read(readBuffer);
|
||||
if (readCount < 1) {
|
||||
readCount = -1;
|
||||
return true;
|
||||
}
|
||||
readOffset = 0;
|
||||
}
|
||||
|
||||
return readCount < 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
|
@ -35,14 +33,29 @@ public class Mp4DashReader {
|
|||
private static final int ATOM_TREX = 0x74726578;
|
||||
private static final int ATOM_TKHD = 0x746B6864;
|
||||
private static final int ATOM_MFRA = 0x6D667261;
|
||||
private static final int ATOM_TFRA = 0x74667261;
|
||||
private static final int ATOM_MDHD = 0x6D646864;
|
||||
private static final int ATOM_EDTS = 0x65647473;
|
||||
private static final int ATOM_ELST = 0x656C7374;
|
||||
private static final int ATOM_HDLR = 0x68646C72;
|
||||
private static final int ATOM_MINF = 0x6D696E66;
|
||||
private static final int ATOM_DINF = 0x64696E66;
|
||||
private static final int ATOM_STBL = 0x7374626C;
|
||||
private static final int ATOM_STSD = 0x73747364;
|
||||
private static final int ATOM_VMHD = 0x766D6864;
|
||||
private static final int ATOM_SMHD = 0x736D6864;
|
||||
|
||||
private static final int BRAND_DASH = 0x64617368;
|
||||
private static final int BRAND_ISO5 = 0x69736F35;
|
||||
|
||||
private static final int HANDLER_VIDE = 0x76696465;
|
||||
private static final int HANDLER_SOUN = 0x736F756E;
|
||||
private static final int HANDLER_SUBT = 0x73756274;
|
||||
// </editor-fold>
|
||||
|
||||
private final DataReader stream;
|
||||
|
||||
private Mp4Track[] tracks = null;
|
||||
private int[] brands = null;
|
||||
|
||||
private Box box;
|
||||
private Moof moof;
|
||||
|
@ -50,9 +63,10 @@ public class Mp4DashReader {
|
|||
private boolean chunkZero = false;
|
||||
|
||||
private int selectedTrack = -1;
|
||||
private Box backupBox = null;
|
||||
|
||||
public enum TrackKind {
|
||||
Audio, Video, Other
|
||||
Audio, Video, Subtitles, Other
|
||||
}
|
||||
|
||||
public Mp4DashReader(SharpStream source) {
|
||||
|
@ -65,8 +79,15 @@ public class Mp4DashReader {
|
|||
}
|
||||
|
||||
box = readBox(ATOM_FTYP);
|
||||
if (parse_ftyp() != BRAND_DASH) {
|
||||
throw new NoSuchElementException("Main Brand is not dash");
|
||||
brands = parse_ftyp(box);
|
||||
switch (brands[0]) {
|
||||
case BRAND_DASH:
|
||||
case BRAND_ISO5:// ¿why not?
|
||||
break;
|
||||
default:
|
||||
throw new NoSuchElementException(
|
||||
"Not a MPEG-4 DASH container, major brand is not 'dash' or 'iso5' is " + boxName(brands[0])
|
||||
);
|
||||
}
|
||||
|
||||
Moov moov = null;
|
||||
|
@ -84,8 +105,6 @@ public class Mp4DashReader {
|
|||
break;
|
||||
case ATOM_MFRA:
|
||||
break;
|
||||
case ATOM_MDAT:
|
||||
throw new IOException("Expected moof, found mdat");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,15 +126,26 @@ public class Mp4DashReader {
|
|||
}
|
||||
}
|
||||
|
||||
if (moov.trak[i].tkhd.bHeight == 0 && moov.trak[i].tkhd.bWidth == 0) {
|
||||
tracks[i].kind = moov.trak[i].tkhd.bVolume == 0 ? TrackKind.Other : TrackKind.Audio;
|
||||
} else {
|
||||
tracks[i].kind = TrackKind.Video;
|
||||
switch (moov.trak[i].mdia.hdlr.subType) {
|
||||
case HANDLER_VIDE:
|
||||
tracks[i].kind = TrackKind.Video;
|
||||
break;
|
||||
case HANDLER_SOUN:
|
||||
tracks[i].kind = TrackKind.Audio;
|
||||
break;
|
||||
case HANDLER_SUBT:
|
||||
tracks[i].kind = TrackKind.Subtitles;
|
||||
break;
|
||||
default:
|
||||
tracks[i].kind = TrackKind.Other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
backupBox = box;
|
||||
}
|
||||
|
||||
public Mp4Track selectTrack(int index) {
|
||||
Mp4Track selectTrack(int index) {
|
||||
selectedTrack = index;
|
||||
return tracks[index];
|
||||
}
|
||||
|
@ -126,7 +156,7 @@ public class Mp4DashReader {
|
|||
* @return list with a basic info
|
||||
* @throws IOException if the source stream is not seekeable
|
||||
*/
|
||||
public int getFragmentsCount() throws IOException {
|
||||
int getFragmentsCount() throws IOException {
|
||||
if (selectedTrack < 0) {
|
||||
throw new IllegalStateException("track no selected");
|
||||
}
|
||||
|
@ -136,7 +166,6 @@ public class Mp4DashReader {
|
|||
|
||||
Box tmp;
|
||||
int count = 0;
|
||||
long orig_offset = stream.position();
|
||||
|
||||
if (box.type == ATOM_MOOF) {
|
||||
tmp = box;
|
||||
|
@ -162,17 +191,36 @@ public class Mp4DashReader {
|
|||
ensure(tmp);
|
||||
} while (stream.available() && (tmp = readBox()) != null);
|
||||
|
||||
stream.rewind();
|
||||
stream.skipBytes((int) orig_offset);
|
||||
rewind();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public int[] getBrands() {
|
||||
if (brands == null) throw new IllegalStateException("Not parsed");
|
||||
return brands;
|
||||
}
|
||||
|
||||
public void rewind() throws IOException {
|
||||
if (!stream.canRewind()) {
|
||||
throw new IOException("The provided stream doesn't allow seek");
|
||||
}
|
||||
if (box == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
box = backupBox;
|
||||
chunkZero = false;
|
||||
|
||||
stream.rewind();
|
||||
stream.skipBytes(backupBox.offset + (DataReader.INTEGER_SIZE * 2));
|
||||
}
|
||||
|
||||
public Mp4Track[] getAvailableTracks() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
public Mp4TrackChunk getNextChunk() throws IOException {
|
||||
public Mp4DashChunk getNextChunk(boolean infoOnly) throws IOException {
|
||||
Mp4Track track = tracks[selectedTrack];
|
||||
|
||||
while (stream.available()) {
|
||||
|
@ -208,7 +256,7 @@ public class Mp4DashReader {
|
|||
if (hasFlag(moof.traf.tfhd.bFlags, 0x10)) {
|
||||
moof.traf.trun.chunkSize = moof.traf.tfhd.defaultSampleSize * moof.traf.trun.entryCount;
|
||||
} else {
|
||||
moof.traf.trun.chunkSize = box.size - 8;
|
||||
moof.traf.trun.chunkSize = (int) (box.size - 8);
|
||||
}
|
||||
}
|
||||
if (!hasFlag(moof.traf.trun.bFlags, 0x900) && moof.traf.trun.chunkDuration == 0) {
|
||||
|
@ -228,9 +276,12 @@ public class Mp4DashReader {
|
|||
continue;// find another chunk
|
||||
}
|
||||
|
||||
Mp4TrackChunk chunk = new Mp4TrackChunk();
|
||||
Mp4DashChunk chunk = new Mp4DashChunk();
|
||||
chunk.moof = moof;
|
||||
chunk.data = new TrackDataChunk(stream, moof.traf.trun.chunkSize);
|
||||
if (!infoOnly) {
|
||||
chunk.data = stream.getView(moof.traf.trun.chunkSize);
|
||||
}
|
||||
|
||||
moof = null;
|
||||
|
||||
stream.skipBytes(chunk.moof.traf.trun.dataOffset);
|
||||
|
@ -269,6 +320,10 @@ public class Mp4DashReader {
|
|||
b.size = stream.readInt();
|
||||
b.type = stream.readInt();
|
||||
|
||||
if (b.size == 1) {
|
||||
b.size = stream.readLong();
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
@ -280,6 +335,25 @@ public class Mp4DashReader {
|
|||
return b;
|
||||
}
|
||||
|
||||
private byte[] readFullBox(Box ref) throws IOException {
|
||||
// full box reading is limited to 2 GiB, and should be enough
|
||||
int size = (int) ref.size;
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||
buffer.putInt(size);
|
||||
buffer.putInt(ref.type);
|
||||
|
||||
int read = size - 8;
|
||||
|
||||
if (stream.read(buffer.array(), 8, read) != read) {
|
||||
throw new EOFException(
|
||||
String.format("EOF reached in box: type=%s offset=%s size=%s", boxName(ref.type), ref.offset, ref.size)
|
||||
);
|
||||
}
|
||||
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
private void ensure(Box ref) throws IOException {
|
||||
long skip = ref.offset + ref.size - stream.position();
|
||||
|
||||
|
@ -310,6 +384,14 @@ public class Mp4DashReader {
|
|||
return null;
|
||||
}
|
||||
|
||||
private Box untilAnyBox(Box ref) throws IOException {
|
||||
if (stream.position() >= (ref.offset + ref.size)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return readBox();
|
||||
}
|
||||
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultState="collapsed" desc="Box readers">
|
||||
|
@ -329,7 +411,7 @@ public class Mp4DashReader {
|
|||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -397,14 +479,14 @@ public class Mp4DashReader {
|
|||
|
||||
private long parse_tfdt() throws IOException {
|
||||
int version = stream.read();
|
||||
stream.skipBytes(3);// flags
|
||||
stream.skipBytes(3);// flags
|
||||
return version == 0 ? readUint() : stream.readLong();
|
||||
}
|
||||
|
||||
private Trun parse_trun() throws IOException {
|
||||
Trun obj = new Trun();
|
||||
obj.bFlags = stream.readInt();
|
||||
obj.entryCount = stream.readInt();// unsigned int
|
||||
obj.entryCount = stream.readInt();// unsigned int
|
||||
|
||||
obj.entries_rowSize = 0;
|
||||
if (hasFlag(obj.bFlags, 0x0100)) {
|
||||
|
@ -448,11 +530,18 @@ public class Mp4DashReader {
|
|||
return obj;
|
||||
}
|
||||
|
||||
private int parse_ftyp() throws IOException {
|
||||
int brand = stream.readInt();
|
||||
private int[] parse_ftyp(Box ref) throws IOException {
|
||||
int i = 0;
|
||||
int[] list = new int[(int) ((ref.offset + ref.size - stream.position() - 4) / 4)];
|
||||
|
||||
list[i++] = stream.readInt();// major brand
|
||||
|
||||
stream.skipBytes(4);// minor version
|
||||
|
||||
return brand;
|
||||
for (; i < list.length; i++)
|
||||
list[i] = stream.readInt();// compatible brands
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private Mvhd parse_mvhd() throws IOException {
|
||||
|
@ -521,32 +610,66 @@ public class Mp4DashReader {
|
|||
trak.tkhd = parse_tkhd();
|
||||
ensure(b);
|
||||
|
||||
b = untilBox(ref, ATOM_MDIA);
|
||||
trak.mdia = new byte[b.size];
|
||||
while ((b = untilBox(ref, ATOM_MDIA, ATOM_EDTS)) != null) {
|
||||
switch (b.type) {
|
||||
case ATOM_MDIA:
|
||||
trak.mdia = parse_mdia(b);
|
||||
break;
|
||||
case ATOM_EDTS:
|
||||
trak.edst_elst = parse_edts(b);
|
||||
break;
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(trak.mdia);
|
||||
buffer.putInt(b.size);
|
||||
buffer.putInt(ATOM_MDIA);
|
||||
stream.read(trak.mdia, 8, b.size - 8);
|
||||
|
||||
trak.mdia_mdhd_timeScale = parse_mdia(buffer);
|
||||
ensure(b);
|
||||
}
|
||||
|
||||
return trak;
|
||||
}
|
||||
|
||||
private int parse_mdia(ByteBuffer data) {
|
||||
while (data.hasRemaining()) {
|
||||
int end = data.position() + data.getInt();
|
||||
if (data.getInt() == ATOM_MDHD) {
|
||||
byte version = data.get();
|
||||
data.position(data.position() + 3 + ((version == 0 ? 4 : 8) * 2));
|
||||
return data.getInt();
|
||||
}
|
||||
private Mdia parse_mdia(Box ref) throws IOException {
|
||||
Mdia obj = new Mdia();
|
||||
|
||||
data.position(end);
|
||||
Box b;
|
||||
while ((b = untilBox(ref, ATOM_MDHD, ATOM_HDLR, ATOM_MINF)) != null) {
|
||||
switch (b.type) {
|
||||
case ATOM_MDHD:
|
||||
obj.mdhd = readFullBox(b);
|
||||
|
||||
// read time scale
|
||||
ByteBuffer buffer = ByteBuffer.wrap(obj.mdhd);
|
||||
byte version = buffer.get(8);
|
||||
buffer.position(12 + ((version == 0 ? 4 : 8) * 2));
|
||||
obj.mdhd_timeScale = buffer.getInt();
|
||||
break;
|
||||
case ATOM_HDLR:
|
||||
obj.hdlr = parse_hdlr(b);
|
||||
break;
|
||||
case ATOM_MINF:
|
||||
obj.minf = parse_minf(b);
|
||||
break;
|
||||
}
|
||||
ensure(b);
|
||||
}
|
||||
|
||||
return 0;// this NEVER should happen
|
||||
return obj;
|
||||
}
|
||||
|
||||
private Hdlr parse_hdlr(Box ref) throws IOException {
|
||||
// version
|
||||
// flags
|
||||
stream.skipBytes(4);
|
||||
|
||||
Hdlr obj = new Hdlr();
|
||||
obj.bReserved = new byte[12];
|
||||
|
||||
obj.type = stream.readInt();
|
||||
obj.subType = stream.readInt();
|
||||
stream.read(obj.bReserved);
|
||||
|
||||
// component name (is a ansi/ascii string)
|
||||
stream.skipBytes((ref.offset + ref.size) - stream.position());
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private Moov parse_moov(Box ref) throws IOException {
|
||||
|
@ -570,7 +693,7 @@ public class Mp4DashReader {
|
|||
ensure(b);
|
||||
}
|
||||
|
||||
moov.trak = tmp.toArray(new Trak[tmp.size()]);
|
||||
moov.trak = tmp.toArray(new Trak[0]);
|
||||
|
||||
return moov;
|
||||
}
|
||||
|
@ -584,7 +707,7 @@ public class Mp4DashReader {
|
|||
ensure(b);
|
||||
}
|
||||
|
||||
return tmp.toArray(new Trex[tmp.size()]);
|
||||
return tmp.toArray(new Trex[0]);
|
||||
}
|
||||
|
||||
private Trex parse_trex() throws IOException {
|
||||
|
@ -602,74 +725,74 @@ public class Mp4DashReader {
|
|||
return obj;
|
||||
}
|
||||
|
||||
private Tfra parse_tfra() throws IOException {
|
||||
int version = stream.read();
|
||||
|
||||
stream.skipBytes(3);// flags
|
||||
|
||||
Tfra tfra = new Tfra();
|
||||
tfra.trackId = stream.readInt();
|
||||
|
||||
stream.skipBytes(3);// reserved
|
||||
int bFlags = stream.read();
|
||||
int size_tts = ((bFlags >> 4) & 3) + ((bFlags >> 2) & 3) + (bFlags & 3);
|
||||
|
||||
tfra.entries_time = new int[stream.readInt()];
|
||||
|
||||
for (int i = 0; i < tfra.entries_time.length; i++) {
|
||||
tfra.entries_time[i] = version == 0 ? stream.readInt() : (int) stream.readLong();
|
||||
stream.skipBytes(size_tts + (version == 0 ? 4 : 8));
|
||||
private Elst parse_edts(Box ref) throws IOException {
|
||||
Box b = untilBox(ref, ATOM_ELST);
|
||||
if (b == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return tfra;
|
||||
}
|
||||
|
||||
private Sidx parse_sidx() throws IOException {
|
||||
int version = stream.read();
|
||||
Elst obj = new Elst();
|
||||
|
||||
boolean v1 = stream.read() == 1;
|
||||
stream.skipBytes(3);// flags
|
||||
|
||||
Sidx obj = new Sidx();
|
||||
obj.referenceId = stream.readInt();
|
||||
obj.timescale = stream.readInt();
|
||||
int entryCount = stream.readInt();
|
||||
if (entryCount < 1) {
|
||||
obj.bMediaRate = 0x00010000;// default media rate (1.0)
|
||||
return obj;
|
||||
}
|
||||
|
||||
// earliest presentation entries_time
|
||||
// first offset
|
||||
// reserved
|
||||
stream.skipBytes((2 * (version == 0 ? 4 : 8)) + 2);
|
||||
if (v1) {
|
||||
stream.skipBytes(DataReader.LONG_SIZE);// segment duration
|
||||
obj.MediaTime = stream.readLong();
|
||||
// ignore all remain entries
|
||||
stream.skipBytes((entryCount - 1) * (DataReader.LONG_SIZE * 2));
|
||||
} else {
|
||||
stream.skipBytes(DataReader.INTEGER_SIZE);// segment duration
|
||||
obj.MediaTime = stream.readInt();
|
||||
}
|
||||
|
||||
obj.entries_subsegmentDuration = new int[stream.readShort()];
|
||||
obj.bMediaRate = stream.readInt();
|
||||
|
||||
for (int i = 0; i < obj.entries_subsegmentDuration.length; i++) {
|
||||
// reference type
|
||||
// referenced size
|
||||
stream.skipBytes(4);
|
||||
obj.entries_subsegmentDuration[i] = stream.readInt();// unsigned int
|
||||
return obj;
|
||||
}
|
||||
|
||||
// starts with SAP
|
||||
// SAP type
|
||||
// SAP delta entries_time
|
||||
stream.skipBytes(4);
|
||||
private Minf parse_minf(Box ref) throws IOException {
|
||||
Minf obj = new Minf();
|
||||
|
||||
Box b;
|
||||
while ((b = untilAnyBox(ref)) != null) {
|
||||
|
||||
switch (b.type) {
|
||||
case ATOM_DINF:
|
||||
obj.dinf = readFullBox(b);
|
||||
break;
|
||||
case ATOM_STBL:
|
||||
obj.stbl_stsd = parse_stbl(b);
|
||||
break;
|
||||
case ATOM_VMHD:
|
||||
case ATOM_SMHD:
|
||||
obj.$mhd = readFullBox(b);
|
||||
break;
|
||||
|
||||
}
|
||||
ensure(b);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private Tfra[] parse_mfra(Box ref, int trackCount) throws IOException {
|
||||
ArrayList<Tfra> tmp = new ArrayList<>(trackCount);
|
||||
long limit = ref.offset + ref.size;
|
||||
/**
|
||||
* this only read the "stsd" box inside
|
||||
*/
|
||||
private byte[] parse_stbl(Box ref) throws IOException {
|
||||
Box b = untilBox(ref, ATOM_STSD);
|
||||
|
||||
while (stream.position() < limit) {
|
||||
box = readBox();
|
||||
|
||||
if (box.type == ATOM_TFRA) {
|
||||
tmp.add(parse_tfra());
|
||||
}
|
||||
|
||||
ensure(box);
|
||||
if (b == null) {
|
||||
return new byte[0];// this never should happens (missing codec startup data)
|
||||
}
|
||||
|
||||
return tmp.toArray(new Tfra[tmp.size()]);
|
||||
return readFullBox(b);
|
||||
}
|
||||
|
||||
// </editor-fold>
|
||||
|
@ -679,14 +802,7 @@ public class Mp4DashReader {
|
|||
|
||||
int type;
|
||||
long offset;
|
||||
int size;
|
||||
}
|
||||
|
||||
class Sidx {
|
||||
|
||||
int timescale;
|
||||
int referenceId;
|
||||
int[] entries_subsegmentDuration;
|
||||
long size;
|
||||
}
|
||||
|
||||
public class Moof {
|
||||
|
@ -711,12 +827,16 @@ public class Mp4DashReader {
|
|||
int defaultSampleFlags;
|
||||
}
|
||||
|
||||
public class TrunEntry {
|
||||
class TrunEntry {
|
||||
|
||||
int sampleDuration;
|
||||
int sampleSize;
|
||||
int sampleFlags;
|
||||
int sampleCompositionTimeOffset;
|
||||
|
||||
boolean hasCompositionTimeOffset;
|
||||
boolean isKeyframe;
|
||||
|
||||
public int sampleDuration;
|
||||
public int sampleSize;
|
||||
public int sampleFlags;
|
||||
public int sampleCompositionTimeOffset;
|
||||
}
|
||||
|
||||
public class Trun {
|
||||
|
@ -749,6 +869,31 @@ public class Mp4DashReader {
|
|||
entry.sampleCompositionTimeOffset = buffer.getInt();
|
||||
}
|
||||
|
||||
entry.hasCompositionTimeOffset = hasFlag(bFlags, 0x0800);
|
||||
entry.isKeyframe = !hasFlag(entry.sampleFlags, 0x10000);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public TrunEntry getAbsoluteEntry(int i, Tfhd header) {
|
||||
TrunEntry entry = getEntry(i);
|
||||
|
||||
if (!hasFlag(bFlags, 0x0100) && hasFlag(header.bFlags, 0x20)) {
|
||||
entry.sampleFlags = header.defaultSampleFlags;
|
||||
}
|
||||
|
||||
if (!hasFlag(bFlags, 0x0200) && hasFlag(header.bFlags, 0x10)) {
|
||||
entry.sampleSize = header.defaultSampleSize;
|
||||
}
|
||||
|
||||
if (!hasFlag(bFlags, 0x0100) && hasFlag(header.bFlags, 0x08)) {
|
||||
entry.sampleDuration = header.defaultSampleDuration;
|
||||
}
|
||||
|
||||
if (i == 0 && hasFlag(bFlags, 0x0004)) {
|
||||
entry.sampleFlags = bFirstSampleFlags;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
@ -768,9 +913,9 @@ public class Mp4DashReader {
|
|||
public class Trak {
|
||||
|
||||
public Tkhd tkhd;
|
||||
public int mdia_mdhd_timeScale;
|
||||
public Elst edst_elst;
|
||||
public Mdia mdia;
|
||||
|
||||
byte[] mdia;
|
||||
}
|
||||
|
||||
class Mvhd {
|
||||
|
@ -786,12 +931,6 @@ public class Mp4DashReader {
|
|||
Trex[] mvex_trex;
|
||||
}
|
||||
|
||||
class Tfra {
|
||||
|
||||
int trackId;
|
||||
int[] entries_time;
|
||||
}
|
||||
|
||||
public class Trex {
|
||||
|
||||
private int trackId;
|
||||
|
@ -801,6 +940,34 @@ public class Mp4DashReader {
|
|||
int defaultSampleFlags;
|
||||
}
|
||||
|
||||
public class Elst {
|
||||
|
||||
public long MediaTime;
|
||||
public int bMediaRate;
|
||||
}
|
||||
|
||||
public class Mdia {
|
||||
|
||||
public int mdhd_timeScale;
|
||||
public byte[] mdhd;
|
||||
public Hdlr hdlr;
|
||||
public Minf minf;
|
||||
}
|
||||
|
||||
public class Hdlr {
|
||||
|
||||
public int type;
|
||||
public int subType;
|
||||
public byte[] bReserved;
|
||||
}
|
||||
|
||||
public class Minf {
|
||||
|
||||
public byte[] dinf;
|
||||
public byte[] stbl_stsd;
|
||||
public byte[] $mhd;
|
||||
}
|
||||
|
||||
public class Mp4Track {
|
||||
|
||||
public TrackKind kind;
|
||||
|
@ -808,10 +975,43 @@ public class Mp4DashReader {
|
|||
public Trex trex;
|
||||
}
|
||||
|
||||
public class Mp4TrackChunk {
|
||||
public class Mp4DashChunk {
|
||||
|
||||
public InputStream data;
|
||||
public Moof moof;
|
||||
private int i = 0;
|
||||
|
||||
public TrunEntry getNextSampleInfo() {
|
||||
if (i >= moof.traf.trun.entryCount) {
|
||||
return null;
|
||||
}
|
||||
return moof.traf.trun.getAbsoluteEntry(i++, moof.traf.tfhd);
|
||||
}
|
||||
|
||||
public Mp4DashSample getNextSample() throws IOException {
|
||||
if (data == null) {
|
||||
throw new IllegalStateException("This chunk has info only");
|
||||
}
|
||||
if (i >= moof.traf.trun.entryCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Mp4DashSample sample = new Mp4DashSample();
|
||||
sample.info = moof.traf.trun.getAbsoluteEntry(i++, moof.traf.tfhd);
|
||||
sample.data = new byte[sample.info.sampleSize];
|
||||
|
||||
if (data.read(sample.data) != sample.info.sampleSize) {
|
||||
throw new EOFException("EOF reached while reading a sample");
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
|
||||
public class Mp4DashSample {
|
||||
|
||||
public TrunEntry info;
|
||||
public byte[] data;
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
|
|
|
@ -1,623 +0,0 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Mp4Track;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Mp4TrackChunk;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Trak;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Trex;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.schabi.newpipe.streams.Mp4DashReader.hasFlag;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kapodamy
|
||||
*/
|
||||
public class Mp4DashWriter {
|
||||
|
||||
private final static byte DIMENSIONAL_FIVE = 5;
|
||||
private final static byte DIMENSIONAL_TWO = 2;
|
||||
private final static short DEFAULT_TIMESCALE = 1000;
|
||||
private final static int BUFFER_SIZE = 8 * 1024;
|
||||
private final static byte DEFAULT_TREX_SIZE = 32;
|
||||
private final static byte[] TFRA_TTS_DEFAULT = new byte[]{0x01, 0x01, 0x01};
|
||||
private final static int EPOCH_OFFSET = 2082844800;
|
||||
|
||||
private Mp4Track[] infoTracks;
|
||||
private SharpStream[] sourceTracks;
|
||||
|
||||
private Mp4DashReader[] readers;
|
||||
private final long time;
|
||||
|
||||
private boolean done = false;
|
||||
private boolean parsed = false;
|
||||
|
||||
private long written = 0;
|
||||
private ArrayList<ArrayList<Integer>> chunkTimes;
|
||||
private ArrayList<Long> moofOffsets;
|
||||
private ArrayList<Integer> fragSizes;
|
||||
|
||||
public Mp4DashWriter(SharpStream... source) {
|
||||
sourceTracks = source;
|
||||
readers = new Mp4DashReader[sourceTracks.length];
|
||||
infoTracks = new Mp4Track[sourceTracks.length];
|
||||
time = (System.currentTimeMillis() / 1000L) + EPOCH_OFFSET;
|
||||
}
|
||||
|
||||
public Mp4Track[] getTracksFromSource(int sourceIndex) throws IllegalStateException {
|
||||
if (!parsed) {
|
||||
throw new IllegalStateException("All sources must be parsed first");
|
||||
}
|
||||
|
||||
return readers[sourceIndex].getAvailableTracks();
|
||||
}
|
||||
|
||||
public void parseSources() throws IOException, IllegalStateException {
|
||||
if (done) {
|
||||
throw new IllegalStateException("already done");
|
||||
}
|
||||
if (parsed) {
|
||||
throw new IllegalStateException("already parsed");
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
readers[i] = new Mp4DashReader(sourceTracks[i]);
|
||||
readers[i].parse();
|
||||
}
|
||||
|
||||
} finally {
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void selectTracks(int... trackIndex) throws IOException {
|
||||
if (done) {
|
||||
throw new IOException("already done");
|
||||
}
|
||||
if (chunkTimes != null) {
|
||||
throw new IOException("tracks already selected");
|
||||
}
|
||||
|
||||
try {
|
||||
chunkTimes = new ArrayList<>(readers.length);
|
||||
moofOffsets = new ArrayList<>(32);
|
||||
fragSizes = new ArrayList<>(32);
|
||||
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
infoTracks[i] = readers[i].selectTrack(trackIndex[i]);
|
||||
|
||||
chunkTimes.add(new ArrayList<Integer>(32));
|
||||
}
|
||||
|
||||
} finally {
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public long getBytesWritten() {
|
||||
return written;
|
||||
}
|
||||
|
||||
public void build(SharpStream out) throws IOException, RuntimeException {
|
||||
if (done) {
|
||||
throw new RuntimeException("already done");
|
||||
}
|
||||
if (!out.canWrite()) {
|
||||
throw new IOException("the provided output is not writable");
|
||||
}
|
||||
|
||||
long sidxOffsets = -1;
|
||||
int maxFrags = 0;
|
||||
|
||||
for (SharpStream stream : sourceTracks) {
|
||||
if (!stream.canRewind()) {
|
||||
sidxOffsets = -2;// sidx not available
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
dump(make_ftyp(), out);
|
||||
dump(make_moov(), out);
|
||||
|
||||
if (sidxOffsets == -1 && out.canRewind()) {
|
||||
//<editor-fold defaultstate="collapsed" desc="calculate sidx">
|
||||
int reserved = 0;
|
||||
for (Mp4DashReader reader : readers) {
|
||||
int count = reader.getFragmentsCount();
|
||||
if (count > maxFrags) {
|
||||
maxFrags = count;
|
||||
}
|
||||
reserved += 12 + calcSidxBodySize(count);
|
||||
}
|
||||
if (maxFrags > 0xFFFF) {
|
||||
sidxOffsets = -3;// TODO: to many fragments, needs a multi-sidx implementation
|
||||
} else {
|
||||
sidxOffsets = written;
|
||||
dump(make_free(reserved), out);
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
ArrayList<Mp4TrackChunk> chunks = new ArrayList<>(readers.length);
|
||||
chunks.add(null);
|
||||
|
||||
int read;
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int sequenceNumber = 1;
|
||||
|
||||
while (true) {
|
||||
chunks.clear();
|
||||
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
Mp4TrackChunk chunk = readers[i].getNextChunk();
|
||||
if (chunk == null || chunk.moof.traf.trun.chunkSize < 1) {
|
||||
continue;
|
||||
}
|
||||
chunk.moof.traf.tfhd.trackId = i + 1;
|
||||
chunks.add(chunk);
|
||||
|
||||
if (sequenceNumber == 1) {
|
||||
if (chunk.moof.traf.trun.entryCount > 0 && hasFlag(chunk.moof.traf.trun.bFlags, 0x0800)) {
|
||||
chunkTimes.get(i).add(chunk.moof.traf.trun.getEntry(0).sampleCompositionTimeOffset);
|
||||
} else {
|
||||
chunkTimes.get(i).add(0);
|
||||
}
|
||||
}
|
||||
|
||||
chunkTimes.get(i).add(chunk.moof.traf.trun.chunkDuration);
|
||||
}
|
||||
|
||||
if (chunks.size() < 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
long offset = written;
|
||||
moofOffsets.add(offset);
|
||||
|
||||
dump(make_moof(sequenceNumber++, chunks, offset), out);
|
||||
dump(make_mdat(chunks), out);
|
||||
|
||||
for (Mp4TrackChunk chunk : chunks) {
|
||||
while ((read = chunk.data.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, read);
|
||||
written += read;
|
||||
}
|
||||
}
|
||||
|
||||
fragSizes.add((int) (written - offset));
|
||||
}
|
||||
|
||||
dump(make_mfra(), out);
|
||||
|
||||
if (sidxOffsets > 0 && moofOffsets.size() == maxFrags) {
|
||||
long len = written;
|
||||
|
||||
out.rewind();
|
||||
out.skip(sidxOffsets);
|
||||
|
||||
written = sidxOffsets;
|
||||
sidxOffsets = moofOffsets.get(0);
|
||||
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
dump(make_sidx(i, sidxOffsets - written), out);
|
||||
}
|
||||
|
||||
written = len;
|
||||
}
|
||||
} finally {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
|
||||
public boolean isParsed() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
done = true;
|
||||
parsed = true;
|
||||
|
||||
for (SharpStream src : sourceTracks) {
|
||||
src.dispose();
|
||||
}
|
||||
|
||||
sourceTracks = null;
|
||||
readers = null;
|
||||
infoTracks = null;
|
||||
moofOffsets = null;
|
||||
chunkTimes = null;
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="Utils">
|
||||
private void dump(byte[][] buffer, SharpStream stream) throws IOException {
|
||||
for (byte[] buff : buffer) {
|
||||
stream.write(buff);
|
||||
written += buff.length;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[][] lengthFor(byte[][] buffer) {
|
||||
int length = 0;
|
||||
for (byte[] buff : buffer) {
|
||||
length += buff.length;
|
||||
}
|
||||
|
||||
ByteBuffer.wrap(buffer[0]).putInt(length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private int calcSidxBodySize(int entryCount) {
|
||||
return 4 + 4 + 8 + 8 + 4 + (entryCount * 12);
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="Box makers">
|
||||
private byte[][] make_moof(int sequence, ArrayList<Mp4TrackChunk> chunks, long referenceOffset) {
|
||||
int pos = 2;
|
||||
TrunExtra[] extra = new TrunExtra[chunks.size()];
|
||||
|
||||
byte[][] buffer = new byte[pos + (extra.length * DIMENSIONAL_FIVE)][];
|
||||
buffer[0] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x6F, 0x6F, 0x66,// info header
|
||||
0x00, 0x00, 0x00, 0x10, 0x6D, 0x66, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00//mfhd
|
||||
};
|
||||
buffer[1] = new byte[4];
|
||||
ByteBuffer.wrap(buffer[1]).putInt(sequence);
|
||||
|
||||
for (int i = 0; i < extra.length; i++) {
|
||||
extra[i] = new TrunExtra();
|
||||
for (byte[] buff : make_traf(chunks.get(i), extra[i], referenceOffset)) {
|
||||
buffer[pos++] = buff;
|
||||
}
|
||||
}
|
||||
|
||||
lengthFor(buffer);
|
||||
|
||||
int offset = 8 + ByteBuffer.wrap(buffer[0]).getInt();
|
||||
|
||||
for (int i = 0; i < extra.length; i++) {
|
||||
extra[i].byteBuffer.putInt(offset);
|
||||
offset += chunks.get(i).moof.traf.trun.chunkSize;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private byte[][] make_traf(Mp4TrackChunk chunk, TrunExtra extra, long moofOffset) {
|
||||
byte[][] buffer = new byte[DIMENSIONAL_FIVE][];
|
||||
buffer[0] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x74, 0x72, 0x61, 0x66,
|
||||
0x00, 0x00, 0x00, 0x00, 0x74, 0x66, 0x68, 0x64
|
||||
};
|
||||
|
||||
int flags = (chunk.moof.traf.tfhd.bFlags & 0x38) | 0x01;
|
||||
byte tfhdBodySize = 8 + 8;
|
||||
if (hasFlag(flags, 0x08)) {
|
||||
tfhdBodySize += 4;
|
||||
}
|
||||
if (hasFlag(flags, 0x10)) {
|
||||
tfhdBodySize += 4;
|
||||
}
|
||||
if (hasFlag(flags, 0x20)) {
|
||||
tfhdBodySize += 4;
|
||||
}
|
||||
buffer[1] = new byte[tfhdBodySize];
|
||||
ByteBuffer set = ByteBuffer.wrap(buffer[1]);
|
||||
set.position(4);
|
||||
set.putInt(chunk.moof.traf.tfhd.trackId);
|
||||
set.putLong(moofOffset);
|
||||
if (hasFlag(flags, 0x08)) {
|
||||
set.putInt(chunk.moof.traf.tfhd.defaultSampleDuration);
|
||||
}
|
||||
if (hasFlag(flags, 0x10)) {
|
||||
set.putInt(chunk.moof.traf.tfhd.defaultSampleSize);
|
||||
}
|
||||
if (hasFlag(flags, 0x20)) {
|
||||
set.putInt(chunk.moof.traf.tfhd.defaultSampleFlags);
|
||||
}
|
||||
set.putInt(0, flags);
|
||||
ByteBuffer.wrap(buffer[0]).putInt(8, 8 + tfhdBodySize);
|
||||
|
||||
buffer[2] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x14,
|
||||
0x74, 0x66, 0x64, 0x74,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
ByteBuffer.wrap(buffer[2]).putLong(12, chunk.moof.traf.tfdt);
|
||||
|
||||
buffer[3] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x74, 0x72, 0x75, 0x6E,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
buffer[4] = chunk.moof.traf.trun.bEntries;
|
||||
|
||||
lengthFor(buffer);
|
||||
|
||||
set = ByteBuffer.wrap(buffer[3]);
|
||||
set.putInt(buffer[3].length + buffer[4].length);
|
||||
set.position(8);
|
||||
set.putInt((chunk.moof.traf.trun.bFlags | 0x01) & 0x0F01);
|
||||
set.putInt(chunk.moof.traf.trun.entryCount);
|
||||
extra.byteBuffer = set;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private byte[][] make_mdat(ArrayList<Mp4TrackChunk> chunks) {
|
||||
byte[][] buffer = new byte[][]{
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x64, 0x61, 0x74
|
||||
}
|
||||
};
|
||||
|
||||
int length = 0;
|
||||
|
||||
for (Mp4TrackChunk chunk : chunks) {
|
||||
length += chunk.moof.traf.trun.chunkSize;
|
||||
}
|
||||
|
||||
ByteBuffer.wrap(buffer[0]).putInt(length + 8);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private byte[][] make_ftyp() {
|
||||
return new byte[][]{
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x64, 0x61, 0x73, 0x68, 0x00, 0x00, 0x00, 0x00,
|
||||
0x6D, 0x70, 0x34, 0x31, 0x69, 0x73, 0x6F, 0x6D, 0x69, 0x73, 0x6F, 0x36, 0x69, 0x73, 0x6F, 0x32
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private byte[][] make_mvhd() {
|
||||
byte[][] buffer = new byte[DIMENSIONAL_FIVE][];
|
||||
|
||||
buffer[0] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x78, 0x6D, 0x76, 0x68, 0x64, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
buffer[1] = new byte[28];
|
||||
buffer[2] = new byte[]{
|
||||
0x00, 0x01, 0x00, 0x00, 0x01, 0x00,// default volume and rate
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// reserved values
|
||||
// default matrix
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00
|
||||
};
|
||||
buffer[3] = new byte[24];// predefined
|
||||
buffer[4] = ByteBuffer.allocate(4).putInt(infoTracks.length + 1).array();
|
||||
|
||||
long longestTrack = 0;
|
||||
|
||||
for (Mp4Track track : infoTracks) {
|
||||
long tmp = (long) ((track.trak.tkhd.duration / (double) track.trak.mdia_mdhd_timeScale) * DEFAULT_TIMESCALE);
|
||||
if (tmp > longestTrack) {
|
||||
longestTrack = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer.wrap(buffer[1])
|
||||
.putLong(time)
|
||||
.putLong(time)
|
||||
.putInt(DEFAULT_TIMESCALE)
|
||||
.putLong(longestTrack);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private byte[][] make_trak(int trackId, Trak trak) throws RuntimeException {
|
||||
if (trak.tkhd.matrix.length != 36) {
|
||||
throw new RuntimeException("bad track matrix length (expected 36)");
|
||||
}
|
||||
|
||||
byte[][] buffer = new byte[DIMENSIONAL_FIVE][];
|
||||
|
||||
buffer[0] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x74, 0x72, 0x61, 0x6B,// trak header
|
||||
0x00, 0x00, 0x00, 0x68, 0x74, 0x6B, 0x68, 0x64, 0x01, 0x00, 0x00, 0x03 // tkhd header
|
||||
};
|
||||
buffer[1] = new byte[48];
|
||||
buffer[2] = trak.tkhd.matrix;
|
||||
buffer[3] = new byte[8];
|
||||
buffer[4] = trak.mdia;
|
||||
|
||||
ByteBuffer set = ByteBuffer.wrap(buffer[1]);
|
||||
set.putLong(time);
|
||||
set.putLong(time);
|
||||
set.putInt(trackId);
|
||||
set.position(24);
|
||||
set.putLong(trak.tkhd.duration);
|
||||
set.position(40);
|
||||
set.putShort(trak.tkhd.bLayer);
|
||||
set.putShort(trak.tkhd.bAlternateGroup);
|
||||
set.putShort(trak.tkhd.bVolume);
|
||||
|
||||
ByteBuffer.wrap(buffer[3])
|
||||
.putInt(trak.tkhd.bWidth)
|
||||
.putInt(trak.tkhd.bHeight);
|
||||
|
||||
return lengthFor(buffer);
|
||||
}
|
||||
|
||||
private byte[][] make_moov() throws RuntimeException {
|
||||
int pos = 1;
|
||||
byte[][] buffer = new byte[2 + (DIMENSIONAL_TWO * infoTracks.length) + (DIMENSIONAL_FIVE * infoTracks.length) + DIMENSIONAL_FIVE + 1][];
|
||||
|
||||
buffer[0] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x6F, 0x6F, 0x76
|
||||
};
|
||||
|
||||
for (byte[] buff : make_mvhd()) {
|
||||
buffer[pos++] = buff;
|
||||
}
|
||||
|
||||
for (int i = 0; i < infoTracks.length; i++) {
|
||||
for (byte[] buff : make_trak(i + 1, infoTracks[i].trak)) {
|
||||
buffer[pos++] = buff;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[pos] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x76, 0x65, 0x78
|
||||
};
|
||||
|
||||
ByteBuffer.wrap(buffer[pos++]).putInt((infoTracks.length * DEFAULT_TREX_SIZE) + 8);
|
||||
|
||||
for (int i = 0; i < infoTracks.length; i++) {
|
||||
for (byte[] buff : make_trex(i + 1, infoTracks[i].trex)) {
|
||||
buffer[pos++] = buff;
|
||||
}
|
||||
}
|
||||
|
||||
// default udta
|
||||
buffer[pos] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x5C, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x54, 0x6D, 0x65, 0x74, 0x61,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x68, 0x64, 0x6C, 0x72, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x64, 0x69, 0x72, 0x61, 0x70, 0x70, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x69, 0x6C, 0x73, 0x74, 0x00, 0x00, 0x00,
|
||||
0x1F, (byte) 0xA9, 0x63, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x17, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x4E, 0x65, 0x77, 0x50, 0x69, 0x70, 0x65// "NewPipe" binary string
|
||||
};
|
||||
|
||||
return lengthFor(buffer);
|
||||
}
|
||||
|
||||
private byte[][] make_trex(int trackId, Trex trex) {
|
||||
byte[][] buffer = new byte[][]{
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x20, 0x74, 0x72, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00
|
||||
},
|
||||
new byte[20]
|
||||
};
|
||||
|
||||
ByteBuffer.wrap(buffer[1])
|
||||
.putInt(trackId)
|
||||
.putInt(trex.defaultSampleDescriptionIndex)
|
||||
.putInt(trex.defaultSampleDuration)
|
||||
.putInt(trex.defaultSampleSize)
|
||||
.putInt(trex.defaultSampleFlags);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private byte[][] make_tfra(int trackId, List<Integer> times, List<Long> moofOffsets) {
|
||||
int entryCount = times.size() - 1;
|
||||
byte[][] buffer = new byte[DIMENSIONAL_TWO][];
|
||||
buffer[0] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x74, 0x66, 0x72, 0x61, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
buffer[1] = new byte[12 + ((16 + TFRA_TTS_DEFAULT.length) * entryCount)];
|
||||
|
||||
ByteBuffer set = ByteBuffer.wrap(buffer[1]);
|
||||
set.putInt(trackId);
|
||||
set.position(8);
|
||||
set.putInt(entryCount);
|
||||
|
||||
long decodeTime = 0;
|
||||
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
decodeTime += times.get(i);
|
||||
set.putLong(decodeTime);
|
||||
set.putLong(moofOffsets.get(i));
|
||||
set.put(TFRA_TTS_DEFAULT);// default values: traf number/trun number/sample number
|
||||
}
|
||||
|
||||
return lengthFor(buffer);
|
||||
}
|
||||
|
||||
private byte[][] make_mfra() {
|
||||
byte[][] buffer = new byte[2 + (DIMENSIONAL_TWO * infoTracks.length)][];
|
||||
buffer[0] = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x66, 0x72, 0x61
|
||||
};
|
||||
int pos = 1;
|
||||
|
||||
for (int i = 0; i < infoTracks.length; i++) {
|
||||
for (byte[] buff : make_tfra(i + 1, chunkTimes.get(i), moofOffsets)) {
|
||||
buffer[pos++] = buff;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[pos] = new byte[]{// mfro
|
||||
0x00, 0x00, 0x00, 0x10, 0x6D, 0x66, 0x72, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
lengthFor(buffer);
|
||||
|
||||
ByteBuffer set = ByteBuffer.wrap(buffer[pos]);
|
||||
set.position(12);
|
||||
set.put(buffer[0], 0, 4);
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
private byte[][] make_sidx(int internalTrackId, long firstOffset) {
|
||||
List<Integer> times = chunkTimes.get(internalTrackId);
|
||||
int count = times.size() - 1;// the first item is ignored (composition time)
|
||||
|
||||
if (count > 65535) {
|
||||
throw new OutOfMemoryError("to many fragments. sidx limit is 65535, found " + String.valueOf(count));
|
||||
}
|
||||
|
||||
byte[][] buffer = new byte[][]{
|
||||
new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x73, 0x69, 0x64, 0x78, 0x01, 0x00, 0x00, 0x00
|
||||
},
|
||||
new byte[calcSidxBodySize(count)]
|
||||
};
|
||||
|
||||
lengthFor(buffer);
|
||||
|
||||
ByteBuffer set = ByteBuffer.wrap(buffer[1]);
|
||||
set.putInt(internalTrackId + 1);
|
||||
set.putInt(infoTracks[internalTrackId].trak.mdia_mdhd_timeScale);
|
||||
set.putLong(0);
|
||||
set.putLong(firstOffset - ByteBuffer.wrap(buffer[0]).getInt());
|
||||
set.putInt(0xFFFF & count);// unsigned
|
||||
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
set.putInt(fragSizes.get(i) & 0x7fffffff);// default reference type is 0
|
||||
set.putInt(times.get(i + 1));
|
||||
set.putInt(0x90000000);// default SAP settings
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private byte[][] make_free(int totalSize) {
|
||||
return lengthFor(new byte[][]{
|
||||
new byte[]{0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x65, 0x65},
|
||||
new byte[totalSize - 8]// this is waste of RAM
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
|
||||
class TrunExtra {
|
||||
|
||||
ByteBuffer byteBuffer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,810 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Hdlr;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Mdia;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Mp4DashChunk;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Mp4DashSample;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.Mp4Track;
|
||||
import org.schabi.newpipe.streams.Mp4DashReader.TrunEntry;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
public class Mp4FromDashWriter {
|
||||
|
||||
private final static int EPOCH_OFFSET = 2082844800;
|
||||
private final static short DEFAULT_TIMESCALE = 1000;
|
||||
private final static byte SAMPLES_PER_CHUNK_INIT = 2;
|
||||
private final static byte SAMPLES_PER_CHUNK = 6;// ffmpeg uses 2, basic uses 1 (with 60fps uses 21 or 22). NewPipe will use 6
|
||||
private final static long THRESHOLD_FOR_CO64 = 0xFFFEFFFFL;// near 3.999 GiB
|
||||
private final static int THRESHOLD_MOOV_LENGTH = (256 * 1024) + (2048 * 1024); // 2.2 MiB enough for: 1080p 60fps 00h35m00s
|
||||
|
||||
private final long time;
|
||||
|
||||
private ByteBuffer auxBuffer;
|
||||
private SharpStream outStream;
|
||||
|
||||
private long lastWriteOffset = -1;
|
||||
private long writeOffset;
|
||||
|
||||
private boolean moovSimulation = true;
|
||||
|
||||
private boolean done = false;
|
||||
private boolean parsed = false;
|
||||
|
||||
private Mp4Track[] tracks;
|
||||
private SharpStream[] sourceTracks;
|
||||
|
||||
private Mp4DashReader[] readers;
|
||||
private Mp4DashChunk[] readersChunks;
|
||||
|
||||
private int overrideMainBrand = 0x00;
|
||||
|
||||
public Mp4FromDashWriter(SharpStream... sources) throws IOException {
|
||||
for (SharpStream src : sources) {
|
||||
if (!src.canRewind() && !src.canRead()) {
|
||||
throw new IOException("All sources must be readable and allow rewind");
|
||||
}
|
||||
}
|
||||
|
||||
sourceTracks = sources;
|
||||
readers = new Mp4DashReader[sourceTracks.length];
|
||||
readersChunks = new Mp4DashChunk[readers.length];
|
||||
time = (System.currentTimeMillis() / 1000L) + EPOCH_OFFSET;
|
||||
}
|
||||
|
||||
public Mp4Track[] getTracksFromSource(int sourceIndex) throws IllegalStateException {
|
||||
if (!parsed) {
|
||||
throw new IllegalStateException("All sources must be parsed first");
|
||||
}
|
||||
|
||||
return readers[sourceIndex].getAvailableTracks();
|
||||
}
|
||||
|
||||
public void parseSources() throws IOException, IllegalStateException {
|
||||
if (done) {
|
||||
throw new IllegalStateException("already done");
|
||||
}
|
||||
if (parsed) {
|
||||
throw new IllegalStateException("already parsed");
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
readers[i] = new Mp4DashReader(sourceTracks[i]);
|
||||
readers[i].parse();
|
||||
}
|
||||
|
||||
} finally {
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void selectTracks(int... trackIndex) throws IOException {
|
||||
if (done) {
|
||||
throw new IOException("already done");
|
||||
}
|
||||
if (tracks != null) {
|
||||
throw new IOException("tracks already selected");
|
||||
}
|
||||
|
||||
try {
|
||||
tracks = new Mp4Track[readers.length];
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
tracks[i] = readers[i].selectTrack(trackIndex[i]);
|
||||
}
|
||||
} finally {
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setMainBrand(int brandId) {
|
||||
overrideMainBrand = brandId;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
|
||||
public boolean isParsed() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
done = true;
|
||||
parsed = true;
|
||||
|
||||
for (SharpStream src : sourceTracks) {
|
||||
src.close();
|
||||
}
|
||||
|
||||
tracks = null;
|
||||
sourceTracks = null;
|
||||
|
||||
readers = null;
|
||||
readersChunks = null;
|
||||
|
||||
auxBuffer = null;
|
||||
outStream = null;
|
||||
}
|
||||
|
||||
public void build(SharpStream output) throws IOException {
|
||||
if (done) {
|
||||
throw new RuntimeException("already done");
|
||||
}
|
||||
if (!output.canWrite()) {
|
||||
throw new IOException("the provided output is not writable");
|
||||
}
|
||||
|
||||
//
|
||||
// WARNING: the muxer requires at least 8 samples of every track
|
||||
// not allowed for very short tracks (less than 0.5 seconds)
|
||||
//
|
||||
outStream = output;
|
||||
int read = 8;// mdat box header size
|
||||
long totalSampleSize = 0;
|
||||
int[] sampleExtra = new int[readers.length];
|
||||
int[] defaultMediaTime = new int[readers.length];
|
||||
int[] defaultSampleDuration = new int[readers.length];
|
||||
int[] sampleCount = new int[readers.length];
|
||||
|
||||
TablesInfo[] tablesInfo = new TablesInfo[tracks.length];
|
||||
for (int i = 0; i < tablesInfo.length; i++) {
|
||||
tablesInfo[i] = new TablesInfo();
|
||||
}
|
||||
|
||||
//<editor-fold defaultstate="expanded" desc="calculate stbl sample tables size and required moov values">
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
int samplesSize = 0;
|
||||
int sampleSizeChanges = 0;
|
||||
int compositionOffsetLast = -1;
|
||||
|
||||
Mp4DashChunk chunk;
|
||||
while ((chunk = readers[i].getNextChunk(true)) != null) {
|
||||
|
||||
if (defaultMediaTime[i] < 1 && chunk.moof.traf.tfhd.defaultSampleDuration > 0) {
|
||||
defaultMediaTime[i] = chunk.moof.traf.tfhd.defaultSampleDuration;
|
||||
}
|
||||
|
||||
read += chunk.moof.traf.trun.chunkSize;
|
||||
sampleExtra[i] += chunk.moof.traf.trun.chunkDuration;// calculate track duration
|
||||
|
||||
TrunEntry info;
|
||||
while ((info = chunk.getNextSampleInfo()) != null) {
|
||||
if (info.isKeyframe) {
|
||||
tablesInfo[i].stss++;
|
||||
}
|
||||
|
||||
if (info.sampleDuration > defaultSampleDuration[i]) {
|
||||
defaultSampleDuration[i] = info.sampleDuration;
|
||||
}
|
||||
|
||||
tablesInfo[i].stsz++;
|
||||
if (samplesSize != info.sampleSize) {
|
||||
samplesSize = info.sampleSize;
|
||||
sampleSizeChanges++;
|
||||
}
|
||||
|
||||
if (info.hasCompositionTimeOffset) {
|
||||
if (info.sampleCompositionTimeOffset != compositionOffsetLast) {
|
||||
tablesInfo[i].ctts++;
|
||||
compositionOffsetLast = info.sampleCompositionTimeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
totalSampleSize += info.sampleSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultMediaTime[i] < 1) {
|
||||
defaultMediaTime[i] = defaultSampleDuration[i];
|
||||
}
|
||||
|
||||
readers[i].rewind();
|
||||
|
||||
int tmp = tablesInfo[i].stsz - SAMPLES_PER_CHUNK_INIT;
|
||||
tablesInfo[i].stco = (tmp / SAMPLES_PER_CHUNK) + 1;// +1 for samples in first chunk
|
||||
|
||||
tmp = tmp % SAMPLES_PER_CHUNK;
|
||||
if (tmp == 0) {
|
||||
tablesInfo[i].stsc = 2;// first chunk (init) and succesive chunks
|
||||
tablesInfo[i].stsc_bEntries = new int[]{
|
||||
1, SAMPLES_PER_CHUNK_INIT, 1,
|
||||
2, SAMPLES_PER_CHUNK, 1
|
||||
};
|
||||
} else {
|
||||
tablesInfo[i].stsc = 3;// first chunk (init) and succesive chunks and remain chunk
|
||||
tablesInfo[i].stsc_bEntries = new int[]{
|
||||
1, SAMPLES_PER_CHUNK_INIT, 1,
|
||||
2, SAMPLES_PER_CHUNK, 1,
|
||||
tablesInfo[i].stco + 1, tmp, 1
|
||||
};
|
||||
tablesInfo[i].stco++;
|
||||
}
|
||||
|
||||
sampleCount[i] = tablesInfo[i].stsz;
|
||||
|
||||
if (sampleSizeChanges == 1) {
|
||||
tablesInfo[i].stsz = 0;
|
||||
tablesInfo[i].stsz_default = samplesSize;
|
||||
} else {
|
||||
tablesInfo[i].stsz_default = 0;
|
||||
}
|
||||
|
||||
if (tablesInfo[i].stss == tablesInfo[i].stsz) {
|
||||
tablesInfo[i].stss = -1;// for audio tracks (all samples are keyframes)
|
||||
}
|
||||
|
||||
// ensure track duration
|
||||
if (tracks[i].trak.tkhd.duration < 1) {
|
||||
tracks[i].trak.tkhd.duration = sampleExtra[i];// this never should happen
|
||||
}
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
boolean is64 = read > THRESHOLD_FOR_CO64;
|
||||
|
||||
// calculate the moov size;
|
||||
int auxSize = make_moov(defaultMediaTime, tablesInfo, is64);
|
||||
|
||||
if (auxSize < THRESHOLD_MOOV_LENGTH) {
|
||||
auxBuffer = ByteBuffer.allocate(auxSize);// cache moov in the memory
|
||||
}
|
||||
|
||||
moovSimulation = false;
|
||||
writeOffset = 0;
|
||||
|
||||
final int ftyp_size = make_ftyp();
|
||||
|
||||
// reserve moov space in the output stream
|
||||
/*if (outStream.canSetLength()) {
|
||||
long length = writeOffset + auxSize;
|
||||
outStream.setLength(length);
|
||||
outSeek(length);
|
||||
} else {*/
|
||||
if (auxSize > 0) {
|
||||
int length = auxSize;
|
||||
byte[] buffer = new byte[8 * 1024];// 8 KiB
|
||||
while (length > 0) {
|
||||
int count = Math.min(length, buffer.length);
|
||||
outWrite(buffer, 0, count);
|
||||
length -= count;
|
||||
}
|
||||
}
|
||||
|
||||
if (auxBuffer == null) {
|
||||
outSeek(ftyp_size);
|
||||
}
|
||||
|
||||
// tablesInfo contais row counts
|
||||
// and after returning from make_moov() will contain table offsets
|
||||
make_moov(defaultMediaTime, tablesInfo, is64);
|
||||
|
||||
// write tables: stts stsc
|
||||
// reset for ctts table: sampleCount sampleExtra
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
writeEntryArray(tablesInfo[i].stts, 2, sampleCount[i], defaultSampleDuration[i]);
|
||||
writeEntryArray(tablesInfo[i].stsc, tablesInfo[i].stsc_bEntries.length, tablesInfo[i].stsc_bEntries);
|
||||
tablesInfo[i].stsc_bEntries = null;
|
||||
if (tablesInfo[i].ctts > 0) {
|
||||
sampleCount[i] = 1;// index is not base zero
|
||||
sampleExtra[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (auxBuffer == null) {
|
||||
outRestore();
|
||||
}
|
||||
|
||||
outWrite(make_mdat(totalSampleSize, is64));
|
||||
|
||||
int[] sampleIndex = new int[readers.length];
|
||||
int[] sizes = new int[SAMPLES_PER_CHUNK];
|
||||
int[] sync = new int[SAMPLES_PER_CHUNK];
|
||||
|
||||
int written = readers.length;
|
||||
while (written > 0) {
|
||||
written = 0;
|
||||
|
||||
for (int i = 0; i < readers.length; i++) {
|
||||
if (sampleIndex[i] < 0) {
|
||||
continue;// track is done
|
||||
}
|
||||
|
||||
long chunkOffset = writeOffset;
|
||||
int syncCount = 0;
|
||||
int limit = sampleIndex[i] == 0 ? SAMPLES_PER_CHUNK_INIT : SAMPLES_PER_CHUNK;
|
||||
|
||||
int j = 0;
|
||||
for (; j < limit; j++) {
|
||||
Mp4DashSample sample = getNextSample(i);
|
||||
|
||||
if (sample == null) {
|
||||
if (tablesInfo[i].ctts > 0 && sampleExtra[i] >= 0) {
|
||||
writeEntryArray(tablesInfo[i].ctts, 1, sampleCount[i], sampleExtra[i]);// flush last entries
|
||||
}
|
||||
sampleIndex[i] = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
sampleIndex[i]++;
|
||||
|
||||
if (tablesInfo[i].ctts > 0) {
|
||||
if (sample.info.sampleCompositionTimeOffset == sampleExtra[i]) {
|
||||
sampleCount[i]++;
|
||||
} else {
|
||||
if (sampleExtra[i] >= 0) {
|
||||
tablesInfo[i].ctts = writeEntryArray(tablesInfo[i].ctts, 2, sampleCount[i], sampleExtra[i]);
|
||||
outRestore();
|
||||
}
|
||||
sampleCount[i] = 1;
|
||||
sampleExtra[i] = sample.info.sampleCompositionTimeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (tablesInfo[i].stss > 0 && sample.info.isKeyframe) {
|
||||
sync[syncCount++] = sampleIndex[i];
|
||||
}
|
||||
|
||||
if (tablesInfo[i].stsz > 0) {
|
||||
sizes[j] = sample.data.length;
|
||||
}
|
||||
|
||||
outWrite(sample.data, 0, sample.data.length);
|
||||
}
|
||||
|
||||
if (j > 0) {
|
||||
written++;
|
||||
|
||||
if (tablesInfo[i].stsz > 0) {
|
||||
tablesInfo[i].stsz = writeEntryArray(tablesInfo[i].stsz, j, sizes);
|
||||
}
|
||||
|
||||
if (syncCount > 0) {
|
||||
tablesInfo[i].stss = writeEntryArray(tablesInfo[i].stss, syncCount, sync);
|
||||
}
|
||||
|
||||
if (is64) {
|
||||
tablesInfo[i].stco = writeEntry64(tablesInfo[i].stco, chunkOffset);
|
||||
} else {
|
||||
tablesInfo[i].stco = writeEntryArray(tablesInfo[i].stco, 1, (int) chunkOffset);
|
||||
}
|
||||
|
||||
outRestore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auxBuffer != null) {
|
||||
// dump moov
|
||||
outSeek(ftyp_size);
|
||||
outStream.write(auxBuffer.array(), 0, auxBuffer.capacity());
|
||||
auxBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Mp4DashSample getNextSample(int track) throws IOException {
|
||||
if (readersChunks[track] == null) {
|
||||
readersChunks[track] = readers[track].getNextChunk(false);
|
||||
if (readersChunks[track] == null) {
|
||||
return null;// EOF reached
|
||||
}
|
||||
}
|
||||
|
||||
Mp4DashSample sample = readersChunks[track].getNextSample();
|
||||
if (sample == null) {
|
||||
readersChunks[track] = null;
|
||||
return getNextSample(track);
|
||||
} else {
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="expanded" desc="Stbl handling">
|
||||
private int writeEntry64(int offset, long value) throws IOException {
|
||||
outBackup();
|
||||
|
||||
auxSeek(offset);
|
||||
auxWrite(ByteBuffer.allocate(8).putLong(value).array());
|
||||
|
||||
return offset + 8;
|
||||
}
|
||||
|
||||
private int writeEntryArray(int offset, int count, int... values) throws IOException {
|
||||
outBackup();
|
||||
|
||||
auxSeek(offset);
|
||||
|
||||
int size = count * 4;
|
||||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
buffer.putInt(values[i]);
|
||||
}
|
||||
|
||||
auxWrite(buffer.array());
|
||||
|
||||
return offset + size;
|
||||
}
|
||||
|
||||
private void outBackup() {
|
||||
if (auxBuffer == null && lastWriteOffset < 0) {
|
||||
lastWriteOffset = writeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore to the previous position before the first call to writeEntry64()
|
||||
* or writeEntryArray() methods.
|
||||
*/
|
||||
private void outRestore() throws IOException {
|
||||
if (lastWriteOffset > 0) {
|
||||
outSeek(lastWriteOffset);
|
||||
lastWriteOffset = -1;
|
||||
}
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultstate="expanded" desc="Utils">
|
||||
private void outWrite(byte[] buffer) throws IOException {
|
||||
outWrite(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
private void outWrite(byte[] buffer, int offset, int count) throws IOException {
|
||||
writeOffset += count;
|
||||
outStream.write(buffer, offset, count);
|
||||
}
|
||||
|
||||
private void outSeek(long offset) throws IOException {
|
||||
if (outStream.canSeek()) {
|
||||
outStream.seek(offset);
|
||||
writeOffset = offset;
|
||||
} else if (outStream.canRewind()) {
|
||||
outStream.rewind();
|
||||
writeOffset = 0;
|
||||
outSkip(offset);
|
||||
} else {
|
||||
throw new IOException("cannot seek or rewind the output stream");
|
||||
}
|
||||
}
|
||||
|
||||
private void outSkip(long amount) throws IOException {
|
||||
outStream.skip(amount);
|
||||
writeOffset += amount;
|
||||
}
|
||||
|
||||
private int lengthFor(int offset) throws IOException {
|
||||
int size = auxOffset() - offset;
|
||||
|
||||
if (moovSimulation) {
|
||||
return size;
|
||||
}
|
||||
|
||||
auxSeek(offset);
|
||||
auxWrite(size);
|
||||
auxSkip(size - 4);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private int make(int type, int extra, int columns, int rows) throws IOException {
|
||||
final byte base = 16;
|
||||
int size = columns * rows * 4;
|
||||
int total = size + base;
|
||||
int offset = auxOffset();
|
||||
|
||||
if (extra >= 0) {
|
||||
total += 4;
|
||||
}
|
||||
|
||||
auxWrite(ByteBuffer.allocate(12)
|
||||
.putInt(total)
|
||||
.putInt(type)
|
||||
.putInt(0x00)// default version & flags
|
||||
.array()
|
||||
);
|
||||
|
||||
if (extra >= 0) {
|
||||
//size += 4;// commented for auxiliar buffer !!!
|
||||
offset += 4;
|
||||
auxWrite(extra);
|
||||
}
|
||||
|
||||
auxWrite(rows);
|
||||
auxSkip(size);
|
||||
|
||||
return offset + base;
|
||||
}
|
||||
|
||||
private void auxWrite(int value) throws IOException {
|
||||
auxWrite(ByteBuffer.allocate(4)
|
||||
.putInt(value)
|
||||
.array()
|
||||
);
|
||||
}
|
||||
|
||||
private void auxWrite(byte[] buffer) throws IOException {
|
||||
if (moovSimulation) {
|
||||
writeOffset += buffer.length;
|
||||
} else if (auxBuffer == null) {
|
||||
outWrite(buffer, 0, buffer.length);
|
||||
} else {
|
||||
auxBuffer.put(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private void auxSeek(int offset) throws IOException {
|
||||
if (moovSimulation) {
|
||||
writeOffset = offset;
|
||||
} else if (auxBuffer == null) {
|
||||
outSeek(offset);
|
||||
} else {
|
||||
auxBuffer.position(offset);
|
||||
}
|
||||
}
|
||||
|
||||
private void auxSkip(int amount) throws IOException {
|
||||
if (moovSimulation) {
|
||||
writeOffset += amount;
|
||||
} else if (auxBuffer == null) {
|
||||
outSkip(amount);
|
||||
} else {
|
||||
auxBuffer.position(auxBuffer.position() + amount);
|
||||
}
|
||||
}
|
||||
|
||||
private int auxOffset() {
|
||||
return auxBuffer == null ? (int) writeOffset : auxBuffer.position();
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultstate="expanded" desc="Box makers">
|
||||
private int make_ftyp() throws IOException {
|
||||
byte[] buffer = new byte[]{
|
||||
0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70,// ftyp
|
||||
0x6D, 0x70, 0x34, 0x32,// mayor brand (mp42)
|
||||
0x00, 0x00, 0x02, 0x00,// default minor version (512)
|
||||
0x6D, 0x70, 0x34, 0x31, 0x69, 0x73, 0x6F, 0x6D, 0x69, 0x73, 0x6F, 0x32// compatible brands: mp41 isom iso2
|
||||
};
|
||||
|
||||
if (overrideMainBrand != 0)
|
||||
ByteBuffer.wrap(buffer).putInt(8, overrideMainBrand);
|
||||
|
||||
outWrite(buffer);
|
||||
|
||||
return buffer.length;
|
||||
}
|
||||
|
||||
private byte[] make_mdat(long refSize, boolean is64) {
|
||||
if (is64) {
|
||||
refSize += 16;
|
||||
} else {
|
||||
refSize += 8;
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(is64 ? 16 : 8)
|
||||
.putInt(is64 ? 0x01 : (int) refSize)
|
||||
.putInt(0x6D646174);// mdat
|
||||
|
||||
if (is64) {
|
||||
buffer.putLong(refSize);
|
||||
}
|
||||
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
private void make_mvhd(long longestTrack) throws IOException {
|
||||
auxWrite(new byte[]{
|
||||
0x00, 0x00, 0x00, 0x78, 0x6D, 0x76, 0x68, 0x64, 0x01, 0x00, 0x00, 0x00
|
||||
});
|
||||
auxWrite(ByteBuffer.allocate(28)
|
||||
.putLong(time)
|
||||
.putLong(time)
|
||||
.putInt(DEFAULT_TIMESCALE)
|
||||
.putLong(longestTrack)
|
||||
.array()
|
||||
);
|
||||
|
||||
auxWrite(new byte[]{
|
||||
0x00, 0x01, 0x00, 0x00, 0x01, 0x00,// default volume and rate
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// reserved values
|
||||
// default matrix
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00
|
||||
});
|
||||
auxWrite(new byte[24]);// predefined
|
||||
auxWrite(ByteBuffer.allocate(4)
|
||||
.putInt(tracks.length + 1)
|
||||
.array()
|
||||
);
|
||||
}
|
||||
|
||||
private int make_moov(int[] defaultMediaTime, TablesInfo[] tablesInfo, boolean is64) throws RuntimeException, IOException {
|
||||
int start = auxOffset();
|
||||
|
||||
auxWrite(new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x6F, 0x6F, 0x76
|
||||
});
|
||||
|
||||
long longestTrack = 0;
|
||||
long[] durations = new long[tracks.length];
|
||||
|
||||
for (int i = 0; i < durations.length; i++) {
|
||||
durations[i] = (long) Math.ceil(
|
||||
((double) tracks[i].trak.tkhd.duration / tracks[i].trak.mdia.mdhd_timeScale) * DEFAULT_TIMESCALE
|
||||
);
|
||||
|
||||
if (durations[i] > longestTrack) {
|
||||
longestTrack = durations[i];
|
||||
}
|
||||
}
|
||||
|
||||
make_mvhd(longestTrack);
|
||||
|
||||
for (int i = 0; i < tracks.length; i++) {
|
||||
if (tracks[i].trak.tkhd.matrix.length != 36) {
|
||||
throw new RuntimeException("bad track matrix length (expected 36) in track n°" + i);
|
||||
}
|
||||
make_trak(i, durations[i], defaultMediaTime[i], tablesInfo[i], is64);
|
||||
}
|
||||
|
||||
// udta/meta/ilst/©too
|
||||
auxWrite(new byte[]{
|
||||
0x00, 0x00, 0x00, 0x5C, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x54, 0x6D, 0x65, 0x74, 0x61,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x68, 0x64, 0x6C, 0x72, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x64, 0x69, 0x72, 0x61, 0x70, 0x70, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x69, 0x6C, 0x73, 0x74, 0x00, 0x00, 0x00,
|
||||
0x1F, (byte) 0xA9, 0x74, 0x6F, 0x6F, 0x00, 0x00, 0x00, 0x17, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x4E, 0x65, 0x77, 0x50, 0x69, 0x70, 0x65// "NewPipe" binary string
|
||||
});
|
||||
|
||||
return lengthFor(start);
|
||||
}
|
||||
|
||||
private void make_trak(int index, long duration, int defaultMediaTime, TablesInfo tables, boolean is64) throws IOException {
|
||||
int start = auxOffset();
|
||||
|
||||
auxWrite(new byte[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x74, 0x72, 0x61, 0x6B,// trak header
|
||||
0x00, 0x00, 0x00, 0x68, 0x74, 0x6B, 0x68, 0x64, 0x01, 0x00, 0x00, 0x03 // tkhd header
|
||||
});
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(48);
|
||||
buffer.putLong(time);
|
||||
buffer.putLong(time);
|
||||
buffer.putInt(index + 1);
|
||||
buffer.position(24);
|
||||
buffer.putLong(duration);
|
||||
buffer.position(40);
|
||||
buffer.putShort(tracks[index].trak.tkhd.bLayer);
|
||||
buffer.putShort(tracks[index].trak.tkhd.bAlternateGroup);
|
||||
buffer.putShort(tracks[index].trak.tkhd.bVolume);
|
||||
auxWrite(buffer.array());
|
||||
|
||||
auxWrite(tracks[index].trak.tkhd.matrix);
|
||||
auxWrite(ByteBuffer.allocate(8)
|
||||
.putInt(tracks[index].trak.tkhd.bWidth)
|
||||
.putInt(tracks[index].trak.tkhd.bHeight)
|
||||
.array()
|
||||
);
|
||||
|
||||
auxWrite(new byte[]{
|
||||
0x00, 0x00, 0x00, 0x24, 0x65, 0x64, 0x74, 0x73,// edts header
|
||||
0x00, 0x00, 0x00, 0x1C, 0x65, 0x6C, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01// elst header
|
||||
});
|
||||
|
||||
int bMediaRate;
|
||||
int mediaTime;
|
||||
|
||||
if (tracks[index].trak.edst_elst == null) {
|
||||
// is a audio track ¿is edst/elst opcional for audio tracks?
|
||||
mediaTime = 0x00;// ffmpeg set this value as zero, instead of defaultMediaTime
|
||||
bMediaRate = 0x00010000;
|
||||
} else {
|
||||
mediaTime = (int) tracks[index].trak.edst_elst.MediaTime;
|
||||
bMediaRate = tracks[index].trak.edst_elst.bMediaRate;
|
||||
}
|
||||
|
||||
auxWrite(ByteBuffer
|
||||
.allocate(12)
|
||||
.putInt((int) duration)
|
||||
.putInt(mediaTime)
|
||||
.putInt(bMediaRate)
|
||||
.array()
|
||||
);
|
||||
|
||||
make_mdia(tracks[index].trak.mdia, tables, is64);
|
||||
|
||||
lengthFor(start);
|
||||
}
|
||||
|
||||
private void make_mdia(Mdia mdia, TablesInfo tablesInfo, boolean is64) throws IOException {
|
||||
|
||||
int start_mdia = auxOffset();
|
||||
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x6D, 0x64, 0x69, 0x61});// mdia
|
||||
auxWrite(mdia.mdhd);
|
||||
auxWrite(make_hdlr(mdia.hdlr));
|
||||
|
||||
int start_minf = auxOffset();
|
||||
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x6D, 0x69, 0x6E, 0x66});// minf
|
||||
auxWrite(mdia.minf.$mhd);
|
||||
auxWrite(mdia.minf.dinf);
|
||||
|
||||
int start_stbl = auxOffset();
|
||||
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x62, 0x6C});// stbl
|
||||
auxWrite(mdia.minf.stbl_stsd);
|
||||
|
||||
//
|
||||
// In audio tracks the following tables is not required: ssts ctts
|
||||
// And stsz can be empty if has a default sample size
|
||||
//
|
||||
if (moovSimulation) {
|
||||
make(0x73747473, -1, 2, 1);
|
||||
if (tablesInfo.stss > 0) {
|
||||
make(0x73747373, -1, 1, tablesInfo.stss);
|
||||
}
|
||||
if (tablesInfo.ctts > 0) {
|
||||
make(0x63747473, -1, 2, tablesInfo.ctts);
|
||||
}
|
||||
make(0x73747363, -1, 3, tablesInfo.stsc);
|
||||
make(0x7374737A, tablesInfo.stsz_default, 1, tablesInfo.stsz);
|
||||
make(is64 ? 0x636F3634 : 0x7374636F, -1, is64 ? 2 : 1, tablesInfo.stco);
|
||||
} else {
|
||||
tablesInfo.stts = make(0x73747473, -1, 2, 1);
|
||||
if (tablesInfo.stss > 0) {
|
||||
tablesInfo.stss = make(0x73747373, -1, 1, tablesInfo.stss);
|
||||
}
|
||||
if (tablesInfo.ctts > 0) {
|
||||
tablesInfo.ctts = make(0x63747473, -1, 2, tablesInfo.ctts);
|
||||
}
|
||||
tablesInfo.stsc = make(0x73747363, -1, 3, tablesInfo.stsc);
|
||||
tablesInfo.stsz = make(0x7374737A, tablesInfo.stsz_default, 1, tablesInfo.stsz);
|
||||
tablesInfo.stco = make(is64 ? 0x636F3634 : 0x7374636F, -1, is64 ? 2 : 1, tablesInfo.stco);
|
||||
}
|
||||
|
||||
lengthFor(start_stbl);
|
||||
lengthFor(start_minf);
|
||||
lengthFor(start_mdia);
|
||||
}
|
||||
|
||||
private byte[] make_hdlr(Hdlr hdlr) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(new byte[]{
|
||||
0x00, 0x00, 0x00, 0x77, 0x68, 0x64, 0x6C, 0x72,// hdlr
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// binary string "ISO Media file created in NewPipe (A libre lightweight streaming frontend for Android)."
|
||||
0x49, 0x53, 0x4F, 0x20, 0x4D, 0x65, 0x64, 0x69, 0x61, 0x20, 0x66, 0x69, 0x6C, 0x65, 0x20, 0x63,
|
||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x4E, 0x65, 0x77, 0x50, 0x69, 0x70,
|
||||
0x65, 0x20, 0x28, 0x41, 0x20, 0x6C, 0x69, 0x62, 0x72, 0x65, 0x20, 0x6C, 0x69, 0x67, 0x68, 0x74,
|
||||
0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x69, 0x6E, 0x67,
|
||||
0x20, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x41, 0x6E,
|
||||
0x64, 0x72, 0x6F, 0x69, 0x64, 0x29, 0x2E
|
||||
});
|
||||
|
||||
buffer.position(12);
|
||||
buffer.putInt(hdlr.type);
|
||||
buffer.putInt(hdlr.subType);
|
||||
buffer.put(hdlr.bReserved);// always is a zero array
|
||||
|
||||
return buffer.array();
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
class TablesInfo {
|
||||
|
||||
public int stts;
|
||||
public int stsc;
|
||||
public int[] stsc_bEntries;
|
||||
public int ctts;
|
||||
public int stsz;
|
||||
public int stsz_default;
|
||||
public int stss;
|
||||
public int stco;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
@ -12,8 +13,6 @@ import java.nio.charset.Charset;
|
|||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
@ -27,11 +26,11 @@ public class SubtitleConverter {
|
|||
|
||||
public void dumpTTML(SharpStream in, final SharpStream out, final boolean ignoreEmptyFrames, final boolean detectYoutubeDuplicateLines
|
||||
) throws IOException, ParseException, SAXException, ParserConfigurationException, XPathExpressionException {
|
||||
|
||||
|
||||
final FrameWriter callback = new FrameWriter() {
|
||||
int frameIndex = 0;
|
||||
final Charset charset = Charset.forName("utf-8");
|
||||
|
||||
|
||||
@Override
|
||||
public void yield(SubtitleFrame frame) throws IOException {
|
||||
if (ignoreEmptyFrames && frame.isEmptyText()) {
|
||||
|
@ -48,13 +47,13 @@ public class SubtitleConverter {
|
|||
out.write(NEW_LINE.getBytes(charset));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
read_xml_based(in, callback, detectYoutubeDuplicateLines,
|
||||
"tt", "xmlns", "http://www.w3.org/ns/ttml",
|
||||
new String[]{"timedtext", "head", "wp"},
|
||||
new String[]{"body", "div", "p"},
|
||||
"begin", "end", true
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
private void read_xml_based(SharpStream source, FrameWriter callback, boolean detectYoutubeDuplicateLines,
|
||||
|
@ -70,7 +69,7 @@ public class SubtitleConverter {
|
|||
* Language parsing is not supported
|
||||
*/
|
||||
|
||||
byte[] buffer = new byte[source.available()];
|
||||
byte[] buffer = new byte[(int) source.available()];
|
||||
source.read(buffer);
|
||||
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
|
@ -206,7 +205,7 @@ public class SubtitleConverter {
|
|||
}
|
||||
}
|
||||
|
||||
private static NodeList selectNodes(Document xml, String[] path, String namespaceUri) throws XPathExpressionException {
|
||||
private static NodeList selectNodes(Document xml, String[] path, String namespaceUri) {
|
||||
Element ref = xml.getDocumentElement();
|
||||
|
||||
for (int i = 0; i < path.length - 1; i++) {
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TrackDataChunk extends InputStream {
|
||||
|
||||
private final DataReader base;
|
||||
private int size;
|
||||
|
||||
public TrackDataChunk(DataReader base, int size) {
|
||||
this.base = base;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (size < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = base.read();
|
||||
|
||||
if (res >= 0) {
|
||||
size--;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
return read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int count) throws IOException {
|
||||
count = Math.min(size, count);
|
||||
int read = base.read(buffer, offset, count);
|
||||
size -= count;
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long amount) throws IOException {
|
||||
long res = base.skipBytes(Math.min(amount, size));
|
||||
size -= res;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -121,7 +122,7 @@ public class WebMReader {
|
|||
}
|
||||
|
||||
private String readString(Element parent) throws IOException {
|
||||
return new String(readBlob(parent), "utf-8");
|
||||
return new String(readBlob(parent), StandardCharsets.UTF_8);// or use "utf-8"
|
||||
}
|
||||
|
||||
private byte[] readBlob(Element parent) throws IOException {
|
||||
|
@ -193,6 +194,7 @@ public class WebMReader {
|
|||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
ensure(elem);
|
||||
}
|
||||
|
||||
|
@ -306,7 +308,7 @@ public class WebMReader {
|
|||
entry.trackNumber = readNumber(elem);
|
||||
break;
|
||||
case ID_TrackType:
|
||||
entry.trackType = (int)readNumber(elem);
|
||||
entry.trackType = (int) readNumber(elem);
|
||||
break;
|
||||
case ID_CodecID:
|
||||
entry.codecId = readString(elem);
|
||||
|
@ -445,7 +447,7 @@ public class WebMReader {
|
|||
|
||||
public class SimpleBlock {
|
||||
|
||||
public TrackDataChunk data;
|
||||
public InputStream data;
|
||||
|
||||
SimpleBlock(Element ref) {
|
||||
this.ref = ref;
|
||||
|
@ -492,7 +494,7 @@ public class WebMReader {
|
|||
|
||||
currentSimpleBlock = readSimpleBlock(elem);
|
||||
if (currentSimpleBlock.trackNumber == tracks[selectedTrack].trackNumber) {
|
||||
currentSimpleBlock.data = new TrackDataChunk(stream, (int) currentSimpleBlock.dataSize);
|
||||
currentSimpleBlock.data = stream.getView((int) currentSimpleBlock.dataSize);
|
||||
return currentSimpleBlock;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
package org.schabi.newpipe.streams;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.streams.WebMReader.Cluster;
|
||||
import org.schabi.newpipe.streams.WebMReader.Segment;
|
||||
import org.schabi.newpipe.streams.WebMReader.SimpleBlock;
|
||||
import org.schabi.newpipe.streams.WebMReader.WebMTrack;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kapodamy
|
||||
*/
|
||||
public class WebMWriter {
|
||||
|
@ -94,10 +94,6 @@ public class WebMWriter {
|
|||
}
|
||||
}
|
||||
|
||||
public long getBytesWritten() {
|
||||
return written;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
|
@ -111,7 +107,7 @@ public class WebMWriter {
|
|||
parsed = true;
|
||||
|
||||
for (SharpStream src : sourceTracks) {
|
||||
src.dispose();
|
||||
src.close();
|
||||
}
|
||||
|
||||
sourceTracks = null;
|
||||
|
@ -138,42 +134,42 @@ public class WebMWriter {
|
|||
|
||||
/* segment */
|
||||
listBuffer.add(new byte[]{
|
||||
0x18, 0x53, (byte) 0x80, 0x67, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00// segment content size
|
||||
0x18, 0x53, (byte) 0x80, 0x67, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00// segment content size
|
||||
});
|
||||
|
||||
long baseSegmentOffset = written + listBuffer.get(0).length;
|
||||
|
||||
/* seek head */
|
||||
listBuffer.add(new byte[]{
|
||||
0x11, 0x4d, (byte) 0x9b, 0x74, (byte) 0xbe,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8b,
|
||||
0x53, (byte) 0xab, (byte) 0x84, 0x15, 0x49, (byte) 0xa9, 0x66, 0x53,
|
||||
(byte) 0xac, (byte) 0x81, /*info offset*/ 0x43,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8b, 0x53, (byte) 0xab,
|
||||
(byte) 0x84, 0x16, 0x54, (byte) 0xae, 0x6b, 0x53, (byte) 0xac, (byte) 0x81,
|
||||
/*tracks offset*/ 0x6a,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8e, 0x53, (byte) 0xab, (byte) 0x84, 0x1f,
|
||||
0x43, (byte) 0xb6, 0x75, 0x53, (byte) 0xac, (byte) 0x84, /*cluster offset [2]*/ 0x00, 0x00, 0x00, 0x00,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8e, 0x53, (byte) 0xab, (byte) 0x84, 0x1c, 0x53,
|
||||
(byte) 0xbb, 0x6b, 0x53, (byte) 0xac, (byte) 0x84, /*cues offset [7]*/ 0x00, 0x00, 0x00, 0x00
|
||||
0x11, 0x4d, (byte) 0x9b, 0x74, (byte) 0xbe,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8b,
|
||||
0x53, (byte) 0xab, (byte) 0x84, 0x15, 0x49, (byte) 0xa9, 0x66, 0x53,
|
||||
(byte) 0xac, (byte) 0x81, /*info offset*/ 0x43,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8b, 0x53, (byte) 0xab,
|
||||
(byte) 0x84, 0x16, 0x54, (byte) 0xae, 0x6b, 0x53, (byte) 0xac, (byte) 0x81,
|
||||
/*tracks offset*/ 0x6a,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8e, 0x53, (byte) 0xab, (byte) 0x84, 0x1f,
|
||||
0x43, (byte) 0xb6, 0x75, 0x53, (byte) 0xac, (byte) 0x84, /*cluster offset [2]*/ 0x00, 0x00, 0x00, 0x00,
|
||||
0x4d, (byte) 0xbb, (byte) 0x8e, 0x53, (byte) 0xab, (byte) 0x84, 0x1c, 0x53,
|
||||
(byte) 0xbb, 0x6b, 0x53, (byte) 0xac, (byte) 0x84, /*cues offset [7]*/ 0x00, 0x00, 0x00, 0x00
|
||||
});
|
||||
|
||||
/* info */
|
||||
listBuffer.add(new byte[]{
|
||||
0x15, 0x49, (byte) 0xa9, 0x66, (byte) 0xa2, 0x2a, (byte) 0xd7, (byte) 0xb1
|
||||
0x15, 0x49, (byte) 0xa9, 0x66, (byte) 0xa2, 0x2a, (byte) 0xd7, (byte) 0xb1
|
||||
});
|
||||
listBuffer.add(encode(DEFAULT_TIMECODE_SCALE, true));// this value MUST NOT exceed 4 bytes
|
||||
listBuffer.add(new byte[]{0x44, (byte) 0x89, (byte) 0x84,
|
||||
0x00, 0x00, 0x00, 0x00,// info.duration
|
||||
|
||||
/* MuxingApp */
|
||||
0x4d, (byte) 0x80, (byte) 0x87, 0x4E,
|
||||
0x65, 0x77, 0x50, 0x69, 0x70, 0x65, // "NewPipe" binary string
|
||||
|
||||
/* WritingApp */
|
||||
0x57, 0x41, (byte) 0x87, 0x4E,
|
||||
0x65, 0x77, 0x50, 0x69, 0x70, 0x65// "NewPipe" binary string
|
||||
0x00, 0x00, 0x00, 0x00,// info.duration
|
||||
|
||||
/* MuxingApp */
|
||||
0x4d, (byte) 0x80, (byte) 0x87, 0x4E,
|
||||
0x65, 0x77, 0x50, 0x69, 0x70, 0x65, // "NewPipe" binary string
|
||||
|
||||
/* WritingApp */
|
||||
0x57, 0x41, (byte) 0x87, 0x4E,
|
||||
0x65, 0x77, 0x50, 0x69, 0x70, 0x65// "NewPipe" binary string
|
||||
});
|
||||
|
||||
/* tracks */
|
||||
|
@ -200,7 +196,6 @@ public class WebMWriter {
|
|||
long nextCueTime = infoTracks[cuesForTrackId].trackType == 1 ? -1 : 0;
|
||||
ArrayList<KeyFrame> keyFrames = new ArrayList<>(32);
|
||||
|
||||
//ArrayList<Block> chunks = new ArrayList<>(readers.length);
|
||||
ArrayList<Long> clusterOffsets = new ArrayList<>(32);
|
||||
ArrayList<Integer> clusterSizes = new ArrayList<>(32);
|
||||
|
||||
|
@ -283,24 +278,21 @@ public class WebMWriter {
|
|||
|
||||
long segmentSize = written - offsetSegmentSizeSet - 7;
|
||||
|
||||
// final step write offsets and sizes
|
||||
out.rewind();
|
||||
written = 0;
|
||||
|
||||
skipTo(out, offsetSegmentSizeSet);
|
||||
/* ---- final step write offsets and sizes ---- */
|
||||
seekTo(out, offsetSegmentSizeSet);
|
||||
writeLong(out, segmentSize);
|
||||
|
||||
if (predefinedDurations[durationFromTrackId] > -1) {
|
||||
duration += predefinedDurations[durationFromTrackId];// this value is full-filled in makeTrackEntry() method
|
||||
}
|
||||
skipTo(out, offsetInfoDurationSet);
|
||||
seekTo(out, offsetInfoDurationSet);
|
||||
writeFloat(out, duration);
|
||||
|
||||
firstClusterOffset -= baseSegmentOffset;
|
||||
skipTo(out, offsetClusterSet);
|
||||
seekTo(out, offsetClusterSet);
|
||||
writeInt(out, firstClusterOffset);
|
||||
|
||||
skipTo(out, cueReservedOffset);
|
||||
seekTo(out, cueReservedOffset);
|
||||
|
||||
/* Cue */
|
||||
dump(new byte[]{0x1c, 0x53, (byte) 0xbb, 0x6b, 0x20, 0x00, 0x00}, out);
|
||||
|
@ -321,20 +313,16 @@ public class WebMWriter {
|
|||
voidBuffer.putShort((short) (firstClusterOffset - written - 4));
|
||||
dump(voidBuffer.array(), out);
|
||||
|
||||
out.rewind();
|
||||
written = 0;
|
||||
|
||||
skipTo(out, offsetCuesSet);
|
||||
seekTo(out, offsetCuesSet);
|
||||
writeInt(out, (int) (cueReservedOffset - baseSegmentOffset));
|
||||
|
||||
skipTo(out, cueReservedOffset + 5);
|
||||
seekTo(out, cueReservedOffset + 5);
|
||||
writeShort(out, cueSize);
|
||||
|
||||
for (int i = 0; i < clusterSizes.size(); i++) {
|
||||
skipTo(out, clusterOffsets.get(i));
|
||||
byte[] size = ByteBuffer.allocate(4).putInt(clusterSizes.get(i) | 0x200000).array();
|
||||
out.write(size, 1, 3);
|
||||
written += 3;
|
||||
seekTo(out, clusterOffsets.get(i));
|
||||
byte[] buffer = ByteBuffer.allocate(4).putInt(clusterSizes.get(i) | 0x10000000).array();
|
||||
dump(buffer, out);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,20 +353,29 @@ public class WebMWriter {
|
|||
bloq.dataSize = (int) res.dataSize;
|
||||
bloq.trackNumber = internalTrackId;
|
||||
bloq.flags = res.flags;
|
||||
bloq.absoluteTimecode = convertTimecode(res.relativeTimeCode, readersSegment[internalTrackId].info.timecodeScale, DEFAULT_TIMECODE_SCALE);
|
||||
bloq.absoluteTimecode = convertTimecode(res.relativeTimeCode, readersSegment[internalTrackId].info.timecodeScale);
|
||||
bloq.absoluteTimecode += readersCluter[internalTrackId].timecode;
|
||||
|
||||
return bloq;
|
||||
}
|
||||
|
||||
private short convertTimecode(int time, long oldTimeScale, int newTimeScale) {
|
||||
return (short) (time * (newTimeScale / oldTimeScale));
|
||||
private short convertTimecode(int time, long oldTimeScale) {
|
||||
return (short) (time * (DEFAULT_TIMECODE_SCALE / oldTimeScale));
|
||||
}
|
||||
|
||||
private void skipTo(SharpStream stream, long absoluteOffset) throws IOException {
|
||||
absoluteOffset -= written;
|
||||
written += absoluteOffset;
|
||||
stream.skip(absoluteOffset);
|
||||
private void seekTo(SharpStream stream, long offset) throws IOException {
|
||||
if (stream.canSeek()) {
|
||||
stream.seek(offset);
|
||||
} else {
|
||||
if (offset > written) {
|
||||
stream.skip(offset - written);
|
||||
} else {
|
||||
stream.rewind();
|
||||
stream.skip(offset);
|
||||
}
|
||||
}
|
||||
|
||||
written = offset;
|
||||
}
|
||||
|
||||
private void writeLong(SharpStream stream, long number) throws IOException {
|
||||
|
@ -453,7 +450,7 @@ public class WebMWriter {
|
|||
/* cluster */
|
||||
dump(new byte[]{0x1f, 0x43, (byte) 0xb6, 0x75}, stream);
|
||||
clusterOffsets.add(written);// warning: max cluster size is 256 MiB
|
||||
dump(new byte[]{0x20, 0x00, 0x00}, stream);
|
||||
dump(new byte[]{0x10, 0x00, 0x00, 0x00}, stream);
|
||||
|
||||
startOffset = written;// size for the this cluster
|
||||
|
||||
|
@ -468,12 +465,12 @@ public class WebMWriter {
|
|||
private void makeEBML(SharpStream stream) throws IOException {
|
||||
// deafult values
|
||||
dump(new byte[]{
|
||||
0x1A, 0x45, (byte) 0xDF, (byte) 0xA3, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x42, (byte) 0x86, (byte) 0x81, 0x01,
|
||||
0x42, (byte) 0xF7, (byte) 0x81, 0x01, 0x42, (byte) 0xF2, (byte) 0x81, 0x04,
|
||||
0x42, (byte) 0xF3, (byte) 0x81, 0x08, 0x42, (byte) 0x82, (byte) 0x84, 0x77,
|
||||
0x65, 0x62, 0x6D, 0x42, (byte) 0x87, (byte) 0x81, 0x02,
|
||||
0x42, (byte) 0x85, (byte) 0x81, 0x02
|
||||
0x1A, 0x45, (byte) 0xDF, (byte) 0xA3, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x42, (byte) 0x86, (byte) 0x81, 0x01,
|
||||
0x42, (byte) 0xF7, (byte) 0x81, 0x01, 0x42, (byte) 0xF2, (byte) 0x81, 0x04,
|
||||
0x42, (byte) 0xF3, (byte) 0x81, 0x08, 0x42, (byte) 0x82, (byte) 0x84, 0x77,
|
||||
0x65, 0x62, 0x6D, 0x42, (byte) 0x87, (byte) 0x81, 0x02,
|
||||
0x42, (byte) 0x85, (byte) 0x81, 0x02
|
||||
}, stream);
|
||||
}
|
||||
|
||||
|
@ -618,9 +615,10 @@ public class WebMWriter {
|
|||
|
||||
int offset = withLength ? 1 : 0;
|
||||
byte[] buffer = new byte[offset + length];
|
||||
long marker = (long) Math.floor((length - 1) / 8);
|
||||
long marker = (long) Math.floor((length - 1f) / 8f);
|
||||
|
||||
for (int i = length - 1, mul = 1; i >= 0; i--, mul *= 0x100) {
|
||||
float mul = 1;
|
||||
for (int i = length - 1; i >= 0; i--, mul *= 0x100) {
|
||||
long b = (long) Math.floor(number / mul);
|
||||
if (!withLength && i == marker) {
|
||||
b = b | (0x80 >> (length - 1));
|
||||
|
@ -637,11 +635,7 @@ public class WebMWriter {
|
|||
|
||||
private ArrayList<byte[]> encode(String value) {
|
||||
byte[] str;
|
||||
try {
|
||||
str = value.getBytes("utf-8");
|
||||
} catch (UnsupportedEncodingException err) {
|
||||
str = value.getBytes();
|
||||
}
|
||||
str = value.getBytes(StandardCharsets.UTF_8);// or use "utf-8"
|
||||
|
||||
ArrayList<byte[]> buffer = new ArrayList<>(2);
|
||||
buffer.add(encode(str.length, false));
|
||||
|
@ -720,9 +714,10 @@ public class WebMWriter {
|
|||
return (flags & 0x80) == 0x80;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("trackNumber=%s isKeyFrame=%S absoluteTimecode=%s", trackNumber, (flags & 0x80) == 0x80, absoluteTimecode);
|
||||
return String.format("trackNumber=%s isKeyFrame=%S absoluteTimecode=%s", trackNumber, isKeyframe(), absoluteTimecode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package org.schabi.newpipe.streams.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* based c#
|
||||
* based on c#
|
||||
*/
|
||||
public abstract class SharpStream {
|
||||
public abstract class SharpStream implements Closeable {
|
||||
|
||||
public abstract int read() throws IOException;
|
||||
|
||||
|
@ -15,16 +16,14 @@ public abstract class SharpStream {
|
|||
|
||||
public abstract long skip(long amount) throws IOException;
|
||||
|
||||
|
||||
public abstract int available();
|
||||
public abstract long available();
|
||||
|
||||
public abstract void rewind() throws IOException;
|
||||
|
||||
public abstract boolean isClosed();
|
||||
|
||||
public abstract void dispose();
|
||||
|
||||
public abstract boolean isDisposed();
|
||||
|
||||
@Override
|
||||
public abstract void close();
|
||||
|
||||
public abstract boolean canRewind();
|
||||
|
||||
|
@ -32,6 +31,13 @@ public abstract class SharpStream {
|
|||
|
||||
public abstract boolean canWrite();
|
||||
|
||||
public boolean canSetLength() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canSeek() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void write(byte value) throws IOException;
|
||||
|
||||
|
@ -39,9 +45,19 @@ public abstract class SharpStream {
|
|||
|
||||
public abstract void write(byte[] buffer, int offset, int count) throws IOException;
|
||||
|
||||
public abstract void flush() throws IOException;
|
||||
public void flush() throws IOException {
|
||||
// STUB
|
||||
}
|
||||
|
||||
public void setLength(long length) throws IOException {
|
||||
throw new IOException("Not implemented");
|
||||
}
|
||||
|
||||
public void seek(long offset) throws IOException {
|
||||
throw new IOException("Not implemented");
|
||||
}
|
||||
|
||||
public long length() throws IOException {
|
||||
throw new UnsupportedOperationException("Unsupported operation");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ import java.util.regex.Pattern;
|
|||
|
||||
public class FilenameUtils {
|
||||
|
||||
private static final String CHARSET_MOST_SPECIAL = "[\\n\\r|?*<\":\\\\>/']+";
|
||||
private static final String CHARSET_ONLY_LETTERS_AND_DIGITS = "[^\\w\\d]+";
|
||||
|
||||
/**
|
||||
* #143 #44 #42 #22: make sure that the filename does not contain illegal chars.
|
||||
* @param context the context to retrieve strings and preferences from
|
||||
|
@ -18,11 +21,28 @@ public class FilenameUtils {
|
|||
*/
|
||||
public static String createFilename(Context context, String title) {
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final String key = context.getString(R.string.settings_file_charset_key);
|
||||
final String value = sharedPreferences.getString(key, context.getString(R.string.default_file_charset_value));
|
||||
Pattern pattern = Pattern.compile(value);
|
||||
|
||||
final String charset_ld = context.getString(R.string.charset_letters_and_digits_value);
|
||||
final String charset_ms = context.getString(R.string.charset_most_special_value);
|
||||
final String defaultCharset = context.getString(R.string.default_file_charset_value);
|
||||
|
||||
final String replacementChar = sharedPreferences.getString(context.getString(R.string.settings_file_replacement_character_key), "_");
|
||||
String selectedCharset = sharedPreferences.getString(context.getString(R.string.settings_file_charset_key), null);
|
||||
|
||||
final String charset;
|
||||
|
||||
if (selectedCharset == null || selectedCharset.isEmpty()) selectedCharset = defaultCharset;
|
||||
|
||||
if (selectedCharset.equals(charset_ld)) {
|
||||
charset = CHARSET_ONLY_LETTERS_AND_DIGITS;
|
||||
} else if (selectedCharset.equals(charset_ms)) {
|
||||
charset = CHARSET_MOST_SPECIAL;
|
||||
} else {
|
||||
charset = selectedCharset;// ¿is the user using a custom charset?
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile(charset);
|
||||
|
||||
return createFilename(title, pattern, replacementChar);
|
||||
}
|
||||
|
||||
|
|
|
@ -430,24 +430,26 @@ public final class ListHelper {
|
|||
*/
|
||||
private static String getResolutionLimit(Context context) {
|
||||
String resolutionLimit = null;
|
||||
if (!isWifiActive(context)) {
|
||||
if (isMeteredNetwork(context)) {
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String defValue = context.getString(R.string.limit_data_usage_none_key);
|
||||
String value = preferences.getString(
|
||||
context.getString(R.string.limit_mobile_data_usage_key), defValue);
|
||||
resolutionLimit = value.equals(defValue) ? null : value;
|
||||
resolutionLimit = defValue.equals(value) ? null : value;
|
||||
}
|
||||
return resolutionLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we connected to wifi?
|
||||
* The current network is metered (like mobile data)?
|
||||
* @param context App context
|
||||
* @return {@code true} if connected to wifi
|
||||
* @return {@code true} if connected to a metered network
|
||||
*/
|
||||
private static boolean isWifiActive(Context context)
|
||||
private static boolean isMeteredNetwork(Context context)
|
||||
{
|
||||
ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return manager != null && manager.getActiveNetworkInfo() != null && manager.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI;
|
||||
if (manager == null || manager.getActiveNetworkInfo() == null) return false;
|
||||
|
||||
return manager.isActiveNetworkMetered();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class SecondaryStreamHelper<T extends Stream> {
|
|||
public static AudioStream getAudioStreamFor(@NonNull List<AudioStream> audioStreams, @NonNull VideoStream videoStream) {
|
||||
switch (videoStream.getFormat()) {
|
||||
case WEBM:
|
||||
case MPEG_4:
|
||||
case MPEG_4:// ¿is mpeg-4 DASH?
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
|
|
|
@ -1,185 +1,191 @@
|
|||
package us.shandian.giga.get;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
|
||||
import us.shandian.giga.util.Utility;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
||||
public class DownloadInitializer extends Thread {
|
||||
private final static String TAG = "DownloadInitializer";
|
||||
final static int mId = 0;
|
||||
|
||||
private DownloadMission mMission;
|
||||
private HttpURLConnection mConn;
|
||||
|
||||
DownloadInitializer(@NonNull DownloadMission mission) {
|
||||
mMission = mission;
|
||||
mConn = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mMission.current > 0) mMission.resetState();
|
||||
|
||||
int retryCount = 0;
|
||||
while (true) {
|
||||
try {
|
||||
mMission.currentThreadCount = mMission.threadCount;
|
||||
|
||||
mConn = mMission.openConnection(mId, -1, -1);
|
||||
mMission.establishConnection(mId, mConn);
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
|
||||
mMission.length = Utility.getContentLength(mConn);
|
||||
|
||||
|
||||
if (mMission.length == 0) {
|
||||
mMission.notifyError(DownloadMission.ERROR_HTTP_NO_CONTENT, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for dynamic generated content
|
||||
if (mMission.length == -1 && mConn.getResponseCode() == 200) {
|
||||
mMission.blocks = 0;
|
||||
mMission.length = 0;
|
||||
mMission.fallback = true;
|
||||
mMission.unknownLength = true;
|
||||
mMission.currentThreadCount = 1;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "falling back (unknown length)");
|
||||
}
|
||||
} else {
|
||||
// Open again
|
||||
mConn = mMission.openConnection(mId, mMission.length - 10, mMission.length);
|
||||
mMission.establishConnection(mId, mConn);
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
|
||||
synchronized (mMission.blockState) {
|
||||
if (mConn.getResponseCode() == 206) {
|
||||
if (mMission.currentThreadCount > 1) {
|
||||
mMission.blocks = mMission.length / DownloadMission.BLOCK_SIZE;
|
||||
|
||||
if (mMission.currentThreadCount > mMission.blocks) {
|
||||
mMission.currentThreadCount = (int) mMission.blocks;
|
||||
}
|
||||
if (mMission.currentThreadCount <= 0) {
|
||||
mMission.currentThreadCount = 1;
|
||||
}
|
||||
if (mMission.blocks * DownloadMission.BLOCK_SIZE < mMission.length) {
|
||||
mMission.blocks++;
|
||||
}
|
||||
} else {
|
||||
// if one thread is solicited don't calculate blocks, is useless
|
||||
mMission.blocks = 1;
|
||||
mMission.fallback = true;
|
||||
mMission.unknownLength = false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "http response code = " + mConn.getResponseCode());
|
||||
}
|
||||
} else {
|
||||
// Fallback to single thread
|
||||
mMission.blocks = 0;
|
||||
mMission.fallback = true;
|
||||
mMission.unknownLength = false;
|
||||
mMission.currentThreadCount = 1;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "falling back due http response code = " + mConn.getResponseCode());
|
||||
}
|
||||
}
|
||||
|
||||
for (long i = 0; i < mMission.currentThreadCount; i++) {
|
||||
mMission.threadBlockPositions.add(i);
|
||||
mMission.threadBytePositions.add(0L);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
}
|
||||
|
||||
File file;
|
||||
if (mMission.current == 0) {
|
||||
file = new File(mMission.location);
|
||||
if (!Utility.mkdir(file, true)) {
|
||||
mMission.notifyError(DownloadMission.ERROR_PATH_CREATION, null);
|
||||
return;
|
||||
}
|
||||
|
||||
file = new File(file, mMission.name);
|
||||
|
||||
// if the name is used by another process, delete it
|
||||
if (file.exists() && !file.isFile() && !file.delete()) {
|
||||
mMission.notifyError(DownloadMission.ERROR_FILE_CREATION, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.exists() && !file.createNewFile()) {
|
||||
mMission.notifyError(DownloadMission.ERROR_FILE_CREATION, null);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
file = new File(mMission.location, mMission.name);
|
||||
}
|
||||
|
||||
RandomAccessFile af = new RandomAccessFile(file, "rw");
|
||||
af.setLength(mMission.offsets[mMission.current] + mMission.length);
|
||||
af.seek(mMission.offsets[mMission.current]);
|
||||
af.close();
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
|
||||
mMission.running = false;
|
||||
break;
|
||||
} catch (InterruptedIOException | ClosedByInterruptException e) {
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
if (!mMission.running) return;
|
||||
|
||||
if (e instanceof IOException && e.getMessage().contains("Permission denied")) {
|
||||
mMission.notifyError(DownloadMission.ERROR_PERMISSION_DENIED, e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (retryCount++ > mMission.maxRetry) {
|
||||
Log.e(TAG, "initializer failed", e);
|
||||
mMission.notifyError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.e(TAG, "initializer failed, retrying", e);
|
||||
}
|
||||
}
|
||||
|
||||
// hide marquee in the progress bar
|
||||
mMission.done++;
|
||||
|
||||
mMission.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interrupt() {
|
||||
super.interrupt();
|
||||
|
||||
if (mConn != null) {
|
||||
try {
|
||||
mConn.disconnect();
|
||||
} catch (Exception e) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package us.shandian.giga.get;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
|
||||
import us.shandian.giga.util.Utility;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
||||
public class DownloadInitializer extends Thread {
|
||||
private final static String TAG = "DownloadInitializer";
|
||||
final static int mId = 0;
|
||||
private final static int RESERVE_SPACE_DEFAULT = 5 * 1024 * 1024;// 5 MiB
|
||||
private final static int RESERVE_SPACE_MAXIMUM = 150 * 1024 * 1024;// 150 MiB
|
||||
|
||||
private DownloadMission mMission;
|
||||
private HttpURLConnection mConn;
|
||||
|
||||
DownloadInitializer(@NonNull DownloadMission mission) {
|
||||
mMission = mission;
|
||||
mConn = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mMission.current > 0) mMission.resetState(false, true, DownloadMission.ERROR_NOTHING);
|
||||
|
||||
int retryCount = 0;
|
||||
while (true) {
|
||||
try {
|
||||
mMission.currentThreadCount = mMission.threadCount;
|
||||
|
||||
if (mMission.blocks < 0 && mMission.current == 0) {
|
||||
// calculate the whole size of the mission
|
||||
long finalLength = 0;
|
||||
long lowestSize = Long.MAX_VALUE;
|
||||
|
||||
for (int i = 0; i < mMission.urls.length && mMission.running; i++) {
|
||||
mConn = mMission.openConnection(mMission.urls[i], mId, -1, -1);
|
||||
mMission.establishConnection(mId, mConn);
|
||||
|
||||
if (Thread.interrupted()) return;
|
||||
long length = Utility.getContentLength(mConn);
|
||||
|
||||
if (i == 0) mMission.length = length;
|
||||
if (length > 0) finalLength += length;
|
||||
if (length < lowestSize) lowestSize = length;
|
||||
}
|
||||
|
||||
mMission.nearLength = finalLength;
|
||||
|
||||
// reserve space at the start of the file
|
||||
if (mMission.psAlgorithm != null && mMission.psAlgorithm.reserveSpace) {
|
||||
if (lowestSize < 1) {
|
||||
// the length is unknown use the default size
|
||||
mMission.offsets[0] = RESERVE_SPACE_DEFAULT;
|
||||
} else {
|
||||
// use the smallest resource size to download, otherwise, use the maximum
|
||||
mMission.offsets[0] = lowestSize < RESERVE_SPACE_MAXIMUM ? lowestSize : RESERVE_SPACE_MAXIMUM;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ask for the current resource length
|
||||
mConn = mMission.openConnection(mId, -1, -1);
|
||||
mMission.establishConnection(mId, mConn);
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
|
||||
mMission.length = Utility.getContentLength(mConn);
|
||||
}
|
||||
|
||||
if (mMission.length == 0 || mConn.getResponseCode() == 204) {
|
||||
mMission.notifyError(DownloadMission.ERROR_HTTP_NO_CONTENT, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for dynamic generated content
|
||||
if (mMission.length == -1 && mConn.getResponseCode() == 200) {
|
||||
mMission.blocks = 0;
|
||||
mMission.length = 0;
|
||||
mMission.fallback = true;
|
||||
mMission.unknownLength = true;
|
||||
mMission.currentThreadCount = 1;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "falling back (unknown length)");
|
||||
}
|
||||
} else {
|
||||
// Open again
|
||||
mConn = mMission.openConnection(mId, mMission.length - 10, mMission.length);
|
||||
mMission.establishConnection(mId, mConn);
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
|
||||
synchronized (mMission.blockState) {
|
||||
if (mConn.getResponseCode() == 206) {
|
||||
if (mMission.currentThreadCount > 1) {
|
||||
mMission.blocks = mMission.length / DownloadMission.BLOCK_SIZE;
|
||||
|
||||
if (mMission.currentThreadCount > mMission.blocks) {
|
||||
mMission.currentThreadCount = (int) mMission.blocks;
|
||||
}
|
||||
if (mMission.currentThreadCount <= 0) {
|
||||
mMission.currentThreadCount = 1;
|
||||
}
|
||||
if (mMission.blocks * DownloadMission.BLOCK_SIZE < mMission.length) {
|
||||
mMission.blocks++;
|
||||
}
|
||||
} else {
|
||||
// if one thread is solicited don't calculate blocks, is useless
|
||||
mMission.blocks = 1;
|
||||
mMission.fallback = true;
|
||||
mMission.unknownLength = false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "http response code = " + mConn.getResponseCode());
|
||||
}
|
||||
} else {
|
||||
// Fallback to single thread
|
||||
mMission.blocks = 0;
|
||||
mMission.fallback = true;
|
||||
mMission.unknownLength = false;
|
||||
mMission.currentThreadCount = 1;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "falling back due http response code = " + mConn.getResponseCode());
|
||||
}
|
||||
}
|
||||
|
||||
for (long i = 0; i < mMission.currentThreadCount; i++) {
|
||||
mMission.threadBlockPositions.add(i);
|
||||
mMission.threadBytePositions.add(0L);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
}
|
||||
|
||||
SharpStream fs = mMission.storage.getStream();
|
||||
fs.setLength(mMission.offsets[mMission.current] + mMission.length);
|
||||
fs.seek(mMission.offsets[mMission.current]);
|
||||
fs.close();
|
||||
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
|
||||
mMission.running = false;
|
||||
break;
|
||||
} catch (InterruptedIOException | ClosedByInterruptException e) {
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
if (!mMission.running) return;
|
||||
|
||||
if (e instanceof IOException && e.getMessage().contains("Permission denied")) {
|
||||
mMission.notifyError(DownloadMission.ERROR_PERMISSION_DENIED, e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (retryCount++ > mMission.maxRetry) {
|
||||
Log.e(TAG, "initializer failed", e);
|
||||
mMission.notifyError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.e(TAG, "initializer failed, retrying", e);
|
||||
}
|
||||
}
|
||||
|
||||
mMission.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interrupt() {
|
||||
super.interrupt();
|
||||
|
||||
if (mConn != null) {
|
||||
try {
|
||||
mConn.disconnect();
|
||||
} catch (Exception e) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,14 @@ import android.os.Handler;
|
|||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -17,6 +20,7 @@ import java.util.List;
|
|||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
import us.shandian.giga.postprocessing.Postprocessing;
|
||||
import us.shandian.giga.service.DownloadManagerService;
|
||||
import us.shandian.giga.util.Utility;
|
||||
|
@ -24,7 +28,7 @@ import us.shandian.giga.util.Utility;
|
|||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
||||
public class DownloadMission extends Mission {
|
||||
private static final long serialVersionUID = 3L;// last bump: 8 november 2018
|
||||
private static final long serialVersionUID = 4L;// last bump: 27 march 2019
|
||||
|
||||
static final int BUFFER_SIZE = 64 * 1024;
|
||||
final static int BLOCK_SIZE = 512 * 1024;
|
||||
|
@ -40,6 +44,11 @@ public class DownloadMission extends Mission {
|
|||
public static final int ERROR_UNKNOWN_HOST = 1005;
|
||||
public static final int ERROR_CONNECT_HOST = 1006;
|
||||
public static final int ERROR_POSTPROCESSING = 1007;
|
||||
public static final int ERROR_POSTPROCESSING_STOPPED = 1008;
|
||||
public static final int ERROR_POSTPROCESSING_HOLD = 1009;
|
||||
public static final int ERROR_INSUFFICIENT_STORAGE = 1010;
|
||||
public static final int ERROR_PROGRESS_LOST = 1011;
|
||||
public static final int ERROR_TIMEOUT = 1012;
|
||||
public static final int ERROR_HTTP_NO_CONTENT = 204;
|
||||
public static final int ERROR_HTTP_UNSUPPORTED_RANGE = 206;
|
||||
|
||||
|
@ -68,43 +77,34 @@ public class DownloadMission extends Mission {
|
|||
*/
|
||||
public long[] offsets;
|
||||
|
||||
/**
|
||||
* The post-processing algorithm arguments
|
||||
*/
|
||||
public String[] postprocessingArgs;
|
||||
|
||||
/**
|
||||
* The post-processing algorithm name
|
||||
*/
|
||||
public String postprocessingName;
|
||||
|
||||
/**
|
||||
* Indicates if the post-processing state:
|
||||
* 0: ready
|
||||
* 1: running
|
||||
* 2: completed
|
||||
* 3: hold
|
||||
*/
|
||||
public int postprocessingState;
|
||||
public volatile int psState;
|
||||
|
||||
/**
|
||||
* Indicate if the post-processing algorithm works on the same file
|
||||
* the post-processing algorithm instance
|
||||
*/
|
||||
public boolean postprocessingThis;
|
||||
public Postprocessing psAlgorithm;
|
||||
|
||||
/**
|
||||
* The current resource to download {@code urls[current]}
|
||||
* The current resource to download, see {@code urls[current]} and {@code offsets[current]}
|
||||
*/
|
||||
public int current;
|
||||
|
||||
/**
|
||||
* Metadata where the mission state is saved
|
||||
*/
|
||||
public File metadata;
|
||||
public transient File metadata;
|
||||
|
||||
/**
|
||||
* maximum attempts
|
||||
*/
|
||||
public int maxRetry;
|
||||
public transient int maxRetry;
|
||||
|
||||
/**
|
||||
* Approximated final length, this represent the sum of all resources sizes
|
||||
|
@ -115,11 +115,11 @@ public class DownloadMission extends Mission {
|
|||
boolean fallback;
|
||||
private int finishCount;
|
||||
public transient boolean running;
|
||||
public transient boolean enqueued = true;
|
||||
public boolean enqueued;
|
||||
|
||||
public int errCode = ERROR_NOTHING;
|
||||
|
||||
public transient Exception errObject = null;
|
||||
public Exception errObject = null;
|
||||
public transient boolean recovered;
|
||||
public transient Handler mHandler;
|
||||
private transient boolean mWritingToFile;
|
||||
|
@ -131,41 +131,26 @@ public class DownloadMission extends Mission {
|
|||
|
||||
private transient boolean deleted;
|
||||
int currentThreadCount;
|
||||
private transient Thread[] threads = new Thread[0];
|
||||
public transient volatile Thread[] threads = new Thread[0];
|
||||
private transient Thread init = null;
|
||||
|
||||
|
||||
protected DownloadMission() {
|
||||
|
||||
}
|
||||
|
||||
public DownloadMission(String url, String name, String location, char kind) {
|
||||
this(new String[]{url}, name, location, kind, null, null);
|
||||
}
|
||||
|
||||
public DownloadMission(String[] urls, String name, String location, char kind, String postprocessingName, String[] postprocessingArgs) {
|
||||
if (name == null) throw new NullPointerException("name is null");
|
||||
if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
|
||||
public DownloadMission(String[] urls, StoredFileHelper storage, char kind, Postprocessing psInstance) {
|
||||
if (urls == null) throw new NullPointerException("urls is null");
|
||||
if (urls.length < 1) throw new IllegalArgumentException("urls is empty");
|
||||
if (location == null) throw new NullPointerException("location is null");
|
||||
if (location.isEmpty()) throw new IllegalArgumentException("location is empty");
|
||||
this.urls = urls;
|
||||
this.name = name;
|
||||
this.location = location;
|
||||
this.kind = kind;
|
||||
this.offsets = new long[urls.length];
|
||||
this.enqueued = true;
|
||||
this.maxRetry = 3;
|
||||
this.storage = storage;
|
||||
this.psAlgorithm = psInstance;
|
||||
|
||||
if (postprocessingName != null) {
|
||||
Postprocessing algorithm = Postprocessing.getAlgorithm(postprocessingName, null);
|
||||
this.postprocessingThis = algorithm.worksOnSameFile;
|
||||
this.offsets[0] = algorithm.recommendedReserve;
|
||||
this.postprocessingName = postprocessingName;
|
||||
this.postprocessingArgs = postprocessingArgs;
|
||||
} else {
|
||||
if (DEBUG && urls.length > 1) {
|
||||
Log.w(TAG, "mission created with multiple urls ¿missing post-processing algorithm?");
|
||||
}
|
||||
if (DEBUG && psInstance == null && urls.length > 1) {
|
||||
Log.w(TAG, "mission created with multiple urls ¿missing post-processing algorithm?");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,6 +168,7 @@ public class DownloadMission extends Mission {
|
|||
*/
|
||||
boolean isBlockPreserved(long block) {
|
||||
checkBlock(block);
|
||||
//noinspection ConstantConditions
|
||||
return blockState.containsKey(block) ? blockState.get(block) : false;
|
||||
}
|
||||
|
||||
|
@ -243,9 +229,18 @@ public class DownloadMission extends Mission {
|
|||
* @throws IOException if an I/O exception occurs.
|
||||
*/
|
||||
HttpURLConnection openConnection(int threadId, long rangeStart, long rangeEnd) throws IOException {
|
||||
URL url = new URL(urls[current]);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
return openConnection(urls[current], threadId, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
HttpURLConnection openConnection(String url, int threadId, long rangeStart, long rangeEnd) throws IOException {
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setInstanceFollowRedirects(true);
|
||||
conn.setRequestProperty("User-Agent", Downloader.USER_AGENT);
|
||||
conn.setRequestProperty("Accept", "*/*");
|
||||
|
||||
// BUG workaround: switching between networks can freeze the download forever
|
||||
conn.setConnectTimeout(30000);
|
||||
conn.setReadTimeout(10000);
|
||||
|
||||
if (rangeStart >= 0) {
|
||||
String req = "bytes=" + rangeStart + "-";
|
||||
|
@ -337,17 +332,42 @@ public class DownloadMission extends Mission {
|
|||
notifyError(ERROR_CONNECT_HOST, null);
|
||||
} else if (err instanceof UnknownHostException) {
|
||||
notifyError(ERROR_UNKNOWN_HOST, null);
|
||||
} else if (err instanceof SocketTimeoutException) {
|
||||
notifyError(ERROR_TIMEOUT, null);
|
||||
} else {
|
||||
notifyError(ERROR_UNKNOWN_EXCEPTION, err);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void notifyError(int code, Exception err) {
|
||||
public synchronized void notifyError(int code, Exception err) {
|
||||
Log.e(TAG, "notifyError() code = " + code, err);
|
||||
|
||||
if (err instanceof IOException) {
|
||||
if (!storage.canWrite() || err.getMessage().contains("Permission denied")) {
|
||||
code = ERROR_PERMISSION_DENIED;
|
||||
err = null;
|
||||
} else if (err.getMessage().contains("ENOSPC")) {
|
||||
code = ERROR_INSUFFICIENT_STORAGE;
|
||||
err = null;
|
||||
}
|
||||
}
|
||||
|
||||
errCode = code;
|
||||
errObject = err;
|
||||
|
||||
switch (code) {
|
||||
case ERROR_SSL_EXCEPTION:
|
||||
case ERROR_UNKNOWN_HOST:
|
||||
case ERROR_CONNECT_HOST:
|
||||
case ERROR_TIMEOUT:
|
||||
// do not change the queue flag for network errors, can be
|
||||
// recovered silently without the user interaction
|
||||
break;
|
||||
default:
|
||||
// also checks for server errors
|
||||
if (code < 500 || code > 599) enqueued = false;
|
||||
}
|
||||
|
||||
pause();
|
||||
|
||||
notify(DownloadManagerService.MESSAGE_ERROR);
|
||||
|
@ -378,6 +398,7 @@ public class DownloadMission extends Mission {
|
|||
|
||||
if (!doPostprocessing()) return;
|
||||
|
||||
enqueued = false;
|
||||
running = false;
|
||||
deleteThisFromFile();
|
||||
|
||||
|
@ -386,25 +407,23 @@ public class DownloadMission extends Mission {
|
|||
}
|
||||
|
||||
private void notifyPostProcessing(int state) {
|
||||
if (DEBUG) {
|
||||
String action;
|
||||
switch (state) {
|
||||
case 1:
|
||||
action = "Running";
|
||||
break;
|
||||
case 2:
|
||||
action = "Completed";
|
||||
break;
|
||||
default:
|
||||
action = "Failed";
|
||||
}
|
||||
|
||||
Log.d(TAG, action + " postprocessing on " + location + File.separator + name);
|
||||
String action;
|
||||
switch (state) {
|
||||
case 1:
|
||||
action = "Running";
|
||||
break;
|
||||
case 2:
|
||||
action = "Completed";
|
||||
break;
|
||||
default:
|
||||
action = "Failed";
|
||||
}
|
||||
|
||||
Log.d(TAG, action + " postprocessing on " + storage.getName());
|
||||
|
||||
synchronized (blockState) {
|
||||
// don't return without fully write the current state
|
||||
postprocessingState = state;
|
||||
psState = state;
|
||||
Utility.writeToFile(metadata, DownloadMission.this);
|
||||
}
|
||||
}
|
||||
|
@ -420,11 +439,10 @@ public class DownloadMission extends Mission {
|
|||
if (threads != null)
|
||||
for (Thread thread : threads) joinForThread(thread);
|
||||
|
||||
enqueued = false;
|
||||
running = true;
|
||||
errCode = ERROR_NOTHING;
|
||||
|
||||
if (current >= urls.length && postprocessingName != null) {
|
||||
if (current >= urls.length && psAlgorithm != null) {
|
||||
runAsync(1, () -> {
|
||||
if (doPostprocessing()) {
|
||||
running = false;
|
||||
|
@ -463,7 +481,7 @@ public class DownloadMission extends Mission {
|
|||
}
|
||||
|
||||
/**
|
||||
* Pause the mission, does not affect the blocks that are being downloaded.
|
||||
* Pause the mission
|
||||
*/
|
||||
public synchronized void pause() {
|
||||
if (!running) return;
|
||||
|
@ -477,12 +495,11 @@ public class DownloadMission extends Mission {
|
|||
|
||||
running = false;
|
||||
recovered = true;
|
||||
enqueued = false;
|
||||
|
||||
if (init != null && Thread.currentThread() != init && init.isAlive()) {
|
||||
init.interrupt();
|
||||
synchronized (blockState) {
|
||||
resetState();
|
||||
resetState(false, true, ERROR_NOTHING);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -514,20 +531,31 @@ public class DownloadMission extends Mission {
|
|||
}
|
||||
|
||||
/**
|
||||
* Removes the file and the meta file
|
||||
* Removes the downloaded file and the meta file
|
||||
*/
|
||||
@Override
|
||||
public boolean delete() {
|
||||
deleted = true;
|
||||
if (psAlgorithm != null) psAlgorithm.cleanupTemporalDir();
|
||||
|
||||
boolean res = deleteThisFromFile();
|
||||
if (!super.delete()) res = false;
|
||||
|
||||
if (!super.delete()) return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
void resetState() {
|
||||
|
||||
/**
|
||||
* Resets the mission state
|
||||
*
|
||||
* @param rollback {@code true} true to forget all progress, otherwise, {@code false}
|
||||
* @param persistChanges {@code true} to commit changes to the metadata file, otherwise, {@code false}
|
||||
*/
|
||||
public void resetState(boolean rollback, boolean persistChanges, int errorCode) {
|
||||
done = 0;
|
||||
blocks = -1;
|
||||
errCode = ERROR_NOTHING;
|
||||
errCode = errorCode;
|
||||
errObject = null;
|
||||
fallback = false;
|
||||
unknownLength = false;
|
||||
finishCount = 0;
|
||||
|
@ -536,7 +564,10 @@ public class DownloadMission extends Mission {
|
|||
blockState.clear();
|
||||
threads = new Thread[0];
|
||||
|
||||
Utility.writeToFile(metadata, DownloadMission.this);
|
||||
if (rollback) current = 0;
|
||||
|
||||
if (persistChanges)
|
||||
Utility.writeToFile(metadata, DownloadMission.this);
|
||||
}
|
||||
|
||||
private void initializer() {
|
||||
|
@ -562,7 +593,7 @@ public class DownloadMission extends Mission {
|
|||
* @return true, otherwise, false
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
return current >= urls.length && (postprocessingName == null || postprocessingState == 2);
|
||||
return current >= urls.length && (psAlgorithm == null || psState == 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -571,7 +602,13 @@ public class DownloadMission extends Mission {
|
|||
* @return {@code true} if this mission is unrecoverable
|
||||
*/
|
||||
public boolean isPsFailed() {
|
||||
return postprocessingName != null && errCode == DownloadMission.ERROR_POSTPROCESSING && postprocessingThis;
|
||||
switch (errCode) {
|
||||
case ERROR_POSTPROCESSING:
|
||||
case ERROR_POSTPROCESSING_STOPPED:
|
||||
return psAlgorithm.worksOnSameFile;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -580,12 +617,26 @@ public class DownloadMission extends Mission {
|
|||
* @return true, otherwise, false
|
||||
*/
|
||||
public boolean isPsRunning() {
|
||||
return postprocessingName != null && postprocessingState == 1;
|
||||
return psAlgorithm != null && (psState == 1 || psState == 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicated if the mission is ready
|
||||
*
|
||||
* @return true, otherwise, false
|
||||
*/
|
||||
public boolean isInitialized() {
|
||||
return blocks >= 0; // DownloadMissionInitializer was executed
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the approximated final length of the file
|
||||
*
|
||||
* @return the length in bytes
|
||||
*/
|
||||
public long getLength() {
|
||||
long calculated;
|
||||
if (postprocessingState == 1) {
|
||||
if (psState == 1 || psState == 3) {
|
||||
calculated = length;
|
||||
} else {
|
||||
calculated = offsets[current < offsets.length ? current : (offsets.length - 1)] + length;
|
||||
|
@ -596,30 +647,67 @@ public class DownloadMission extends Mission {
|
|||
return calculated > nearLength ? calculated : nearLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* set this mission state on the queue
|
||||
*
|
||||
* @param queue true to add to the queue, otherwise, false
|
||||
*/
|
||||
public void setEnqueued(boolean queue) {
|
||||
enqueued = queue;
|
||||
runAsync(-2, this::writeThisToFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to continue a blocked post-processing
|
||||
*
|
||||
* @param recover {@code true} to retry, otherwise, {@code false} to cancel
|
||||
*/
|
||||
public void psContinue(boolean recover) {
|
||||
psState = 1;
|
||||
errCode = recover ? ERROR_NOTHING : ERROR_POSTPROCESSING;
|
||||
threads[0].interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whatever the backed storage is invalid
|
||||
*
|
||||
* @return {@code true}, if storage is invalid and cannot be used
|
||||
*/
|
||||
public boolean hasInvalidStorage() {
|
||||
return errCode == ERROR_PROGRESS_LOST || storage == null || storage.isInvalid() || !storage.existsAsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whatever is possible to start the mission
|
||||
*
|
||||
* @return {@code true} is this mission its "healthy", otherwise, {@code false}
|
||||
*/
|
||||
public boolean isCorrupt() {
|
||||
return (isPsFailed() || errCode == ERROR_POSTPROCESSING_HOLD) || isFinished() || hasInvalidStorage();
|
||||
}
|
||||
|
||||
private boolean doPostprocessing() {
|
||||
if (postprocessingName == null || postprocessingState == 2) return true;
|
||||
if (psAlgorithm == null || psState == 2) return true;
|
||||
|
||||
errObject = null;
|
||||
|
||||
notifyPostProcessing(1);
|
||||
notifyProgress(0);
|
||||
|
||||
Thread.currentThread().setName("[" + TAG + "] post-processing = " + postprocessingName + " filename = " + name);
|
||||
if (DEBUG)
|
||||
Thread.currentThread().setName("[" + TAG + "] ps = " +
|
||||
psAlgorithm.getClass().getSimpleName() +
|
||||
" filename = " + storage.getName()
|
||||
);
|
||||
|
||||
threads = new Thread[]{Thread.currentThread()};
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
try {
|
||||
Postprocessing
|
||||
.getAlgorithm(postprocessingName, this)
|
||||
.run();
|
||||
psAlgorithm.run(this);
|
||||
} catch (Exception err) {
|
||||
StringBuilder args = new StringBuilder(" ");
|
||||
if (postprocessingArgs != null) {
|
||||
for (String arg : postprocessingArgs) {
|
||||
args.append(", ");
|
||||
args.append(arg);
|
||||
}
|
||||
args.delete(0, 1);
|
||||
}
|
||||
Log.e(TAG, String.format("Post-processing failed. algorithm = %s args = [%s]", postprocessingName, args), err);
|
||||
Log.e(TAG, "Post-processing failed. " + psAlgorithm.toString(), err);
|
||||
|
||||
if (errCode == ERROR_NOTHING) errCode = ERROR_POSTPROCESSING;
|
||||
|
||||
|
@ -669,7 +757,7 @@ public class DownloadMission extends Mission {
|
|||
// >=1: any download thread
|
||||
|
||||
if (DEBUG) {
|
||||
who.setName(String.format("%s[%s] %s", TAG, id, name));
|
||||
who.setName(String.format("%s[%s] %s", TAG, id, storage.getName()));
|
||||
}
|
||||
|
||||
who.start();
|
||||
|
|
|
@ -2,9 +2,10 @@ package us.shandian.giga.get;
|
|||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
|
||||
|
@ -26,7 +27,6 @@ public class DownloadRunnable extends Thread {
|
|||
if (mission == null) throw new NullPointerException("mission is null");
|
||||
mMission = mission;
|
||||
mId = id;
|
||||
mConn = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,12 +40,12 @@ public class DownloadRunnable extends Thread {
|
|||
Log.d(TAG, mId + ":recovered: " + mMission.recovered);
|
||||
}
|
||||
|
||||
RandomAccessFile f;
|
||||
SharpStream f;
|
||||
InputStream is = null;
|
||||
|
||||
try {
|
||||
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
||||
} catch (FileNotFoundException e) {
|
||||
f = mMission.storage.getStream();
|
||||
} catch (IOException e) {
|
||||
mMission.notifyError(e);// this never should happen
|
||||
return;
|
||||
}
|
||||
|
@ -136,6 +136,10 @@ public class DownloadRunnable extends Thread {
|
|||
mMission.setThreadBytePosition(mId, total);// download paused, save progress for this block
|
||||
|
||||
} catch (Exception e) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, mId + ": position=" + blockPosition + " total=" + total + " stopped due exception", e);
|
||||
}
|
||||
|
||||
mMission.setThreadBytePosition(mId, total);
|
||||
|
||||
if (!mMission.running || e instanceof ClosedByInterruptException) break;
|
||||
|
@ -145,10 +149,6 @@ public class DownloadRunnable extends Thread {
|
|||
break;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, mId + ":position " + blockPosition + " retrying due exception", e);
|
||||
}
|
||||
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
package us.shandian.giga.get;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
|
||||
|
||||
import us.shandian.giga.util.Utility;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
@ -19,21 +18,17 @@ import static org.schabi.newpipe.BuildConfig.DEBUG;
|
|||
* Single-threaded fallback mode
|
||||
*/
|
||||
public class DownloadRunnableFallback extends Thread {
|
||||
private static final String TAG = "DownloadRunnableFallback";
|
||||
private static final String TAG = "DownloadRunnableFallbac";
|
||||
|
||||
private final DownloadMission mMission;
|
||||
private final int mId = 1;
|
||||
|
||||
private int mRetryCount = 0;
|
||||
private InputStream mIs;
|
||||
private RandomAccessFile mF;
|
||||
private SharpStream mF;
|
||||
private HttpURLConnection mConn;
|
||||
|
||||
DownloadRunnableFallback(@NonNull DownloadMission mission) {
|
||||
mMission = mission;
|
||||
mIs = null;
|
||||
mF = null;
|
||||
mConn = null;
|
||||
}
|
||||
|
||||
private void dispose() {
|
||||
|
@ -43,15 +38,10 @@ public class DownloadRunnableFallback extends Thread {
|
|||
// nothing to do
|
||||
}
|
||||
|
||||
try {
|
||||
if (mF != null) mF.close();
|
||||
} catch (IOException e) {
|
||||
// ¿ejected media storage? ¿file deleted? ¿storage ran out of space?
|
||||
}
|
||||
if (mF != null) mF.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("LongLogTag")
|
||||
public void run() {
|
||||
boolean done;
|
||||
|
||||
|
@ -67,6 +57,7 @@ public class DownloadRunnableFallback extends Thread {
|
|||
try {
|
||||
long rangeStart = (mMission.unknownLength || start < 1) ? -1 : start;
|
||||
|
||||
int mId = 1;
|
||||
mConn = mMission.openConnection(mId, rangeStart, -1);
|
||||
mMission.establishConnection(mId, mConn);
|
||||
|
||||
|
@ -81,7 +72,7 @@ public class DownloadRunnableFallback extends Thread {
|
|||
if (!mMission.unknownLength)
|
||||
mMission.unknownLength = Utility.getContentLength(mConn) == -1;
|
||||
|
||||
mF = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
||||
mF = mMission.storage.getStream();
|
||||
mF.seek(mMission.offsets[mMission.current] + start);
|
||||
|
||||
mIs = mConn.getInputStream();
|
||||
|
@ -110,6 +101,10 @@ public class DownloadRunnableFallback extends Thread {
|
|||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.e(TAG, "got exception, retrying...", e);
|
||||
}
|
||||
|
||||
run();// try again
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package us.shandian.giga.get;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public class FinishedMission extends Mission {
|
||||
|
||||
public FinishedMission() {
|
||||
}
|
||||
|
||||
public FinishedMission(DownloadMission mission) {
|
||||
public FinishedMission(@NonNull DownloadMission mission) {
|
||||
source = mission.source;
|
||||
length = mission.length;// ¿or mission.done?
|
||||
timestamp = mission.timestamp;
|
||||
name = mission.name;
|
||||
location = mission.location;
|
||||
kind = mission.kind;
|
||||
storage = mission.storage;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package us.shandian.giga.get;
|
||||
|
||||
import java.io.File;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
|
||||
public abstract class Mission implements Serializable {
|
||||
private static final long serialVersionUID = 0L;// last bump: 5 october 2018
|
||||
private static final long serialVersionUID = 1L;// last bump: 27 march 2019
|
||||
|
||||
/**
|
||||
* Source url of the resource
|
||||
|
@ -23,33 +25,24 @@ public abstract class Mission implements Serializable {
|
|||
*/
|
||||
public long timestamp;
|
||||
|
||||
/**
|
||||
* The filename
|
||||
*/
|
||||
public String name;
|
||||
|
||||
/**
|
||||
* The directory to store the download
|
||||
*/
|
||||
public String location;
|
||||
|
||||
/**
|
||||
* pre-defined content type
|
||||
*/
|
||||
public char kind;
|
||||
|
||||
/**
|
||||
* get the target file on the storage
|
||||
*
|
||||
* @return File object
|
||||
* The downloaded file
|
||||
*/
|
||||
public File getDownloadedFile() {
|
||||
return new File(location, name);
|
||||
}
|
||||
public StoredFileHelper storage;
|
||||
|
||||
/**
|
||||
* Delete the downloaded file
|
||||
*
|
||||
* @return {@code true] if and only if the file is successfully deleted, otherwise, {@code false}
|
||||
*/
|
||||
public boolean delete() {
|
||||
deleted = true;
|
||||
return getDownloadedFile().delete();
|
||||
if (storage != null) return storage.delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,10 +50,11 @@ public abstract class Mission implements Serializable {
|
|||
*/
|
||||
public transient boolean deleted = false;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(timestamp);
|
||||
return "[" + calendar.getTime().toString() + "] " + location + File.separator + name;
|
||||
return "[" + calendar.getTime().toString() + "] " + (storage.isInvalid() ? storage.getName() : storage.getUri());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
package us.shandian.giga.get.sqlite;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.get.FinishedMission;
|
||||
import us.shandian.giga.get.Mission;
|
||||
|
||||
import static us.shandian.giga.get.sqlite.DownloadMissionHelper.KEY_LOCATION;
|
||||
import static us.shandian.giga.get.sqlite.DownloadMissionHelper.KEY_NAME;
|
||||
import static us.shandian.giga.get.sqlite.DownloadMissionHelper.MISSIONS_TABLE_NAME;
|
||||
|
||||
public class DownloadDataSource {
|
||||
|
||||
private static final String TAG = "DownloadDataSource";
|
||||
private final DownloadMissionHelper downloadMissionHelper;
|
||||
|
||||
public DownloadDataSource(Context context) {
|
||||
downloadMissionHelper = new DownloadMissionHelper(context);
|
||||
}
|
||||
|
||||
public ArrayList<FinishedMission> loadFinishedMissions() {
|
||||
SQLiteDatabase database = downloadMissionHelper.getReadableDatabase();
|
||||
Cursor cursor = database.query(MISSIONS_TABLE_NAME, null, null,
|
||||
null, null, null, DownloadMissionHelper.KEY_TIMESTAMP);
|
||||
|
||||
int count = cursor.getCount();
|
||||
if (count == 0) return new ArrayList<>(1);
|
||||
|
||||
ArrayList<FinishedMission> result = new ArrayList<>(count);
|
||||
while (cursor.moveToNext()) {
|
||||
result.add(DownloadMissionHelper.getMissionFromCursor(cursor));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addMission(DownloadMission downloadMission) {
|
||||
if (downloadMission == null) throw new NullPointerException("downloadMission is null");
|
||||
SQLiteDatabase database = downloadMissionHelper.getWritableDatabase();
|
||||
ContentValues values = DownloadMissionHelper.getValuesOfMission(downloadMission);
|
||||
database.insert(MISSIONS_TABLE_NAME, null, values);
|
||||
}
|
||||
|
||||
public void deleteMission(Mission downloadMission) {
|
||||
if (downloadMission == null) throw new NullPointerException("downloadMission is null");
|
||||
SQLiteDatabase database = downloadMissionHelper.getWritableDatabase();
|
||||
database.delete(MISSIONS_TABLE_NAME,
|
||||
KEY_LOCATION + " = ? AND " +
|
||||
KEY_NAME + " = ?",
|
||||
new String[]{downloadMission.location, downloadMission.name});
|
||||
}
|
||||
|
||||
public void updateMission(DownloadMission downloadMission) {
|
||||
if (downloadMission == null) throw new NullPointerException("downloadMission is null");
|
||||
SQLiteDatabase database = downloadMissionHelper.getWritableDatabase();
|
||||
ContentValues values = DownloadMissionHelper.getValuesOfMission(downloadMission);
|
||||
String whereClause = KEY_LOCATION + " = ? AND " +
|
||||
KEY_NAME + " = ?";
|
||||
int rowsAffected = database.update(MISSIONS_TABLE_NAME, values,
|
||||
whereClause, new String[]{downloadMission.location, downloadMission.name});
|
||||
if (rowsAffected != 1) {
|
||||
Log.e(TAG, "Expected 1 row to be affected by update but got " + rowsAffected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
package us.shandian.giga.get.sqlite;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.get.FinishedMission;
|
||||
|
||||
/**
|
||||
* SQLiteHelper to store finished {@link us.shandian.giga.get.DownloadMission}'s
|
||||
*/
|
||||
public class DownloadMissionHelper extends SQLiteOpenHelper {
|
||||
private final String TAG = "DownloadMissionHelper";
|
||||
|
||||
// TODO: use NewPipeSQLiteHelper ('s constants) when playlist branch is merged (?)
|
||||
private static final String DATABASE_NAME = "downloads.db";
|
||||
|
||||
private static final int DATABASE_VERSION = 3;
|
||||
|
||||
/**
|
||||
* The table name of download missions
|
||||
*/
|
||||
static final String MISSIONS_TABLE_NAME = "download_missions";
|
||||
|
||||
/**
|
||||
* The key to the directory location of the mission
|
||||
*/
|
||||
static final String KEY_LOCATION = "location";
|
||||
/**
|
||||
* The key to the urls of a mission
|
||||
*/
|
||||
static final String KEY_SOURCE_URL = "url";
|
||||
/**
|
||||
* The key to the name of a mission
|
||||
*/
|
||||
static final String KEY_NAME = "name";
|
||||
|
||||
/**
|
||||
* The key to the done.
|
||||
*/
|
||||
static final String KEY_DONE = "bytes_downloaded";
|
||||
|
||||
static final String KEY_TIMESTAMP = "timestamp";
|
||||
|
||||
static final String KEY_KIND = "kind";
|
||||
|
||||
/**
|
||||
* The statement to create the table
|
||||
*/
|
||||
private static final String MISSIONS_CREATE_TABLE =
|
||||
"CREATE TABLE " + MISSIONS_TABLE_NAME + " (" +
|
||||
KEY_LOCATION + " TEXT NOT NULL, " +
|
||||
KEY_NAME + " TEXT NOT NULL, " +
|
||||
KEY_SOURCE_URL + " TEXT NOT NULL, " +
|
||||
KEY_DONE + " INTEGER NOT NULL, " +
|
||||
KEY_TIMESTAMP + " INTEGER NOT NULL, " +
|
||||
KEY_KIND + " TEXT NOT NULL, " +
|
||||
" UNIQUE(" + KEY_LOCATION + ", " + KEY_NAME + "));";
|
||||
|
||||
public DownloadMissionHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(MISSIONS_CREATE_TABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion == 2) {
|
||||
db.execSQL("ALTER TABLE " + MISSIONS_TABLE_NAME + " ADD COLUMN " + KEY_KIND + " TEXT;");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all values of the download mission as ContentValues.
|
||||
*
|
||||
* @param downloadMission the download mission
|
||||
* @return the content values
|
||||
*/
|
||||
public static ContentValues getValuesOfMission(DownloadMission downloadMission) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(KEY_SOURCE_URL, downloadMission.source);
|
||||
values.put(KEY_LOCATION, downloadMission.location);
|
||||
values.put(KEY_NAME, downloadMission.name);
|
||||
values.put(KEY_DONE, downloadMission.done);
|
||||
values.put(KEY_TIMESTAMP, downloadMission.timestamp);
|
||||
values.put(KEY_KIND, String.valueOf(downloadMission.kind));
|
||||
return values;
|
||||
}
|
||||
|
||||
public static FinishedMission getMissionFromCursor(Cursor cursor) {
|
||||
if (cursor == null) throw new NullPointerException("cursor is null");
|
||||
|
||||
String kind = cursor.getString(cursor.getColumnIndex(KEY_KIND));
|
||||
if (kind == null || kind.isEmpty()) kind = "?";
|
||||
|
||||
FinishedMission mission = new FinishedMission();
|
||||
mission.name = cursor.getString(cursor.getColumnIndexOrThrow(KEY_NAME));
|
||||
mission.location = cursor.getString(cursor.getColumnIndexOrThrow(KEY_LOCATION));
|
||||
mission.source = cursor.getString(cursor.getColumnIndexOrThrow(KEY_SOURCE_URL));;
|
||||
mission.length = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_DONE));
|
||||
mission.timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_TIMESTAMP));
|
||||
mission.kind = kind.charAt(0);
|
||||
|
||||
return mission;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
package us.shandian.giga.get.sqlite;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.get.FinishedMission;
|
||||
import us.shandian.giga.get.Mission;
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
|
||||
/**
|
||||
* SQLite helper to store finished {@link us.shandian.giga.get.FinishedMission}'s
|
||||
*/
|
||||
public class FinishedMissionStore extends SQLiteOpenHelper {
|
||||
|
||||
// TODO: use NewPipeSQLiteHelper ('s constants) when playlist branch is merged (?)
|
||||
private static final String DATABASE_NAME = "downloads.db";
|
||||
|
||||
private static final int DATABASE_VERSION = 4;
|
||||
|
||||
/**
|
||||
* The table name of download missions (old)
|
||||
*/
|
||||
private static final String MISSIONS_TABLE_NAME_v2 = "download_missions";
|
||||
|
||||
/**
|
||||
* The table name of download missions
|
||||
*/
|
||||
private static final String FINISHED_TABLE_NAME = "finished_missions";
|
||||
|
||||
/**
|
||||
* The key to the urls of a mission
|
||||
*/
|
||||
private static final String KEY_SOURCE = "url";
|
||||
|
||||
|
||||
/**
|
||||
* The key to the done.
|
||||
*/
|
||||
private static final String KEY_DONE = "bytes_downloaded";
|
||||
|
||||
private static final String KEY_TIMESTAMP = "timestamp";
|
||||
|
||||
private static final String KEY_KIND = "kind";
|
||||
|
||||
private static final String KEY_PATH = "path";
|
||||
|
||||
/**
|
||||
* The statement to create the table
|
||||
*/
|
||||
private static final String MISSIONS_CREATE_TABLE =
|
||||
"CREATE TABLE " + FINISHED_TABLE_NAME + " (" +
|
||||
KEY_PATH + " TEXT NOT NULL, " +
|
||||
KEY_SOURCE + " TEXT NOT NULL, " +
|
||||
KEY_DONE + " INTEGER NOT NULL, " +
|
||||
KEY_TIMESTAMP + " INTEGER NOT NULL, " +
|
||||
KEY_KIND + " TEXT NOT NULL, " +
|
||||
" UNIQUE(" + KEY_TIMESTAMP + ", " + KEY_PATH + "));";
|
||||
|
||||
|
||||
private Context context;
|
||||
|
||||
public FinishedMissionStore(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(MISSIONS_CREATE_TABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion == 2) {
|
||||
db.execSQL("ALTER TABLE " + MISSIONS_TABLE_NAME_v2 + " ADD COLUMN " + KEY_KIND + " TEXT;");
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (oldVersion == 3) {
|
||||
final String KEY_LOCATION = "location";
|
||||
final String KEY_NAME = "name";
|
||||
|
||||
db.execSQL(MISSIONS_CREATE_TABLE);
|
||||
|
||||
Cursor cursor = db.query(MISSIONS_TABLE_NAME_v2, null, null,
|
||||
null, null, null, KEY_TIMESTAMP);
|
||||
|
||||
int count = cursor.getCount();
|
||||
if (count > 0) {
|
||||
db.beginTransaction();
|
||||
while (cursor.moveToNext()) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(KEY_SOURCE, cursor.getString(cursor.getColumnIndex(KEY_SOURCE)));
|
||||
values.put(KEY_DONE, cursor.getString(cursor.getColumnIndex(KEY_DONE)));
|
||||
values.put(KEY_TIMESTAMP, cursor.getLong(cursor.getColumnIndex(KEY_TIMESTAMP)));
|
||||
values.put(KEY_KIND, cursor.getString(cursor.getColumnIndex(KEY_KIND)));
|
||||
values.put(KEY_PATH, Uri.fromFile(
|
||||
new File(
|
||||
cursor.getString(cursor.getColumnIndex(KEY_LOCATION)),
|
||||
cursor.getString(cursor.getColumnIndex(KEY_NAME))
|
||||
)
|
||||
).toString());
|
||||
|
||||
db.insert(FINISHED_TABLE_NAME, null, values);
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
db.execSQL("DROP TABLE " + MISSIONS_TABLE_NAME_v2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all values of the download mission as ContentValues.
|
||||
*
|
||||
* @param downloadMission the download mission
|
||||
* @return the content values
|
||||
*/
|
||||
private ContentValues getValuesOfMission(@NonNull Mission downloadMission) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(KEY_SOURCE, downloadMission.source);
|
||||
values.put(KEY_PATH, downloadMission.storage.getUri().toString());
|
||||
values.put(KEY_DONE, downloadMission.length);
|
||||
values.put(KEY_TIMESTAMP, downloadMission.timestamp);
|
||||
values.put(KEY_KIND, String.valueOf(downloadMission.kind));
|
||||
return values;
|
||||
}
|
||||
|
||||
private FinishedMission getMissionFromCursor(Cursor cursor) {
|
||||
if (cursor == null) throw new NullPointerException("cursor is null");
|
||||
|
||||
String kind = cursor.getString(cursor.getColumnIndex(KEY_KIND));
|
||||
if (kind == null || kind.isEmpty()) kind = "?";
|
||||
|
||||
String path = cursor.getString(cursor.getColumnIndexOrThrow(KEY_PATH));
|
||||
|
||||
FinishedMission mission = new FinishedMission();
|
||||
|
||||
mission.source = cursor.getString(cursor.getColumnIndexOrThrow(KEY_SOURCE));
|
||||
mission.length = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_DONE));
|
||||
mission.timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_TIMESTAMP));
|
||||
mission.kind = kind.charAt(0);
|
||||
|
||||
try {
|
||||
mission.storage = new StoredFileHelper(context,null, Uri.parse(path), "");
|
||||
} catch (Exception e) {
|
||||
Log.e("FinishedMissionStore", "failed to load the storage path of: " + path, e);
|
||||
mission.storage = new StoredFileHelper(null, path, "", "");
|
||||
}
|
||||
|
||||
return mission;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
// Data source methods
|
||||
///////////////////////////////////
|
||||
|
||||
public ArrayList<FinishedMission> loadFinishedMissions() {
|
||||
SQLiteDatabase database = getReadableDatabase();
|
||||
Cursor cursor = database.query(FINISHED_TABLE_NAME, null, null,
|
||||
null, null, null, KEY_TIMESTAMP + " DESC");
|
||||
|
||||
int count = cursor.getCount();
|
||||
if (count == 0) return new ArrayList<>(1);
|
||||
|
||||
ArrayList<FinishedMission> result = new ArrayList<>(count);
|
||||
while (cursor.moveToNext()) {
|
||||
result.add(getMissionFromCursor(cursor));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addFinishedMission(DownloadMission downloadMission) {
|
||||
if (downloadMission == null) throw new NullPointerException("downloadMission is null");
|
||||
SQLiteDatabase database = getWritableDatabase();
|
||||
ContentValues values = getValuesOfMission(downloadMission);
|
||||
database.insert(FINISHED_TABLE_NAME, null, values);
|
||||
}
|
||||
|
||||
public void deleteMission(Mission mission) {
|
||||
if (mission == null) throw new NullPointerException("mission is null");
|
||||
String ts = String.valueOf(mission.timestamp);
|
||||
|
||||
SQLiteDatabase database = getWritableDatabase();
|
||||
|
||||
if (mission instanceof FinishedMission) {
|
||||
if (mission.storage.isInvalid()) {
|
||||
database.delete(FINISHED_TABLE_NAME, KEY_TIMESTAMP + " = ?", new String[]{ts});
|
||||
} else {
|
||||
database.delete(FINISHED_TABLE_NAME, KEY_TIMESTAMP + " = ? AND " + KEY_PATH + " = ?", new String[]{
|
||||
ts, mission.storage.getUri().toString()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("DownloadMission");
|
||||
}
|
||||
}
|
||||
|
||||
public void updateMission(Mission mission) {
|
||||
if (mission == null) throw new NullPointerException("mission is null");
|
||||
SQLiteDatabase database = getWritableDatabase();
|
||||
ContentValues values = getValuesOfMission(mission);
|
||||
String ts = String.valueOf(mission.timestamp);
|
||||
|
||||
int rowsAffected;
|
||||
|
||||
if (mission instanceof FinishedMission) {
|
||||
if (mission.storage.isInvalid()) {
|
||||
rowsAffected = database.update(FINISHED_TABLE_NAME, values, KEY_TIMESTAMP + " = ?", new String[]{ts});
|
||||
} else {
|
||||
rowsAffected = database.update(FINISHED_TABLE_NAME, values, KEY_PATH + " = ?", new String[]{
|
||||
mission.storage.getUri().toString()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("DownloadMission");
|
||||
}
|
||||
|
||||
if (rowsAffected != 1) {
|
||||
Log.e("FinishedMissionStore", "Expected 1 row to be affected by update but got " + rowsAffected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,153 +1,148 @@
|
|||
package us.shandian.giga.postprocessing.io;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class ChunkFileInputStream extends SharpStream {
|
||||
|
||||
private RandomAccessFile source;
|
||||
private final long offset;
|
||||
private final long length;
|
||||
private long position;
|
||||
|
||||
public ChunkFileInputStream(File file, long start, long end, String mode) throws IOException {
|
||||
source = new RandomAccessFile(file, mode);
|
||||
offset = start;
|
||||
length = end - start;
|
||||
position = 0;
|
||||
|
||||
if (length < 1) {
|
||||
source.close();
|
||||
throw new IOException("The chunk is empty or invalid");
|
||||
}
|
||||
if (source.length() < end) {
|
||||
try {
|
||||
throw new IOException(String.format("invalid file length. expected = %s found = %s", end, source.length()));
|
||||
} finally {
|
||||
source.close();
|
||||
}
|
||||
}
|
||||
|
||||
source.seek(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get absolute position on file
|
||||
*
|
||||
* @return the position
|
||||
*/
|
||||
public long getFilePointer() {
|
||||
return offset + position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if ((position + 1) > length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = source.read();
|
||||
if (res >= 0) {
|
||||
position++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[]) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if ((position + len) > length) {
|
||||
len = (int) (length - position);
|
||||
}
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = source.read(b, off, len);
|
||||
position += res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long pos) throws IOException {
|
||||
pos = Math.min(pos + position, length);
|
||||
|
||||
if (pos == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
source.seek(offset + pos);
|
||||
|
||||
long oldPos = position;
|
||||
position = pos;
|
||||
|
||||
return pos - oldPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return (int) (length - position);
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyCatchBlock")
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
source.close();
|
||||
} catch (IOException err) {
|
||||
} finally {
|
||||
source = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisposed() {
|
||||
return source == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() throws IOException {
|
||||
position = 0;
|
||||
source.seek(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
}
|
||||
package us.shandian.giga.io;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ChunkFileInputStream extends SharpStream {
|
||||
|
||||
private SharpStream source;
|
||||
private final long offset;
|
||||
private final long length;
|
||||
private long position;
|
||||
|
||||
public ChunkFileInputStream(SharpStream target, long start) throws IOException {
|
||||
this(target, start, target.length());
|
||||
}
|
||||
|
||||
public ChunkFileInputStream(SharpStream target, long start, long end) throws IOException {
|
||||
source = target;
|
||||
offset = start;
|
||||
length = end - start;
|
||||
position = 0;
|
||||
|
||||
if (length < 1) {
|
||||
source.close();
|
||||
throw new IOException("The chunk is empty or invalid");
|
||||
}
|
||||
if (source.length() < end) {
|
||||
try {
|
||||
throw new IOException(String.format("invalid file length. expected = %s found = %s", end, source.length()));
|
||||
} finally {
|
||||
source.close();
|
||||
}
|
||||
}
|
||||
|
||||
source.seek(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get absolute position on file
|
||||
*
|
||||
* @return the position
|
||||
*/
|
||||
public long getFilePointer() {
|
||||
return offset + position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if ((position + 1) > length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = source.read();
|
||||
if (res >= 0) {
|
||||
position++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[]) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if ((position + len) > length) {
|
||||
len = (int) (length - position);
|
||||
}
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = source.read(b, off, len);
|
||||
position += res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long pos) throws IOException {
|
||||
pos = Math.min(pos + position, length);
|
||||
|
||||
if (pos == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
source.seek(offset + pos);
|
||||
|
||||
long oldPos = position;
|
||||
position = pos;
|
||||
|
||||
return pos - oldPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long available() {
|
||||
return (int) (length - position);
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyCatchBlock")
|
||||
@Override
|
||||
public void close() {
|
||||
source.close();
|
||||
source = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return source == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() throws IOException {
|
||||
position = 0;
|
||||
source.seek(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int count) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,497 @@
|
|||
package us.shandian.giga.io;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CircularFileWriter extends SharpStream {
|
||||
|
||||
private final static int QUEUE_BUFFER_SIZE = 8 * 1024;// 8 KiB
|
||||
private final static int COPY_BUFFER_SIZE = 128 * 1024; // 128 KiB
|
||||
private final static int NOTIFY_BYTES_INTERVAL = 64 * 1024;// 64 KiB
|
||||
private final static int THRESHOLD_AUX_LENGTH = 15 * 1024 * 1024;// 15 MiB
|
||||
|
||||
private OffsetChecker callback;
|
||||
|
||||
public ProgressReport onProgress;
|
||||
public WriteErrorHandle onWriteError;
|
||||
|
||||
private long reportPosition;
|
||||
private long maxLengthKnown = -1;
|
||||
|
||||
private BufferedFile out;
|
||||
private BufferedFile aux;
|
||||
|
||||
public CircularFileWriter(SharpStream target, File temp, OffsetChecker checker) throws IOException {
|
||||
if (checker == null) {
|
||||
throw new NullPointerException("checker is null");
|
||||
}
|
||||
|
||||
if (!temp.exists()) {
|
||||
if (!temp.createNewFile()) {
|
||||
throw new IOException("Cannot create a temporal file");
|
||||
}
|
||||
}
|
||||
|
||||
aux = new BufferedFile(temp);
|
||||
out = new BufferedFile(target);
|
||||
|
||||
callback = checker;
|
||||
|
||||
reportPosition = NOTIFY_BYTES_INTERVAL;
|
||||
}
|
||||
|
||||
private void flushAuxiliar(long amount) throws IOException {
|
||||
if (aux.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
out.flush();
|
||||
aux.flush();
|
||||
|
||||
boolean underflow = aux.offset < aux.length || out.offset < out.length;
|
||||
byte[] buffer = new byte[COPY_BUFFER_SIZE];
|
||||
|
||||
aux.target.seek(0);
|
||||
out.target.seek(out.length);
|
||||
|
||||
long length = amount;
|
||||
while (length > 0) {
|
||||
int read = (int) Math.min(length, Integer.MAX_VALUE);
|
||||
read = aux.target.read(buffer, 0, Math.min(read, buffer.length));
|
||||
|
||||
if (read < 1) {
|
||||
amount -= length;
|
||||
break;
|
||||
}
|
||||
|
||||
out.writeProof(buffer, read);
|
||||
length -= read;
|
||||
}
|
||||
|
||||
if (underflow) {
|
||||
if (out.offset >= out.length) {
|
||||
// calculate the aux underflow pointer
|
||||
if (aux.offset < amount) {
|
||||
out.offset += aux.offset;
|
||||
aux.offset = 0;
|
||||
out.target.seek(out.offset);
|
||||
} else {
|
||||
aux.offset -= amount;
|
||||
out.offset = out.length + amount;
|
||||
}
|
||||
} else {
|
||||
aux.offset = 0;
|
||||
}
|
||||
} else {
|
||||
out.offset += amount;
|
||||
aux.offset -= amount;
|
||||
}
|
||||
|
||||
out.length += amount;
|
||||
|
||||
if (out.length > maxLengthKnown) {
|
||||
maxLengthKnown = out.length;
|
||||
}
|
||||
|
||||
if (amount < aux.length) {
|
||||
// move the excess data to the beginning of the file
|
||||
long readOffset = amount;
|
||||
long writeOffset = 0;
|
||||
|
||||
aux.length -= amount;
|
||||
length = aux.length;
|
||||
while (length > 0) {
|
||||
int read = (int) Math.min(length, Integer.MAX_VALUE);
|
||||
read = aux.target.read(buffer, 0, Math.min(read, buffer.length));
|
||||
|
||||
aux.target.seek(writeOffset);
|
||||
aux.writeProof(buffer, read);
|
||||
|
||||
writeOffset += read;
|
||||
readOffset += read;
|
||||
length -= read;
|
||||
|
||||
aux.target.seek(readOffset);
|
||||
}
|
||||
|
||||
aux.target.setLength(aux.length);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aux.length > THRESHOLD_AUX_LENGTH) {
|
||||
aux.target.setLength(THRESHOLD_AUX_LENGTH);// or setLength(0);
|
||||
}
|
||||
|
||||
aux.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any buffer and close the output file. Use this method if the
|
||||
* operation is successful
|
||||
*
|
||||
* @return the final length of the file
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public long finalizeFile() throws IOException {
|
||||
flushAuxiliar(aux.length);
|
||||
|
||||
out.flush();
|
||||
|
||||
// change file length (if required)
|
||||
long length = Math.max(maxLengthKnown, out.length);
|
||||
if (length != out.target.length()) {
|
||||
out.target.setLength(length);
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the file without flushing any buffer
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
out = null;
|
||||
}
|
||||
if (aux != null) {
|
||||
aux.close();
|
||||
aux = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte b) throws IOException {
|
||||
write(new byte[]{b}, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte b[]) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
long available;
|
||||
long offsetOut = out.getOffset();
|
||||
long offsetAux = aux.getOffset();
|
||||
long end = callback.check();
|
||||
|
||||
if (end == -1) {
|
||||
available = Integer.MAX_VALUE;
|
||||
} else if (end < offsetOut) {
|
||||
throw new IOException("The reported offset is invalid: " + end + "<" + offsetOut);
|
||||
} else {
|
||||
available = end - offsetOut;
|
||||
}
|
||||
|
||||
boolean usingAux = aux.length > 0 && offsetOut >= out.length;
|
||||
boolean underflow = offsetAux < aux.length || offsetOut < out.length;
|
||||
|
||||
if (usingAux) {
|
||||
// before continue calculate the final length of aux
|
||||
long length = offsetAux + len;
|
||||
if (underflow) {
|
||||
if (aux.length > length) {
|
||||
length = aux.length;// the length is not changed
|
||||
}
|
||||
} else {
|
||||
length = aux.length + len;
|
||||
}
|
||||
|
||||
aux.write(b, off, len);
|
||||
|
||||
if (length >= THRESHOLD_AUX_LENGTH && length <= available) {
|
||||
flushAuxiliar(available);
|
||||
}
|
||||
} else {
|
||||
if (underflow) {
|
||||
available = out.length - offsetOut;
|
||||
}
|
||||
|
||||
int length = Math.min(len, (int) available);
|
||||
out.write(b, off, length);
|
||||
|
||||
len -= length;
|
||||
off += length;
|
||||
|
||||
if (len > 0) {
|
||||
aux.write(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (onProgress != null) {
|
||||
long absoluteOffset = out.getOffset() + aux.getOffset();
|
||||
if (absoluteOffset > reportPosition) {
|
||||
reportPosition = absoluteOffset + NOTIFY_BYTES_INTERVAL;
|
||||
onProgress.report(absoluteOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
aux.flush();
|
||||
out.flush();
|
||||
|
||||
long total = out.length + aux.length;
|
||||
if (total > maxLengthKnown) {
|
||||
maxLengthKnown = total;// save the current file length in case the method {@code rewind()} is called
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long amount) throws IOException {
|
||||
seek(out.getOffset() + aux.getOffset() + amount);
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() throws IOException {
|
||||
if (onProgress != null) {
|
||||
onProgress.report(-out.length - aux.length);// rollback the whole progress
|
||||
}
|
||||
|
||||
seek(0);
|
||||
|
||||
reportPosition = NOTIFY_BYTES_INTERVAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long offset) throws IOException {
|
||||
long total = out.length + aux.length;
|
||||
|
||||
if (offset == total) {
|
||||
// do not ignore the seek offset if a underflow exists
|
||||
long relativeOffset = out.getOffset() + aux.getOffset();
|
||||
if (relativeOffset == total) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// flush everything, avoid any underflow
|
||||
flush();
|
||||
|
||||
if (offset < 0 || offset > total) {
|
||||
throw new IOException("desired offset is outside of range=0-" + total + " offset=" + offset);
|
||||
}
|
||||
|
||||
if (offset > out.length) {
|
||||
out.seek(out.length);
|
||||
aux.seek(offset - out.length);
|
||||
} else {
|
||||
out.seek(offset);
|
||||
aux.seek(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return out == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeek() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="stub read methods">
|
||||
@Override
|
||||
public boolean canRead() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer
|
||||
) {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int count
|
||||
) {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long available() {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
public interface OffsetChecker {
|
||||
|
||||
/**
|
||||
* Checks the amount of available space ahead
|
||||
*
|
||||
* @return absolute offset in the file where no more data SHOULD NOT be
|
||||
* written. If the value is -1 the whole file will be used
|
||||
*/
|
||||
long check();
|
||||
}
|
||||
|
||||
public interface ProgressReport {
|
||||
|
||||
/**
|
||||
* Report the size of the new file
|
||||
*
|
||||
* @param progress the new size
|
||||
*/
|
||||
void report(long progress);
|
||||
}
|
||||
|
||||
public interface WriteErrorHandle {
|
||||
|
||||
/**
|
||||
* Attempts to handle a I/O exception
|
||||
*
|
||||
* @param err the cause
|
||||
* @return {@code true} to retry and continue, otherwise, {@code false}
|
||||
* and throw the exception
|
||||
*/
|
||||
boolean handle(Exception err);
|
||||
}
|
||||
|
||||
class BufferedFile {
|
||||
|
||||
protected final SharpStream target;
|
||||
|
||||
private long offset;
|
||||
protected long length;
|
||||
|
||||
private byte[] queue = new byte[QUEUE_BUFFER_SIZE];
|
||||
private int queueSize;
|
||||
|
||||
BufferedFile(File file) throws FileNotFoundException {
|
||||
this.target = new FileStream(file);
|
||||
}
|
||||
|
||||
BufferedFile(SharpStream target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
protected long getOffset() {
|
||||
return offset + queueSize;// absolute offset in the file
|
||||
}
|
||||
|
||||
protected void close() {
|
||||
queue = null;
|
||||
target.close();
|
||||
}
|
||||
|
||||
protected void write(byte b[], int off, int len) throws IOException {
|
||||
while (len > 0) {
|
||||
// if the queue is full, the method available() will flush the queue
|
||||
int read = Math.min(available(), len);
|
||||
|
||||
// enqueue incoming buffer
|
||||
System.arraycopy(b, off, queue, queueSize, read);
|
||||
queueSize += read;
|
||||
|
||||
len -= read;
|
||||
off += read;
|
||||
}
|
||||
|
||||
long total = offset + queueSize;
|
||||
if (total > length) {
|
||||
length = total;// save length
|
||||
}
|
||||
}
|
||||
|
||||
void flush() throws IOException {
|
||||
writeProof(queue, queueSize);
|
||||
offset += queueSize;
|
||||
queueSize = 0;
|
||||
}
|
||||
|
||||
protected void rewind() throws IOException {
|
||||
offset = 0;
|
||||
target.seek(0);
|
||||
}
|
||||
|
||||
protected int available() throws IOException {
|
||||
if (queueSize >= queue.length) {
|
||||
flush();
|
||||
return queue.length;
|
||||
}
|
||||
|
||||
return queue.length - queueSize;
|
||||
}
|
||||
|
||||
void reset() throws IOException {
|
||||
offset = 0;
|
||||
length = 0;
|
||||
target.seek(0);
|
||||
}
|
||||
|
||||
protected void seek(long absoluteOffset) throws IOException {
|
||||
if (absoluteOffset == offset) {
|
||||
return;// nothing to do
|
||||
}
|
||||
offset = absoluteOffset;
|
||||
target.seek(absoluteOffset);
|
||||
}
|
||||
|
||||
void writeProof(byte[] buffer, int length) throws IOException {
|
||||
if (onWriteError == null) {
|
||||
target.write(buffer, 0, length);
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
target.write(buffer, 0, length);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
if (!onWriteError.handle(e)) {
|
||||
throw e;// give up
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
String absLength;
|
||||
|
||||
try {
|
||||
absLength = Long.toString(target.length());
|
||||
} catch (IOException e) {
|
||||
absLength = "[" + e.getLocalizedMessage() + "]";
|
||||
}
|
||||
|
||||
return String.format(
|
||||
"offset=%s length=%s queue=%s absLength=%s",
|
||||
offset, length, queueSize, absLength
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,126 +1,131 @@
|
|||
package us.shandian.giga.postprocessing.io;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
public class FileStream extends SharpStream {
|
||||
|
||||
public enum Mode {
|
||||
Read,
|
||||
ReadWrite
|
||||
}
|
||||
|
||||
public RandomAccessFile source;
|
||||
private final Mode mode;
|
||||
|
||||
public FileStream(String path, Mode mode) throws IOException {
|
||||
String flags;
|
||||
|
||||
if (mode == Mode.Read) {
|
||||
flags = "r";
|
||||
} else {
|
||||
flags = "rw";
|
||||
}
|
||||
|
||||
this.mode = mode;
|
||||
source = new RandomAccessFile(path, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return source.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[]) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
return source.read(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long pos) throws IOException {
|
||||
FileChannel fc = source.getChannel();
|
||||
fc.position(fc.position() + pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
try {
|
||||
return (int) (source.length() - source.getFilePointer());
|
||||
} catch (IOException ex) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyCatchBlock")
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
source.close();
|
||||
} catch (IOException err) {
|
||||
|
||||
} finally {
|
||||
source = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisposed() {
|
||||
return source == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() throws IOException {
|
||||
source.getChannel().position(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead() {
|
||||
return mode == Mode.Read || mode == Mode.ReadWrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite() {
|
||||
return mode == Mode.ReadWrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte value) throws IOException {
|
||||
source.write(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) throws IOException {
|
||||
source.write(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int count) throws IOException {
|
||||
source.write(buffer, offset, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(long length) throws IOException {
|
||||
source.setLength(length);
|
||||
}
|
||||
}
|
||||
package us.shandian.giga.io;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
public class FileStream extends SharpStream {
|
||||
|
||||
public RandomAccessFile source;
|
||||
|
||||
public FileStream(@NonNull File target) throws FileNotFoundException {
|
||||
this.source = new RandomAccessFile(target, "rw");
|
||||
}
|
||||
|
||||
public FileStream(@NonNull String path) throws FileNotFoundException {
|
||||
this.source = new RandomAccessFile(path, "rw");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return source.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[]) throws IOException {
|
||||
return source.read(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
return source.read(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long pos) throws IOException {
|
||||
return source.skipBytes((int) pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long available() {
|
||||
try {
|
||||
return source.length() - source.getFilePointer();
|
||||
} catch (IOException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (source == null) return;
|
||||
try {
|
||||
source.close();
|
||||
} catch (IOException err) {
|
||||
// nothing to do
|
||||
}
|
||||
source = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return source == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() throws IOException {
|
||||
source.seek(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeek() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSetLength() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte value) throws IOException {
|
||||
source.write(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) throws IOException {
|
||||
source.write(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int count) throws IOException {
|
||||
source.write(buffer, offset, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(long length) throws IOException {
|
||||
source.setLength(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long offset) throws IOException {
|
||||
source.seek(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length() throws IOException {
|
||||
return source.length();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package us.shandian.giga.io;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
public class FileStreamSAF extends SharpStream {
|
||||
|
||||
private final FileInputStream in;
|
||||
private final FileOutputStream out;
|
||||
private final FileChannel channel;
|
||||
private final ParcelFileDescriptor file;
|
||||
|
||||
private boolean disposed;
|
||||
|
||||
public FileStreamSAF(@NonNull ContentResolver contentResolver, Uri fileUri) throws IOException {
|
||||
// Notes:
|
||||
// the file must exists first
|
||||
// ¡read-write mode must allow seek!
|
||||
// It is not guaranteed to work with files in the cloud (virtual files), tested in local storage devices
|
||||
|
||||
file = contentResolver.openFileDescriptor(fileUri, "rw");
|
||||
|
||||
if (file == null) {
|
||||
throw new IOException("Cannot get the ParcelFileDescriptor for " + fileUri.toString());
|
||||
}
|
||||
|
||||
in = new FileInputStream(file.getFileDescriptor());
|
||||
out = new FileOutputStream(file.getFileDescriptor());
|
||||
channel = out.getChannel();// or use in.getChannel()
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return in.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
return in.read(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int count) throws IOException {
|
||||
return in.read(buffer, offset, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long amount) throws IOException {
|
||||
return in.skip(amount);// ¿or use channel.position(channel.position() + amount)?
|
||||
}
|
||||
|
||||
@Override
|
||||
public long available() {
|
||||
try {
|
||||
return in.available();
|
||||
} catch (IOException e) {
|
||||
return 0;// ¡but not -1!
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() throws IOException {
|
||||
seek(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
disposed = true;
|
||||
|
||||
file.close();
|
||||
in.close();
|
||||
out.close();
|
||||
channel.close();
|
||||
} catch (IOException e) {
|
||||
Log.e("FileStreamSAF", "close() error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return disposed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canSetLength() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canSeek() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte value) throws IOException {
|
||||
out.write(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) throws IOException {
|
||||
out.write(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int count) throws IOException {
|
||||
out.write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public void setLength(long length) throws IOException {
|
||||
channel.truncate(length);
|
||||
}
|
||||
|
||||
public void seek(long offset) throws IOException {
|
||||
channel.position(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length() throws IOException {
|
||||
return channel.size();
|
||||
}
|
||||
}
|
|
@ -1,59 +1,61 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package us.shandian.giga.postprocessing.io;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Wrapper for the classic {@link java.io.InputStream}
|
||||
* @author kapodamy
|
||||
*/
|
||||
public class SharpInputStream extends InputStream {
|
||||
|
||||
private final SharpStream base;
|
||||
|
||||
public SharpInputStream(SharpStream base) throws IOException {
|
||||
if (!base.canRead()) {
|
||||
throw new IOException("The provided stream is not readable");
|
||||
}
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return base.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] bytes) throws IOException {
|
||||
return base.read(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] bytes, int i, int i1) throws IOException {
|
||||
return base.read(bytes, i, i1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long l) throws IOException {
|
||||
return base.skip(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return base.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
base.dispose();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package us.shandian.giga.io;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Wrapper for the classic {@link java.io.InputStream}
|
||||
*
|
||||
* @author kapodamy
|
||||
*/
|
||||
public class SharpInputStream extends InputStream {
|
||||
|
||||
private final SharpStream base;
|
||||
|
||||
public SharpInputStream(SharpStream base) throws IOException {
|
||||
if (!base.canRead()) {
|
||||
throw new IOException("The provided stream is not readable");
|
||||
}
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return base.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] bytes) throws IOException {
|
||||
return base.read(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] bytes, int i, int i1) throws IOException {
|
||||
return base.read(bytes, i, i1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long l) throws IOException {
|
||||
return base.skip(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
long res = base.available();
|
||||
return res > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
base.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
package us.shandian.giga.io;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import static android.provider.DocumentsContract.Document.COLUMN_DISPLAY_NAME;
|
||||
import static android.provider.DocumentsContract.Root.COLUMN_DOCUMENT_ID;
|
||||
|
||||
|
||||
public class StoredDirectoryHelper {
|
||||
public final static int PERMISSION_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||
|
||||
private File ioTree;
|
||||
private DocumentFile docTree;
|
||||
|
||||
private Context context;
|
||||
|
||||
private String tag;
|
||||
|
||||
public StoredDirectoryHelper(@NonNull Context context, @NonNull Uri path, String tag) throws IOException {
|
||||
this.tag = tag;
|
||||
|
||||
if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(path.getScheme())) {
|
||||
this.ioTree = new File(URI.create(path.toString()));
|
||||
return;
|
||||
}
|
||||
|
||||
this.context = context;
|
||||
|
||||
try {
|
||||
this.context.getContentResolver().takePersistableUriPermission(path, PERMISSION_FLAGS);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
||||
throw new IOException("Storage Access Framework with Directory API is not available");
|
||||
|
||||
this.docTree = DocumentFile.fromTreeUri(context, path);
|
||||
|
||||
if (this.docTree == null)
|
||||
throw new IOException("Failed to create the tree from Uri");
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public StoredDirectoryHelper(@NonNull URI location, String tag) {
|
||||
ioTree = new File(location);
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public StoredFileHelper createFile(String filename, String mime) {
|
||||
return createFile(filename, mime, false);
|
||||
}
|
||||
|
||||
public StoredFileHelper createUniqueFile(String name, String mime) {
|
||||
ArrayList<String> matches = new ArrayList<>();
|
||||
String[] filename = splitFilename(name);
|
||||
String lcFilename = filename[0].toLowerCase();
|
||||
|
||||
if (docTree == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
for (File file : ioTree.listFiles())
|
||||
addIfStartWith(matches, lcFilename, file.getName());
|
||||
} else {
|
||||
// warning: SAF file listing is very slow
|
||||
Uri docTreeChildren = DocumentsContract.buildChildDocumentsUriUsingTree(
|
||||
docTree.getUri(), DocumentsContract.getDocumentId(docTree.getUri())
|
||||
);
|
||||
|
||||
String[] projection = new String[]{COLUMN_DISPLAY_NAME};
|
||||
String selection = "(LOWER(" + COLUMN_DISPLAY_NAME + ") LIKE ?%";
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
|
||||
try (Cursor cursor = cr.query(docTreeChildren, projection, selection, new String[]{lcFilename}, null)) {
|
||||
if (cursor != null) {
|
||||
while (cursor.moveToNext())
|
||||
addIfStartWith(matches, lcFilename, cursor.getString(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matches.size() < 1) {
|
||||
return createFile(name, mime, true);
|
||||
} else {
|
||||
// check if the filename is in use
|
||||
String lcName = name.toLowerCase();
|
||||
for (String testName : matches) {
|
||||
if (testName.equals(lcName)) {
|
||||
lcName = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if not in use
|
||||
if (lcName != null) return createFile(name, mime, true);
|
||||
}
|
||||
|
||||
Collections.sort(matches, String::compareTo);
|
||||
|
||||
for (int i = 1; i < 1000; i++) {
|
||||
if (Collections.binarySearch(matches, makeFileName(lcFilename, i, filename[1])) < 0)
|
||||
return createFile(makeFileName(filename[0], i, filename[1]), mime, true);
|
||||
}
|
||||
|
||||
return createFile(String.valueOf(System.currentTimeMillis()).concat(filename[1]), mime, false);
|
||||
}
|
||||
|
||||
private StoredFileHelper createFile(String filename, String mime, boolean safe) {
|
||||
StoredFileHelper storage;
|
||||
|
||||
try {
|
||||
if (docTree == null)
|
||||
storage = new StoredFileHelper(ioTree, filename, mime);
|
||||
else
|
||||
storage = new StoredFileHelper(context, docTree, filename, mime, safe);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
storage.tag = tag;
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
public Uri getUri() {
|
||||
return docTree == null ? Uri.fromFile(ioTree) : docTree.getUri();
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return docTree == null ? ioTree.exists() : docTree.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whatever if is possible access using the {@code java.io} API
|
||||
*
|
||||
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
|
||||
*/
|
||||
public boolean isDirect() {
|
||||
return docTree == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only using Java I/O. Creates the directory named by this abstract pathname, including any
|
||||
* necessary but nonexistent parent directories. Note that if this
|
||||
* operation fails it may have succeeded in creating some of the necessary
|
||||
* parent directories.
|
||||
*
|
||||
* @return <code>true</code> if and only if the directory was created,
|
||||
* along with all necessary parent directories or already exists; <code>false</code>
|
||||
* otherwise
|
||||
*/
|
||||
public boolean mkdirs() {
|
||||
if (docTree == null) {
|
||||
return ioTree.exists() || ioTree.mkdirs();
|
||||
}
|
||||
|
||||
if (docTree.exists()) return true;
|
||||
|
||||
try {
|
||||
DocumentFile parent;
|
||||
String child = docTree.getName();
|
||||
|
||||
while (true) {
|
||||
parent = docTree.getParentFile();
|
||||
if (parent == null || child == null) break;
|
||||
if (parent.exists()) return true;
|
||||
|
||||
parent.createDirectory(child);
|
||||
|
||||
child = parent.getName();// for the next iteration
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// no more parent directories or unsupported by the storage provider
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public Uri findFile(String filename) {
|
||||
if (docTree == null) {
|
||||
File res = new File(ioTree, filename);
|
||||
return res.exists() ? Uri.fromFile(res) : null;
|
||||
}
|
||||
|
||||
DocumentFile res = findFileSAFHelper(context, docTree, filename);
|
||||
return res == null ? null : res.getUri();
|
||||
}
|
||||
|
||||
public boolean canWrite() {
|
||||
return docTree == null ? ioTree.canWrite() : docTree.canWrite();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return docTree == null ? Uri.fromFile(ioTree).toString() : docTree.getUri().toString();
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// Utils
|
||||
///////////////////
|
||||
|
||||
private static void addIfStartWith(ArrayList<String> list, @NonNull String base, String str) {
|
||||
if (str == null || str.isEmpty()) return;
|
||||
str = str.toLowerCase();
|
||||
if (str.startsWith(base)) list.add(str);
|
||||
}
|
||||
|
||||
private static String[] splitFilename(@NonNull String filename) {
|
||||
int dotIndex = filename.lastIndexOf('.');
|
||||
|
||||
if (dotIndex < 0 || (dotIndex == filename.length() - 1))
|
||||
return new String[]{filename, ""};
|
||||
|
||||
return new String[]{filename.substring(0, dotIndex), filename.substring(dotIndex)};
|
||||
}
|
||||
|
||||
private static String makeFileName(String name, int idx, String ext) {
|
||||
return name.concat(" (").concat(String.valueOf(idx)).concat(")").concat(ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast (but not enough) file/directory finder under the storage access framework
|
||||
*
|
||||
* @param context The context
|
||||
* @param tree Directory where search
|
||||
* @param filename Target filename
|
||||
* @return A {@link android.support.v4.provider.DocumentFile} contain the reference, otherwise, null
|
||||
*/
|
||||
static DocumentFile findFileSAFHelper(@Nullable Context context, DocumentFile tree, String filename) {
|
||||
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
return tree.findFile(filename);// warning: this is very slow
|
||||
}
|
||||
|
||||
if (!tree.canRead()) return null;// missing read permission
|
||||
|
||||
final int name = 0;
|
||||
final int documentId = 1;
|
||||
|
||||
// LOWER() SQL function is not supported
|
||||
String selection = COLUMN_DISPLAY_NAME + " = ?";
|
||||
//String selection = COLUMN_DISPLAY_NAME + " LIKE ?%";
|
||||
|
||||
Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
|
||||
tree.getUri(), DocumentsContract.getDocumentId(tree.getUri())
|
||||
);
|
||||
String[] projection = {COLUMN_DISPLAY_NAME, COLUMN_DOCUMENT_ID};
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
|
||||
filename = filename.toLowerCase();
|
||||
|
||||
try (Cursor cursor = contentResolver.query(childrenUri, projection, selection, new String[]{filename}, null)) {
|
||||
if (cursor == null) return null;
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
if (cursor.isNull(name) || !cursor.getString(name).toLowerCase().startsWith(filename))
|
||||
continue;
|
||||
|
||||
return DocumentFile.fromSingleUri(
|
||||
context, DocumentsContract.buildDocumentUriUsingTree(
|
||||
tree.getUri(), cursor.getString(documentId)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,381 @@
|
|||
package us.shandian.giga.io;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
|
||||
public class StoredFileHelper implements Serializable {
|
||||
private static final long serialVersionUID = 0L;
|
||||
public static final String DEFAULT_MIME = "application/octet-stream";
|
||||
|
||||
private transient DocumentFile docFile;
|
||||
private transient DocumentFile docTree;
|
||||
private transient File ioFile;
|
||||
private transient Context context;
|
||||
|
||||
protected String source;
|
||||
private String sourceTree;
|
||||
|
||||
protected String tag;
|
||||
|
||||
private String srcName;
|
||||
private String srcType;
|
||||
|
||||
public StoredFileHelper(@Nullable Uri parent, String filename, String mime, String tag) {
|
||||
this.source = null;// this instance will be "invalid" see invalidate()/isInvalid() methods
|
||||
|
||||
this.srcName = filename;
|
||||
this.srcType = mime == null ? DEFAULT_MIME : mime;
|
||||
if (parent != null) this.sourceTree = parent.toString();
|
||||
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
StoredFileHelper(@Nullable Context context, DocumentFile tree, String filename, String mime, boolean safe) throws IOException {
|
||||
this.docTree = tree;
|
||||
this.context = context;
|
||||
|
||||
DocumentFile res;
|
||||
|
||||
if (safe) {
|
||||
// no conflicts (the filename is not in use)
|
||||
res = this.docTree.createFile(mime, filename);
|
||||
if (res == null) throw new IOException("Cannot create the file");
|
||||
} else {
|
||||
res = createSAF(context, mime, filename);
|
||||
}
|
||||
|
||||
this.docFile = res;
|
||||
|
||||
this.source = docFile.getUri().toString();
|
||||
this.sourceTree = docTree.getUri().toString();
|
||||
|
||||
this.srcName = this.docFile.getName();
|
||||
this.srcType = this.docFile.getType();
|
||||
}
|
||||
|
||||
StoredFileHelper(File location, String filename, String mime) throws IOException {
|
||||
this.ioFile = new File(location, filename);
|
||||
|
||||
if (this.ioFile.exists()) {
|
||||
if (!this.ioFile.isFile() && !this.ioFile.delete())
|
||||
throw new IOException("The filename is already in use by non-file entity and cannot overwrite it");
|
||||
} else {
|
||||
if (!this.ioFile.createNewFile())
|
||||
throw new IOException("Cannot create the file");
|
||||
}
|
||||
|
||||
this.source = Uri.fromFile(this.ioFile).toString();
|
||||
this.sourceTree = Uri.fromFile(location).toString();
|
||||
|
||||
this.srcName = ioFile.getName();
|
||||
this.srcType = mime;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
public StoredFileHelper(Context context, @Nullable Uri parent, @NonNull Uri path, String tag) throws IOException {
|
||||
this.tag = tag;
|
||||
this.source = path.toString();
|
||||
|
||||
if (path.getScheme() == null || path.getScheme().equalsIgnoreCase(ContentResolver.SCHEME_FILE)) {
|
||||
this.ioFile = new File(URI.create(this.source));
|
||||
} else {
|
||||
DocumentFile file = DocumentFile.fromSingleUri(context, path);
|
||||
|
||||
if (file == null) throw new RuntimeException("SAF not available");
|
||||
|
||||
this.context = context;
|
||||
|
||||
if (file.getName() == null) {
|
||||
this.source = null;
|
||||
return;
|
||||
} else {
|
||||
this.docFile = file;
|
||||
takePermissionSAF();
|
||||
}
|
||||
}
|
||||
|
||||
if (parent != null) {
|
||||
if (!ContentResolver.SCHEME_FILE.equals(parent.getScheme()))
|
||||
this.docTree = DocumentFile.fromTreeUri(context, parent);
|
||||
|
||||
this.sourceTree = parent.toString();
|
||||
}
|
||||
|
||||
this.srcName = getName();
|
||||
this.srcType = getType();
|
||||
}
|
||||
|
||||
|
||||
public static StoredFileHelper deserialize(@NonNull StoredFileHelper storage, Context context) throws IOException {
|
||||
Uri treeUri = storage.sourceTree == null ? null : Uri.parse(storage.sourceTree);
|
||||
|
||||
if (storage.isInvalid())
|
||||
return new StoredFileHelper(treeUri, storage.srcName, storage.srcType, storage.tag);
|
||||
|
||||
StoredFileHelper instance = new StoredFileHelper(context, treeUri, Uri.parse(storage.source), storage.tag);
|
||||
|
||||
// under SAF, if the target document is deleted, conserve the filename and mime
|
||||
if (instance.srcName == null) instance.srcName = storage.srcName;
|
||||
if (instance.srcType == null) instance.srcType = storage.srcType;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void requestSafWithFileCreation(@NonNull Fragment who, int requestCode, String filename, String mime) {
|
||||
// SAF notes:
|
||||
// ACTION_OPEN_DOCUMENT Do not let you create the file, useful for overwrite files
|
||||
// ACTION_CREATE_DOCUMENT No overwrite support, useless the file provider resolve the conflict
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||
.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
.setType(mime)
|
||||
.putExtra(Intent.EXTRA_TITLE, filename)
|
||||
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | StoredDirectoryHelper.PERMISSION_FLAGS)
|
||||
.putExtra("android.content.extra.SHOW_ADVANCED", true);// hack, show all storage disks
|
||||
|
||||
who.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
|
||||
public SharpStream getStream() throws IOException {
|
||||
invalid();
|
||||
|
||||
if (docFile == null)
|
||||
return new FileStream(ioFile);
|
||||
else
|
||||
return new FileStreamSAF(context.getContentResolver(), docFile.getUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whatever if is possible access using the {@code java.io} API
|
||||
*
|
||||
* @return {@code true} for Java I/O API, otherwise, {@code false} for Storage Access Framework
|
||||
*/
|
||||
public boolean isDirect() {
|
||||
invalid();
|
||||
|
||||
return docFile == null;
|
||||
}
|
||||
|
||||
public boolean isInvalid() {
|
||||
return source == null;
|
||||
}
|
||||
|
||||
public Uri getUri() {
|
||||
invalid();
|
||||
|
||||
return docFile == null ? Uri.fromFile(ioFile) : docFile.getUri();
|
||||
}
|
||||
|
||||
public Uri getParentUri() {
|
||||
invalid();
|
||||
|
||||
return sourceTree == null ? null : Uri.parse(sourceTree);
|
||||
}
|
||||
|
||||
public void truncate() throws IOException {
|
||||
invalid();
|
||||
|
||||
try (SharpStream fs = getStream()) {
|
||||
fs.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean delete() {
|
||||
if (source == null) return true;
|
||||
if (docFile == null) return ioFile.delete();
|
||||
|
||||
|
||||
boolean res = docFile.delete();
|
||||
|
||||
try {
|
||||
int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||
context.getContentResolver().releasePersistableUriPermission(docFile.getUri(), flags);
|
||||
} catch (Exception ex) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public long length() {
|
||||
invalid();
|
||||
|
||||
return docFile == null ? ioFile.length() : docFile.length();
|
||||
}
|
||||
|
||||
public boolean canWrite() {
|
||||
if (source == null) return false;
|
||||
return docFile == null ? ioFile.canWrite() : docFile.canWrite();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (source == null)
|
||||
return srcName;
|
||||
else if (docFile == null)
|
||||
return ioFile.getName();
|
||||
|
||||
String name = docFile.getName();
|
||||
return name == null ? srcName : name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
if (source == null || docFile == null)
|
||||
return srcType;
|
||||
|
||||
String type = docFile.getType();
|
||||
return type == null ? srcType : type;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public boolean existsAsFile() {
|
||||
if (source == null) return false;
|
||||
|
||||
boolean exists = docFile == null ? ioFile.exists() : docFile.exists();
|
||||
boolean isFile = docFile == null ? ioFile.isFile() : docFile.isFile();// ¿docFile.isVirtual() means is no-physical?
|
||||
|
||||
return exists && isFile;
|
||||
}
|
||||
|
||||
public boolean create() {
|
||||
invalid();
|
||||
boolean result;
|
||||
|
||||
if (docFile == null) {
|
||||
try {
|
||||
result = ioFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
} else if (docTree == null) {
|
||||
result = false;
|
||||
} else {
|
||||
if (!docTree.canRead() || !docTree.canWrite()) return false;
|
||||
try {
|
||||
docFile = createSAF(context, srcType, srcName);
|
||||
if (docFile == null || docFile.getName() == null) return false;
|
||||
result = true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
source = (docFile == null ? Uri.fromFile(ioFile) : docFile.getUri()).toString();
|
||||
srcName = getName();
|
||||
srcType = getType();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
if (source == null) return;
|
||||
|
||||
srcName = getName();
|
||||
srcType = getType();
|
||||
|
||||
source = null;
|
||||
|
||||
docTree = null;
|
||||
docFile = null;
|
||||
ioFile = null;
|
||||
context = null;
|
||||
}
|
||||
|
||||
public boolean equals(StoredFileHelper storage) {
|
||||
if (this == storage) return true;
|
||||
|
||||
// note: do not compare tags, files can have the same parent folder
|
||||
//if (stringMismatch(this.tag, storage.tag)) return false;
|
||||
|
||||
if (stringMismatch(getLowerCase(this.sourceTree), getLowerCase(this.sourceTree)))
|
||||
return false;
|
||||
|
||||
if (this.isInvalid() || storage.isInvalid()) {
|
||||
return this.srcName.equalsIgnoreCase(storage.srcName) && this.srcType.equalsIgnoreCase(storage.srcType);
|
||||
}
|
||||
|
||||
if (this.isDirect() != storage.isDirect()) return false;
|
||||
|
||||
if (this.isDirect())
|
||||
return this.ioFile.getPath().equalsIgnoreCase(storage.ioFile.getPath());
|
||||
|
||||
return DocumentsContract.getDocumentId(
|
||||
this.docFile.getUri()
|
||||
).equalsIgnoreCase(DocumentsContract.getDocumentId(
|
||||
storage.docFile.getUri()
|
||||
));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
if (source == null)
|
||||
return "[Invalid state] name=" + srcName + " type=" + srcType + " tag=" + tag;
|
||||
else
|
||||
return "sourceFile=" + source + " treeSource=" + (sourceTree == null ? "" : sourceTree) + " tag=" + tag;
|
||||
}
|
||||
|
||||
|
||||
private void invalid() {
|
||||
if (source == null)
|
||||
throw new IllegalStateException("In invalid state");
|
||||
}
|
||||
|
||||
private void takePermissionSAF() throws IOException {
|
||||
try {
|
||||
context.getContentResolver().takePersistableUriPermission(docFile.getUri(), StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||
} catch (Exception e) {
|
||||
if (docFile.getName() == null) throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private DocumentFile createSAF(@Nullable Context context, String mime, String filename) throws IOException {
|
||||
DocumentFile res = StoredDirectoryHelper.findFileSAFHelper(context, docTree, filename);
|
||||
|
||||
if (res != null && res.exists() && res.isDirectory()) {
|
||||
if (!res.delete())
|
||||
throw new IOException("Directory with the same name found but cannot delete");
|
||||
res = null;
|
||||
}
|
||||
|
||||
if (res == null) {
|
||||
res = this.docTree.createFile(srcType == null ? DEFAULT_MIME : mime, filename);
|
||||
if (res == null) throw new IOException("Cannot create the file");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private String getLowerCase(String str) {
|
||||
return str == null ? null : str.toLowerCase();
|
||||
}
|
||||
|
||||
private boolean stringMismatch(String str1, String str2) {
|
||||
if (str1 == null && str2 == null) return false;
|
||||
if ((str1 == null) != (str2 == null)) return true;
|
||||
|
||||
return !str1.equals(str2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import org.schabi.newpipe.streams.Mp4DashReader;
|
||||
import org.schabi.newpipe.streams.Mp4FromDashWriter;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
class M4aNoDash extends Postprocessing {
|
||||
|
||||
M4aNoDash() {
|
||||
super(false, true, ALGORITHM_M4A_NO_DASH);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean test(SharpStream... sources) throws IOException {
|
||||
// check if the mp4 file is DASH (youtube)
|
||||
|
||||
Mp4DashReader reader = new Mp4DashReader(sources[0]);
|
||||
reader.parse();
|
||||
|
||||
switch (reader.getBrands()[0]) {
|
||||
case 0x64617368:// DASH
|
||||
case 0x69736F35:// ISO5
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
Mp4FromDashWriter muxer = new Mp4FromDashWriter(sources[0]);
|
||||
muxer.setMainBrand(0x4D344120);// binary string "M4A "
|
||||
muxer.parseSources();
|
||||
muxer.selectTracks(0);
|
||||
muxer.build(out);
|
||||
|
||||
return OK_RESULT;
|
||||
}
|
||||
}
|
|
@ -1,29 +1,27 @@
|
|||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import org.schabi.newpipe.streams.Mp4DashWriter;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
class Mp4DashMuxer extends Postprocessing {
|
||||
|
||||
Mp4DashMuxer(DownloadMission mission) {
|
||||
super(mission, 15360 * 1024/* 15 MiB */, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
Mp4DashWriter muxer = new Mp4DashWriter(sources);
|
||||
muxer.parseSources();
|
||||
muxer.selectTracks(0, 0);
|
||||
muxer.build(out);
|
||||
|
||||
return OK_RESULT;
|
||||
}
|
||||
|
||||
}
|
||||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import org.schabi.newpipe.streams.Mp4FromDashWriter;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
class Mp4FromDashMuxer extends Postprocessing {
|
||||
|
||||
Mp4FromDashMuxer() {
|
||||
super(true, true, ALGORITHM_MP4_FROM_DASH_MUXER);
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
Mp4FromDashWriter muxer = new Mp4FromDashWriter(sources);
|
||||
muxer.parseSources();
|
||||
muxer.selectTracks(0, 0);
|
||||
muxer.build(out);
|
||||
|
||||
return OK_RESULT;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.media.MediaExtractor;
|
||||
import android.media.MediaMuxer;
|
||||
import android.media.MediaMuxer.OutputFormat;
|
||||
import android.util.Log;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
|
||||
|
||||
class Mp4Muxer extends Postprocessing {
|
||||
private static final String TAG = "Mp4Muxer";
|
||||
private static final int NOTIFY_BYTES_INTERVAL = 128 * 1024;// 128 KiB
|
||||
|
||||
Mp4Muxer(DownloadMission mission) {
|
||||
super(mission, 0, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
File dlFile = mission.getDownloadedFile();
|
||||
File tmpFile = new File(mission.location, mission.name.concat(".tmp"));
|
||||
|
||||
if (tmpFile.exists())
|
||||
if (!tmpFile.delete()) return DownloadMission.ERROR_FILE_CREATION;
|
||||
|
||||
if (!tmpFile.createNewFile()) return DownloadMission.ERROR_FILE_CREATION;
|
||||
|
||||
FileInputStream source = null;
|
||||
MediaMuxer muxer = null;
|
||||
|
||||
//noinspection TryFinallyCanBeTryWithResources
|
||||
try {
|
||||
source = new FileInputStream(dlFile);
|
||||
MediaExtractor tracks[] = {
|
||||
getMediaExtractor(source, mission.offsets[0], mission.offsets[1] - mission.offsets[0]),
|
||||
getMediaExtractor(source, mission.offsets[1], mission.length - mission.offsets[1])
|
||||
};
|
||||
|
||||
muxer = new MediaMuxer(tmpFile.getAbsolutePath(), OutputFormat.MUXER_OUTPUT_MPEG_4);
|
||||
|
||||
int tracksIndex[] = {
|
||||
muxer.addTrack(tracks[0].getTrackFormat(0)),
|
||||
muxer.addTrack(tracks[1].getTrackFormat(0))
|
||||
};
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(512 * 1024);// 512 KiB
|
||||
BufferInfo info = new BufferInfo();
|
||||
|
||||
long written = 0;
|
||||
long nextReport = NOTIFY_BYTES_INTERVAL;
|
||||
|
||||
muxer.start();
|
||||
|
||||
while (true) {
|
||||
int done = 0;
|
||||
|
||||
for (int i = 0; i < tracks.length; i++) {
|
||||
if (tracksIndex[i] < 0) continue;
|
||||
|
||||
info.set(0,
|
||||
tracks[i].readSampleData(buffer, 0),
|
||||
tracks[i].getSampleTime(),
|
||||
tracks[i].getSampleFlags()
|
||||
);
|
||||
|
||||
if (info.size >= 0) {
|
||||
muxer.writeSampleData(tracksIndex[i], buffer, info);
|
||||
written += info.size;
|
||||
done++;
|
||||
}
|
||||
if (!tracks[i].advance()) {
|
||||
// EOF reached
|
||||
tracks[i].release();
|
||||
tracksIndex[i] = -1;
|
||||
}
|
||||
|
||||
if (written > nextReport) {
|
||||
nextReport = written + NOTIFY_BYTES_INTERVAL;
|
||||
super.progressReport(written);
|
||||
}
|
||||
}
|
||||
|
||||
if (done < 1) break;
|
||||
}
|
||||
|
||||
// this part should not fail
|
||||
if (!dlFile.delete()) return DownloadMission.ERROR_FILE_CREATION;
|
||||
if (!tmpFile.renameTo(dlFile)) return DownloadMission.ERROR_FILE_CREATION;
|
||||
|
||||
return OK_RESULT;
|
||||
} finally {
|
||||
try {
|
||||
if (muxer != null) {
|
||||
muxer.stop();
|
||||
muxer.release();
|
||||
}
|
||||
} catch (Exception err) {
|
||||
if (DEBUG)
|
||||
Log.e(TAG, "muxer stop/release failed", err);
|
||||
}
|
||||
|
||||
if (source != null) {
|
||||
try {
|
||||
source.close();
|
||||
} catch (IOException e) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
// if the operation fails, delete the temporal file
|
||||
if (tmpFile.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MediaExtractor getMediaExtractor(FileInputStream source, long offset, long length) throws IOException {
|
||||
MediaExtractor extractor = new MediaExtractor();
|
||||
extractor.setDataSource(source.getFD(), offset, length);
|
||||
extractor.selectTrack(0);
|
||||
|
||||
return extractor;
|
||||
}
|
||||
}
|
|
@ -1,164 +1,256 @@
|
|||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import android.os.Message;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.postprocessing.io.ChunkFileInputStream;
|
||||
import us.shandian.giga.postprocessing.io.CircularFile;
|
||||
import us.shandian.giga.service.DownloadManagerService;
|
||||
|
||||
public abstract class Postprocessing {
|
||||
|
||||
static final byte OK_RESULT = DownloadMission.ERROR_NOTHING;
|
||||
|
||||
public static final String ALGORITHM_TTML_CONVERTER = "ttml";
|
||||
public static final String ALGORITHM_MP4_DASH_MUXER = "mp4D";
|
||||
public static final String ALGORITHM_MP4_MUXER = "mp4";
|
||||
public static final String ALGORITHM_WEBM_MUXER = "webm";
|
||||
|
||||
public static Postprocessing getAlgorithm(String algorithmName, DownloadMission mission) {
|
||||
if (null == algorithmName) {
|
||||
throw new NullPointerException("algorithmName");
|
||||
} else switch (algorithmName) {
|
||||
case ALGORITHM_TTML_CONVERTER:
|
||||
return new TtmlConverter(mission);
|
||||
case ALGORITHM_MP4_DASH_MUXER:
|
||||
return new Mp4DashMuxer(mission);
|
||||
case ALGORITHM_MP4_MUXER:
|
||||
return new Mp4Muxer(mission);
|
||||
case ALGORITHM_WEBM_MUXER:
|
||||
return new WebMMuxer(mission);
|
||||
/*case "example-algorithm":
|
||||
return new ExampleAlgorithm(mission);*/
|
||||
default:
|
||||
throw new RuntimeException("Unimplemented post-processing algorithm: " + algorithmName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value that indicate if the given algorithm work on the same
|
||||
* file
|
||||
*/
|
||||
public boolean worksOnSameFile;
|
||||
|
||||
/**
|
||||
* Get the recommended space to reserve for the given algorithm. The amount
|
||||
* is in bytes
|
||||
*/
|
||||
public int recommendedReserve;
|
||||
|
||||
/**
|
||||
* the download to post-process
|
||||
*/
|
||||
protected DownloadMission mission;
|
||||
|
||||
Postprocessing(DownloadMission mission, int recommendedReserve, boolean worksOnSameFile) {
|
||||
this.mission = mission;
|
||||
this.recommendedReserve = recommendedReserve;
|
||||
this.worksOnSameFile = worksOnSameFile;
|
||||
}
|
||||
|
||||
public void run() throws IOException {
|
||||
File file = mission.getDownloadedFile();
|
||||
CircularFile out = null;
|
||||
int result;
|
||||
long finalLength = -1;
|
||||
|
||||
mission.done = 0;
|
||||
mission.length = file.length();
|
||||
|
||||
if (worksOnSameFile) {
|
||||
ChunkFileInputStream[] sources = new ChunkFileInputStream[mission.urls.length];
|
||||
try {
|
||||
int i = 0;
|
||||
for (; i < sources.length - 1; i++) {
|
||||
sources[i] = new ChunkFileInputStream(file, mission.offsets[i], mission.offsets[i + 1], "rw");
|
||||
}
|
||||
sources[i] = new ChunkFileInputStream(file, mission.offsets[i], mission.getDownloadedFile().length(), "rw");
|
||||
|
||||
int[] idx = {0};
|
||||
CircularFile.OffsetChecker checker = () -> {
|
||||
while (idx[0] < sources.length) {
|
||||
/*
|
||||
* WARNING: never use rewind() in any chunk after any writing (especially on first chunks)
|
||||
* or the CircularFile can lead to unexpected results
|
||||
*/
|
||||
if (sources[idx[0]].isDisposed() || sources[idx[0]].available() < 1) {
|
||||
idx[0]++;
|
||||
continue;// the selected source is not used anymore
|
||||
}
|
||||
|
||||
return sources[idx[0]].getFilePointer() - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
out = new CircularFile(file, 0, this::progressReport, checker);
|
||||
|
||||
result = process(out, sources);
|
||||
|
||||
if (result == OK_RESULT)
|
||||
finalLength = out.finalizeFile();
|
||||
} finally {
|
||||
for (SharpStream source : sources) {
|
||||
if (source != null && !source.isDisposed()) {
|
||||
source.dispose();
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
out.dispose();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = process(null);
|
||||
}
|
||||
|
||||
if (result == OK_RESULT) {
|
||||
if (finalLength < 0) finalLength = file.length();
|
||||
mission.done = finalLength;
|
||||
mission.length = finalLength;
|
||||
} else {
|
||||
mission.errCode = DownloadMission.ERROR_UNKNOWN_EXCEPTION;
|
||||
mission.errObject = new RuntimeException("post-processing algorithm returned " + result);
|
||||
}
|
||||
|
||||
if (result != OK_RESULT && worksOnSameFile) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method to execute the pos-processing algorithm
|
||||
*
|
||||
* @param out output stream
|
||||
* @param sources files to be processed
|
||||
* @return a error code, 0 means the operation was successful
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
abstract int process(SharpStream out, SharpStream... sources) throws IOException;
|
||||
|
||||
String getArgumentAt(int index, String defaultValue) {
|
||||
if (mission.postprocessingArgs == null || index >= mission.postprocessingArgs.length) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return mission.postprocessingArgs[index];
|
||||
}
|
||||
|
||||
void progressReport(long done) {
|
||||
mission.done = done;
|
||||
if (mission.length < mission.done) mission.length = mission.done;
|
||||
|
||||
Message m = new Message();
|
||||
m.what = DownloadManagerService.MESSAGE_PROGRESS;
|
||||
m.obj = mission;
|
||||
|
||||
mission.mHandler.sendMessage(m);
|
||||
}
|
||||
}
|
||||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import android.os.Message;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.io.ChunkFileInputStream;
|
||||
import us.shandian.giga.io.CircularFileWriter;
|
||||
import us.shandian.giga.io.CircularFileWriter.OffsetChecker;
|
||||
import us.shandian.giga.service.DownloadManagerService;
|
||||
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_HOLD;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_EXCEPTION;
|
||||
|
||||
public abstract class Postprocessing implements Serializable {
|
||||
|
||||
static transient final byte OK_RESULT = ERROR_NOTHING;
|
||||
|
||||
public transient static final String ALGORITHM_TTML_CONVERTER = "ttml";
|
||||
public transient static final String ALGORITHM_WEBM_MUXER = "webm";
|
||||
public transient static final String ALGORITHM_MP4_FROM_DASH_MUXER = "mp4D-mp4";
|
||||
public transient static final String ALGORITHM_M4A_NO_DASH = "mp4D-m4a";
|
||||
|
||||
public static Postprocessing getAlgorithm(@NonNull String algorithmName, String[] args) {
|
||||
Postprocessing instance;
|
||||
|
||||
switch (algorithmName) {
|
||||
case ALGORITHM_TTML_CONVERTER:
|
||||
instance = new TtmlConverter();
|
||||
break;
|
||||
case ALGORITHM_WEBM_MUXER:
|
||||
instance = new WebMMuxer();
|
||||
break;
|
||||
case ALGORITHM_MP4_FROM_DASH_MUXER:
|
||||
instance = new Mp4FromDashMuxer();
|
||||
break;
|
||||
case ALGORITHM_M4A_NO_DASH:
|
||||
instance = new M4aNoDash();
|
||||
break;
|
||||
/*case "example-algorithm":
|
||||
instance = new ExampleAlgorithm();*/
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unimplemented post-processing algorithm: " + algorithmName);
|
||||
}
|
||||
|
||||
instance.args = args;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value that indicate if the given algorithm work on the same
|
||||
* file
|
||||
*/
|
||||
public final boolean worksOnSameFile;
|
||||
|
||||
/**
|
||||
* Indicates whether the selected algorithm needs space reserved at the beginning of the file
|
||||
*/
|
||||
public final boolean reserveSpace;
|
||||
|
||||
/**
|
||||
* Gets the given algorithm short name
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
|
||||
private String[] args;
|
||||
|
||||
protected transient DownloadMission mission;
|
||||
|
||||
private File tempFile;
|
||||
|
||||
Postprocessing(boolean reserveSpace, boolean worksOnSameFile, String algorithmName) {
|
||||
this.reserveSpace = reserveSpace;
|
||||
this.worksOnSameFile = worksOnSameFile;
|
||||
this.name = algorithmName;// for debugging only
|
||||
}
|
||||
|
||||
public void setTemporalDir(@NonNull File directory) {
|
||||
long rnd = (int) (Math.random() * 100000f);
|
||||
tempFile = new File(directory, rnd + "_" + System.nanoTime() + ".tmp");
|
||||
}
|
||||
|
||||
public void cleanupTemporalDir() {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
tempFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void run(DownloadMission target) throws IOException {
|
||||
this.mission = target;
|
||||
|
||||
CircularFileWriter out = null;
|
||||
int result;
|
||||
long finalLength = -1;
|
||||
|
||||
mission.done = 0;
|
||||
mission.length = mission.storage.length();
|
||||
|
||||
if (worksOnSameFile) {
|
||||
ChunkFileInputStream[] sources = new ChunkFileInputStream[mission.urls.length];
|
||||
try {
|
||||
int i = 0;
|
||||
for (; i < sources.length - 1; i++) {
|
||||
sources[i] = new ChunkFileInputStream(mission.storage.getStream(), mission.offsets[i], mission.offsets[i + 1]);
|
||||
}
|
||||
sources[i] = new ChunkFileInputStream(mission.storage.getStream(), mission.offsets[i]);
|
||||
|
||||
if (test(sources)) {
|
||||
for (SharpStream source : sources) source.rewind();
|
||||
|
||||
OffsetChecker checker = () -> {
|
||||
for (ChunkFileInputStream source : sources) {
|
||||
/*
|
||||
* WARNING: never use rewind() in any chunk after any writing (especially on first chunks)
|
||||
* or the CircularFileWriter can lead to unexpected results
|
||||
*/
|
||||
if (source.isClosed() || source.available() < 1) {
|
||||
continue;// the selected source is not used anymore
|
||||
}
|
||||
|
||||
return source.getFilePointer() - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
out = new CircularFileWriter(mission.storage.getStream(), tempFile, checker);
|
||||
out.onProgress = this::progressReport;
|
||||
|
||||
out.onWriteError = (err) -> {
|
||||
mission.psState = 3;
|
||||
mission.notifyError(ERROR_POSTPROCESSING_HOLD, err);
|
||||
|
||||
try {
|
||||
synchronized (this) {
|
||||
while (mission.psState == 3)
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// nothing to do
|
||||
Log.e(this.getClass().getSimpleName(), "got InterruptedException");
|
||||
}
|
||||
|
||||
return mission.errCode == ERROR_NOTHING;
|
||||
};
|
||||
|
||||
result = process(out, sources);
|
||||
|
||||
if (result == OK_RESULT)
|
||||
finalLength = out.finalizeFile();
|
||||
} else {
|
||||
result = OK_RESULT;
|
||||
}
|
||||
} finally {
|
||||
for (SharpStream source : sources) {
|
||||
if (source != null && !source.isClosed()) {
|
||||
source.close();
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (tempFile != null) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
tempFile.delete();
|
||||
tempFile = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = test() ? process(null) : OK_RESULT;
|
||||
}
|
||||
|
||||
if (result == OK_RESULT) {
|
||||
if (finalLength != -1) {
|
||||
mission.done = finalLength;
|
||||
mission.length = finalLength;
|
||||
}
|
||||
} else {
|
||||
mission.errCode = ERROR_UNKNOWN_EXCEPTION;
|
||||
mission.errObject = new RuntimeException("post-processing algorithm returned " + result);
|
||||
}
|
||||
|
||||
if (result != OK_RESULT && worksOnSameFile) mission.storage.delete();
|
||||
|
||||
this.mission = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the post-processing algorithm can be skipped
|
||||
*
|
||||
* @param sources files to be processed
|
||||
* @return {@code true} if the post-processing is required, otherwise, {@code false}
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
boolean test(SharpStream... sources) throws IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method to execute the post-processing algorithm
|
||||
*
|
||||
* @param out output stream
|
||||
* @param sources files to be processed
|
||||
* @return a error code, 0 means the operation was successful
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
abstract int process(SharpStream out, SharpStream... sources) throws IOException;
|
||||
|
||||
String getArgumentAt(int index, String defaultValue) {
|
||||
if (args == null || index >= args.length) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return args[index];
|
||||
}
|
||||
|
||||
private void progressReport(long done) {
|
||||
mission.done = done;
|
||||
if (mission.length < mission.done) mission.length = mission.done;
|
||||
|
||||
Message m = new Message();
|
||||
m.what = DownloadManagerService.MESSAGE_PROGRESS;
|
||||
m.obj = mission;
|
||||
|
||||
mission.mHandler.sendMessage(m);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append("name=").append(name).append('[');
|
||||
|
||||
if (args != null) {
|
||||
for (String arg : args) {
|
||||
str.append(", ");
|
||||
str.append(arg);
|
||||
}
|
||||
str.delete(0, 1);
|
||||
}
|
||||
|
||||
return str.append(']').toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,75 +1,72 @@
|
|||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
import org.schabi.newpipe.streams.SubtitleConverter;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.postprocessing.io.SharpInputStream;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
class TtmlConverter extends Postprocessing {
|
||||
private static final String TAG = "TtmlConverter";
|
||||
|
||||
TtmlConverter(DownloadMission mission) {
|
||||
// due how XmlPullParser works, the xml is fully loaded on the ram
|
||||
super(mission, 0, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
// check if the subtitle is already in srt and copy, this should never happen
|
||||
String format = getArgumentAt(0, null);
|
||||
|
||||
if (format == null || format.equals("ttml")) {
|
||||
SubtitleConverter ttmlDumper = new SubtitleConverter();
|
||||
|
||||
try {
|
||||
ttmlDumper.dumpTTML(
|
||||
sources[0],
|
||||
out,
|
||||
getArgumentAt(1, "true").equals("true"),
|
||||
getArgumentAt(2, "true").equals("true")
|
||||
);
|
||||
} catch (Exception err) {
|
||||
Log.e(TAG, "subtitle parse failed", err);
|
||||
|
||||
if (err instanceof IOException) {
|
||||
return 1;
|
||||
} else if (err instanceof ParseException) {
|
||||
return 2;
|
||||
} else if (err instanceof SAXException) {
|
||||
return 3;
|
||||
} else if (err instanceof ParserConfigurationException) {
|
||||
return 4;
|
||||
} else if (err instanceof XPathExpressionException) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
return OK_RESULT;
|
||||
} else if (format.equals("srt")) {
|
||||
byte[] buffer = new byte[8 * 1024];
|
||||
int read;
|
||||
while ((read = sources[0].read(buffer)) > 0) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
return OK_RESULT;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Can't convert this subtitle, unimplemented format: " + format);
|
||||
}
|
||||
|
||||
}
|
||||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.schabi.newpipe.streams.SubtitleConverter;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
class TtmlConverter extends Postprocessing {
|
||||
private static final String TAG = "TtmlConverter";
|
||||
|
||||
TtmlConverter() {
|
||||
// due how XmlPullParser works, the xml is fully loaded on the ram
|
||||
super(false, true, ALGORITHM_TTML_CONVERTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
// check if the subtitle is already in srt and copy, this should never happen
|
||||
String format = getArgumentAt(0, null);
|
||||
|
||||
if (format == null || format.equals("ttml")) {
|
||||
SubtitleConverter ttmlDumper = new SubtitleConverter();
|
||||
|
||||
try {
|
||||
ttmlDumper.dumpTTML(
|
||||
sources[0],
|
||||
out,
|
||||
getArgumentAt(1, "true").equals("true"),
|
||||
getArgumentAt(2, "true").equals("true")
|
||||
);
|
||||
} catch (Exception err) {
|
||||
Log.e(TAG, "subtitle parse failed", err);
|
||||
|
||||
if (err instanceof IOException) {
|
||||
return 1;
|
||||
} else if (err instanceof ParseException) {
|
||||
return 2;
|
||||
} else if (err instanceof SAXException) {
|
||||
return 3;
|
||||
} else if (err instanceof ParserConfigurationException) {
|
||||
return 4;
|
||||
} else if (err instanceof XPathExpressionException) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
return OK_RESULT;
|
||||
} else if (format.equals("srt")) {
|
||||
byte[] buffer = new byte[8 * 1024];
|
||||
int read;
|
||||
while ((read = sources[0].read(buffer)) > 0) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
return OK_RESULT;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Can't convert this subtitle, unimplemented format: " + format);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,42 +1,44 @@
|
|||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import org.schabi.newpipe.streams.WebMReader.TrackKind;
|
||||
import org.schabi.newpipe.streams.WebMReader.WebMTrack;
|
||||
import org.schabi.newpipe.streams.WebMWriter;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
class WebMMuxer extends Postprocessing {
|
||||
|
||||
WebMMuxer(DownloadMission mission) {
|
||||
super(mission, 2048 * 1024/* 2 MiB */, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
WebMWriter muxer = new WebMWriter(sources);
|
||||
muxer.parseSources();
|
||||
|
||||
// youtube uses a webm with a fake video track that acts as a "cover image"
|
||||
WebMTrack[] tracks = muxer.getTracksFromSource(1);
|
||||
int audioTrackIndex = 0;
|
||||
for (int i = 0; i < tracks.length; i++) {
|
||||
if (tracks[i].kind == TrackKind.Audio) {
|
||||
audioTrackIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
muxer.selectTracks(0, audioTrackIndex);
|
||||
muxer.build(out);
|
||||
|
||||
return OK_RESULT;
|
||||
}
|
||||
|
||||
}
|
||||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import org.schabi.newpipe.streams.WebMReader.TrackKind;
|
||||
import org.schabi.newpipe.streams.WebMReader.WebMTrack;
|
||||
import org.schabi.newpipe.streams.WebMWriter;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kapodamy
|
||||
*/
|
||||
class WebMMuxer extends Postprocessing {
|
||||
|
||||
WebMMuxer() {
|
||||
super(true, true, ALGORITHM_WEBM_MUXER);
|
||||
}
|
||||
|
||||
@Override
|
||||
int process(SharpStream out, SharpStream... sources) throws IOException {
|
||||
WebMWriter muxer = new WebMWriter(sources);
|
||||
muxer.parseSources();
|
||||
|
||||
// youtube uses a webm with a fake video track that acts as a "cover image"
|
||||
int[] indexes = new int[sources.length];
|
||||
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
WebMTrack[] tracks = muxer.getTracksFromSource(i);
|
||||
for (int j = 0; j < tracks.length; j++) {
|
||||
if (tracks[j].kind == TrackKind.Audio) {
|
||||
indexes[i] = j;
|
||||
i = sources.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
muxer.selectTracks(indexes);
|
||||
muxer.build(out);
|
||||
|
||||
return OK_RESULT;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,375 +0,0 @@
|
|||
package us.shandian.giga.postprocessing.io;
|
||||
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CircularFile extends SharpStream {
|
||||
|
||||
private final static int AUX_BUFFER_SIZE = 1024 * 1024;// 1 MiB
|
||||
private final static int AUX_BUFFER_SIZE2 = 512 * 1024;// 512 KiB
|
||||
private final static int NOTIFY_BYTES_INTERVAL = 64 * 1024;// 64 KiB
|
||||
private final static int QUEUE_BUFFER_SIZE = 8 * 1024;// 8 KiB
|
||||
private final static boolean IMMEDIATE_AUX_BUFFER_FLUSH = false;
|
||||
|
||||
private RandomAccessFile out;
|
||||
private long position;
|
||||
private long maxLengthKnown = -1;
|
||||
|
||||
private ArrayList<ManagedBuffer> auxiliaryBuffers;
|
||||
private OffsetChecker callback;
|
||||
private ManagedBuffer queue;
|
||||
private long startOffset;
|
||||
private ProgressReport onProgress;
|
||||
private long reportPosition;
|
||||
|
||||
public CircularFile(File file, long offset, ProgressReport progressReport, OffsetChecker checker) throws IOException {
|
||||
if (checker == null) {
|
||||
throw new NullPointerException("checker is null");
|
||||
}
|
||||
|
||||
try {
|
||||
queue = new ManagedBuffer(QUEUE_BUFFER_SIZE);
|
||||
out = new RandomAccessFile(file, "rw");
|
||||
out.seek(offset);
|
||||
position = offset;
|
||||
} catch (IOException err) {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// nothing to do
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
auxiliaryBuffers = new ArrayList<>(15);
|
||||
callback = checker;
|
||||
startOffset = offset;
|
||||
reportPosition = offset;
|
||||
onProgress = progressReport;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the file without flushing any buffer
|
||||
*/
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
auxiliaryBuffers = null;
|
||||
if (out != null) {
|
||||
out.close();
|
||||
out = null;
|
||||
}
|
||||
} catch (IOException err) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any buffer and close the output file. Use this method if the
|
||||
* operation is successful
|
||||
*
|
||||
* @return the final length of the file
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public long finalizeFile() throws IOException {
|
||||
flushEverything();
|
||||
|
||||
if (maxLengthKnown > -1) {
|
||||
position = maxLengthKnown;
|
||||
}
|
||||
if (position < out.length()) {
|
||||
out.setLength(position);
|
||||
}
|
||||
|
||||
dispose();
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte b) throws IOException {
|
||||
write(new byte[]{b}, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte b[]) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
long end = callback.check();
|
||||
long available;
|
||||
|
||||
if (end == -1) {
|
||||
available = Long.MAX_VALUE;
|
||||
} else {
|
||||
if (end < startOffset) {
|
||||
throw new IOException("The reported offset is invalid. reported offset is " + String.valueOf(end));
|
||||
}
|
||||
available = end - position;
|
||||
}
|
||||
|
||||
// Check if possible flush one or more auxiliary buffer
|
||||
if (auxiliaryBuffers.size() > 0) {
|
||||
ManagedBuffer aux = auxiliaryBuffers.get(0);
|
||||
|
||||
// check if there is enough space to flush it completely
|
||||
while (available >= (aux.size + queue.size)) {
|
||||
available -= aux.size;
|
||||
writeQueue(aux.buffer, 0, aux.size);
|
||||
aux.dereference();
|
||||
auxiliaryBuffers.remove(0);
|
||||
|
||||
if (auxiliaryBuffers.size() < 1) {
|
||||
aux = null;
|
||||
break;
|
||||
}
|
||||
aux = auxiliaryBuffers.get(0);
|
||||
}
|
||||
|
||||
if (IMMEDIATE_AUX_BUFFER_FLUSH) {
|
||||
// try partial flush to avoid allocate another auxiliary buffer
|
||||
if (aux != null && aux.available() < len && available > queue.size) {
|
||||
int size = Math.min(aux.size, (int) available - queue.size);
|
||||
|
||||
writeQueue(aux.buffer, 0, size);
|
||||
aux.dereference(size);
|
||||
|
||||
available -= size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auxiliaryBuffers.size() < 1 && available > (len + queue.size)) {
|
||||
writeQueue(b, off, len);
|
||||
} else {
|
||||
int i = auxiliaryBuffers.size() - 1;
|
||||
while (len > 0) {
|
||||
if (i < 0) {
|
||||
// allocate a new auxiliary buffer
|
||||
auxiliaryBuffers.add(new ManagedBuffer(AUX_BUFFER_SIZE));
|
||||
i++;
|
||||
}
|
||||
|
||||
ManagedBuffer aux = auxiliaryBuffers.get(i);
|
||||
available = aux.available();
|
||||
|
||||
if (available < 1) {
|
||||
// secondary auxiliary buffer
|
||||
available = len;
|
||||
aux = new ManagedBuffer(Math.max(len, AUX_BUFFER_SIZE2));
|
||||
auxiliaryBuffers.add(aux);
|
||||
i++;
|
||||
} else {
|
||||
available = Math.min(len, available);
|
||||
}
|
||||
|
||||
aux.write(b, off, (int) available);
|
||||
|
||||
len -= available;
|
||||
if (len > 0) off += available;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOutside(byte buffer[], int offset, int length) throws IOException {
|
||||
out.write(buffer, offset, length);
|
||||
position += length;
|
||||
|
||||
if (onProgress != null && position > reportPosition) {
|
||||
reportPosition = position + NOTIFY_BYTES_INTERVAL;
|
||||
onProgress.report(position);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeQueue(byte[] buffer, int offset, int length) throws IOException {
|
||||
while (length > 0) {
|
||||
if (queue.available() < length) {
|
||||
flushQueue();
|
||||
|
||||
if (length >= queue.buffer.length) {
|
||||
writeOutside(buffer, offset, length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int size = Math.min(queue.available(), length);
|
||||
queue.write(buffer, offset, size);
|
||||
|
||||
offset += size;
|
||||
length -= size;
|
||||
}
|
||||
|
||||
if (queue.size >= queue.buffer.length) {
|
||||
flushQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private void flushQueue() throws IOException {
|
||||
writeOutside(queue.buffer, 0, queue.size);
|
||||
queue.size = 0;
|
||||
}
|
||||
|
||||
private void flushEverything() throws IOException {
|
||||
flushQueue();
|
||||
|
||||
if (auxiliaryBuffers.size() > 0) {
|
||||
for (ManagedBuffer aux : auxiliaryBuffers) {
|
||||
writeOutside(aux.buffer, 0, aux.size);
|
||||
aux.dereference();
|
||||
}
|
||||
auxiliaryBuffers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any buffer directly to the file. Warning: use this method ONLY if
|
||||
* all read dependencies are disposed
|
||||
*
|
||||
* @throws IOException if the dependencies are not disposed
|
||||
*/
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
if (callback.check() != -1) {
|
||||
throw new IOException("All read dependencies of this file must be disposed first");
|
||||
}
|
||||
flushEverything();
|
||||
|
||||
// Save the current file length in case the method {@code rewind()} is called
|
||||
if (position > maxLengthKnown) {
|
||||
maxLengthKnown = position;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() throws IOException {
|
||||
flush();
|
||||
out.seek(startOffset);
|
||||
|
||||
if (onProgress != null) {
|
||||
onProgress.report(-position);
|
||||
}
|
||||
|
||||
position = startOffset;
|
||||
reportPosition = startOffset;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long amount) throws IOException {
|
||||
flush();
|
||||
position += amount;
|
||||
|
||||
out.seek(position);
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisposed() {
|
||||
return out == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite() {
|
||||
return true;
|
||||
}
|
||||
|
||||
//<editor-fold defaultState="collapsed" desc="stub read methods">
|
||||
@Override
|
||||
public boolean canRead() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int count) {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
throw new UnsupportedOperationException("write-only");
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
public interface OffsetChecker {
|
||||
|
||||
/**
|
||||
* Checks the amount of available space ahead
|
||||
*
|
||||
* @return absolute offset in the file where no more data SHOULD NOT be
|
||||
* written. If the value is -1 the whole file will be used
|
||||
*/
|
||||
long check();
|
||||
}
|
||||
|
||||
public interface ProgressReport {
|
||||
|
||||
void report(long progress);
|
||||
}
|
||||
|
||||
class ManagedBuffer {
|
||||
|
||||
byte[] buffer;
|
||||
int size;
|
||||
|
||||
ManagedBuffer(int length) {
|
||||
buffer = new byte[length];
|
||||
}
|
||||
|
||||
void dereference() {
|
||||
buffer = null;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
void dereference(int amount) {
|
||||
if (amount > size) {
|
||||
throw new IndexOutOfBoundsException("Invalid dereference amount (" + amount + ">=" + size + ")");
|
||||
}
|
||||
size -= amount;
|
||||
System.arraycopy(buffer, amount, buffer, 0, size);
|
||||
}
|
||||
|
||||
protected int available() {
|
||||
return buffer.length - size;
|
||||
}
|
||||
|
||||
private void write(byte[] b, int off, int len) {
|
||||
System.arraycopy(b, off, buffer, size, len);
|
||||
size += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "holding: " + String.valueOf(size) + " length: " + String.valueOf(buffer.length) + " available: " + String.valueOf(available());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -13,14 +13,15 @@ import org.schabi.newpipe.R;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.get.FinishedMission;
|
||||
import us.shandian.giga.get.Mission;
|
||||
import us.shandian.giga.get.sqlite.DownloadDataSource;
|
||||
import us.shandian.giga.get.sqlite.FinishedMissionStore;
|
||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
import us.shandian.giga.util.Utility;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
@ -28,13 +29,16 @@ import static org.schabi.newpipe.BuildConfig.DEBUG;
|
|||
public class DownloadManager {
|
||||
private static final String TAG = DownloadManager.class.getSimpleName();
|
||||
|
||||
enum NetworkState {Unavailable, WifiOperating, MobileOperating, OtherOperating}
|
||||
enum NetworkState {Unavailable, Operating, MeteredOperating}
|
||||
|
||||
public final static int SPECIAL_NOTHING = 0;
|
||||
public final static int SPECIAL_PENDING = 1;
|
||||
public final static int SPECIAL_FINISHED = 2;
|
||||
|
||||
private final DownloadDataSource mDownloadDataSource;
|
||||
static final String TAG_AUDIO = "audio";
|
||||
static final String TAG_VIDEO = "video";
|
||||
|
||||
private final FinishedMissionStore mFinishedMissionStore;
|
||||
|
||||
private final ArrayList<DownloadMission> mMissionsPending = new ArrayList<>();
|
||||
private final ArrayList<FinishedMission> mMissionsFinished;
|
||||
|
@ -45,7 +49,12 @@ public class DownloadManager {
|
|||
private NetworkState mLastNetworkStatus = NetworkState.Unavailable;
|
||||
|
||||
int mPrefMaxRetry;
|
||||
boolean mPrefCrossNetwork;
|
||||
boolean mPrefMeteredDownloads;
|
||||
boolean mPrefQueueLimit;
|
||||
private boolean mSelfMissionsControl;
|
||||
|
||||
StoredDirectoryHelper mMainStorageAudio;
|
||||
StoredDirectoryHelper mMainStorageVideo;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
|
@ -53,13 +62,15 @@ public class DownloadManager {
|
|||
* @param context Context for the data source for finished downloads
|
||||
* @param handler Thread required for Messaging
|
||||
*/
|
||||
DownloadManager(@NonNull Context context, Handler handler) {
|
||||
DownloadManager(@NonNull Context context, Handler handler, StoredDirectoryHelper storageVideo, StoredDirectoryHelper storageAudio) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "new DownloadManager instance. 0x" + Integer.toHexString(this.hashCode()));
|
||||
}
|
||||
|
||||
mDownloadDataSource = new DownloadDataSource(context);
|
||||
mFinishedMissionStore = new FinishedMissionStore(context);
|
||||
mHandler = handler;
|
||||
mMainStorageAudio = storageAudio;
|
||||
mMainStorageVideo = storageVideo;
|
||||
mMissionsFinished = loadFinishedMissions();
|
||||
mPendingMissionsDir = getPendingDir(context);
|
||||
|
||||
|
@ -67,7 +78,7 @@ public class DownloadManager {
|
|||
throw new RuntimeException("failed to create pending_downloads in data directory");
|
||||
}
|
||||
|
||||
loadPendingMissions();
|
||||
loadPendingMissions(context);
|
||||
}
|
||||
|
||||
private static File getPendingDir(@NonNull Context context) {
|
||||
|
@ -88,29 +99,24 @@ public class DownloadManager {
|
|||
* Loads finished missions from the data source
|
||||
*/
|
||||
private ArrayList<FinishedMission> loadFinishedMissions() {
|
||||
ArrayList<FinishedMission> finishedMissions = mDownloadDataSource.loadFinishedMissions();
|
||||
ArrayList<FinishedMission> finishedMissions = mFinishedMissionStore.loadFinishedMissions();
|
||||
|
||||
// missions always is stored by creation order, simply reverse the list
|
||||
ArrayList<FinishedMission> result = new ArrayList<>(finishedMissions.size());
|
||||
// check if the files exists, otherwise, forget the download
|
||||
for (int i = finishedMissions.size() - 1; i >= 0; i--) {
|
||||
FinishedMission mission = finishedMissions.get(i);
|
||||
File file = mission.getDownloadedFile();
|
||||
|
||||
if (!file.isFile()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "downloaded file removed: " + file.getAbsolutePath());
|
||||
}
|
||||
mDownloadDataSource.deleteMission(mission);
|
||||
continue;
|
||||
if (!mission.storage.existsAsFile()) {
|
||||
if (DEBUG) Log.d(TAG, "downloaded file removed: " + mission.storage.getName());
|
||||
|
||||
mFinishedMissionStore.deleteMission(mission);
|
||||
finishedMissions.remove(i);
|
||||
}
|
||||
|
||||
result.add(mission);
|
||||
}
|
||||
|
||||
return result;
|
||||
return finishedMissions;
|
||||
}
|
||||
|
||||
private void loadPendingMissions() {
|
||||
private void loadPendingMissions(Context ctx) {
|
||||
File[] subs = mPendingMissionsDir.listFiles();
|
||||
|
||||
if (subs == null) {
|
||||
|
@ -125,109 +131,76 @@ public class DownloadManager {
|
|||
}
|
||||
|
||||
for (File sub : subs) {
|
||||
if (sub.isFile()) {
|
||||
DownloadMission mis = Utility.readFromFile(sub);
|
||||
if (!sub.isFile()) continue;
|
||||
|
||||
if (mis == null) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
sub.delete();
|
||||
} else {
|
||||
if (mis.isFinished()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
sub.delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
File dl = mis.getDownloadedFile();
|
||||
boolean exists = dl.exists();
|
||||
|
||||
if (mis.isPsRunning()) {
|
||||
if (mis.postprocessingThis) {
|
||||
// Incomplete post-processing results in a corrupted download file
|
||||
// because the selected algorithm works on the same file to save space.
|
||||
if (exists && dl.isFile() && !dl.delete())
|
||||
Log.w(TAG, "Unable to delete incomplete download file: " + sub.getPath());
|
||||
|
||||
exists = true;
|
||||
}
|
||||
|
||||
mis.postprocessingState = 0;
|
||||
mis.errCode = DownloadMission.ERROR_POSTPROCESSING;
|
||||
mis.errObject = new RuntimeException("stopped unexpectedly");
|
||||
} else if (exists && !dl.isFile()) {
|
||||
// probably a folder, this should never happens
|
||||
if (!sub.delete()) {
|
||||
Log.w(TAG, "Unable to delete serialized file: " + sub.getPath());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
// downloaded file deleted, reset mission state
|
||||
DownloadMission m = new DownloadMission(mis.urls, mis.name, mis.location, mis.kind, mis.postprocessingName, mis.postprocessingArgs);
|
||||
m.timestamp = mis.timestamp;
|
||||
m.threadCount = mis.threadCount;
|
||||
m.source = mis.source;
|
||||
m.maxRetry = mis.maxRetry;
|
||||
m.nearLength = mis.nearLength;
|
||||
mis = m;
|
||||
}
|
||||
|
||||
mis.running = false;
|
||||
mis.recovered = exists;
|
||||
mis.metadata = sub;
|
||||
mis.mHandler = mHandler;
|
||||
|
||||
mMissionsPending.add(mis);
|
||||
}
|
||||
DownloadMission mis = Utility.readFromFile(sub);
|
||||
if (mis == null || mis.isFinished()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
sub.delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean exists;
|
||||
try {
|
||||
mis.storage = StoredFileHelper.deserialize(mis.storage, ctx);
|
||||
exists = !mis.storage.isInvalid() && mis.storage.existsAsFile();
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to load the file source of " + mis.storage.toString(), ex);
|
||||
mis.storage.invalidate();
|
||||
exists = false;
|
||||
}
|
||||
|
||||
if (mis.isPsRunning()) {
|
||||
if (mis.psAlgorithm.worksOnSameFile) {
|
||||
// Incomplete post-processing results in a corrupted download file
|
||||
// because the selected algorithm works on the same file to save space.
|
||||
// the file will be deleted if the storage API
|
||||
// is Java IO (avoid showing the "Save as..." dialog)
|
||||
if (exists && mis.storage.isDirect() && !mis.storage.delete())
|
||||
Log.w(TAG, "Unable to delete incomplete download file: " + sub.getPath());
|
||||
|
||||
exists = true;
|
||||
}
|
||||
|
||||
mis.psState = 0;
|
||||
mis.errCode = DownloadMission.ERROR_POSTPROCESSING_STOPPED;
|
||||
} else if (!exists) {
|
||||
tryRecover(mis);
|
||||
|
||||
// the progress is lost, reset mission state
|
||||
if (mis.isInitialized())
|
||||
mis.resetState(true, true, DownloadMission.ERROR_PROGRESS_LOST);
|
||||
}
|
||||
|
||||
if (mis.psAlgorithm != null) {
|
||||
mis.psAlgorithm.cleanupTemporalDir();
|
||||
mis.psAlgorithm.setTemporalDir(pickAvailableTemporalDir(ctx));
|
||||
}
|
||||
|
||||
mis.recovered = exists;
|
||||
mis.metadata = sub;
|
||||
mis.maxRetry = mPrefMaxRetry;
|
||||
mis.mHandler = mHandler;
|
||||
|
||||
mMissionsPending.add(mis);
|
||||
}
|
||||
|
||||
if (mMissionsPending.size() > 1) {
|
||||
if (mMissionsPending.size() > 1)
|
||||
Collections.sort(mMissionsPending, (mission1, mission2) -> Long.compare(mission1.timestamp, mission2.timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new download mission
|
||||
*
|
||||
* @param urls the list of urls to download
|
||||
* @param location the location
|
||||
* @param name the name of the file to create
|
||||
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
|
||||
* @param threads the number of threads maximal used to download chunks of the file.
|
||||
* @param psName the name of the required post-processing algorithm, or {@code null} to ignore.
|
||||
* @param source source url of the resource
|
||||
* @param psArgs the arguments for the post-processing algorithm.
|
||||
* @param mission the new download mission to add and run (if possible)
|
||||
*/
|
||||
void startMission(String[] urls, String location, String name, char kind, int threads,
|
||||
String source, String psName, String[] psArgs, long nearLength) {
|
||||
void startMission(DownloadMission mission) {
|
||||
synchronized (this) {
|
||||
// check for existing pending download
|
||||
DownloadMission pendingMission = getPendingMission(location, name);
|
||||
if (pendingMission != null) {
|
||||
// generate unique filename (?)
|
||||
try {
|
||||
name = generateUniqueName(location, name);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to generate unique name", e);
|
||||
name = System.currentTimeMillis() + name;
|
||||
Log.i(TAG, "Using " + name);
|
||||
}
|
||||
} else {
|
||||
// check for existing finished download
|
||||
int index = getFinishedMissionIndex(location, name);
|
||||
if (index >= 0) mDownloadDataSource.deleteMission(mMissionsFinished.remove(index));
|
||||
}
|
||||
|
||||
DownloadMission mission = new DownloadMission(urls, name, location, kind, psName, psArgs);
|
||||
mission.timestamp = System.currentTimeMillis();
|
||||
mission.threadCount = threads;
|
||||
mission.source = source;
|
||||
mission.mHandler = mHandler;
|
||||
mission.maxRetry = mPrefMaxRetry;
|
||||
mission.nearLength = nearLength;
|
||||
|
||||
// create metadata file
|
||||
while (true) {
|
||||
mission.metadata = new File(mPendingMissionsDir, String.valueOf(mission.timestamp));
|
||||
if (!mission.metadata.isFile() && !mission.metadata.exists()) {
|
||||
|
@ -242,14 +215,25 @@ public class DownloadManager {
|
|||
mission.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
mSelfMissionsControl = true;
|
||||
mMissionsPending.add(mission);
|
||||
|
||||
// Before starting, save the state in case the internet connection is not available
|
||||
// Before continue, save the metadata in case the internet connection is not available
|
||||
Utility.writeToFile(mission.metadata, mission);
|
||||
|
||||
if (canDownloadInCurrentNetwork() && (getRunningMissionsCount() < 1)) {
|
||||
if (mission.storage == null) {
|
||||
// noting to do here
|
||||
mission.errCode = DownloadMission.ERROR_FILE_CREATION;
|
||||
if (mission.errObject != null)
|
||||
mission.errObject = new IOException("DownloadMission.storage == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean start = !mPrefQueueLimit || getRunningMissionsCount() < 1;
|
||||
|
||||
if (canDownloadInCurrentNetwork() && start) {
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
mission.start();
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_RUNNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,13 +241,14 @@ public class DownloadManager {
|
|||
|
||||
public void resumeMission(DownloadMission mission) {
|
||||
if (!mission.running) {
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
mission.start();
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
public void pauseMission(DownloadMission mission) {
|
||||
if (mission.running) {
|
||||
mission.setEnqueued(false);
|
||||
mission.pause();
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
}
|
||||
|
@ -275,7 +260,7 @@ public class DownloadManager {
|
|||
mMissionsPending.remove(mission);
|
||||
} else if (mission instanceof FinishedMission) {
|
||||
mMissionsFinished.remove(mission);
|
||||
mDownloadDataSource.deleteMission(mission);
|
||||
mFinishedMissionStore.deleteMission(mission);
|
||||
}
|
||||
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_DELETED);
|
||||
|
@ -283,18 +268,54 @@ public class DownloadManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void forgetMission(StoredFileHelper storage) {
|
||||
synchronized (this) {
|
||||
Mission mission = getAnyMission(storage);
|
||||
if (mission == null) return;
|
||||
|
||||
if (mission instanceof DownloadMission) {
|
||||
mMissionsPending.remove(mission);
|
||||
} else if (mission instanceof FinishedMission) {
|
||||
mMissionsFinished.remove(mission);
|
||||
mFinishedMissionStore.deleteMission(mission);
|
||||
}
|
||||
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_DELETED);
|
||||
mission.storage = null;
|
||||
mission.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void tryRecover(DownloadMission mission) {
|
||||
StoredDirectoryHelper mainStorage = getMainStorage(mission.storage.getTag());
|
||||
|
||||
if (!mission.storage.isInvalid() && mission.storage.create()) return;
|
||||
|
||||
// using javaIO cannot recreate the file
|
||||
// using SAF in older devices (no tree available)
|
||||
//
|
||||
// force the user to pick again the save path
|
||||
mission.storage.invalidate();
|
||||
|
||||
if (mainStorage == null) return;
|
||||
|
||||
// if the user has changed the save path before this download, the original save path will be lost
|
||||
StoredFileHelper newStorage = mainStorage.createFile(mission.storage.getName(), mission.storage.getType());
|
||||
|
||||
if (newStorage != null) mission.storage = newStorage;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a pending mission by its location and name
|
||||
* Get a pending mission by its path
|
||||
*
|
||||
* @param location the location
|
||||
* @param name the name
|
||||
* @param storage where the file possible is stored
|
||||
* @return the mission or null if no such mission exists
|
||||
*/
|
||||
@Nullable
|
||||
private DownloadMission getPendingMission(String location, String name) {
|
||||
private DownloadMission getPendingMission(StoredFileHelper storage) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (location.equalsIgnoreCase(mission.location) && name.equalsIgnoreCase(mission.name)) {
|
||||
if (mission.storage.equals(storage)) {
|
||||
return mission;
|
||||
}
|
||||
}
|
||||
|
@ -302,16 +323,14 @@ public class DownloadManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a finished mission by its location and name
|
||||
* Get a finished mission by its path
|
||||
*
|
||||
* @param location the location
|
||||
* @param name the name
|
||||
* @param storage where the file possible is stored
|
||||
* @return the mission index or -1 if no such mission exists
|
||||
*/
|
||||
private int getFinishedMissionIndex(String location, String name) {
|
||||
private int getFinishedMissionIndex(StoredFileHelper storage) {
|
||||
for (int i = 0; i < mMissionsFinished.size(); i++) {
|
||||
FinishedMission mission = mMissionsFinished.get(i);
|
||||
if (location.equalsIgnoreCase(mission.location) && name.equalsIgnoreCase(mission.name)) {
|
||||
if (mMissionsFinished.get(i).storage.equals(storage)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -319,12 +338,12 @@ public class DownloadManager {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public Mission getAnyMission(String location, String name) {
|
||||
private Mission getAnyMission(StoredFileHelper storage) {
|
||||
synchronized (this) {
|
||||
Mission mission = getPendingMission(location, name);
|
||||
Mission mission = getPendingMission(storage);
|
||||
if (mission != null) return mission;
|
||||
|
||||
int idx = getFinishedMissionIndex(location, name);
|
||||
int idx = getFinishedMissionIndex(storage);
|
||||
if (idx >= 0) return mMissionsFinished.get(idx);
|
||||
}
|
||||
|
||||
|
@ -335,7 +354,7 @@ public class DownloadManager {
|
|||
int count = 0;
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running && !mission.isFinished() && !mission.isPsFailed())
|
||||
if (mission.running && !mission.isPsFailed() && !mission.isFinished())
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -343,62 +362,36 @@ public class DownloadManager {
|
|||
return count;
|
||||
}
|
||||
|
||||
void pauseAllMissions() {
|
||||
public void pauseAllMissions(boolean force) {
|
||||
boolean flag = false;
|
||||
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) mission.pause();
|
||||
}
|
||||
}
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (!mission.running || mission.isPsRunning() || mission.isFinished()) continue;
|
||||
|
||||
if (force) mission.threads = null;// avoid waiting for threads
|
||||
|
||||
/**
|
||||
* Splits the filename into name and extension
|
||||
* <p>
|
||||
* Dots are ignored if they appear: not at all, at the beginning of the file,
|
||||
* at the end of the file
|
||||
*
|
||||
* @param name the name to split
|
||||
* @return a string array with a length of 2 containing the name and the extension
|
||||
*/
|
||||
private static String[] splitName(String name) {
|
||||
int dotIndex = name.lastIndexOf('.');
|
||||
if (dotIndex <= 0 || (dotIndex == name.length() - 1)) {
|
||||
return new String[]{name, ""};
|
||||
} else {
|
||||
return new String[]{name.substring(0, dotIndex), name.substring(dotIndex + 1)};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique file name.
|
||||
* <p>
|
||||
* e.g. "myName (1).txt" if the name "myName.txt" exists.
|
||||
*
|
||||
* @param location the location (to check for existing files)
|
||||
* @param name the name of the file
|
||||
* @return the unique file name
|
||||
* @throws IllegalArgumentException if the location is not a directory
|
||||
* @throws SecurityException if the location is not readable
|
||||
*/
|
||||
private static String generateUniqueName(String location, String name) {
|
||||
if (location == null) throw new NullPointerException("location is null");
|
||||
if (name == null) throw new NullPointerException("name is null");
|
||||
File destination = new File(location);
|
||||
if (!destination.isDirectory()) {
|
||||
throw new IllegalArgumentException("location is not a directory: " + location);
|
||||
}
|
||||
final String[] nameParts = splitName(name);
|
||||
String[] existingName = destination.list((dir, name1) -> name1.startsWith(nameParts[0]));
|
||||
Arrays.sort(existingName);
|
||||
String newName;
|
||||
int downloadIndex = 0;
|
||||
do {
|
||||
newName = nameParts[0] + " (" + downloadIndex + ")." + nameParts[1];
|
||||
++downloadIndex;
|
||||
if (downloadIndex == 1000) { // Probably an error on our side
|
||||
throw new RuntimeException("Too many existing files");
|
||||
mission.pause();
|
||||
flag = true;
|
||||
}
|
||||
} while (Arrays.binarySearch(existingName, newName) >= 0);
|
||||
return newName;
|
||||
}
|
||||
|
||||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
}
|
||||
|
||||
public void startAllMissions() {
|
||||
boolean flag = false;
|
||||
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running || mission.isCorrupt()) continue;
|
||||
|
||||
flag = true;
|
||||
mission.start();
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -410,36 +403,41 @@ public class DownloadManager {
|
|||
synchronized (this) {
|
||||
mMissionsPending.remove(mission);
|
||||
mMissionsFinished.add(0, new FinishedMission(mission));
|
||||
mDownloadDataSource.addMission(mission);
|
||||
mFinishedMissionStore.addFinishedMission(mission);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* runs another mission in queue if possible
|
||||
* runs one or multiple missions in from queue if possible
|
||||
*
|
||||
* @return true if exits pending missions running or a mission was started, otherwise, false
|
||||
* @return true if one or multiple missions are running, otherwise, false
|
||||
*/
|
||||
boolean runAnotherMission() {
|
||||
boolean runMissions() {
|
||||
synchronized (this) {
|
||||
if (mMissionsPending.size() < 1) return false;
|
||||
|
||||
int i = getRunningMissionsCount();
|
||||
if (i > 0) return true;
|
||||
|
||||
if (!canDownloadInCurrentNetwork()) return false;
|
||||
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (!mission.running && mission.errCode == DownloadMission.ERROR_NOTHING && mission.enqueued) {
|
||||
resumeMission(mission);
|
||||
return true;
|
||||
}
|
||||
if (mPrefQueueLimit) {
|
||||
for (DownloadMission mission : mMissionsPending)
|
||||
if (!mission.isFinished() && mission.running) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
boolean flag = false;
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running || !mission.enqueued || mission.isFinished() || mission.hasInvalidStorage())
|
||||
continue;
|
||||
|
||||
resumeMission(mission);
|
||||
if (mPrefQueueLimit) return true;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
public MissionIterator getIterator() {
|
||||
mSelfMissionsControl = true;
|
||||
return new MissionIterator();
|
||||
}
|
||||
|
||||
|
@ -449,7 +447,7 @@ public class DownloadManager {
|
|||
public void forgetFinishedDownloads() {
|
||||
synchronized (this) {
|
||||
for (FinishedMission mission : mMissionsFinished) {
|
||||
mDownloadDataSource.deleteMission(mission);
|
||||
mFinishedMissionStore.deleteMission(mission);
|
||||
}
|
||||
mMissionsFinished.clear();
|
||||
}
|
||||
|
@ -457,31 +455,43 @@ public class DownloadManager {
|
|||
|
||||
private boolean canDownloadInCurrentNetwork() {
|
||||
if (mLastNetworkStatus == NetworkState.Unavailable) return false;
|
||||
return !(mPrefCrossNetwork && mLastNetworkStatus == NetworkState.MobileOperating);
|
||||
return !(mPrefMeteredDownloads && mLastNetworkStatus == NetworkState.MeteredOperating);
|
||||
}
|
||||
|
||||
void handleConnectivityChange(NetworkState currentStatus) {
|
||||
void handleConnectivityState(NetworkState currentStatus, boolean updateOnly) {
|
||||
if (currentStatus == mLastNetworkStatus) return;
|
||||
|
||||
mLastNetworkStatus = currentStatus;
|
||||
if (currentStatus == NetworkState.Unavailable) return;
|
||||
|
||||
if (currentStatus == NetworkState.Unavailable) {
|
||||
return;
|
||||
} else if (currentStatus != NetworkState.MobileOperating || !mPrefCrossNetwork) {
|
||||
return;
|
||||
if (!mSelfMissionsControl || updateOnly) {
|
||||
return;// don't touch anything without the user interaction
|
||||
}
|
||||
|
||||
boolean flag = false;
|
||||
boolean isMetered = mPrefMeteredDownloads && mLastNetworkStatus == NetworkState.MeteredOperating;
|
||||
|
||||
int running = 0;
|
||||
int paused = 0;
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running && !mission.isFinished() && !mission.isPsRunning()) {
|
||||
flag = true;
|
||||
if (mission.isCorrupt() || mission.isPsRunning()) continue;
|
||||
|
||||
if (mission.running && isMetered) {
|
||||
paused++;
|
||||
mission.pause();
|
||||
} else if (!mission.running && !isMetered && mission.enqueued) {
|
||||
running++;
|
||||
mission.start();
|
||||
if (mPrefQueueLimit) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
if (running > 0) {
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
return;
|
||||
}
|
||||
if (paused > 0) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
}
|
||||
|
||||
void updateMaximumAttempts() {
|
||||
|
@ -506,21 +516,46 @@ public class DownloadManager {
|
|||
), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
void checkForRunningMission(String location, String name, DownloadManagerService.DMChecker check) {
|
||||
boolean listed;
|
||||
boolean finished = false;
|
||||
|
||||
public MissionState checkForExistingMission(StoredFileHelper storage) {
|
||||
synchronized (this) {
|
||||
DownloadMission mission = getPendingMission(location, name);
|
||||
if (mission != null) {
|
||||
listed = true;
|
||||
DownloadMission pending = getPendingMission(storage);
|
||||
|
||||
if (pending == null) {
|
||||
if (getFinishedMissionIndex(storage) >= 0) return MissionState.Finished;
|
||||
} else {
|
||||
listed = getFinishedMissionIndex(location, name) >= 0;
|
||||
finished = listed;
|
||||
if (pending.isFinished()) {
|
||||
return MissionState.Finished;// this never should happen (race-condition)
|
||||
} else {
|
||||
return pending.running ? MissionState.PendingRunning : MissionState.Pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check.callback(listed, finished);
|
||||
return MissionState.None;
|
||||
}
|
||||
|
||||
private static boolean isDirectoryAvailable(File directory) {
|
||||
return directory != null && directory.canWrite() && directory.exists();
|
||||
}
|
||||
|
||||
static File pickAvailableTemporalDir(@NonNull Context ctx) {
|
||||
if (isDirectoryAvailable(ctx.getExternalFilesDir(null)))
|
||||
return ctx.getExternalFilesDir(null);
|
||||
else if (isDirectoryAvailable(ctx.getFilesDir()))
|
||||
return ctx.getFilesDir();
|
||||
|
||||
// this never should happen
|
||||
return ctx.getDir("tmp", Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private StoredDirectoryHelper getMainStorage(@NonNull String tag) {
|
||||
if (tag.equals(TAG_AUDIO)) return mMainStorageAudio;
|
||||
if (tag.equals(TAG_VIDEO)) return mMainStorageVideo;
|
||||
|
||||
Log.w(TAG, "Unknown download category, not [audio video]: " + tag);
|
||||
|
||||
return null;// this never should happen
|
||||
}
|
||||
|
||||
public class MissionIterator extends DiffUtil.Callback {
|
||||
|
@ -592,39 +627,6 @@ public class DownloadManager {
|
|||
return SPECIAL_NOTHING;
|
||||
}
|
||||
|
||||
public MissionItem getItemUnsafe(int position) {
|
||||
synchronized (DownloadManager.this) {
|
||||
int count = mMissionsPending.size();
|
||||
int count2 = mMissionsFinished.size();
|
||||
|
||||
if (count > 0) {
|
||||
position--;
|
||||
if (position == -1)
|
||||
return new MissionItem(SPECIAL_PENDING);
|
||||
else if (position < count)
|
||||
return new MissionItem(SPECIAL_NOTHING, mMissionsPending.get(position));
|
||||
else if (position == count && count2 > 0)
|
||||
return new MissionItem(SPECIAL_FINISHED);
|
||||
else
|
||||
position -= count;
|
||||
} else {
|
||||
if (count2 > 0 && position == 0) {
|
||||
return new MissionItem(SPECIAL_FINISHED);
|
||||
}
|
||||
}
|
||||
|
||||
position--;
|
||||
|
||||
if (count2 < 1) {
|
||||
throw new RuntimeException(
|
||||
String.format("Out of range. pending_count=%s finished_count=%s position=%s", count, count2, position)
|
||||
);
|
||||
}
|
||||
|
||||
return new MissionItem(SPECIAL_NOTHING, mMissionsFinished.get(position));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void start() {
|
||||
current = getSpecialItems();
|
||||
|
@ -647,6 +649,32 @@ public class DownloadManager {
|
|||
return hasFinished;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if exists missions running and paused. Corrupted and hidden missions are not counted
|
||||
*
|
||||
* @return two-dimensional array contains the current missions state.
|
||||
* 1° entry: true if has at least one mission running
|
||||
* 2° entry: true if has at least one mission paused
|
||||
*/
|
||||
public boolean[] hasValidPendingMissions() {
|
||||
boolean running = false;
|
||||
boolean paused = false;
|
||||
|
||||
synchronized (DownloadManager.this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (hidden.contains(mission) || mission.isCorrupt())
|
||||
continue;
|
||||
|
||||
if (mission.running)
|
||||
paused = true;
|
||||
else
|
||||
running = true;
|
||||
}
|
||||
}
|
||||
|
||||
return new boolean[]{running, paused};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getOldListSize() {
|
||||
|
@ -665,7 +693,14 @@ public class DownloadManager {
|
|||
|
||||
@Override
|
||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
return areItemsTheSame(oldItemPosition, newItemPosition);
|
||||
Object x = snapshot.get(oldItemPosition);
|
||||
Object y = current.get(newItemPosition);
|
||||
|
||||
if (x instanceof Mission && y instanceof Mission) {
|
||||
return ((Mission) x).storage.equals(((Mission) y).storage);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
package us.shandian.giga.service;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
|
@ -24,6 +25,9 @@ import android.os.IBinder;
|
|||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationCompat.Builder;
|
||||
import android.support.v4.content.PermissionChecker;
|
||||
|
@ -36,9 +40,13 @@ import org.schabi.newpipe.download.DownloadActivity;
|
|||
import org.schabi.newpipe.player.helper.LockManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.io.StoredDirectoryHelper;
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
import us.shandian.giga.postprocessing.Postprocessing;
|
||||
import us.shandian.giga.service.DownloadManager.NetworkState;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.APPLICATION_ID;
|
||||
|
@ -48,7 +56,6 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
private static final String TAG = "DownloadManagerService";
|
||||
|
||||
public static final int MESSAGE_RUNNING = 0;
|
||||
public static final int MESSAGE_PAUSED = 1;
|
||||
public static final int MESSAGE_FINISHED = 2;
|
||||
public static final int MESSAGE_PROGRESS = 3;
|
||||
|
@ -59,24 +66,25 @@ public class DownloadManagerService extends Service {
|
|||
private static final int DOWNLOADS_NOTIFICATION_ID = 1001;
|
||||
|
||||
private static final String EXTRA_URLS = "DownloadManagerService.extra.urls";
|
||||
private static final String EXTRA_NAME = "DownloadManagerService.extra.name";
|
||||
private static final String EXTRA_LOCATION = "DownloadManagerService.extra.location";
|
||||
private static final String EXTRA_KIND = "DownloadManagerService.extra.kind";
|
||||
private static final String EXTRA_THREADS = "DownloadManagerService.extra.threads";
|
||||
private static final String EXTRA_POSTPROCESSING_NAME = "DownloadManagerService.extra.postprocessingName";
|
||||
private static final String EXTRA_POSTPROCESSING_ARGS = "DownloadManagerService.extra.postprocessingArgs";
|
||||
private static final String EXTRA_SOURCE = "DownloadManagerService.extra.source";
|
||||
private static final String EXTRA_NEAR_LENGTH = "DownloadManagerService.extra.nearLength";
|
||||
private static final String EXTRA_PATH = "DownloadManagerService.extra.storagePath";
|
||||
private static final String EXTRA_PARENT_PATH = "DownloadManagerService.extra.storageParentPath";
|
||||
private static final String EXTRA_STORAGE_TAG = "DownloadManagerService.extra.storageTag";
|
||||
|
||||
private static final String ACTION_RESET_DOWNLOAD_FINISHED = APPLICATION_ID + ".reset_download_finished";
|
||||
private static final String ACTION_OPEN_DOWNLOADS_FINISHED = APPLICATION_ID + ".open_downloads_finished";
|
||||
|
||||
private DMBinder mBinder;
|
||||
private DownloadManagerBinder mBinder;
|
||||
private DownloadManager mManager;
|
||||
private Notification mNotification;
|
||||
private Handler mHandler;
|
||||
private boolean mForeground = false;
|
||||
private NotificationManager notificationManager = null;
|
||||
private NotificationManager mNotificationManager = null;
|
||||
private boolean mDownloadNotificationEnable = true;
|
||||
|
||||
private int downloadDoneCount = 0;
|
||||
|
@ -85,7 +93,9 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
private final ArrayList<Handler> mEchoObservers = new ArrayList<>(1);
|
||||
|
||||
private BroadcastReceiver mNetworkStateListener;
|
||||
private ConnectivityManager mConnectivityManager;
|
||||
private BroadcastReceiver mNetworkStateListener = null;
|
||||
private ConnectivityManager.NetworkCallback mNetworkStateListenerL = null;
|
||||
|
||||
private SharedPreferences mPrefs = null;
|
||||
private final SharedPreferences.OnSharedPreferenceChangeListener mPrefChangeListener = this::handlePreferenceChange;
|
||||
|
@ -106,10 +116,10 @@ public class DownloadManagerService extends Service {
|
|||
/**
|
||||
* notify media scanner on downloaded media file ...
|
||||
*
|
||||
* @param file the downloaded file
|
||||
* @param file the downloaded file uri
|
||||
*/
|
||||
private void notifyMediaScanner(File file) {
|
||||
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
|
||||
private void notifyMediaScanner(Uri file) {
|
||||
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, file));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -120,7 +130,7 @@ public class DownloadManagerService extends Service {
|
|||
Log.d(TAG, "onCreate");
|
||||
}
|
||||
|
||||
mBinder = new DMBinder();
|
||||
mBinder = new DownloadManagerBinder();
|
||||
mHandler = new Handler(Looper.myLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
|
@ -128,7 +138,9 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
};
|
||||
|
||||
mManager = new DownloadManager(this, mHandler);
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
mManager = new DownloadManager(this, mHandler, loadMainVideoStorage(), loadMainAudioStorage());
|
||||
|
||||
Intent openDownloadListIntent = new Intent(this, DownloadActivity.class)
|
||||
.setAction(Intent.ACTION_MAIN);
|
||||
|
@ -147,54 +159,55 @@ public class DownloadManagerService extends Service {
|
|||
.setContentText(getString(R.string.msg_running_detail));
|
||||
|
||||
mNotification = builder.build();
|
||||
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
mNetworkStateListener = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
|
||||
handleConnectivityChange(null);
|
||||
return;
|
||||
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
mNetworkStateListenerL = new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
handleConnectivityState(false);
|
||||
}
|
||||
handleConnectivityChange(intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
|
||||
}
|
||||
};
|
||||
registerReceiver(mNetworkStateListener, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
handleConnectivityState(false);
|
||||
}
|
||||
};
|
||||
mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder().build(), mNetworkStateListenerL);
|
||||
} else {
|
||||
mNetworkStateListener = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
handleConnectivityState(false);
|
||||
}
|
||||
};
|
||||
registerReceiver(mNetworkStateListener, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
}
|
||||
|
||||
mPrefs.registerOnSharedPreferenceChangeListener(mPrefChangeListener);
|
||||
|
||||
handlePreferenceChange(mPrefs, getString(R.string.downloads_cross_network));
|
||||
handlePreferenceChange(mPrefs, getString(R.string.downloads_maximum_retry));
|
||||
handlePreferenceChange(mPrefs, getString(R.string.downloads_queue_limit));
|
||||
|
||||
mLock = new LockManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
public int onStartCommand(final Intent intent, int flags, int startId) {
|
||||
if (DEBUG) {
|
||||
if (intent == null) {
|
||||
Log.d(TAG, "Restarting");
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
Log.d(TAG, "Starting");
|
||||
Log.d(TAG, intent == null ? "Restarting" : "Starting");
|
||||
}
|
||||
|
||||
if (intent == null) return START_NOT_STICKY;
|
||||
|
||||
Log.i(TAG, "Got intent: " + intent);
|
||||
String action = intent.getAction();
|
||||
if (action != null) {
|
||||
if (action.equals(Intent.ACTION_RUN)) {
|
||||
String[] urls = intent.getStringArrayExtra(EXTRA_URLS);
|
||||
String name = intent.getStringExtra(EXTRA_NAME);
|
||||
String location = intent.getStringExtra(EXTRA_LOCATION);
|
||||
int threads = intent.getIntExtra(EXTRA_THREADS, 1);
|
||||
char kind = intent.getCharExtra(EXTRA_KIND, '?');
|
||||
String psName = intent.getStringExtra(EXTRA_POSTPROCESSING_NAME);
|
||||
String[] psArgs = intent.getStringArrayExtra(EXTRA_POSTPROCESSING_ARGS);
|
||||
String source = intent.getStringExtra(EXTRA_SOURCE);
|
||||
long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0);
|
||||
|
||||
mHandler.post(() -> mManager.startMission(urls, location, name, kind, threads, source, psName, psArgs, nearLength));
|
||||
|
||||
mHandler.post(() -> startMission(intent));
|
||||
} else if (downloadDoneNotification != null) {
|
||||
if (action.equals(ACTION_RESET_DOWNLOAD_FINISHED) || action.equals(ACTION_OPEN_DOWNLOADS_FINISHED)) {
|
||||
downloadDoneCount = 0;
|
||||
|
@ -221,32 +234,36 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
stopForeground(true);
|
||||
|
||||
if (notificationManager != null && downloadDoneNotification != null) {
|
||||
if (mNotificationManager != null && downloadDoneNotification != null) {
|
||||
downloadDoneNotification.setDeleteIntent(null);// prevent NewPipe running when is killed, cleared from recent, etc
|
||||
notificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
mNotificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
}
|
||||
|
||||
mManager.pauseAllMissions();
|
||||
|
||||
manageLock(false);
|
||||
|
||||
unregisterReceiver(mNetworkStateListener);
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
mConnectivityManager.unregisterNetworkCallback(mNetworkStateListenerL);
|
||||
else
|
||||
unregisterReceiver(mNetworkStateListener);
|
||||
|
||||
mPrefs.unregisterOnSharedPreferenceChangeListener(mPrefChangeListener);
|
||||
|
||||
if (icDownloadDone != null) icDownloadDone.recycle();
|
||||
if (icDownloadFailed != null) icDownloadFailed.recycle();
|
||||
if (icLauncher != null) icLauncher.recycle();
|
||||
|
||||
mManager.pauseAllMissions(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
int permissionCheck;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
|
||||
permissionCheck = PermissionChecker.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
if (permissionCheck == PermissionChecker.PERMISSION_DENIED) {
|
||||
Toast.makeText(this, "Permission denied (read)", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
// if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
|
||||
// permissionCheck = PermissionChecker.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
// if (permissionCheck == PermissionChecker.PERMISSION_DENIED) {
|
||||
// Toast.makeText(this, "Permission denied (read)", Toast.LENGTH_SHORT).show();
|
||||
// }
|
||||
// }
|
||||
|
||||
permissionCheck = PermissionChecker.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
if (permissionCheck == PermissionChecker.PERMISSION_DENIED) {
|
||||
|
@ -261,18 +278,19 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
switch (msg.what) {
|
||||
case MESSAGE_FINISHED:
|
||||
notifyMediaScanner(mission.getDownloadedFile());
|
||||
notifyFinishedDownload(mission.name);
|
||||
notifyMediaScanner(mission.storage.getUri());
|
||||
notifyFinishedDownload(mission.storage.getName());
|
||||
mManager.setFinished(mission);
|
||||
updateForegroundState(mManager.runAnotherMission());
|
||||
handleConnectivityState(false);
|
||||
updateForegroundState(mManager.runMissions());
|
||||
break;
|
||||
case MESSAGE_RUNNING:
|
||||
case MESSAGE_PROGRESS:
|
||||
updateForegroundState(true);
|
||||
break;
|
||||
case MESSAGE_ERROR:
|
||||
notifyFailedDownload(mission);
|
||||
updateForegroundState(mManager.runAnotherMission());
|
||||
handleConnectivityState(false);
|
||||
updateForegroundState(mManager.runMissions());
|
||||
break;
|
||||
case MESSAGE_PAUSED:
|
||||
updateForegroundState(mManager.getRunningMissionsCount() > 0);
|
||||
|
@ -293,46 +311,46 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleConnectivityChange(NetworkInfo info) {
|
||||
private void handleConnectivityState(boolean updateOnly) {
|
||||
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
|
||||
NetworkState status;
|
||||
|
||||
if (info == null) {
|
||||
status = NetworkState.Unavailable;
|
||||
Log.i(TAG, "actual connectivity status is unavailable");
|
||||
} else if (!info.isAvailable() || !info.isConnected()) {
|
||||
status = NetworkState.Unavailable;
|
||||
Log.i(TAG, "actual connectivity status is not available and not connected");
|
||||
Log.i(TAG, "Active network [connectivity is unavailable]");
|
||||
} else {
|
||||
int type = info.getType();
|
||||
if (type == ConnectivityManager.TYPE_MOBILE || type == ConnectivityManager.TYPE_MOBILE_DUN) {
|
||||
status = NetworkState.MobileOperating;
|
||||
} else if (type == ConnectivityManager.TYPE_WIFI) {
|
||||
status = NetworkState.WifiOperating;
|
||||
} else if (type == ConnectivityManager.TYPE_WIMAX ||
|
||||
type == ConnectivityManager.TYPE_ETHERNET ||
|
||||
type == ConnectivityManager.TYPE_BLUETOOTH) {
|
||||
status = NetworkState.OtherOperating;
|
||||
} else {
|
||||
boolean connected = info.isConnected();
|
||||
boolean metered = mConnectivityManager.isActiveNetworkMetered();
|
||||
|
||||
if (connected)
|
||||
status = metered ? NetworkState.MeteredOperating : NetworkState.Operating;
|
||||
else
|
||||
status = NetworkState.Unavailable;
|
||||
}
|
||||
Log.i(TAG, "actual connectivity status is " + status.name());
|
||||
|
||||
Log.i(TAG, "Active network [connected=" + connected + " metered=" + metered + "] " + info.toString());
|
||||
}
|
||||
|
||||
if (mManager == null) return;// avoid race-conditions while the service is starting
|
||||
mManager.handleConnectivityChange(status);
|
||||
mManager.handleConnectivityState(status, updateOnly);
|
||||
}
|
||||
|
||||
private void handlePreferenceChange(SharedPreferences prefs, String key) {
|
||||
private void handlePreferenceChange(SharedPreferences prefs, @NonNull String key) {
|
||||
if (key.equals(getString(R.string.downloads_maximum_retry))) {
|
||||
try {
|
||||
String value = prefs.getString(key, getString(R.string.downloads_maximum_retry_default));
|
||||
mManager.mPrefMaxRetry = Integer.parseInt(value);
|
||||
mManager.mPrefMaxRetry = value == null ? 0 : Integer.parseInt(value);
|
||||
} catch (Exception e) {
|
||||
mManager.mPrefMaxRetry = 0;
|
||||
}
|
||||
mManager.updateMaximumAttempts();
|
||||
} else if (key.equals(getString(R.string.downloads_cross_network))) {
|
||||
mManager.mPrefCrossNetwork = prefs.getBoolean(key, false);
|
||||
mManager.mPrefMeteredDownloads = prefs.getBoolean(key, false);
|
||||
} else if (key.equals(getString(R.string.downloads_queue_limit))) {
|
||||
mManager.mPrefQueueLimit = prefs.getBoolean(key, true);
|
||||
} else if (key.equals(getString(R.string.download_path_video_key))) {
|
||||
mManager.mMainStorageVideo = loadMainVideoStorage();
|
||||
} else if (key.equals(getString(R.string.download_path_audio_key))) {
|
||||
mManager.mMainStorageAudio = loadMainAudioStorage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,46 +368,78 @@ public class DownloadManagerService extends Service {
|
|||
mForeground = state;
|
||||
}
|
||||
|
||||
public static void startMission(Context context, String urls[], String location, String name, char kind,
|
||||
/**
|
||||
* Start a new download mission
|
||||
*
|
||||
* @param context the activity context
|
||||
* @param urls the list of urls to download
|
||||
* @param storage where the file is saved
|
||||
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
|
||||
* @param threads the number of threads maximal used to download chunks of the file.
|
||||
* @param psName the name of the required post-processing algorithm, or {@code null} to ignore.
|
||||
* @param source source url of the resource
|
||||
* @param psArgs the arguments for the post-processing algorithm.
|
||||
* @param nearLength the approximated final length of the file
|
||||
*/
|
||||
public static void startMission(Context context, String[] urls, StoredFileHelper storage, char kind,
|
||||
int threads, String source, String psName, String[] psArgs, long nearLength) {
|
||||
Intent intent = new Intent(context, DownloadManagerService.class);
|
||||
intent.setAction(Intent.ACTION_RUN);
|
||||
intent.putExtra(EXTRA_URLS, urls);
|
||||
intent.putExtra(EXTRA_NAME, name);
|
||||
intent.putExtra(EXTRA_LOCATION, location);
|
||||
intent.putExtra(EXTRA_KIND, kind);
|
||||
intent.putExtra(EXTRA_THREADS, threads);
|
||||
intent.putExtra(EXTRA_SOURCE, source);
|
||||
intent.putExtra(EXTRA_POSTPROCESSING_NAME, psName);
|
||||
intent.putExtra(EXTRA_POSTPROCESSING_ARGS, psArgs);
|
||||
intent.putExtra(EXTRA_NEAR_LENGTH, nearLength);
|
||||
|
||||
intent.putExtra(EXTRA_PARENT_PATH, storage.getParentUri());
|
||||
intent.putExtra(EXTRA_PATH, storage.getUri());
|
||||
intent.putExtra(EXTRA_STORAGE_TAG, storage.getTag());
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
public static void checkForRunningMission(Context context, String location, String name, DMChecker check) {
|
||||
Intent intent = new Intent();
|
||||
intent.setClass(context, DownloadManagerService.class);
|
||||
context.bindService(intent, new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName cname, IBinder service) {
|
||||
try {
|
||||
((DMBinder) service).getDownloadManager().checkForRunningMission(location, name, check);
|
||||
} catch (Exception err) {
|
||||
Log.w(TAG, "checkForRunningMission() callback is defective", err);
|
||||
}
|
||||
private void startMission(Intent intent) {
|
||||
String[] urls = intent.getStringArrayExtra(EXTRA_URLS);
|
||||
Uri path = intent.getParcelableExtra(EXTRA_PATH);
|
||||
Uri parentPath = intent.getParcelableExtra(EXTRA_PARENT_PATH);
|
||||
int threads = intent.getIntExtra(EXTRA_THREADS, 1);
|
||||
char kind = intent.getCharExtra(EXTRA_KIND, '?');
|
||||
String psName = intent.getStringExtra(EXTRA_POSTPROCESSING_NAME);
|
||||
String[] psArgs = intent.getStringArrayExtra(EXTRA_POSTPROCESSING_ARGS);
|
||||
String source = intent.getStringExtra(EXTRA_SOURCE);
|
||||
long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0);
|
||||
String tag = intent.getStringExtra(EXTRA_STORAGE_TAG);
|
||||
|
||||
// TODO: find a efficient way to unbind the service. This destroy the service due idle, but is started again when the user start a download.
|
||||
context.unbindService(this);
|
||||
}
|
||||
StoredFileHelper storage;
|
||||
try {
|
||||
storage = new StoredFileHelper(this, parentPath, path, tag);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);// this never should happen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
}
|
||||
}, Context.BIND_AUTO_CREATE);
|
||||
Postprocessing ps;
|
||||
if (psName == null)
|
||||
ps = null;
|
||||
else
|
||||
ps = Postprocessing.getAlgorithm(psName, psArgs);
|
||||
|
||||
final DownloadMission mission = new DownloadMission(urls, storage, kind, ps);
|
||||
mission.threadCount = threads;
|
||||
mission.source = source;
|
||||
mission.nearLength = nearLength;
|
||||
|
||||
if (ps != null)
|
||||
ps.setTemporalDir(DownloadManager.pickAvailableTemporalDir(this));
|
||||
|
||||
handleConnectivityState(true);// first check the actual network status
|
||||
|
||||
mManager.startMission(mission);
|
||||
}
|
||||
|
||||
public void notifyFinishedDownload(String name) {
|
||||
if (!mDownloadNotificationEnable || notificationManager == null) {
|
||||
if (!mDownloadNotificationEnable || mNotificationManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -428,7 +478,7 @@ public class DownloadManagerService extends Service {
|
|||
downloadDoneNotification.setContentText(downloadDoneList);
|
||||
}
|
||||
|
||||
notificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
mNotificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
downloadDoneCount++;
|
||||
}
|
||||
|
||||
|
@ -450,15 +500,15 @@ public class DownloadManagerService extends Service {
|
|||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
downloadFailedNotification.setContentTitle(getString(R.string.app_name));
|
||||
downloadFailedNotification.setStyle(new NotificationCompat.BigTextStyle()
|
||||
.bigText(getString(R.string.download_failed).concat(": ").concat(mission.name)));
|
||||
.bigText(getString(R.string.download_failed).concat(": ").concat(mission.storage.getName())));
|
||||
} else {
|
||||
downloadFailedNotification.setContentTitle(getString(R.string.download_failed));
|
||||
downloadFailedNotification.setContentText(mission.name);
|
||||
downloadFailedNotification.setContentText(mission.storage.getName());
|
||||
downloadFailedNotification.setStyle(new NotificationCompat.BigTextStyle()
|
||||
.bigText(mission.name));
|
||||
.bigText(mission.storage.getName()));
|
||||
}
|
||||
|
||||
notificationManager.notify(id, downloadFailedNotification.build());
|
||||
mNotificationManager.notify(id, downloadFailedNotification.build());
|
||||
}
|
||||
|
||||
private PendingIntent makePendingIntent(String action) {
|
||||
|
@ -487,12 +537,66 @@ public class DownloadManagerService extends Service {
|
|||
mLockAcquired = acquire;
|
||||
}
|
||||
|
||||
// Wrapper of DownloadManager
|
||||
public class DMBinder extends Binder {
|
||||
private StoredDirectoryHelper loadMainVideoStorage() {
|
||||
return loadMainStorage(R.string.download_path_video_key, DownloadManager.TAG_VIDEO);
|
||||
}
|
||||
|
||||
private StoredDirectoryHelper loadMainAudioStorage() {
|
||||
return loadMainStorage(R.string.download_path_audio_key, DownloadManager.TAG_AUDIO);
|
||||
}
|
||||
|
||||
private StoredDirectoryHelper loadMainStorage(@StringRes int prefKey, String tag) {
|
||||
String path = mPrefs.getString(getString(prefKey), null);
|
||||
|
||||
if (path == null || path.isEmpty()) return null;
|
||||
|
||||
if (path.charAt(0) == File.separatorChar) {
|
||||
Log.i(TAG, "Old save path style present: " + path);
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
||||
path = Uri.fromFile(new File(path)).toString();
|
||||
else
|
||||
path = "";
|
||||
|
||||
mPrefs.edit().putString(getString(prefKey), "").apply();
|
||||
}
|
||||
|
||||
try {
|
||||
return new StoredDirectoryHelper(this, Uri.parse(path), tag);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to load the storage of " + tag + " from " + path, e);
|
||||
Toast.makeText(this, R.string.no_available_dir, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Wrappers for DownloadManager
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public class DownloadManagerBinder extends Binder {
|
||||
public DownloadManager getDownloadManager() {
|
||||
return mManager;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public StoredDirectoryHelper getMainStorageVideo() {
|
||||
return mManager.mMainStorageVideo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public StoredDirectoryHelper getMainStorageAudio() {
|
||||
return mManager.mMainStorageAudio;
|
||||
}
|
||||
|
||||
public boolean askForSavePath() {
|
||||
return DownloadManagerService.this.mPrefs.getBoolean(
|
||||
DownloadManagerService.this.getString(R.string.downloads_storage_ask),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public void addMissionEventListener(Handler handler) {
|
||||
manageObservers(handler, true);
|
||||
}
|
||||
|
@ -502,15 +606,15 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
|
||||
public void clearDownloadNotifications() {
|
||||
if (notificationManager == null) return;
|
||||
if (mNotificationManager == null) return;
|
||||
if (downloadDoneNotification != null) {
|
||||
notificationManager.cancel(DOWNLOADS_NOTIFICATION_ID);
|
||||
mNotificationManager.cancel(DOWNLOADS_NOTIFICATION_ID);
|
||||
downloadDoneList.setLength(0);
|
||||
downloadDoneCount = 0;
|
||||
}
|
||||
if (downloadFailedNotification != null) {
|
||||
for (; downloadFailedNotificationID > DOWNLOADS_NOTIFICATION_ID; downloadFailedNotificationID--) {
|
||||
notificationManager.cancel(downloadFailedNotificationID);
|
||||
mNotificationManager.cancel(downloadFailedNotificationID);
|
||||
}
|
||||
mFailedDownloads.clear();
|
||||
downloadFailedNotificationID++;
|
||||
|
@ -523,8 +627,4 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
}
|
||||
|
||||
public interface DMChecker {
|
||||
void callback(boolean listed, boolean finished);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package us.shandian.giga.service;
|
||||
|
||||
public enum MissionState {
|
||||
None, Pending, PendingRunning, Finished
|
||||
}
|
|
@ -8,21 +8,22 @@ import android.content.Intent;
|
|||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.util.DiffUtil;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import android.support.v7.widget.RecyclerView.Adapter;
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
@ -36,14 +37,20 @@ import android.widget.Toast;
|
|||
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.get.FinishedMission;
|
||||
import us.shandian.giga.get.Mission;
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
import us.shandian.giga.service.DownloadManager;
|
||||
import us.shandian.giga.service.DownloadManagerService;
|
||||
import us.shandian.giga.ui.common.Deleter;
|
||||
|
@ -57,11 +64,16 @@ import static us.shandian.giga.get.DownloadMission.ERROR_CONNECT_HOST;
|
|||
import static us.shandian.giga.get.DownloadMission.ERROR_FILE_CREATION;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_NO_CONTENT;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_UNSUPPORTED_RANGE;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_INSUFFICIENT_STORAGE;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_PATH_CREATION;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_PERMISSION_DENIED;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_HOLD;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_STOPPED;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_PROGRESS_LOST;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_SSL_EXCEPTION;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_TIMEOUT;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_EXCEPTION;
|
||||
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_HOST;
|
||||
|
||||
|
@ -69,6 +81,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
private static final SparseArray<String> ALGORITHMS = new SparseArray<>();
|
||||
private static final String TAG = "MissionAdapter";
|
||||
private static final String UNDEFINED_PROGRESS = "--.-%";
|
||||
private static final String DEFAULT_MIME_TYPE = "*/*";
|
||||
|
||||
|
||||
static {
|
||||
|
@ -85,9 +98,12 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
private ArrayList<ViewHolderItem> mPendingDownloadsItems = new ArrayList<>();
|
||||
private Handler mHandler;
|
||||
private MenuItem mClear;
|
||||
private MenuItem mStartButton;
|
||||
private MenuItem mPauseButton;
|
||||
private View mEmptyMessage;
|
||||
private RecoverHelper mRecover;
|
||||
|
||||
public MissionAdapter(Context context, DownloadManager downloadManager, MenuItem clearButton, View emptyMessage) {
|
||||
public MissionAdapter(Context context, @NonNull DownloadManager downloadManager, View emptyMessage) {
|
||||
mContext = context;
|
||||
mDownloadManager = downloadManager;
|
||||
mDeleter = null;
|
||||
|
@ -105,10 +121,18 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
onServiceMessage(msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mStartButton != null && mPauseButton != null) switch (msg.what) {
|
||||
case DownloadManagerService.MESSAGE_DELETED:
|
||||
case DownloadManagerService.MESSAGE_ERROR:
|
||||
case DownloadManagerService.MESSAGE_FINISHED:
|
||||
case DownloadManagerService.MESSAGE_PAUSED:
|
||||
checkMasterButtonsVisibility();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mClear = clearButton;
|
||||
mEmptyMessage = emptyMessage;
|
||||
|
||||
mIterator = downloadManager.getIterator();
|
||||
|
@ -137,7 +161,11 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
|
||||
if (h.item.mission instanceof DownloadMission) {
|
||||
mPendingDownloadsItems.remove(h);
|
||||
if (mPendingDownloadsItems.size() < 1) setAutoRefresh(false);
|
||||
if (mPendingDownloadsItems.size() < 1) {
|
||||
setAutoRefresh(false);
|
||||
if (mStartButton != null) mStartButton.setVisible(false);
|
||||
if (mPauseButton != null) mPauseButton.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
h.popupMenu.dismiss();
|
||||
|
@ -170,10 +198,10 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
ViewHolderItem h = (ViewHolderItem) view;
|
||||
h.item = item;
|
||||
|
||||
Utility.FileType type = Utility.getFileType(item.mission.kind, item.mission.name);
|
||||
Utility.FileType type = Utility.getFileType(item.mission.kind, item.mission.storage.getName());
|
||||
|
||||
h.icon.setImageResource(Utility.getIconForFileType(type));
|
||||
h.name.setText(item.mission.name);
|
||||
h.name.setText(item.mission.storage.getName());
|
||||
|
||||
h.progress.setColors(Utility.getBackgroundForFileType(mContext, type), Utility.getForegroundForFileType(mContext, type));
|
||||
|
||||
|
@ -225,8 +253,10 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
long deltaDone = mission.done - h.lastDone;
|
||||
boolean hasError = mission.errCode != ERROR_NOTHING;
|
||||
|
||||
// on error hide marquee or show if condition (mission.done < 1 || mission.unknownLength) is true
|
||||
h.progress.setMarquee(!hasError && (mission.done < 1 || mission.unknownLength));
|
||||
// hide on error
|
||||
// show if current resource length is not fetched
|
||||
// show if length is unknown
|
||||
h.progress.setMarquee(!hasError && (!mission.isInitialized() || mission.unknownLength));
|
||||
|
||||
float progress;
|
||||
if (mission.unknownLength) {
|
||||
|
@ -252,7 +282,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
long length = mission.getLength();
|
||||
|
||||
int state;
|
||||
if (mission.isPsFailed()) {
|
||||
if (mission.isPsFailed() || mission.errCode == ERROR_POSTPROCESSING_HOLD) {
|
||||
state = 0;
|
||||
} else if (!mission.running) {
|
||||
state = mission.enqueued ? 1 : 2;
|
||||
|
@ -305,36 +335,78 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean viewWithFileProvider(@NonNull File file) {
|
||||
if (!file.exists()) return true;
|
||||
private void viewWithFileProvider(Mission mission) {
|
||||
if (checkInvalidFile(mission)) return;
|
||||
|
||||
String ext = Utility.getFileExt(file.getName());
|
||||
if (ext == null) return false;
|
||||
String mimeType = resolveMimeType(mission);
|
||||
|
||||
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1));
|
||||
Log.v(TAG, "Mime: " + mimeType + " package: " + BuildConfig.APPLICATION_ID + ".provider");
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.v(TAG, "Mime: " + mimeType + " package: " + BuildConfig.APPLICATION_ID + ".provider");
|
||||
|
||||
Uri uri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID + ".provider", file);
|
||||
Uri uri;
|
||||
|
||||
if (mission.storage.isDirect()) {
|
||||
uri = FileProvider.getUriForFile(
|
||||
mContext,
|
||||
BuildConfig.APPLICATION_ID + ".provider",
|
||||
new File(URI.create(mission.storage.getUri().toString()))
|
||||
);
|
||||
} else {
|
||||
uri = mission.storage.getUri();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
|
||||
//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();
|
||||
Toast.makeText(mContext, R.string.toast_no_player, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void shareFile(Mission mission) {
|
||||
if (checkInvalidFile(mission)) return;
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType(resolveMimeType(mission));
|
||||
intent.putExtra(Intent.EXTRA_STREAM, mission.storage.getUri());
|
||||
|
||||
mContext.startActivity(Intent.createChooser(intent, null));
|
||||
}
|
||||
|
||||
private static String resolveMimeType(@NonNull Mission mission) {
|
||||
String mimeType;
|
||||
|
||||
if (!mission.storage.isInvalid()) {
|
||||
mimeType = mission.storage.getType();
|
||||
if (mimeType != null && mimeType.length() > 0 && !mimeType.equals(StoredFileHelper.DEFAULT_MIME))
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
String ext = Utility.getFileExt(mission.storage.getName());
|
||||
if (ext == null) return DEFAULT_MIME_TYPE;
|
||||
|
||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1));
|
||||
|
||||
return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;
|
||||
}
|
||||
|
||||
private boolean checkInvalidFile(@NonNull Mission mission) {
|
||||
if (mission.storage.existsAsFile()) return false;
|
||||
|
||||
Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -343,15 +415,9 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
}
|
||||
|
||||
private void onServiceMessage(@NonNull Message msg) {
|
||||
switch (msg.what) {
|
||||
case DownloadManagerService.MESSAGE_PROGRESS:
|
||||
setAutoRefresh(true);
|
||||
return;
|
||||
case DownloadManagerService.MESSAGE_ERROR:
|
||||
case DownloadManagerService.MESSAGE_FINISHED:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
if (msg.what == DownloadManagerService.MESSAGE_PROGRESS) {
|
||||
setAutoRefresh(true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mPendingDownloadsItems.size(); i++) {
|
||||
|
@ -370,74 +436,104 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
}
|
||||
|
||||
private void showError(@NonNull DownloadMission mission) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(mContext.getString(R.string.label_code));
|
||||
str.append(": ");
|
||||
str.append(mission.errCode);
|
||||
str.append('\n');
|
||||
@StringRes int msg = R.string.general_error;
|
||||
String msgEx = null;
|
||||
|
||||
switch (mission.errCode) {
|
||||
case 416:
|
||||
str.append(mContext.getString(R.string.error_http_requested_range_not_satisfiable));
|
||||
msg = R.string.error_http_requested_range_not_satisfiable;
|
||||
break;
|
||||
case 404:
|
||||
str.append(mContext.getString(R.string.error_http_not_found));
|
||||
msg = R.string.error_http_not_found;
|
||||
break;
|
||||
case ERROR_NOTHING:
|
||||
str.append("¿?");
|
||||
break;
|
||||
return;// this never should happen
|
||||
case ERROR_FILE_CREATION:
|
||||
str.append(mContext.getString(R.string.error_file_creation));
|
||||
msg = R.string.error_file_creation;
|
||||
break;
|
||||
case ERROR_HTTP_NO_CONTENT:
|
||||
str.append(mContext.getString(R.string.error_http_no_content));
|
||||
msg = R.string.error_http_no_content;
|
||||
break;
|
||||
case ERROR_HTTP_UNSUPPORTED_RANGE:
|
||||
str.append(mContext.getString(R.string.error_http_unsupported_range));
|
||||
msg = R.string.error_http_unsupported_range;
|
||||
break;
|
||||
case ERROR_PATH_CREATION:
|
||||
str.append(mContext.getString(R.string.error_path_creation));
|
||||
msg = R.string.error_path_creation;
|
||||
break;
|
||||
case ERROR_PERMISSION_DENIED:
|
||||
str.append(mContext.getString(R.string.permission_denied));
|
||||
msg = R.string.permission_denied;
|
||||
break;
|
||||
case ERROR_SSL_EXCEPTION:
|
||||
str.append(mContext.getString(R.string.error_ssl_exception));
|
||||
msg = R.string.error_ssl_exception;
|
||||
break;
|
||||
case ERROR_UNKNOWN_HOST:
|
||||
str.append(mContext.getString(R.string.error_unknown_host));
|
||||
msg = R.string.error_unknown_host;
|
||||
break;
|
||||
case ERROR_CONNECT_HOST:
|
||||
str.append(mContext.getString(R.string.error_connect_host));
|
||||
msg = R.string.error_connect_host;
|
||||
break;
|
||||
case ERROR_POSTPROCESSING_STOPPED:
|
||||
msg = R.string.error_postprocessing_stopped;
|
||||
break;
|
||||
case ERROR_POSTPROCESSING:
|
||||
str.append(mContext.getString(R.string.error_postprocessing_failed));
|
||||
case ERROR_POSTPROCESSING_HOLD:
|
||||
showError(mission.errObject, UserAction.DOWNLOAD_POSTPROCESSING, R.string.error_postprocessing_failed);
|
||||
return;
|
||||
case ERROR_INSUFFICIENT_STORAGE:
|
||||
msg = R.string.error_insufficient_storage;
|
||||
break;
|
||||
case ERROR_UNKNOWN_EXCEPTION:
|
||||
showError(mission.errObject, UserAction.DOWNLOAD_FAILED, R.string.general_error);
|
||||
return;
|
||||
case ERROR_PROGRESS_LOST:
|
||||
msg = R.string.error_progress_lost;
|
||||
break;
|
||||
case ERROR_TIMEOUT:
|
||||
msg = R.string.error_timeout;
|
||||
break;
|
||||
default:
|
||||
if (mission.errCode >= 100 && mission.errCode < 600) {
|
||||
str = new StringBuilder(8);
|
||||
str.append("HTTP ");
|
||||
str.append(mission.errCode);
|
||||
msgEx = "HTTP " + mission.errCode;
|
||||
} else if (mission.errObject == null) {
|
||||
str.append("(not_decelerated_error_code)");
|
||||
msgEx = "(not_decelerated_error_code)";
|
||||
} else {
|
||||
showError(mission.errObject, UserAction.DOWNLOAD_FAILED, msg);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (mission.errObject != null) {
|
||||
str.append("\n\n");
|
||||
str.append(mission.errObject.toString());
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
|
||||
|
||||
if (msgEx != null)
|
||||
builder.setMessage(msgEx);
|
||||
else
|
||||
builder.setMessage(msg);
|
||||
|
||||
// add report button for non-HTTP errors (range 100-599)
|
||||
if (mission.errObject != null && (mission.errCode < 100 || mission.errCode >= 600)) {
|
||||
@StringRes final int mMsg = msg;
|
||||
builder.setPositiveButton(R.string.error_report_title, (dialog, which) ->
|
||||
showError(mission.errObject, UserAction.DOWNLOAD_FAILED, mMsg)
|
||||
);
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
|
||||
builder.setTitle(mission.name)
|
||||
.setMessage(str)
|
||||
.setNegativeButton(android.R.string.ok, (dialog, which) -> dialog.cancel())
|
||||
builder.setNegativeButton(android.R.string.ok, (dialog, which) -> dialog.cancel())
|
||||
.setTitle(mission.storage.getName())
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showError(Exception exception, UserAction action, @StringRes int reason) {
|
||||
ErrorActivity.reportError(
|
||||
mContext,
|
||||
Collections.singletonList(exception),
|
||||
null,
|
||||
null,
|
||||
ErrorActivity.ErrorInfo.make(action, "-", "-", reason)
|
||||
);
|
||||
}
|
||||
|
||||
public void clearFinishedDownloads() {
|
||||
mDownloadManager.forgetFinishedDownloads();
|
||||
applyChanges();
|
||||
|
@ -466,16 +562,33 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
showError(mission);
|
||||
return true;
|
||||
case R.id.queue:
|
||||
h.queue.setChecked(!h.queue.isChecked());
|
||||
mission.enqueued = h.queue.isChecked();
|
||||
boolean flag = !h.queue.isChecked();
|
||||
h.queue.setChecked(flag);
|
||||
mission.setEnqueued(flag);
|
||||
updateProgress(h);
|
||||
return true;
|
||||
case R.id.retry:
|
||||
if (mission.hasInvalidStorage()) {
|
||||
mDownloadManager.tryRecover(mission);
|
||||
if (mission.storage.isInvalid())
|
||||
mRecover.tryRecover(mission);
|
||||
else
|
||||
recoverMission(mission);
|
||||
|
||||
return true;
|
||||
}
|
||||
mission.psContinue(true);
|
||||
return true;
|
||||
case R.id.cancel:
|
||||
mission.psContinue(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case R.id.open:
|
||||
return viewWithFileProvider(h.item.mission.getDownloadedFile());
|
||||
case R.id.menu_item_share:
|
||||
shareFile(h.item.mission);
|
||||
return true;
|
||||
case R.id.delete:
|
||||
if (mDeleter == null) {
|
||||
mDownloadManager.deleteMission(h.item.mission);
|
||||
|
@ -486,7 +599,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
return true;
|
||||
case R.id.md5:
|
||||
case R.id.sha1:
|
||||
new ChecksumTask(mContext).execute(h.item.mission.getDownloadedFile().getAbsolutePath(), ALGORITHMS.get(id));
|
||||
new ChecksumTask(mContext).execute(h.item.mission.storage, ALGORITHMS.get(id));
|
||||
return true;
|
||||
case R.id.source:
|
||||
/*Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(h.item.mission.source));
|
||||
|
@ -529,29 +642,74 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
}
|
||||
|
||||
public void setClearButton(MenuItem clearButton) {
|
||||
if (mClear == null) clearButton.setVisible(mIterator.hasFinishedMissions());
|
||||
if (mClear == null)
|
||||
clearButton.setVisible(mIterator.hasFinishedMissions());
|
||||
|
||||
mClear = clearButton;
|
||||
}
|
||||
|
||||
public void setMasterButtons(MenuItem startButton, MenuItem pauseButton) {
|
||||
boolean init = mStartButton == null || mPauseButton == null;
|
||||
|
||||
mStartButton = startButton;
|
||||
mPauseButton = pauseButton;
|
||||
|
||||
if (init) checkMasterButtonsVisibility();
|
||||
}
|
||||
|
||||
private void checkEmptyMessageVisibility() {
|
||||
int flag = mIterator.getOldListSize() > 0 ? View.GONE : View.VISIBLE;
|
||||
if (mEmptyMessage.getVisibility() != flag) mEmptyMessage.setVisibility(flag);
|
||||
}
|
||||
|
||||
private void checkMasterButtonsVisibility() {
|
||||
boolean[] state = mIterator.hasValidPendingMissions();
|
||||
|
||||
public void deleterDispose(Bundle bundle) {
|
||||
if (mDeleter != null) mDeleter.dispose(bundle);
|
||||
mStartButton.setVisible(state[0]);
|
||||
mPauseButton.setVisible(state[1]);
|
||||
}
|
||||
|
||||
public void deleterLoad(Bundle bundle, View view) {
|
||||
public void ensurePausedMissions() {
|
||||
for (ViewHolderItem h : mPendingDownloadsItems) {
|
||||
if (((DownloadMission) h.item.mission).running) continue;
|
||||
updateProgress(h);
|
||||
h.lastTimeStamp = -1;
|
||||
h.lastDone = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void deleterDispose(boolean commitChanges) {
|
||||
if (mDeleter != null) mDeleter.dispose(commitChanges);
|
||||
}
|
||||
|
||||
public void deleterLoad(View view) {
|
||||
if (mDeleter == null)
|
||||
mDeleter = new Deleter(bundle, view, mContext, this, mDownloadManager, mIterator, mHandler);
|
||||
mDeleter = new Deleter(view, mContext, this, mDownloadManager, mIterator, mHandler);
|
||||
}
|
||||
|
||||
public void deleterResume() {
|
||||
if (mDeleter != null) mDeleter.resume();
|
||||
}
|
||||
|
||||
public void recoverMission(DownloadMission mission) {
|
||||
for (ViewHolderItem h : mPendingDownloadsItems) {
|
||||
if (mission != h.item.mission) continue;
|
||||
|
||||
mission.errObject = null;
|
||||
mission.resetState(true, false, DownloadMission.ERROR_NOTHING);
|
||||
|
||||
h.status.setText(UNDEFINED_PROGRESS);
|
||||
h.state = -1;
|
||||
h.size.setText(Utility.formatBytes(mission.getLength()));
|
||||
h.progress.setMarquee(true);
|
||||
|
||||
mDownloadManager.resumeMission(mission);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean mUpdaterRunning = false;
|
||||
private final Runnable rUpdater = this::updater;
|
||||
|
@ -593,6 +751,10 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
return Float.isNaN(value) || Float.isInfinite(value);
|
||||
}
|
||||
|
||||
public void setRecover(@NonNull RecoverHelper callback) {
|
||||
mRecover = callback;
|
||||
}
|
||||
|
||||
|
||||
class ViewHolderItem extends RecyclerView.ViewHolder {
|
||||
DownloadManager.MissionItem item;
|
||||
|
@ -604,6 +766,8 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
ProgressDrawable progress;
|
||||
|
||||
PopupMenu popupMenu;
|
||||
MenuItem retry;
|
||||
MenuItem cancel;
|
||||
MenuItem start;
|
||||
MenuItem pause;
|
||||
MenuItem open;
|
||||
|
@ -636,22 +800,34 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
button.setOnClickListener(v -> showPopupMenu());
|
||||
|
||||
Menu menu = popupMenu.getMenu();
|
||||
retry = menu.findItem(R.id.retry);
|
||||
cancel = menu.findItem(R.id.cancel);
|
||||
start = menu.findItem(R.id.start);
|
||||
pause = menu.findItem(R.id.pause);
|
||||
open = menu.findItem(R.id.open);
|
||||
open = menu.findItem(R.id.menu_item_share);
|
||||
queue = menu.findItem(R.id.queue);
|
||||
showError = menu.findItem(R.id.error_message_view);
|
||||
delete = menu.findItem(R.id.delete);
|
||||
source = menu.findItem(R.id.source);
|
||||
checksum = menu.findItem(R.id.checksum);
|
||||
|
||||
itemView.setOnClickListener((v) -> {
|
||||
itemView.setHapticFeedbackEnabled(true);
|
||||
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (item.mission instanceof FinishedMission)
|
||||
viewWithFileProvider(item.mission.getDownloadedFile());
|
||||
viewWithFileProvider(item.mission);
|
||||
});
|
||||
|
||||
itemView.setOnLongClickListener(v -> {
|
||||
v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
showPopupMenu();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void showPopupMenu() {
|
||||
retry.setVisible(false);
|
||||
cancel.setVisible(false);
|
||||
start.setVisible(false);
|
||||
pause.setVisible(false);
|
||||
open.setVisible(false);
|
||||
|
@ -664,7 +840,20 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
DownloadMission mission = item.mission instanceof DownloadMission ? (DownloadMission) item.mission : null;
|
||||
|
||||
if (mission != null) {
|
||||
if (!mission.isPsRunning()) {
|
||||
if (mission.hasInvalidStorage()) {
|
||||
retry.setVisible(true);
|
||||
delete.setVisible(true);
|
||||
showError.setVisible(true);
|
||||
} else if (mission.isPsRunning()) {
|
||||
switch (mission.errCode) {
|
||||
case ERROR_INSUFFICIENT_STORAGE:
|
||||
case ERROR_POSTPROCESSING_HOLD:
|
||||
retry.setVisible(true);
|
||||
cancel.setVisible(true);
|
||||
showError.setVisible(true);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (mission.running) {
|
||||
pause.setVisible(true);
|
||||
} else {
|
||||
|
@ -713,7 +902,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
}
|
||||
|
||||
|
||||
static class ChecksumTask extends AsyncTask<String, Void, String> {
|
||||
static class ChecksumTask extends AsyncTask<Object, Void, String> {
|
||||
ProgressDialog progressDialog;
|
||||
WeakReference<Activity> weakReference;
|
||||
|
||||
|
@ -736,8 +925,8 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... params) {
|
||||
return Utility.checksum(params[0], params[1]);
|
||||
protected String doInBackground(Object... params) {
|
||||
return Utility.checksum((StoredFileHelper) params[0], (String) params[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -764,4 +953,8 @@ public class MissionAdapter extends Adapter<ViewHolder> {
|
|||
}
|
||||
}
|
||||
|
||||
public interface RecoverHelper {
|
||||
void tryRecover(DownloadMission mission);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package us.shandian.giga.ui.common;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.view.View;
|
||||
|
@ -23,8 +21,6 @@ public class Deleter {
|
|||
private static final int TIMEOUT = 5000;// ms
|
||||
private static final int DELAY = 350;// ms
|
||||
private static final int DELAY_RESUME = 400;// ms
|
||||
private static final String BUNDLE_NAMES = "us.shandian.giga.ui.common.deleter.names";
|
||||
private static final String BUNDLE_LOCATIONS = "us.shandian.giga.ui.common.deleter.locations";
|
||||
|
||||
private Snackbar snackbar;
|
||||
private ArrayList<Mission> items;
|
||||
|
@ -41,7 +37,7 @@ public class Deleter {
|
|||
private final Runnable rNext;
|
||||
private final Runnable rCommit;
|
||||
|
||||
public Deleter(Bundle b, View v, Context c, MissionAdapter a, DownloadManager d, MissionIterator i, Handler h) {
|
||||
public Deleter(View v, Context c, MissionAdapter a, DownloadManager d, MissionIterator i, Handler h) {
|
||||
mView = v;
|
||||
mContext = c;
|
||||
mAdapter = a;
|
||||
|
@ -55,27 +51,6 @@ public class Deleter {
|
|||
rCommit = this::commit;
|
||||
|
||||
items = new ArrayList<>(2);
|
||||
|
||||
if (b != null) {
|
||||
String[] names = b.getStringArray(BUNDLE_NAMES);
|
||||
String[] locations = b.getStringArray(BUNDLE_LOCATIONS);
|
||||
|
||||
if (names == null || locations == null) return;
|
||||
if (names.length < 1 || locations.length < 1) return;
|
||||
if (names.length != locations.length) return;
|
||||
|
||||
items.ensureCapacity(names.length);
|
||||
|
||||
for (int j = 0; j < locations.length; j++) {
|
||||
Mission mission = mDownloadManager.getAnyMission(locations[j], names[j]);
|
||||
if (mission == null) continue;
|
||||
|
||||
items.add(mission);
|
||||
mIterator.hide(mission);
|
||||
}
|
||||
|
||||
if (items.size() > 0) resume();
|
||||
}
|
||||
}
|
||||
|
||||
public void append(Mission item) {
|
||||
|
@ -104,7 +79,7 @@ public class Deleter {
|
|||
private void next() {
|
||||
if (items.size() < 1) return;
|
||||
|
||||
String msg = mContext.getString(R.string.file_deleted).concat(":\n").concat(items.get(0).name);
|
||||
String msg = mContext.getString(R.string.file_deleted).concat(":\n").concat(items.get(0).storage.getName());
|
||||
|
||||
snackbar = Snackbar.make(mView, msg, Snackbar.LENGTH_INDEFINITE);
|
||||
snackbar.setAction(R.string.undo, s -> forget());
|
||||
|
@ -125,7 +100,7 @@ public class Deleter {
|
|||
mDownloadManager.deleteMission(mission);
|
||||
|
||||
if (mission instanceof FinishedMission) {
|
||||
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(mission.getDownloadedFile())));
|
||||
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -151,27 +126,14 @@ public class Deleter {
|
|||
mHandler.postDelayed(rShow, DELAY_RESUME);
|
||||
}
|
||||
|
||||
public void dispose(Bundle bundle) {
|
||||
public void dispose(boolean commitChanges) {
|
||||
if (items.size() < 1) return;
|
||||
|
||||
pause();
|
||||
|
||||
if (bundle == null) {
|
||||
for (Mission mission : items) mDownloadManager.deleteMission(mission);
|
||||
items = null;
|
||||
return;
|
||||
}
|
||||
if (!commitChanges) return;
|
||||
|
||||
String[] names = new String[items.size()];
|
||||
String[] locations = new String[items.size()];
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
Mission mission = items.get(i);
|
||||
names[i] = mission.name;
|
||||
locations[i] = mission.location;
|
||||
}
|
||||
|
||||
bundle.putStringArray(BUNDLE_NAMES, names);
|
||||
bundle.putStringArray(BUNDLE_LOCATIONS, locations);
|
||||
for (Mission mission : items) mDownloadManager.deleteMission(mission);
|
||||
items = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package us.shandian.giga.ui.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -10,6 +10,8 @@ import android.content.SharedPreferences;
|
|||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
@ -18,23 +20,31 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
import us.shandian.giga.service.DownloadManager;
|
||||
import us.shandian.giga.service.DownloadManagerService;
|
||||
import us.shandian.giga.service.DownloadManagerService.DMBinder;
|
||||
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
|
||||
import us.shandian.giga.ui.adapter.MissionAdapter;
|
||||
|
||||
public class MissionsFragment extends Fragment {
|
||||
|
||||
private static final int SPAN_SIZE = 2;
|
||||
private static final int REQUEST_DOWNLOAD_PATH_SAF = 0x1230;
|
||||
|
||||
private SharedPreferences mPrefs;
|
||||
private boolean mLinear;
|
||||
private MenuItem mSwitch;
|
||||
private MenuItem mClear = null;
|
||||
private MenuItem mStart = null;
|
||||
private MenuItem mPause = null;
|
||||
|
||||
private RecyclerView mList;
|
||||
private View mEmpty;
|
||||
|
@ -43,21 +53,24 @@ public class MissionsFragment extends Fragment {
|
|||
private LinearLayoutManager mLinearManager;
|
||||
private Context mContext;
|
||||
|
||||
private DMBinder mBinder;
|
||||
private Bundle mBundle;
|
||||
private DownloadManagerBinder mBinder;
|
||||
private boolean mForceUpdate;
|
||||
|
||||
private DownloadMission unsafeMissionTarget = null;
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||
mBinder = (DownloadManagerService.DMBinder) binder;
|
||||
mBinder = (DownloadManagerBinder) binder;
|
||||
mBinder.clearDownloadNotifications();
|
||||
|
||||
mAdapter = new MissionAdapter(mContext, mBinder.getDownloadManager(), mClear, mEmpty);
|
||||
mAdapter.deleterLoad(mBundle, getView());
|
||||
mAdapter = new MissionAdapter(mContext, mBinder.getDownloadManager(), mEmpty);
|
||||
mAdapter.deleterLoad(getView());
|
||||
|
||||
mBundle = null;
|
||||
mAdapter.setRecover(MissionsFragment.this::recoverMission);
|
||||
|
||||
setAdapterButtons();
|
||||
|
||||
mBinder.addMissionEventListener(mAdapter.getMessenger());
|
||||
mBinder.enableNotifications(false);
|
||||
|
@ -74,15 +87,12 @@ public class MissionsFragment extends Fragment {
|
|||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.missions, container, false);
|
||||
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
mLinear = mPrefs.getBoolean("linear", false);
|
||||
|
||||
//mContext = getActivity().getApplicationContext();
|
||||
mBundle = savedInstanceState;
|
||||
|
||||
// Bind the service
|
||||
mContext.bindService(new Intent(mContext, DownloadManagerService.class), mConnection, Context.BIND_AUTO_CREATE);
|
||||
|
||||
|
@ -132,7 +142,7 @@ public class MissionsFragment extends Fragment {
|
|||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
mContext = activity.getApplicationContext();
|
||||
mContext = activity;
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,7 +154,7 @@ public class MissionsFragment extends Fragment {
|
|||
mBinder.removeMissionEventListener(mAdapter.getMessenger());
|
||||
mBinder.enableNotifications(true);
|
||||
mContext.unbindService(mConnection);
|
||||
mAdapter.deleterDispose(null);
|
||||
mAdapter.deleterDispose(true);
|
||||
|
||||
mBinder = null;
|
||||
mAdapter = null;
|
||||
|
@ -154,7 +164,11 @@ public class MissionsFragment extends Fragment {
|
|||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
mSwitch = menu.findItem(R.id.switch_mode);
|
||||
mClear = menu.findItem(R.id.clear_list);
|
||||
if (mAdapter != null) mAdapter.setClearButton(mClear);
|
||||
mStart = menu.findItem(R.id.start_downloads);
|
||||
mPause = menu.findItem(R.id.pause_downloads);
|
||||
|
||||
if (mAdapter != null) setAdapterButtons();
|
||||
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
|
@ -166,8 +180,23 @@ public class MissionsFragment extends Fragment {
|
|||
updateList();
|
||||
return true;
|
||||
case R.id.clear_list:
|
||||
mAdapter.clearFinishedDownloads();
|
||||
AlertDialog.Builder prompt = new AlertDialog.Builder(mContext);
|
||||
prompt.setTitle(R.string.clear_finished_download);
|
||||
prompt.setMessage(R.string.confirm_prompt);
|
||||
prompt.setPositiveButton(android.R.string.ok, (dialog, which) -> mAdapter.clearFinishedDownloads());
|
||||
prompt.setNegativeButton(R.string.cancel, null);
|
||||
prompt.create().show();
|
||||
return true;
|
||||
case R.id.start_downloads:
|
||||
item.setVisible(false);
|
||||
mPause.setVisible(true);
|
||||
mBinder.getDownloadManager().startAllMissions();
|
||||
return true;
|
||||
case R.id.pause_downloads:
|
||||
item.setVisible(false);
|
||||
mStart.setVisible(true);
|
||||
mBinder.getDownloadManager().pauseAllMissions(false);
|
||||
mAdapter.ensurePausedMissions();// update items view
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
@ -193,9 +222,9 @@ public class MissionsFragment extends Fragment {
|
|||
int icon;
|
||||
|
||||
if (mLinear)
|
||||
icon = isLight ? R.drawable.ic_list_black_24dp : R.drawable.ic_list_white_24dp;
|
||||
else
|
||||
icon = isLight ? R.drawable.ic_grid_black_24dp : R.drawable.ic_grid_white_24dp;
|
||||
else
|
||||
icon = isLight ? R.drawable.ic_list_black_24dp : R.drawable.ic_list_white_24dp;
|
||||
|
||||
mSwitch.setIcon(icon);
|
||||
mSwitch.setTitle(mLinear ? R.string.grid : R.string.list);
|
||||
|
@ -203,12 +232,29 @@ public class MissionsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
private void setAdapterButtons() {
|
||||
if (mClear == null || mStart == null || mPause == null) return;
|
||||
|
||||
mAdapter.setClearButton(mClear);
|
||||
mAdapter.setMasterButtons(mStart, mPause);
|
||||
}
|
||||
|
||||
private void recoverMission(@NonNull DownloadMission mission) {
|
||||
unsafeMissionTarget = mission;
|
||||
StoredFileHelper.requestSafWithFileCreation(
|
||||
MissionsFragment.this,
|
||||
REQUEST_DOWNLOAD_PATH_SAF,
|
||||
mission.storage.getName(),
|
||||
mission.storage.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
if (mAdapter != null) {
|
||||
mAdapter.deleterDispose(outState);
|
||||
mAdapter.deleterDispose(false);
|
||||
mForceUpdate = true;
|
||||
mBinder.removeMissionEventListener(mAdapter.getMessenger());
|
||||
}
|
||||
|
@ -237,4 +283,23 @@ public class MissionsFragment extends Fragment {
|
|||
if (mAdapter != null) mAdapter.onPaused();
|
||||
if (mBinder != null) mBinder.enableNotifications(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode != REQUEST_DOWNLOAD_PATH_SAF || resultCode != Activity.RESULT_OK) return;
|
||||
|
||||
if (unsafeMissionTarget == null || data.getData() == null) {
|
||||
return;// unsafeMissionTarget cannot be null
|
||||
}
|
||||
|
||||
try {
|
||||
String tag = unsafeMissionTarget.storage.getTag();
|
||||
unsafeMissionTarget.storage = new StoredFileHelper(mContext, null, data.getData(), tag);
|
||||
mAdapter.recoverMission(unsafeMissionTarget);
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(mContext, R.string.general_error, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,14 +9,15 @@ import android.support.annotation.DrawableRes;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.streams.io.SharpStream;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
|
@ -25,7 +26,8 @@ import java.io.Serializable;
|
|||
import java.net.HttpURLConnection;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Locale;
|
||||
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
|
||||
public class Utility {
|
||||
|
||||
|
@ -80,6 +82,7 @@ public class Utility {
|
|||
objectInputStream = new ObjectInputStream(new FileInputStream(file));
|
||||
object = (T) objectInputStream.readObject();
|
||||
} catch (Exception e) {
|
||||
Log.e("Utility", "Failed to deserialize the object", e);
|
||||
object = null;
|
||||
}
|
||||
|
||||
|
@ -206,7 +209,7 @@ public class Utility {
|
|||
Toast.makeText(context, R.string.msg_copied, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public static String checksum(String path, String algorithm) {
|
||||
public static String checksum(StoredFileHelper source, String algorithm) {
|
||||
MessageDigest md;
|
||||
|
||||
try {
|
||||
|
@ -215,11 +218,11 @@ public class Utility {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
FileInputStream i;
|
||||
SharpStream i;
|
||||
|
||||
try {
|
||||
i = new FileInputStream(path);
|
||||
} catch (FileNotFoundException e) {
|
||||
i = source.getStream();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
@ -247,15 +250,15 @@ public class Utility {
|
|||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public static boolean mkdir(File path, boolean allDirs) {
|
||||
if (path.exists()) return true;
|
||||
public static boolean mkdir(File p, boolean allDirs) {
|
||||
if (p.exists()) return true;
|
||||
|
||||
if (allDirs)
|
||||
path.mkdirs();
|
||||
p.mkdirs();
|
||||
else
|
||||
path.mkdir();
|
||||
p.mkdir();
|
||||
|
||||
return path.exists();
|
||||
return p.exists();
|
||||
}
|
||||
|
||||
public static long getContentLength(HttpURLConnection connection) {
|
||||
|
@ -264,8 +267,7 @@ public class Utility {
|
|||
}
|
||||
|
||||
try {
|
||||
long length = Long.parseLong(connection.getHeaderField("Content-Length"));
|
||||
if (length >= 0) return length;
|
||||
return Long.parseLong(connection.getHeaderField("Content-Length"));
|
||||
} catch (Exception err) {
|
||||
// nothing to do
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 135 B |
After Width: | Height: | Size: 138 B |
After Width: | Height: | Size: 109 B |
After Width: | Height: | Size: 112 B |
After Width: | Height: | Size: 162 B |
After Width: | Height: | Size: 139 B |
After Width: | Height: | Size: 196 B |
After Width: | Height: | Size: 206 B |
After Width: | Height: | Size: 248 B |
After Width: | Height: | Size: 254 B |
|
@ -7,6 +7,18 @@
|
|||
android:title="@string/grid"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item android:id="@+id/start_downloads"
|
||||
android:visible="false"
|
||||
android:icon="?attr/play"
|
||||
android:title="@string/start_downloads"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item android:id="@+id/pause_downloads"
|
||||
android:visible="false"
|
||||
android:icon="?attr/pause"
|
||||
android:title="@string/pause_downloads"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item android:id="@+id/clear_list"
|
||||
android:visible="false"
|
||||
android:icon="?attr/ic_delete"
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/retry"
|
||||
android:title="@string/retry" />
|
||||
|
||||
<item
|
||||
android:id="@+id/cancel"
|
||||
android:title="@string/cancel" />
|
||||
|
||||
<item
|
||||
android:id="@+id/start"
|
||||
android:title="@string/start" />
|
||||
|
@ -13,8 +22,8 @@
|
|||
android:checkable="true"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/open"
|
||||
android:title="@string/view" />
|
||||
android:id="@+id/menu_item_share"
|
||||
android:title="@string/share" />
|
||||
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<string name="light_theme_title">مضيء</string>
|
||||
<string name="list_thumbnail_view_description">صور معاينة الفيديو</string>
|
||||
<string name="network_error">خطأ في الشبكة</string>
|
||||
<string name="next_video_title">التالى</string>
|
||||
<string name="next_video_title">التالي</string>
|
||||
<string name="no_player_found">لا يوجد مشغل فيديو. هل تريد تثبيت VLC ؟</string>
|
||||
<string name="open_in_browser">افتح في المتصفح</string>
|
||||
<string name="play_audio">الصوت</string>
|
||||
|
@ -38,15 +38,15 @@
|
|||
<string name="settings">الإعدادات</string>
|
||||
<string name="settings_category_appearance_title">المظهر</string>
|
||||
<string name="settings_category_other_title">اخرى</string>
|
||||
<string name="settings_category_video_audio_title">الفيديو & الصوتيات</string>
|
||||
<string name="settings_category_video_audio_title">الفيديو و الصوتيات</string>
|
||||
<string name="share">مشاركة</string>
|
||||
<string name="share_dialog_title">مشاركة بواسطة</string>
|
||||
<string name="show_next_and_similar_title">عرض مقاطع الفيديو \"التالية\" و \"شبيه\"</string>
|
||||
<string name="show_next_and_similar_title">عرض مقاطع الفيديو \"التالية\" و \"المشابهة\"</string>
|
||||
<string name="show_play_with_kodi_summary">عرض خيار لتشغيل الفيديو بواسطة مشغل كودي</string>
|
||||
<string name="show_play_with_kodi_title">عرض خيار التشغيل بواسطة كودي</string>
|
||||
<string name="theme_title">السمة</string>
|
||||
<string name="upload_date_text">تم النشر يوم %1$s</string>
|
||||
<string name="url_not_supported_toast">رابط غير معتمد URL</string>
|
||||
<string name="url_not_supported_toast">رابط URL غير معتمد</string>
|
||||
<string name="use_external_audio_player_title">استخدام مشغل صوت خارجي</string>
|
||||
<string name="use_external_video_player_title">استخدام مشغل فيديو خارجي</string>
|
||||
<string name="use_tor_summary">(إختبارية) إجراء التنزيلات من خلال استخدام بروكسي Tor لزيادة الخصوصية ( تشغيل الفيديو المباشر غير مدعوم حتى الأن ).</string>
|
||||
|
@ -58,19 +58,17 @@
|
|||
<string name="general_error">خطأ</string>
|
||||
<string name="parsing_error">تعذرت عملية تحليل الموقع</string>
|
||||
<string name="youtube_signature_decryption_error">تعذر فك تشفير توقيع رابط الفيديو</string>
|
||||
<string name="main_bg_subtitle">اضغط بحث للبدء</string>
|
||||
<string name="main_bg_subtitle">اضغط بحث للبدء</string>
|
||||
<string name="subscribe_button_title">اشتراك</string>
|
||||
<string name="subscribed_button_title">مشترك</string>
|
||||
<string name="tab_main">الرئيسية</string>
|
||||
<string name="tab_subscriptions">الاشتراكات</string>
|
||||
|
||||
<string name="fragment_whats_new">ما الجديد</string>
|
||||
|
||||
<string name="controls_background_title">في الخلفية</string>
|
||||
<string name="autoplay_by_calling_app_title">تشغيل تلقائي</string>
|
||||
<string name="black_theme_title">اسود</string>
|
||||
<string name="enable_watch_history_title">التاريخ وذاكرة التخزين المؤقت</string>
|
||||
<string name="settings_category_history_title">التاريخ & ذاكرة التخزين المؤقت</string>
|
||||
<string name="settings_category_history_title">التاريخ و ذاكرة التخزين المؤقت</string>
|
||||
<string name="content">المحتوى</string>
|
||||
<string name="downloads">التنزيلات</string>
|
||||
<string name="downloads_title">التنزيلات</string>
|
||||
|
@ -83,14 +81,12 @@
|
|||
<string name="title_activity_history">التاريخ</string>
|
||||
<string name="action_history">التاريخ</string>
|
||||
<string name="open_in_popup_mode">افتح في وضع النافذة المنبثقة</string>
|
||||
<string name="use_external_video_player_summary">يزيل الصوت في بعض القرارات</string>
|
||||
<string name="use_external_video_player_summary">يزيل الصوت في بعض الخيارات</string>
|
||||
<string name="popup_mode_share_menu_title">وضع النوافذ المنبثقة NewPipe</string>
|
||||
<string name="channel_unsubscribed">تم إلغاء الاشتراك في القناة</string>
|
||||
<string name="subscription_change_failed">تعذر تغيير حالة الاشتراك</string>
|
||||
<string name="subscription_update_failed">تعذر تحديث الاشتراك</string>
|
||||
|
||||
<string name="controls_popup_title">نافذة المنبثقة</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_summary">تشغيل مقطع الفيديو عند إستدعاء NewPipe من تطبيق آخر</string>
|
||||
<string name="default_popup_resolution_title">الدقة الافتراضية لنوافذ المنبثقة</string>
|
||||
<string name="show_higher_resolutions_title">"عرض أعلى جودة "</string>
|
||||
|
@ -130,22 +126,18 @@
|
|||
<string name="best_resolution">أفضل دقة</string>
|
||||
<string name="undo">تراجع</string>
|
||||
<string name="play_all">تشغيل الكل</string>
|
||||
|
||||
<string name="notification_channel_name">تنبيهات NewPipe</string>
|
||||
<string name="notification_channel_description">تنبيهات مشغل NewPipe للخلفية والنوافذ المنبثقة</string>
|
||||
|
||||
<string name="unknown_content">[غير معروف]</string>
|
||||
|
||||
<string name="light_parsing_error">لا يمكن تحليل الموقع بشكل كلي</string>
|
||||
<string name="could_not_setup_download_menu">تعذرت عملية إعداد قائمة التنزيل</string>
|
||||
<string name="live_streams_not_supported">لبث المباشر غير مدعوم حتى الآن</string>
|
||||
<string name="live_streams_not_supported">البث المباشر غير مدعوم حتى الآن</string>
|
||||
<string name="could_not_get_stream">تعذر الحصول على أي بث</string>
|
||||
<string name="could_not_load_image">تعذرت عملية تحميل الصورة</string>
|
||||
<string name="app_ui_crash">تعطل التطبيق / واجهة المستخدم</string>
|
||||
<string name="player_stream_failure">لا يمكن تشغيل هذا البث</string>
|
||||
<string name="player_unrecoverable_failure">حدث خطأ للمشغل غير قابل للاسترداد</string>
|
||||
<string name="player_recoverable_failure">استرداد المشغل من الخطأ</string>
|
||||
|
||||
<string name="sorry_string">عذرا، لا ينبغي أن يحدث ذلك.</string>
|
||||
<string name="error_report_button_text">الإبلاغ عن خطأ عبر البريد الإلكتروني</string>
|
||||
<string name="error_snackbar_message">عذرا، حدثت بعض الأخطاء.</string>
|
||||
|
@ -155,31 +147,25 @@
|
|||
<string name="info_labels">ماذا:\\nطلب:\\nيحتوى اللغة:\\nSالخدمات:\\nتوقيت غرينتش:\\nحزمة:\\nالإصدار:\\nOS إصدار نظام التشغيل:</string>
|
||||
<string name="your_comment">تعليقك (باللغة الإنجليزية):</string>
|
||||
<string name="error_details_headline">التفاصيل:</string>
|
||||
|
||||
|
||||
<string name="report_error">الإبلاغ عن خطأ</string>
|
||||
<string name="user_report">تقرير المستخدم</string>
|
||||
<string name="search_no_results">لم يتم العثور على نتائج</string>
|
||||
<string name="empty_subscription_feed_subtitle">لا شيء هنا غير الصراصير</string>
|
||||
|
||||
<string name="audio">الصوت</string>
|
||||
<string name="retry">إعادة المحاولة</string>
|
||||
<string name="storage_permission_denied">تم رفض إذن الوصول إلى التخزين</string>
|
||||
|
||||
<string name="short_thousand">ألف</string>
|
||||
<string name="short_million">مليون</string>
|
||||
<string name="short_billion">بليون</string>
|
||||
|
||||
<string name="no_subscribers">ليس هناك مشترِكون</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="zero">%s لا يوجد مشترك</item>
|
||||
<item quantity="one">%s مشترك</item>
|
||||
<item quantity="two">%s اثنتين مشتركين</item>
|
||||
<item quantity="few">%s اشتراكات</item>
|
||||
<item quantity="many">%s مشتركين</item>
|
||||
<item quantity="other">%s مشتركون</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="zero">%s لا يوجد مشترك</item>
|
||||
<item quantity="one">%s مشترك</item>
|
||||
<item quantity="two">%s اثنتين مشتركين</item>
|
||||
<item quantity="few">%s اشتراكات</item>
|
||||
<item quantity="many">%s مشتركين</item>
|
||||
<item quantity="other">%s مشتركون</item>
|
||||
</plurals>
|
||||
<string name="no_views">دون مشاهدات</string>
|
||||
<string name="no_videos">لاتوجد فيديوهات</string>
|
||||
<string name="start">ابدأ</string>
|
||||
|
@ -187,10 +173,8 @@
|
|||
<string name="view">شغل</string>
|
||||
<string name="delete">حذف</string>
|
||||
<string name="checksum">التوقيع</string>
|
||||
|
||||
<string name="add">مهمة جديدة</string>
|
||||
<string name="finish">حسناً</string>
|
||||
|
||||
<string name="msg_name">اسم الملف</string>
|
||||
<string name="msg_threads">التقسيم</string>
|
||||
<string name="msg_error">الخطأ</string>
|
||||
|
@ -204,15 +188,12 @@
|
|||
<string name="no_available_dir">الرجاء تحديد مجلد لحفظ التنزيلات</string>
|
||||
<string name="msg_popup_permission">هذا الإذن مطلوب
|
||||
\nللفتح في وضع النافذة المنبثقة</string>
|
||||
|
||||
<string name="reCaptchaActivity">اختبار reCAPTCHA</string>
|
||||
<string name="settings_file_charset_title">السماح بالرموز في أسماء الملفات</string>
|
||||
<string name="settings_file_replacement_character_summary">يتم استبدال الرموز غير المسموح بها بهذه القيمة</string>
|
||||
<string name="settings_file_replacement_character_title">استبدال الحرف</string>
|
||||
|
||||
<string name="charset_letters_and_digits">الحروف والأرقام</string>
|
||||
<string name="charset_most_special_characters">معظم الأحرف الخاصة</string>
|
||||
|
||||
<string name="title_activity_about">عن تطبيق نيوپايپ</string>
|
||||
<string name="action_settings">الإعدادات</string>
|
||||
<string name="title_licenses">تراخيص الجهات الخارجية</string>
|
||||
|
@ -231,8 +212,6 @@
|
|||
<string name="website_encouragement">قم بزيارة موقع NewPipe لمزيد من المعلومات والمستجدات.</string>
|
||||
<string name="app_license_title">تراخيص NewPipe</string>
|
||||
<string name="read_full_license">قراءة الرخصة</string>
|
||||
|
||||
|
||||
<string name="title_history_search">التي تم البحث عنها</string>
|
||||
<string name="title_history_view">تمت مشاهدتها</string>
|
||||
<string name="history_disabled">تم تعطيل السجل</string>
|
||||
|
@ -240,7 +219,6 @@
|
|||
<string name="history_cleared">تم مسح التاريخ</string>
|
||||
<string name="item_deleted">تم حذف العنصر</string>
|
||||
<string name="delete_item_search_history">هل تريد حذف هذا العنصر من سجل البحث؟</string>
|
||||
|
||||
<string name="main_page_content">محتوى الشاشة الرئيسية</string>
|
||||
<string name="blank_page_summary">صفحة فارغة</string>
|
||||
<string name="subscription_page_summary">صفحة الاشتراك</string>
|
||||
|
@ -258,82 +236,67 @@
|
|||
<string name="play_queue_audio_settings">الإعدادات الصوتية</string>
|
||||
<string name="start_here_on_main">تشغيل هنا</string>
|
||||
<string name="start_here_on_popup">تشغيل هنا في وضع النافذة المنبثقة</string>
|
||||
<string name="reCaptcha_title">تحدي الكابتشا</string>
|
||||
<string name="reCaptcha_title">تحدي الكابتشا</string>
|
||||
<string name="hold_to_append">اضغط للإدراج في قائمة الانتظار</string>
|
||||
<plurals name="views">
|
||||
<item quantity="zero">بدون مشاهدات</item>
|
||||
<item quantity="one">%s مشاهدة</item>
|
||||
<item quantity="two">%s مشاهدتين</item>
|
||||
<item quantity="few">%s مشاهدون</item>
|
||||
<item quantity="many">%s مشاهدات</item>
|
||||
<item quantity="other">%s مشاهدين</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="zero">بدون مشاهدات</item>
|
||||
<item quantity="one">%s مشاهدة</item>
|
||||
<item quantity="two">%s مشاهدتين</item>
|
||||
<item quantity="few">%s مشاهدون</item>
|
||||
<item quantity="many">%s مشاهدات</item>
|
||||
<item quantity="other">%s مشاهدين</item>
|
||||
</plurals>
|
||||
<plurals name="videos">
|
||||
<item quantity="zero">%s فيديو</item>
|
||||
<item quantity="one">%s فيديو</item>
|
||||
<item quantity="two">%s فيديوهان</item>
|
||||
<item quantity="few">%s فيديو</item>
|
||||
<item quantity="many">%s فيديوهات</item>
|
||||
<item quantity="other">%s فيديو</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="zero">%s فيديو</item>
|
||||
<item quantity="one">%s فيديو</item>
|
||||
<item quantity="two">%s فيديوهان</item>
|
||||
<item quantity="few">%s فيديو</item>
|
||||
<item quantity="many">%s فيديوهات</item>
|
||||
<item quantity="other">%s فيديو</item>
|
||||
</plurals>
|
||||
<string name="recaptcha_request_toast">طلب اختبار الكابتشا مطلوب</string>
|
||||
|
||||
<string name="copyright" formatted="true">© %1$sبواسطة%2$sتحت%3$s</string>
|
||||
<string name="kiosk_page_summary">صفحة الكشك</string>
|
||||
<string name="select_a_kiosk">حدد كشك</string>
|
||||
|
||||
<string name="kiosk">الكشك</string>
|
||||
<string name="enqueue_on_background">إدراج في قائمة الانتظار في الخلفية</string>
|
||||
<string name="enqueue_on_popup">إدراج في قائمة الانتظار على المنبثقة</string>
|
||||
<string name="start_here_on_background">تشغيل في الخلفية</string>
|
||||
<string name="default_content_country_title">المحتوى الإفتراضي حسب البلد</string>
|
||||
<string name="default_content_country_title">المحتوى الإفتراضي حسب البلد</string>
|
||||
<string name="toggle_orientation">تغيير الإتجاه</string>
|
||||
<string name="switch_to_background">الإنتقال إلى التشغيل في الخلفية</string>
|
||||
<string name="switch_to_popup">الإنتقال إلى التشغيل في النافذة المنبثقة</string>
|
||||
<string name="switch_to_main">الإنتقال إلى الرئيسية</string>
|
||||
|
||||
<string name="service_title">الخدمة</string>
|
||||
<string name="drawer_open">فتح الدرج</string>
|
||||
<string name="drawer_close">إغلاق الدرج</string>
|
||||
<string name="always">دائماً</string>
|
||||
<string name="just_once">مرة واحدة فقط</string>
|
||||
|
||||
<string name="invalid_url_toast">العنوان خاطئ</string>
|
||||
<string name="no_player_found_toast">لم يتم العثور على مشغل تدفق (يمكنك تثبيت VLC وتشغيله).</string>
|
||||
<string name="no_player_found_toast">لم يتم العثور على مشغل الفيديو (يمكنك تثبيت VLC وتشغيله).</string>
|
||||
<string name="import_data_title">استيراد قاعدة البيانات</string>
|
||||
<string name="export_data_title">تصدير قاعدة البيانات</string>
|
||||
<string name="import_data_summary">"الكتابة فوق سجل التاريخ والاشتراكات الحالية "</string>
|
||||
<string name="export_data_summary">تصدير السجل، الإشتراكات وقوائم التشغيل</string>
|
||||
<string name="show_info">عرض المعلومات</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">إضافة إلى</string>
|
||||
|
||||
<string name="settings_category_debug_title">تحليل</string>
|
||||
<string name="video_streams_empty">لم يتم العثور على أي بث مرئي</string>
|
||||
<string name="audio_streams_empty">لم يتم العثور على أي بث صوتي</string>
|
||||
|
||||
<string name="detail_drag_description">إسحب للقيام بالترتيب</string>
|
||||
|
||||
<string name="create">إنشاء</string>
|
||||
<string name="delete_one">إحذف واحدة</string>
|
||||
<string name="delete_all">حذف الكل</string>
|
||||
<string name="dismiss">إلغاء</string>
|
||||
<string name="rename">إعادة التسمية</string>
|
||||
|
||||
<string name="export_complete_toast">تمت عملية التصدير</string>
|
||||
<string name="import_complete_toast">إكتَملَت عملية الإستيراد</string>
|
||||
<string name="could_not_import_all_files">تنبيه : تعذرت عملية استيراد كافة الملفات.</string>
|
||||
<string name="drawer_header_action_paceholder_text">سوف يظهر شيء هنا قريبا ;D</string>
|
||||
|
||||
|
||||
<string name="video_player">مشغل الفيديو</string>
|
||||
<string name="always_ask_open_action">السؤال دائماً</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">الحصول على المعلومات …</string>
|
||||
<string name="preferred_player_fetcher_notification_message">تحميل المحتوى المطلوب</string>
|
||||
|
||||
<string name="create_playlist">إنشاء قائمة تشغيل جديدة</string>
|
||||
<string name="delete_playlist">حذف قائمة التشغيل</string>
|
||||
<string name="rename_playlist">"إعادة تسمية قائمة التشغيل "</string>
|
||||
|
@ -343,60 +306,52 @@
|
|||
<string name="playlist_creation_success">تم إنشاء قائمة التشغيل</string>
|
||||
<string name="playlist_add_stream_success">تمت إضافتها إلى قائمة التشغيل</string>
|
||||
<string name="playlist_delete_failure">لا يمكن حذف قائمة التشغيل.</string>
|
||||
|
||||
<string name="resize_fill">ملئ الشاشة</string>
|
||||
<string name="resize_zoom">تكبير</string>
|
||||
|
||||
<string name="caption_font_size_settings_title">حجم خط التسمية</string>
|
||||
<string name="smaller_caption_font_size">أصغر خط</string>
|
||||
<string name="normal_caption_font_size">خط عادي</string>
|
||||
<string name="larger_caption_font_size">خط ذو حجم كبير</string>
|
||||
<string name="live_sync">مُزامَنة</string>
|
||||
<string name="controls_download_desc">تنزيل ملف البث</string>
|
||||
<string name="tab_bookmarks">الإشارات المرجعية</string>
|
||||
|
||||
<string name="use_inexact_seek_title">استعمال التقديم السريع الغير دقيق</string>
|
||||
<string name="use_inexact_seek_summary">"التقديم الغير دقيق يسمح للمشغل بالإطلاع الى الأماكن بشكل اسرع مع دقة اقل "</string>
|
||||
<string name="download_thumbnail_title">تحميل الصور المصغرة</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">تم إفراغ مساحة ذاكرة التخزين المؤقتة الخاصة بالصور</string>
|
||||
<string name="file">الملف</string>
|
||||
|
||||
<string name="invalid_directory">لا يوجد مثل هذا المجلد</string>
|
||||
<string name="file_name_empty_error">لا يمكن أن يكون اسم الملف فارغا</string>
|
||||
<string name="error_occurred_detail">طرأ هناك خطأ: %1$s</string>
|
||||
<string name="no_valid_zip_file">ملف مضغوط ZIP غير صالح</string>
|
||||
<string name="unbookmark_playlist">إزالة الفواصل المرجعية</string>
|
||||
|
||||
<string name="resize_fit">تناسب مع الشاشة</string>
|
||||
<string name="caption_auto_generated">توليد تلقائي</string>
|
||||
|
||||
<string name="import_export_title">إستيراد او تصدير</string>
|
||||
<string name="import_title">إستيراد</string>
|
||||
<string name="import_from">إستعادة مِن</string>
|
||||
<string name="export_to">تصدير إلى</string>
|
||||
|
||||
<string name="import_ongoing">عملية الإستعادة جارية …</string>
|
||||
<string name="export_ongoing">عملية التصدير جارية …</string>
|
||||
|
||||
<string name="import_file_title">إستيراد ملف</string>
|
||||
<string name="import_soundcloud_instructions_hint">"معرفك , soundcloud.com/ الخاص بك "</string>
|
||||
|
||||
<string name="download_thumbnail_summary">عند إيقاف تحميل أي صور مصغرة ، وتوفير البيانات واستخدام الذاكرة. تعمل التغييرات على محو ذاكرة التخزين المؤقت للصورة الموجودة على الذاكرة أو على القرص.</string>
|
||||
<string name="playback_default">إفتراضي</string>
|
||||
<string name="download_thumbnail_summary">عند إيقاف تحميل أي صور مصغرة ، وتوفير البيانات واستخدام الذاكرة. تعمل التغييرات على محو ذاكرة التخزين المؤقت للصورة الموجودة على الذاكرة أو على القرص.</string>
|
||||
<string name="metadata_cache_wipe_title">امسح البيانات الوصفية المخزنة مؤقتًا</string>
|
||||
<string name="metadata_cache_wipe_summary">إزالة جميع بيانات صفحات الويب المخزنة مؤقتًا</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">تم محو ذاكرة التخزين المؤقت للبيانات الوصفية</string>
|
||||
<string name="auto_queue_title">وضع البث القادم تلقائيا في قائمة الإنتظار</string>
|
||||
<string name="auto_queue_summary">رفض التدفق-التلقائي المشابه في حال كان التدفق السابق يعمل في-حالة عدم التكرار.</string>
|
||||
<string name="set_as_playlist_thumbnail">إضافة صورة مصغرة إلى قائمة التشغيل</string>
|
||||
|
||||
<string name="bookmark_playlist">تفضيل قائمة التشغيل</string>
|
||||
<string name="playlist_thumbnail_change_success">تم تغيير الصورة المصغرة لقائمة التشغيل.</string>
|
||||
<string name="caption_none">بدون تسميات توضيحية</string>
|
||||
|
||||
<string name="caption_setting_title">تسميات توضيحية</string>
|
||||
<string name="caption_setting_description">تعديل مشغل نص التسمية التوضيحية وأنماط الخلفية. يتطلب إعادة تشغيل التطبيق لتصبح التغييرات سارية المفعول.</string>
|
||||
|
||||
<string name="enable_leak_canary_title">تمكين LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">قد تتسبب مراقبة تسرب الذاكرة في عدم استجابة التطبيق عند تفريغ السجلات</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">تقرير الأخطاء خارج دورة الحياة</string>
|
||||
<string name="enable_disposed_exceptions_summary">فرض الإبلاغ عن استثناءات Rx غير القابلة للتسليم خارج دورة حياة الجزء أو النشاط بعد التخلص منها</string>
|
||||
|
||||
<string name="clear_views_history_title">محو سجل المشاهدة</string>
|
||||
<string name="clear_views_history_summary">احذف سِجل الفيديوهات التي تم تشغيلها</string>
|
||||
<string name="delete_view_history_alert">حذف سجل المشاهدة بالكامل\?</string>
|
||||
|
@ -409,29 +364,21 @@
|
|||
<string name="invalid_source">لا يوجد مثل هذا الملف/مصدر المحتوى</string>
|
||||
<string name="invalid_file">الملف غير موجود أو الإذن بالقراءة أو الكتابة إليه غير موجود</string>
|
||||
<string name="no_streams_available_download">لا يوجد بث متاح للتنزيل</string>
|
||||
|
||||
<string name="one_item_deleted">تم حذف عنصر واحد.</string>
|
||||
|
||||
<string name="toast_no_player">لم يتم تثبيت أي تطبيق لتشغيل هذا الملف</string>
|
||||
|
||||
<string name="app_license">NewPipe هو برنامج مفتوح المصدر حقوق متروكة: يمكنك استخدام الكود ودراسته وتحسينه كما شئت. و على وجه التحديد يمكنك إعادة توزيعه / أو تعديله تحت شروط رخصة GNU العمومية والتي نشرتها مؤسسة البرمجيات الحرة، سواء الإصدار 3 من الرخصة، أو (باختيارك) أي إصدار جديد.</string>
|
||||
<string name="app_license">NewPipe هو برنامج مفتوح المصدر و بحقوق متروكة: يمكنك استخدام الكود ودراسته وتحسينه كما شئت. و على وجه التحديد يمكنك إعادة توزيعه / أو تعديله تحت شروط رخصة GNU العمومية والتي نشرتها مؤسسة البرمجيات الحرة، سواء الإصدار 3 من الرخصة، أو (باختيارك) أي إصدار جديد.</string>
|
||||
<string name="delete_stream_history_prompt">هل تريد حذف هذا العنصر من سجل المشاهدة؟</string>
|
||||
<string name="delete_all_history_prompt">هل أنت متأكد من أنك تريد حذف كل العناصر من السجل؟</string>
|
||||
<string name="title_last_played">آخر ما تم تشغيله</string>
|
||||
<string name="title_most_played">الأكثر تشغيلا</string>
|
||||
|
||||
<string name="override_current_data">هذا سوف يُزيل إعداداتك الحالية.</string>
|
||||
|
||||
<string name="preferred_open_action_settings_title">طريقة \'التشغيل\' المفضلة</string>
|
||||
<string name="preferred_open_action_settings_summary">"الإجراء الافتراضي عند فتح المحتوى — %s"</string>
|
||||
|
||||
<string name="background_player">مشغل الخلفية</string>
|
||||
<string name="popup_player">المشغل المنبثق</string>
|
||||
<string name="previous_export">نسخة احتياطية</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">تعذر استيراد الاشتراكات</string>
|
||||
<string name="subscriptions_export_unsuccessful">لا يمكن تصدير الاشتراكات</string>
|
||||
|
||||
<string name="import_youtube_instructions">استيراد اشتراكات YouTube عن طريق تنزيل ملف التصدير:
|
||||
\n
|
||||
\n1. انتقل إلى عنوان URL هذا: %1$s
|
||||
|
@ -446,13 +393,11 @@
|
|||
<string name="import_network_expensive_warning">ضع في اعتبارك أن هذه العملية يمكن أن تكون مكلفة اذا كنت تستخدم بيانات اشتراك انترنت.
|
||||
\n
|
||||
\nهل تريد الاستمرار؟</string>
|
||||
|
||||
<string name="playback_speed_control">ضوابط سرعة التشغيل</string>
|
||||
<string name="playback_tempo">سرعة الأداء</string>
|
||||
<string name="playback_pitch">تردد الصوت</string>
|
||||
<string name="unhook_checkbox">نزع الإرتباط (قد يسبب تشويه)</string>
|
||||
<string name="import_settings">هل تريد أيضا استيراد الإعدادات؟</string>
|
||||
|
||||
<string name="privacy_policy_title">"سياسة الخصوصية في NewPipe "</string>
|
||||
<string name="privacy_policy_encouragement">يأخذ مشروع NewPipe خصوصيتك على محمل الجد. لذلك ، لا يجمع التطبيق أي بيانات دون موافقتك.
|
||||
\nتوضح سياسة خصوصية NewPipe بالتفصيل البيانات التي يتم إرسالها وتخزينها عند إرسال تقرير الأعطال.</string>
|
||||
|
@ -461,20 +406,17 @@
|
|||
\nو يجب عليك قبولها لإرسال تقرير الأخطاء إلينا.</string>
|
||||
<string name="accept">قبول</string>
|
||||
<string name="decline">رفض</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">لا حدود</string>
|
||||
<string name="limit_mobile_data_usage_title">الحد من جودة الفيديو عند استخدام بيانات الهاتف المحمول</string>
|
||||
<string name="skip_silence_checkbox">تسريع إلى الأمام أثناء الصمت</string>
|
||||
<string name="playback_step">خطوة</string>
|
||||
<string name="playback_reset">إعادة تعيين</string>
|
||||
|
||||
<string name="minimize_on_exit_title">تصغير عند تبديل التطبيق</string>
|
||||
<string name="minimize_on_exit_summary">الإجراء عند التبديل إلى تطبيق آخر من مشغل الفيديو الرئيسي — %s</string>
|
||||
<string name="minimize_on_exit_none_description">لاشيء</string>
|
||||
<string name="minimize_on_exit_background_description">تصغير إلى مشغل الخلفية</string>
|
||||
<string name="minimize_on_exit_popup_description">تصغير إلى مشغل منبثق</string>
|
||||
|
||||
<string name="channels">القنوات</string>
|
||||
<string name="channels">القنوات</string>
|
||||
<string name="playlists">قوائم التشغيل</string>
|
||||
<string name="tracks">المسارات</string>
|
||||
<string name="users">المستخدمين</string>
|
||||
|
@ -490,8 +432,8 @@
|
|||
<string name="volume_gesture_control_title">إيماءة التحكم بالصوت</string>
|
||||
<string name="events">الأحداث</string>
|
||||
<string name="app_update_notification_channel_description">التنبيه بإصدارات newpipe الجديدة</string>
|
||||
<string name="download_to_sdcard_error_title">ذاكرة التخزين الخارجي غير متوفر</string>
|
||||
<string name="download_to_sdcard_error_message">تحميل إلى بطاقة SD الخارجية ليس متاحا حتى الآن. إعادة تعيين موقع مجلد التحميل؟</string>
|
||||
<string name="download_to_sdcard_error_title">ذاكرة التخزين الخارجي غير متوفرة</string>
|
||||
<string name="download_to_sdcard_error_message">التحميل إلى بطاقة الذاكرة الخارجية ليس متاحا حتى الآن. إعادة تعيين موقع مجلد التحميل؟</string>
|
||||
<string name="saved_tabs_invalid_json">باستخدام علامات الجدولة الافتراضية، حدث خطأ أثناء قراءة علامات التبويب المحفوظة</string>
|
||||
<string name="restore_defaults">استعادة الافتراضيات</string>
|
||||
<string name="restore_defaults_confirmation">هل تريد استعادة الإعدادات الافتراضية؟</string>
|
||||
|
@ -509,10 +451,10 @@
|
|||
<string name="app_update_notification_content_title">يتوفر تحديث ل newpipe!</string>
|
||||
<string name="app_update_notification_content_text">اضغط لتنزيل</string>
|
||||
<string name="missions_header_finished">انتهى</string>
|
||||
<string name="missions_header_pending">في قائمة الانتظار</string>
|
||||
<string name="missions_header_pending">ريثما</string>
|
||||
<string name="paused">متوقف</string>
|
||||
<string name="queued">في قائمة الانتظار</string>
|
||||
<string name="post_processing">بعد المعالجة</string>
|
||||
<string name="post_processing">قيد المعالجة</string>
|
||||
<string name="enqueue">قائمة الانتظار</string>
|
||||
<string name="permission_denied">تم رفضها من قبل النظام</string>
|
||||
<string name="download_failed">فشل التنزيل</string>
|
||||
|
@ -520,12 +462,12 @@
|
|||
<string name="download_finished_more">%s أنتهى التحميل</string>
|
||||
<string name="generate_unique_name">إنشاء اسم فريد</string>
|
||||
<string name="overwrite">الكتابة فوق</string>
|
||||
<string name="overwrite_warning">يوجد ملف تحميل بهذا الاسم موجود مسبقاً</string>
|
||||
<string name="overwrite_finished_warning">يوجد ملف تحميل بهذا الاسم موجود مسبقاً</string>
|
||||
<string name="download_already_running">هنالك تحميل قيد التقدم بهذا الاسم</string>
|
||||
<string name="show_error">إظهار خطأ</string>
|
||||
<string name="label_code">كود</string>
|
||||
<string name="error_path_creation">لا يمكن إنشاء الملف</string>
|
||||
<string name="error_file_creation">لا يمكن إنشاء المجلد الوجهة</string>
|
||||
<string name="error_file_creation">لا يمكن إنشاء الملف</string>
|
||||
<string name="error_path_creation">لا يمكن إنشاء المجلد الوجهة</string>
|
||||
<string name="error_permission_denied">تم رفضها من قبل النظام</string>
|
||||
<string name="error_ssl_exception">فشل اتصال الأمن</string>
|
||||
<string name="error_unknown_host">تعذر العثور على الخادم</string>
|
||||
|
@ -535,7 +477,7 @@
|
|||
<string name="error_http_requested_range_not_satisfiable">عدم استيفاء النطاق المطلوب</string>
|
||||
<string name="error_http_not_found">غير موجود</string>
|
||||
<string name="error_postprocessing_failed">فشلت المعالجة الاولية</string>
|
||||
<string name="clear_finished_download">حذف التنزيل المنتهية</string>
|
||||
<string name="clear_finished_download">حذف التنزيلات المنتهية</string>
|
||||
<string name="msg_pending_downloads">"قم بإستكمال %s حيثما يتم التحويل من التنزيلات"</string>
|
||||
<string name="stop">توقف</string>
|
||||
<string name="max_retry_msg">أقصى عدد للمحاولات</string>
|
||||
|
|
|
@ -134,8 +134,6 @@
|
|||
<string name="later">Más sero</string>
|
||||
<string name="disabled">Desactivóse</string>
|
||||
|
||||
<string name="use_old_player_title">Usar reproductor vieyu</string>
|
||||
|
||||
|
||||
<string name="short_thousand">M</string>
|
||||
<string name="short_million">Mill</string>
|
||||
|
@ -168,8 +166,7 @@
|
|||
<string name="settings_category_popup_title">Ventanu emerxente</string>
|
||||
<string name="popup_resizing_indicator_title">Redimensionáu</string>
|
||||
|
||||
<string name="use_old_player_summary">Reproductor vieyu integráu de Mediaframework</string>
|
||||
<string name="subscribe_button_title">Soscribise</string>
|
||||
<string name="subscribe_button_title">Soscribise</string>
|
||||
<string name="subscribed_button_title">Soscribiéstite</string>
|
||||
<string name="channel_unsubscribed">Desoscribiéstite de la canal</string>
|
||||
<string name="subscription_change_failed">Nun pue camudase la resolución</string>
|
||||
|
@ -325,8 +322,7 @@
|
|||
<string name="video_player">Reproductor de videu</string>
|
||||
<string name="background_player">Reproductor en segundu planu</string>
|
||||
<string name="popup_player">Reproductor en ventanu</string>
|
||||
<string name="always_ask_player">Entrugar siempres</string>
|
||||
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Consiguiendo información…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Ta cargando\'l conteníu solicitáu</string>
|
||||
<string name="controls_download_desc">Baxa\'l ficheru del fluxu.</string>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources><string name="main_bg_subtitle">Націсніце пошук, каб пачаць</string>
|
||||
<resources>
|
||||
<string name="main_bg_subtitle">Націсніце пошук, каб пачаць</string>
|
||||
<string name="view_count_text">%1$s праглядаў</string>
|
||||
<string name="upload_date_text">Апублікавана %1$s</string>
|
||||
<string name="no_player_found">Патокавы плэер не знойдзены. Усталяваць VLC?</string>
|
||||
|
@ -27,25 +28,19 @@
|
|||
<string name="subscription_change_failed">Не атрымалася змяніць падпіску</string>
|
||||
<string name="subscription_update_failed">Не атрымалася абнавіць падпіску</string>
|
||||
<string name="show_info">Паказаць звесткі</string>
|
||||
|
||||
<string name="tab_main">Галоўная</string>
|
||||
<string name="tab_subscriptions">Падпіскі</string>
|
||||
<string name="tab_bookmarks">Адзначаныя плэйлісты</string>
|
||||
|
||||
<string name="fragment_whats_new">Што новага</string>
|
||||
|
||||
<string name="controls_background_title">У фоне</string>
|
||||
<string name="controls_popup_title">У акне</string>
|
||||
<string name="controls_add_to_playlist_title">Дадаць да</string>
|
||||
|
||||
<string name="download_path_title">Шлях загрузкі відэа</string>
|
||||
<string name="download_path_summary">Папка для захоўвання загружаных відэа</string>
|
||||
<string name="download_path_dialog_title">Увядзіце шлях да папкі для загрузкі відэа</string>
|
||||
|
||||
<string name="download_path_audio_title">Тэчка загрузкі аўдыё</string>
|
||||
<string name="download_path_audio_summary">"Сюды захоўваецца загружанае аўдыё "</string>
|
||||
<string name="download_path_audio_dialog_title">Увядзіце шлях да папкі для загрузкі аўдыё</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">Аўтапрайграванне</string>
|
||||
<string name="autoplay_by_calling_app_summary">Прайграваць відэа пры выкліку NewPipe з іншага прыкладання</string>
|
||||
<string name="default_resolution_title">Разрознянне па змаўчанні</string>
|
||||
|
@ -59,8 +54,6 @@
|
|||
<string name="play_audio">Аўдыё</string>
|
||||
<string name="default_audio_format_title">Фармат аўдыё па змаўчанні</string>
|
||||
<string name="default_video_format_title">Фармат відэа па змаўчанні</string>
|
||||
<string name="webm_description">WebM - свабодны</string>
|
||||
<string name="m4a_description">M4A - вышэй якасць</string>
|
||||
<string name="theme_title">Тэма</string>
|
||||
<string name="light_theme_title">Светлая</string>
|
||||
<string name="dark_theme_title">Цёмная</string>
|
||||
|
@ -136,17 +129,13 @@
|
|||
<string name="always">Заўсёды</string>
|
||||
<string name="just_once">Толькі цяпер</string>
|
||||
<string name="file">Файл</string>
|
||||
|
||||
<string name="notification_channel_name">Апавяшчэнне NewPipe</string>
|
||||
<string name="notification_channel_description">Апавяшчэнні для NewPipe ў фоне і ва ўсплываючым акне</string>
|
||||
|
||||
<string name="unknown_content">[Невядома]</string>
|
||||
|
||||
<string name="toggle_orientation">Пераключыць арыентацыю</string>
|
||||
<string name="switch_to_background">Перайсці ў фон</string>
|
||||
<string name="switch_to_popup">Перайсці ў акно</string>
|
||||
<string name="switch_to_main">Перайсці ў галоўнае акно</string>
|
||||
|
||||
<string name="import_data_title">Імпарт дадзеных</string>
|
||||
<string name="export_data_title">Экспарт дадзеных</string>
|
||||
<string name="import_data_summary">Ваша бягучая гісторыя і падпіскі перазапішуцца</string>
|
||||
|
@ -185,7 +174,6 @@
|
|||
<string name="file_name_empty_error">Імя файла не можа быць пустым</string>
|
||||
<string name="error_occurred_detail">Адбылася памылка: %1$s</string>
|
||||
<string name="no_streams_available_download">Няма патокаў, даступных для загрузкі</string>
|
||||
|
||||
<string name="sorry_string">Прабачце, гэта не павінна было адбыцца.</string>
|
||||
<string name="error_report_button_text">Адправіць справаздачу па e-mail</string>
|
||||
<string name="error_snackbar_message">Прабачце, адбыліся памылкі.</string>
|
||||
|
@ -195,8 +183,6 @@
|
|||
<string name="info_labels">Што:\\nЗапыт:\\nМова кантэнту:\\nСэрвіс:\\nЧас па Грынвічы:\\nПакет:\\nВерсія:\\nВерсія АС:</string>
|
||||
<string name="your_comment">Ваш каментар (English):</string>
|
||||
<string name="error_details_headline">Падрабязнасці:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">Мініяцюра відэа-прэв\'ю</string>
|
||||
<string name="detail_thumbnail_view_description">Мініяцюра відэа-прэв\'ю</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Мініяцюра аватара карыстальніка</string>
|
||||
|
@ -209,42 +195,33 @@
|
|||
<string name="search_no_results">Няма вынікаў</string>
|
||||
<string name="empty_subscription_feed_subtitle">Нічога няма</string>
|
||||
<string name="detail_drag_description">Перацягніце, каб змяніць парадак</string>
|
||||
|
||||
<string name="err_dir_create">Не атрымалася стварыць папку для загрузкі \"%1$s\"</string>
|
||||
<string name="info_dir_created">Створана папка для загрузак \"%1$s\"</string>
|
||||
|
||||
<string name="video">Відэа</string>
|
||||
<string name="audio">Аўдыё</string>
|
||||
<string name="retry">Паспрабаваць зноў</string>
|
||||
<string name="storage_permission_denied">Няма доступу да носьбіта</string>
|
||||
<string name="use_old_player_title">Стары плэер</string>
|
||||
<string name="use_old_player_summary">Стары убудаваны плэер на Mediaframework</string>
|
||||
|
||||
<string name="short_thousand">тыс.</string>
|
||||
<string name="short_million">млн.</string>
|
||||
<string name="short_billion">млрд.</string>
|
||||
|
||||
<string name="no_subscribers">Няма падпісчыкаў</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s падпісчык</item>
|
||||
<item quantity="few">%s падпісчыка</item>
|
||||
<item quantity="many">%s падпісчыкаў</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s падпісчык</item>
|
||||
<item quantity="few">%s падпісчыка</item>
|
||||
<item quantity="many">%s падпісчыкаў</item>
|
||||
</plurals>
|
||||
<string name="no_views">Няма праглядаў</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s прагляд</item>
|
||||
<item quantity="few">%s прагляда</item>
|
||||
<item quantity="many">%s праглядаў</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s прагляд</item>
|
||||
<item quantity="few">%s прагляда</item>
|
||||
<item quantity="many">%s праглядаў</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Няма відэа</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s відэа</item>
|
||||
<item quantity="few">%s відэа</item>
|
||||
<item quantity="many">%s відэа</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s відэа</item>
|
||||
<item quantity="few">%s відэа</item>
|
||||
<item quantity="many">%s відэа</item>
|
||||
</plurals>
|
||||
<string name="start">Пачаць</string>
|
||||
<string name="pause">Паўза</string>
|
||||
<string name="view">Прайграць</string>
|
||||
|
@ -255,10 +232,8 @@
|
|||
<string name="checksum">Кантрольная сума</string>
|
||||
<string name="dismiss">Адхіліць</string>
|
||||
<string name="rename">Перайменаваць</string>
|
||||
|
||||
<string name="add">Новая мэта</string>
|
||||
<string name="finish">ОК</string>
|
||||
|
||||
<string name="msg_name">Імя файла</string>
|
||||
<string name="msg_threads">Патокі</string>
|
||||
<string name="msg_error">Памылка</string>
|
||||
|
@ -273,21 +248,16 @@
|
|||
<string name="msg_popup_permission">Гэтае разрозненне трэба для
|
||||
\nпрайгравання ў акне</string>
|
||||
<string name="one_item_deleted">1 элемент выдалены.</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">Запыт reCAPTCHA</string>
|
||||
<string name="recaptcha_request_toast">Запытаны ўвод reCAPTCHA</string>
|
||||
|
||||
<string name="settings_category_downloads_title">Загрузкі</string>
|
||||
<string name="settings_file_charset_title">Дапушчальныя сімвалы назвы файлаў</string>
|
||||
<string name="settings_file_replacement_character_summary">Недапушчальныя сімвалы замяняюцца на гэтыя</string>
|
||||
<string name="settings_file_replacement_character_title">Сімвал для замены</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Літары і лічбы</string>
|
||||
<string name="charset_most_special_characters">Большасць спецзнакаў</string>
|
||||
|
||||
<string name="toast_no_player">Прыкладанне для прайгравання гэтага файла не ўстаноўлена</string>
|
||||
|
||||
<string name="title_activity_about">Аб NewPipe</string>
|
||||
<string name="action_settings">Налады</string>
|
||||
<string name="action_about">Аб дадатку</string>
|
||||
|
@ -314,8 +284,6 @@
|
|||
<string name="app_license_title">Ліцэнзія NewPipe</string>
|
||||
<string name="app_license">NewPipe - свабоднае праграмнае забеспячэнне: вы можаце выкарыстоўваць, вывучаць і паляпшаць яго па сваім меркаванні. У прыватнасці, вы можаце распаўсюджваць і / або змяняць яго ў адпаведнасці з умовамі GNU General Public License, апублікаванай Free Software Foundation, альбо версіі 3, альбо (па вашаму выбару) любой больш позняй версіі.</string>
|
||||
<string name="read_full_license">Прачытаць ліцэнзію</string>
|
||||
|
||||
|
||||
<string name="title_activity_history">Гісторыя</string>
|
||||
<string name="title_history_search">Гісторыя пошуку</string>
|
||||
<string name="title_history_view">Прагледжана</string>
|
||||
|
@ -329,7 +297,6 @@
|
|||
<string name="delete_all_history_prompt">Выдаліць усе элементы з гісторыі?</string>
|
||||
<string name="title_last_played">Нядаўна прайграныя</string>
|
||||
<string name="title_most_played">Часта прайграваемыя</string>
|
||||
|
||||
<string name="main_page_content">Кантэнт галоўнай старонкі</string>
|
||||
<string name="blank_page_summary">Пустая старонка</string>
|
||||
<string name="kiosk_page_summary">Старонка кіёска</string>
|
||||
|
@ -345,7 +312,6 @@
|
|||
<string name="could_not_import_all_files">Увага: не ўсе файлы былі імпартаваныя.</string>
|
||||
<string name="override_current_data">Бягучыя дадзеныя будуць замененыя.</string>
|
||||
<string name="import_settings">Хочаце імпартаваць налады?</string>
|
||||
|
||||
<string name="kiosk">Кіёск</string>
|
||||
<string name="trending">Трэнды</string>
|
||||
<string name="top_50">Топ 50</string>
|
||||
|
@ -357,74 +323,55 @@
|
|||
<string name="play_queue_audio_settings">Налады аўдыё</string>
|
||||
<string name="hold_to_append">Зацісніце, каб дадаць у чаргу</string>
|
||||
<string name="enqueue_on_background">У чаргу \"У фоне\"</string>
|
||||
<string name="enqueue_on_popup">У чаргу \"У фоне\"</string>
|
||||
<string name="enqueue_on_popup">У чаргу \"У акне\"</string>
|
||||
<string name="start_here_on_main">Відэаплэер</string>
|
||||
<string name="start_here_on_background">Фонавы плэер</string>
|
||||
<string name="start_here_on_popup">Плэер у акне</string>
|
||||
|
||||
<string name="drawer_open">Адкрыць бакавую панэль</string>
|
||||
<string name="drawer_close">Зачыніць бакавую панэль</string>
|
||||
<string name="drawer_header_action_paceholder_text">Хутка тут сёе-тое з\'явіцца ;D</string>
|
||||
|
||||
|
||||
<string name="preferred_open_action_settings_title">Пры адкрыцці кантэнту</string>
|
||||
<string name="preferred_open_action_settings_summary">Пры адкрыцці спасылкі на кантэнт — %s</string>
|
||||
|
||||
<string name="video_player">Відэаплэер</string>
|
||||
<string name="background_player">Фонавы плэер</string>
|
||||
<string name="popup_player">Плэер у акне</string>
|
||||
<string name="always_ask_open_action">Заўсёды пытацца</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Атрыманне звестак…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Загрузка запытанага кантэнту</string>
|
||||
|
||||
<string name="create_playlist">Стварыць плэйліст</string>
|
||||
<string name="delete_playlist">Выдаліць плэйліст</string>
|
||||
<string name="rename_playlist">Перайменаваць плэйліст</string>
|
||||
<string name="playlist_name_input">Імя</string>
|
||||
<string name="append_playlist">Дадаць у плэйліст</string>
|
||||
<string name="set_as_playlist_thumbnail">На мініяцюру плэйліста</string>
|
||||
|
||||
<string name="bookmark_playlist">Дадаць плэйліст у закладкі</string>
|
||||
<string name="unbookmark_playlist">Выдаліць закладку</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Выдаліць гэты плэйліст?</string>
|
||||
<string name="playlist_creation_success">Плэйліст створаны</string>
|
||||
<string name="playlist_add_stream_success">Дададзена ў плэйліст</string>
|
||||
<string name="playlist_thumbnail_change_success">Мініяцюра плэйліста зменена</string>
|
||||
<string name="playlist_delete_failure">Не атрымалася выдаліць плэйліст</string>
|
||||
|
||||
<string name="caption_none">Без тытраў</string>
|
||||
|
||||
<string name="resize_fit">Падагнаць</string>
|
||||
<string name="resize_fill">Запоўніць</string>
|
||||
<string name="resize_zoom">Наблізіць</string>
|
||||
|
||||
<string name="caption_auto_generated">Створаны аўтаматычна</string>
|
||||
|
||||
<string name="caption_setting_title">Тытры</string>
|
||||
<string name="caption_setting_description">Змяніць памер і фон тытраў. Змены ўступяць у сілу пасля перазапуску</string>
|
||||
|
||||
<string name="enable_leak_canary_title">Уключыць LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">Маніторынг уцечкі памяці можа прывесці да завісання прыкладання</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Паведамляць пра памылкі жыццёвага цыклу</string>
|
||||
<string name="enable_disposed_exceptions_summary">Прымусова паведамляць пра недастаўляемыя Rx-выключэнні па-за фрагментам або жыццёвым цыкле пасля выдалення</string>
|
||||
|
||||
<string name="import_export_title">Імпарт/Экспарт</string>
|
||||
<string name="import_title">Імпарт</string>
|
||||
<string name="import_from">Імпарт з</string>
|
||||
<string name="export_to">Экспарт у</string>
|
||||
|
||||
<string name="import_ongoing">Імпарт…</string>
|
||||
<string name="export_ongoing">Экспарт…</string>
|
||||
|
||||
<string name="import_file_title">Імпарт файла</string>
|
||||
<string name="previous_export">Папярэдні экспарт</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Не атрымалася імпартаваць падпіскі</string>
|
||||
<string name="subscriptions_export_unsuccessful">Не атрымалася экспартаваць падпіскі</string>
|
||||
|
||||
<string name="import_youtube_instructions">Імпарт падпісак з YouTube загрузкай файла экспарту:
|
||||
\n
|
||||
\n1. Перайдзіце на: %1$s
|
||||
|
@ -437,11 +384,9 @@
|
|||
\n3. Увайдзіце, калі неабходна
|
||||
\n4. Скапіруйце адрас з адраснага радка.</string>
|
||||
<string name="import_soundcloud_instructions_hint">вашID, soundcloud.com/вашID</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Гэтае дзеянне можа выклікаць вялікі расход трафіку.
|
||||
\n
|
||||
\nПрацягнуць?</string>
|
||||
|
||||
<string name="playback_speed_control">Кіраванне хуткасцю прайгравання</string>
|
||||
<string name="playback_tempo">Тэмп</string>
|
||||
<string name="playback_pitch">Тон</string>
|
||||
|
@ -449,12 +394,10 @@
|
|||
<string name="skip_silence_checkbox">Прапускаць цішыню</string>
|
||||
<string name="playback_step">Крок</string>
|
||||
<string name="playback_reset">Скід</string>
|
||||
|
||||
<string name="start_accept_privacy_policy">У адпаведнасці з Агульным рэгламентам па абароне дадзеных ЕС (GDPR), звяртаем вашу ўвагу на палітыку прыватнасці NewPipe. Калі ласка, уважліва азнаёмцеся з ёй.
|
||||
\nВам неабходна прыняць яе ўмовы, каб адправіць нам справаздачу пра памылку.</string>
|
||||
<string name="accept">Прыняць</string>
|
||||
<string name="decline">Адмовіцца</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Без абмежаванняў</string>
|
||||
<string name="limit_mobile_data_usage_title">Ліміт разрознення ў мабільнай сетцы</string>
|
||||
<string name="minimize_on_exit_title">Пры згортванні плэера</string>
|
||||
|
@ -462,5 +405,5 @@
|
|||
<string name="minimize_on_exit_none_description">Нічога не рабіць</string>
|
||||
<string name="minimize_on_exit_background_description">Фонавы плэер</string>
|
||||
<string name="minimize_on_exit_popup_description">Плэер у акне</string>
|
||||
|
||||
<string name="unsubscribe">Адпісацца</string>
|
||||
</resources>
|
|
@ -156,8 +156,6 @@
|
|||
<string name="audio">Аудио</string>
|
||||
<string name="retry">Опитай отново</string>
|
||||
<string name="storage_permission_denied">Достъпа до хранилището е отказан</string>
|
||||
<string name="use_old_player_title">Използвай стария плейър</string>
|
||||
<string name="use_old_player_summary">Използваю стария вграден Mediaframewoek плейър</string>
|
||||
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s абонат</item>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="main_bg_subtitle">শুরু করতে অনুসন্ধান এ আলতো চাপ</string>
|
||||
<string name="view_count_text">%1$s বার দেখা হয়েছে</string>
|
||||
|
@ -8,30 +8,26 @@
|
|||
<string name="cancel">"বাদ দিন "</string>
|
||||
<!-- <string name="fdroid_vlc_url" translatable="false">https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc</string> -->
|
||||
<string name="open_in_browser">"ব্রাউজারে ওপেন করো "</string>
|
||||
<string name="open_in_popup_mode">"popup মোডে Open করো "</string>
|
||||
<string name="open_in_popup_mode">"পপ-আপ মোডে ওপেন করো "</string>
|
||||
<string name="share">শেয়ার</string>
|
||||
<string name="download">ডাউনলোড</string>
|
||||
<string name="search">খোঁজ</string>
|
||||
<string name="settings">"সেটিংস "</string>
|
||||
<string name="download">ডাউনলোউড</string>
|
||||
<string name="search">খুঁজুন</string>
|
||||
<string name="settings">সেটিংস</string>
|
||||
<string name="did_you_mean">আপনি কি বুঝিয়েছেনঃ %1$s ?</string>
|
||||
<string name="share_dialog_title">শেয়ার কর</string>
|
||||
<string name="choose_browser">ব্রাউজার পছন্দ কর</string>
|
||||
<string name="share_dialog_title">শেয়ার করুন</string>
|
||||
<string name="choose_browser">ব্রাউজার বাছাই করুন</string>
|
||||
<string name="screen_rotation">রোটেশন</string>
|
||||
<string name="use_external_video_player_title">বাহ্যিক ভিডিও প্লেয়ার ব্যবহার করো</string>
|
||||
<string name="use_external_audio_player_title">বাহ্যিক অডিও প্লেয়ার ব্যবহার করো</string>
|
||||
<string name="use_external_video_player_title">বাইরের ভিডিও প্লেয়ার ব্যবহার করুন</string>
|
||||
<string name="use_external_audio_player_title">বহির্গত অডিও প্লেয়ার ব্যবহার করুন</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe পপআপ মোড</string>
|
||||
|
||||
<string name="controls_background_title">ব্যাকগ্রাউন্ড</string>
|
||||
<string name="controls_popup_title">পপআপ</string>
|
||||
|
||||
<string name="download_path_title">ভিডিও ডাউনলোড করার পাথ</string>
|
||||
<string name="download_path_summary">ডাউনলোড করা ভিডিওগুলো রাখার ফোল্ডার</string>
|
||||
<string name="download_path_dialog_title">ভিডিওগুলির জন্য ডাউনলোডের পাথ প্রবেশ করাও</string>
|
||||
|
||||
<string name="download_path_audio_title">অডিও ডাউনলোড পাথ</string>
|
||||
<string name="download_path_audio_summary">ডাউনলোড করা অডিও সঞ্চয় করার পাথ</string>
|
||||
<string name="download_path_audio_dialog_title">অডিও ফাইলগুলির জন্য ডাউনলোডের পাথ প্রবেশ করাও</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">স্বয়ংক্রিয়ভাবে প্লে করো যখন অন্য অ্যাপ্লিকেশন থেকে চালু করা হয়</string>
|
||||
<string name="autoplay_by_calling_app_summary">স্বয়ংক্রিয়ভাবে একটি ভিডিও প্লে করো যখন NewPipe অন্য অ্যাপ্লিকেশন থেকে চালু করা হয়।</string>
|
||||
<string name="default_resolution_title">ডিফল্ট রেজোল্যুশন</string>
|
||||
|
@ -52,7 +48,6 @@
|
|||
<string name="black_theme_title">কালো</string>
|
||||
<string name="popup_remember_size_pos_title">পপআপ আকার এবং অবস্থান মনে রাখো</string>
|
||||
<string name="popup_remember_size_pos_summary">শেষ আকার এবং পপআপ সেট অবস্থান মনে রাখো</string>
|
||||
|
||||
<string name="download_dialog_title">ডাউনলোড</string>
|
||||
<string name="next_video_title">পরবর্তী ভিডিও</string>
|
||||
<string name="show_next_and_similar_title">পরবর্তী এবং অনুরূপ ভিডিওগুলি দেখাও</string>
|
||||
|
@ -83,7 +78,6 @@
|
|||
<string name="refresh">রিফ্রেশ</string>
|
||||
<string name="clear">পরিষ্কার</string>
|
||||
<string name="popup_resizing_indicator_title">আকার পরিবর্তন</string>
|
||||
|
||||
<!-- error strings -->
|
||||
<string name="general_error">ত্রুটি</string>
|
||||
<string name="network_error">নেটওয়ার্ক ত্রুটি</string>
|
||||
|
@ -108,8 +102,6 @@
|
|||
<string name="what_happened_headline">কি হয়েছিল:</string>
|
||||
<string name="your_comment">তোমার মন্তব্য (ইংরেজিতে):</string>
|
||||
<string name="error_details_headline">বর্ণনা:</string>
|
||||
|
||||
|
||||
<!-- Content descriptions (for better accessibility) -->
|
||||
<string name="list_thumbnail_view_description">ভিডিও প্রাকদর্শন থাম্বনেইল</string>
|
||||
<string name="detail_thumbnail_view_description">ভিডিও প্রাকদর্শন থাম্বনেইল</string>
|
||||
|
@ -120,34 +112,24 @@
|
|||
<string name="use_tor_summary">(পরীক্ষামূলক) গোপনীয়তা বর্ধিত করতে টর এর মাধ্যমে ডাউনলোড ট্রাফিক জোরপুর্বক পাঠাও (ভিডিওগুলি স্ট্রিমিং এ সমর্থিত নয়)।</string>
|
||||
<string name="report_error">একটি ত্রুটি রিপোর্ট করো</string>
|
||||
<string name="user_report">ব্যবহারকারীর প্রতিবেদন</string>
|
||||
|
||||
<string name="err_dir_create">\'%1$s\' ডাউনলোড ডিরেক্টরি তৈরি করতে পারছে না</string>
|
||||
<string name="info_dir_created">\'%1$s\' ডাউনলোড ডিরেক্টরি তৈরি করা হয়েছে</string>
|
||||
|
||||
<string name="video">ভিডিও</string>
|
||||
<string name="audio">অডিও</string>
|
||||
<string name="retry">পুনরায় চেষ্টা করো</string>
|
||||
<string name="storage_permission_denied">স্টোরেজ অ্যাক্সেস করার অনুমতি অস্বীকার করা হয়েছে</string>
|
||||
<string name="use_old_player_title">পুরানো প্লেয়ার ব্যবহার করো</string>
|
||||
<string name="use_old_player_summary">মিডিয়াফ্রেমওয়ার্ক প্লেয়ারের পুরানো বিল্ড।</string>
|
||||
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">B</string>
|
||||
|
||||
<!-- Missions -->
|
||||
<string name="start">শুরু</string>
|
||||
<string name="pause">বিরতি</string>
|
||||
<string name="view">প্রদর্শন</string>
|
||||
<string name="delete">ডিলেট</string>
|
||||
<string name="checksum">চেকসাম</string>
|
||||
|
||||
<!-- Fragment -->
|
||||
<string name="add">নতুন মিশন</string>
|
||||
<string name="finish">ঠিক আছে</string>
|
||||
|
||||
|
||||
<!-- Msg -->
|
||||
<string name="msg_name">ফাইলের নাম</string>
|
||||
<string name="msg_threads">থ্রেড</string>
|
||||
|
@ -161,24 +143,18 @@
|
|||
<string name="msg_copied">ক্লিপবোর্ডে অনুলিপি করা হয়েছে।</string>
|
||||
<string name="no_available_dir">অনুগ্রহ করে একটি উপলব্ধ ডাউনলোড ডিরেক্টরি নির্বাচন করো।</string>
|
||||
<string name="msg_popup_permission">এই অনুমতিটি পপআপ মোডে খুলতে প্রয়োজন</string>
|
||||
|
||||
<!-- Checksum types -->
|
||||
<!-- <string name="md5" translatable="false">MD5</string> -->
|
||||
<!-- <string name="sha1" translatable="false">SHA1</string> -->
|
||||
<string name="reCaptchaActivity">রিক্যাপচা</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA চ্যালেঞ্জ</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA চ্যালেঞ্জ অনুরোধ করা হয়েছে</string>
|
||||
|
||||
<!-- End of GigaGet's Strings -->
|
||||
|
||||
<string name="info_labels">কি:\\nঅনুরোধ:\\nকন্টেন্ট ভাষা:\\nসার্ভিস:\\nসময়(GMT এ):\\nপ্যাকেজ:\\nসংস্করণ:\\nওএস সংস্করণ:\\nআইপি পরিসর:</string>
|
||||
<string name="controls_download_desc">Stream file ডাউনলোড করুন।</string>
|
||||
<string name="show_info">তথ্য দেখান</string>
|
||||
|
||||
<string name="controls_download_desc">স্ট্রিম ফাইল ডাউনলোড করুন।</string>
|
||||
<string name="show_info">তথ্য দেখুন</string>
|
||||
<string name="fragment_whats_new">কি নতুন</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">যুক্ত করুন</string>
|
||||
|
||||
<string name="enable_search_history_title">খোজ ইতিহাস</string>
|
||||
<string name="enable_watch_history_title">ইতিহাস</string>
|
||||
<string name="service_title">সেবা</string>
|
||||
|
@ -189,25 +165,23 @@
|
|||
<string name="playlist">প্লেলিস্ট</string>
|
||||
<string name="always">সবসময়</string>
|
||||
<string name="just_once">একবার মাত্র</string>
|
||||
|
||||
<string name="unknown_content">[অজানা]</string>
|
||||
|
||||
<string name="no_views">কোন ভিউ নেই</string>
|
||||
<string name="rename">নাম পরিবর্তন করুন</string>
|
||||
|
||||
<string name="action_settings">সেটিংস</string>
|
||||
<string name="action_open_website">ওয়েব সাইট খুলুন</string>
|
||||
<string name="website_title">ওয়েব সাইট</string>
|
||||
<string name="no_player_found_toast">"কোন স্ট্রিম প্লেয়ার পাওয়া যায়নি (প্লে করতে VLC ইন্সটল করতে পারেন) "</string>
|
||||
<string name="use_external_video_player_summary">যদি এই অপশন অন থাকে তবে কিছু ভিডিওর অডিও কাজ নাও করতে পারে</string>
|
||||
<string name="no_player_found_toast">কোন স্ট্রিম প্লেয়ার পাওয়া যায়নি (প্লে করতে VLC ইন্সটল করতে পারেন)</string>
|
||||
<string name="use_external_video_player_summary">কিছু রেজোলিউশনে ভিডিওর অডিও কাজ করে না</string>
|
||||
<string name="subscribe_button_title">সাবস্ক্রাইব</string>
|
||||
<string name="subscribed_button_title">সাবস্ক্রাইব করা আছে</string>
|
||||
<string name="channel_unsubscribed">চ্যানেল সাবস্ক্রাইব করা হয়েছে</string>
|
||||
<string name="subscription_change_failed">সাবস্ক্রিপশন পরিবর্তন করা হয়নি</string>
|
||||
<string name="subscription_update_failed">সাবস্ক্রিপশন আপডেট করতে ব্যার্থ হয়েছে</string>
|
||||
<string name="channel_unsubscribed">চ্যানেল থেকে আনসাবস্ক্রাইব্ড</string>
|
||||
<string name="subscription_change_failed">সাবস্ক্রিপশন পরিবর্তন করা যায়নি</string>
|
||||
<string name="subscription_update_failed">সাবস্ক্রিপশন আপডেটে ব্যার্থ</string>
|
||||
<string name="tab_main">প্রধান</string>
|
||||
<string name="tab_subscriptions">সাবস্ক্রিপশন</string>
|
||||
<string name="tab_bookmarks">বুকমার্কস</string>
|
||||
|
||||
<string name="tab_bookmarks">বুকমার্ককৃত প্লেলিস্টসমূহ</string>
|
||||
<string name="use_inexact_seek_title">দ্রুত টানা ব্যাবহার করুন</string>
|
||||
</resources>
|
||||
<string name="unsubscribe">আনসাবস্ক্রাইব</string>
|
||||
<string name="tab_new">নতুন ট্যাব</string>
|
||||
</resources>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources><string name="install">Instal·la</string>
|
||||
<resources>
|
||||
<string name="install">Instal·la</string>
|
||||
<string name="cancel">Cancel·la</string>
|
||||
<string name="open_in_browser">Obre al navegador</string>
|
||||
<string name="share">Comparteix</string>
|
||||
|
@ -10,12 +11,9 @@
|
|||
<string name="subscribe_button_title">Subscriu-t\'hi</string>
|
||||
<string name="subscribed_button_title">Subscrit</string>
|
||||
<string name="show_info">Mostra la informació</string>
|
||||
|
||||
<string name="tab_subscriptions">Subscripcions</string>
|
||||
<string name="tab_bookmarks">Llistes de reproducció desades</string>
|
||||
|
||||
<string name="fragment_whats_new">Novetats</string>
|
||||
|
||||
<string name="download_path_title">Ruta de baixada dels vídeos</string>
|
||||
<string name="download_path_audio_title">Carpeta de baixada dels fitxers d\'àudio</string>
|
||||
<string name="autoplay_by_calling_app_title">Reproducció automàtica</string>
|
||||
|
@ -39,7 +37,7 @@
|
|||
<string name="settings_category_debug_title">Depuració</string>
|
||||
<string name="content">Contingut</string>
|
||||
<string name="show_age_restricted_content_title">Desactiva les restriccions per edat</string>
|
||||
<string name="video_is_age_restricted">Vídeo restringit per edat. Podeu permetre aquesta mena de continguts des de la configuració.</string>
|
||||
<string name="video_is_age_restricted">Mostra el vídeo restringit per edat. Podeu permetre aquesta mena de continguts des de la configuració.</string>
|
||||
<string name="duration_live">EN DIRECTE</string>
|
||||
<string name="downloads">Baixades</string>
|
||||
<string name="downloads_title">Baixades</string>
|
||||
|
@ -54,9 +52,7 @@
|
|||
<string name="always">Sempre</string>
|
||||
<string name="just_once">Només una vegada</string>
|
||||
<string name="file">Fitxer</string>
|
||||
|
||||
<string name="unknown_content">[Desconegut]</string>
|
||||
|
||||
<string name="import_data_title">Importa una base de dades</string>
|
||||
<string name="export_data_title">Exporta una base de dades</string>
|
||||
<string name="export_data_summary">Exporta l\'historial, les subscripcions i les llistes de reproducció</string>
|
||||
|
@ -65,12 +61,10 @@
|
|||
<string name="video">Vídeo</string>
|
||||
<string name="audio">Àudio</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s subscriptor</item>
|
||||
<item quantity="other">%s subscriptors</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s subscriptor</item>
|
||||
<item quantity="other">%s subscriptors</item>
|
||||
</plurals>
|
||||
<string name="finish">D\'acord</string>
|
||||
|
||||
<string name="msg_name">Nom de fitxer</string>
|
||||
<string name="msg_error">Error</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
|
@ -87,8 +81,6 @@
|
|||
<string name="website_title">Lloc web</string>
|
||||
<string name="app_license_title">Llicència del NewPipe</string>
|
||||
<string name="read_full_license">Llegeix la llicència</string>
|
||||
|
||||
|
||||
<string name="title_activity_history">Historial</string>
|
||||
<string name="history_disabled">L\'historial està desactivat</string>
|
||||
<string name="action_history">Historial</string>
|
||||
|
@ -111,7 +103,6 @@
|
|||
<string name="background_player">Reproductor en segon pla</string>
|
||||
<string name="popup_player">Reproductor emergent</string>
|
||||
<string name="always_ask_open_action">Demana-ho sempre</string>
|
||||
|
||||
<string name="create_playlist">Crea una llista de reproducció</string>
|
||||
<string name="delete_playlist">Elimina</string>
|
||||
<string name="rename_playlist">Canvia el nom</string>
|
||||
|
@ -120,13 +111,11 @@
|
|||
<string name="import_title">Importa</string>
|
||||
<string name="import_from">Importa des de</string>
|
||||
<string name="export_to">Exporta a</string>
|
||||
|
||||
<string name="import_ongoing">S\'està important…</string>
|
||||
<string name="export_ongoing">S\'està exportant…</string>
|
||||
|
||||
<string name="import_file_title">Importa un fitxer</string>
|
||||
<string name="playback_default">Per defecte</string>
|
||||
<string name="view_count_text">%1$s reproduccions</string>
|
||||
<string name="view_count_text">%1$s reproduccions</string>
|
||||
<string name="upload_date_text">Publicat el %1$s</string>
|
||||
<string name="no_player_found">No s\'ha trobat un reproductor de fluxos. Voleu instal·lar el VLC?</string>
|
||||
<string name="no_player_found_toast">No s\'ha trobat cap reproductor de fluxos (podeu instal·lar el VLC per reproduir-lo).</string>
|
||||
|
@ -144,13 +133,10 @@
|
|||
<string name="controls_background_title">Segon pla</string>
|
||||
<string name="controls_popup_title">Emergent</string>
|
||||
<string name="controls_add_to_playlist_title">Afegeix a</string>
|
||||
|
||||
<string name="download_path_summary">Ruta on es desaran els vídeos baixats</string>
|
||||
<string name="download_path_dialog_title">Introduïu una ruta de baixada per als vídeos</string>
|
||||
|
||||
<string name="download_path_audio_summary">Els fitxers d\'àudio baixats es desaran aquí</string>
|
||||
<string name="download_path_audio_dialog_title">Introduïu una ruta de baixada per als fitxers d\'àudio</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_summary">Reprodueix un vídeo quan el NewPipe s\'executa des d\'una altra aplicació</string>
|
||||
<string name="default_popup_resolution_title">Resolució per defecte del mode emergent</string>
|
||||
<string name="show_higher_resolutions_title">Mostra resolucions superiors</string>
|
||||
|
@ -186,7 +172,6 @@
|
|||
<string name="play_btn_text">Reprodueix</string>
|
||||
<string name="notification_channel_name">Notificació del NewPipe</string>
|
||||
<string name="notification_channel_description">Notificacions dels reproductors en segon pla o emergents del NewPipe</string>
|
||||
|
||||
<string name="could_not_load_thumbnails">No s\'han pogut carregar totes les miniatures</string>
|
||||
<string name="youtube_signature_decryption_error">No s\'ha pogut desencriptar la signatura de l\'URL del vídeo</string>
|
||||
<string name="parsing_error">No s\'ha pogut processar el lloc web</string>
|
||||
|
@ -216,8 +201,6 @@
|
|||
<string name="what_happened_headline">Què ha passat:</string>
|
||||
<string name="your_comment">Comentari (en anglès):</string>
|
||||
<string name="error_details_headline">Detalls:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">Miniatura de previsualització del vídeo</string>
|
||||
<string name="detail_thumbnail_view_description">Miniatura de previsualització del vídeo</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Miniatura de l\'avatar del propietari</string>
|
||||
|
@ -231,25 +214,19 @@
|
|||
<string name="empty_subscription_feed_subtitle">No hi ha res aquí</string>
|
||||
<string name="err_dir_create">No s\'ha pogut crear el directori de baixades «%1$s»</string>
|
||||
<string name="info_dir_created">S\'ha creat el directori de baixades «%1$s»</string>
|
||||
|
||||
<string name="retry">Torna a intentar-ho</string>
|
||||
<string name="storage_permission_denied">S\'ha denegat el permís d\'accés a l\'emmagatzematge</string>
|
||||
<string name="use_old_player_title">Fes servir el reproductor antic</string>
|
||||
<string name="use_old_player_summary">Antic reproductor integrat de Mediaframework</string>
|
||||
|
||||
<string name="no_subscribers">Sense subscriptors</string>
|
||||
<string name="no_views">Sense reproduccions</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s reproducció</item>
|
||||
<item quantity="other">%s reproduccions</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s reproducció</item>
|
||||
<item quantity="other">%s reproduccions</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Sense vídeos</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s vídeo</item>
|
||||
<item quantity="other">%s vídeos</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Vídeo</item>
|
||||
<item quantity="other">Vídeos</item>
|
||||
</plurals>
|
||||
<string name="pause">Pausa</string>
|
||||
<string name="view">Reprodueix</string>
|
||||
<string name="create">Crea</string>
|
||||
|
@ -259,7 +236,6 @@
|
|||
<string name="checksum">Suma de verificació</string>
|
||||
<string name="dismiss">Tanca</string>
|
||||
<string name="rename">Canvia el nom</string>
|
||||
|
||||
<string name="msg_threads">Fils</string>
|
||||
<string name="msg_server_unsupported">Servidor incompatible</string>
|
||||
<string name="msg_exists">El fitxer ja existeix</string>
|
||||
|
@ -276,7 +252,6 @@
|
|||
<string name="website_encouragement">Per a més informació i notícies, visiteu el nostre lloc web.</string>
|
||||
<string name="title_last_played">Última reproducció</string>
|
||||
<string name="title_most_played">Més reproduïts</string>
|
||||
|
||||
<string name="kiosk_page_summary">Pàgina d\'un quiosc</string>
|
||||
<string name="feed_page_summary">Pàgina de novetats</string>
|
||||
<string name="channel_page_summary">Pàgina d\'un canal</string>
|
||||
|
@ -284,7 +259,6 @@
|
|||
<string name="no_valid_zip_file">El fitxer no té un format ZIP vàlid</string>
|
||||
<string name="could_not_import_all_files">Avís: No s\'han pogut importar tots els fitxers.</string>
|
||||
<string name="override_current_data">Això sobreescriurà la configuració actual.</string>
|
||||
|
||||
<string name="kiosk">Quiosc</string>
|
||||
<string name="trending">Tendències</string>
|
||||
<string name="top_50">Els millors 50</string>
|
||||
|
@ -297,10 +271,8 @@
|
|||
<string name="drawer_close">Tanca el calaix</string>
|
||||
<string name="preferred_player_fetcher_notification_title">S\'està obtenint la informació…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">S\'està carregant el contingut seleccionat</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Voleu eliminar aquesta llista de reproducció?</string>
|
||||
<string name="playlist_delete_failure">No s\'ha pogut eliminar la llista de reproducció.</string>
|
||||
|
||||
<string name="import_export_title">Importació i exportació</string>
|
||||
<string name="playback_speed_control">Controls de la velocitat de reproducció</string>
|
||||
<string name="playback_tempo">Tempo</string>
|
||||
|
@ -323,31 +295,24 @@
|
|||
<string name="switch_to_background">Canvia al mode en segon pla</string>
|
||||
<string name="switch_to_popup">Canvia al mode emergent</string>
|
||||
<string name="switch_to_main">Canvia al mode principal</string>
|
||||
|
||||
<string name="import_data_summary">Sobreescriu l\'historial i les subscripcions actuals</string>
|
||||
<string name="player_recoverable_failure">S\'està recuperant el reproductor després de l\'error</string>
|
||||
<string name="sorry_string">Ho sentim, això no hauria d\'haver ocorregut.</string>
|
||||
<string name="detail_drag_description">Arrossegueu per a reordenar la llista</string>
|
||||
|
||||
<string name="short_thousand">mil</string>
|
||||
<string name="short_million">milions</string>
|
||||
<string name="short_billion">mil milions</string>
|
||||
|
||||
<string name="start">Inicia</string>
|
||||
<string name="add">Nova missió</string>
|
||||
<string name="msg_url_malform">L\'URL té un format incorrecte o no hi ha connexió a internet</string>
|
||||
<string name="msg_running_detail">Toqueu aquí per a més detalls</string>
|
||||
<string name="no_available_dir">Trieu una carpeta de baixades disponible</string>
|
||||
<string name="msg_popup_permission">Es necessita aquest permís per a obrir el mode emergent</string>
|
||||
|
||||
<string name="reCaptcha_title">Camp reCAPTCHA</string>
|
||||
<string name="recaptcha_request_toast">S\'ha sol·licitat l\'emplenament d\'un camp reCAPTCHA</string>
|
||||
|
||||
<string name="settings_file_replacement_character_summary">Se substituiran els caràcters no vàlids amb aquest valor</string>
|
||||
<string name="settings_file_replacement_character_title">Caràcter de substitució</string>
|
||||
|
||||
<string name="charset_most_special_characters">Principals caràcters especials</string>
|
||||
|
||||
<string name="contribution_encouragement">Ja siguin idees, traduccions, canvis en el disseny, una neteja del codi o canvis importants de programació, la vostra ajuda sempre és benvinguda. Com més feina feta hi hagi, millor!</string>
|
||||
<string name="donation_encouragement">El NewPipe està desenvolupat per voluntaris que fan servir el seu temps lliure per a oferir-vos la millor experiència possible. Feu una aportació per assegurar que els nostres desenvolupadors puguin millorar encara més el NewPipe mentre fan un cafè.</string>
|
||||
<string name="give_back">Fes la teva aportació</string>
|
||||
|
@ -358,33 +323,25 @@
|
|||
<string name="hold_to_append">Manteniu premut per afegir a la cua</string>
|
||||
<string name="start_here_on_background">Reprodueix aquí en segon pla</string>
|
||||
<string name="start_here_on_popup">Reprodueix aquí en mode emergent</string>
|
||||
|
||||
<string name="set_as_playlist_thumbnail">Defineix com a miniatura de la llista de reproducció</string>
|
||||
|
||||
<string name="bookmark_playlist">Afegeix la llista de reproducció a les adreces d\'interès</string>
|
||||
<string name="unbookmark_playlist">Elimina l\'adreça d\'interès</string>
|
||||
|
||||
<string name="playlist_creation_success">S\'ha creat la llista de reproducció</string>
|
||||
<string name="playlist_add_stream_success">S\'ha afegit a la llista de reproducció</string>
|
||||
<string name="playlist_thumbnail_change_success">S\'ha canviat la miniatura de la llista de reproducció.</string>
|
||||
<string name="caption_none">Sense subtítols</string>
|
||||
|
||||
<string name="resize_fit">Ajusta</string>
|
||||
<string name="resize_fill">Omple</string>
|
||||
<string name="resize_zoom">Escala</string>
|
||||
|
||||
<string name="caption_auto_generated">Generats automàticament</string>
|
||||
<string name="caption_font_size_settings_title">Mida dels subtítols</string>
|
||||
<string name="smaller_caption_font_size">Mida més petita</string>
|
||||
<string name="normal_caption_font_size">Mida normal</string>
|
||||
<string name="larger_caption_font_size">Mida més gran</string>
|
||||
|
||||
<string name="enable_leak_canary_title">Habilita el LeakCanary</string>
|
||||
<string name="previous_export">Darrera exportació</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">No s\'han pogut importar les subscripcions</string>
|
||||
<string name="subscriptions_export_unsuccessful">No s\'han pogut exportar les subscripcions</string>
|
||||
|
||||
<string name="unhook_checkbox">Desvincula (pot provocar distorsió)</string>
|
||||
<string name="playback_nightcore">Nightcore</string>
|
||||
<string name="metadata_cache_wipe_summary">Elimina totes les dades de llocs web de la memòria cau</string>
|
||||
|
@ -393,16 +350,11 @@
|
|||
<string name="show_hold_to_append_summary">Mostra un missatge d\'ajuda quan el botó de mode en segon pla o emergent estigui premut a la pàgina de detalls d\'un vídeo</string>
|
||||
<string name="info_labels">Què ha passat:\\nPetició:\\nIdioma del contingut:\\nServei:\\nHora GMT:\\nPaquet:\\nVersió:\\nVersió del SO:</string>
|
||||
<string name="drawer_header_action_paceholder_text">Aviat hi haurà novetats aquí ;D</string>
|
||||
|
||||
|
||||
<string name="preferred_open_action_settings_title">Acció d\'obertura preferida</string>
|
||||
<string name="preferred_open_action_settings_summary">Acció per defecte en obrir continguts — %s</string>
|
||||
|
||||
<string name="enable_leak_canary_summary">"La supervisió de fugues de memòria pot fer que l\'aplicació deixi de respondre mentre es bolca la memòria "</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Informa d\'errors fora del cicle de vida</string>
|
||||
<string name="enable_disposed_exceptions_summary">Força l\'informe d\'excepcions Rx que no es puguin transmetre que tinguin lloc fora del cicle de vida d\'un fragment o activitat després de disposar-los</string>
|
||||
|
||||
<string name="import_youtube_instructions">Importeu les vostres subscripcions de YouTube mitjançant el fitxer d\'exportació:
|
||||
\n
|
||||
\n1. Aneu a aquesta URL: %1$s
|
||||
|
@ -415,18 +367,13 @@
|
|||
\n3. Inicieu sessió al vostre compte quan se us demani
|
||||
\n4. Copieu l\'URL de la pàgina on se us redireccioni</string>
|
||||
<string name="import_soundcloud_instructions_hint">identificador, soundcloud.com/identificador</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Tingueu en compte que això pot comportar un ús intensiu de la xarxa.
|
||||
\n
|
||||
\nVoleu continuar?</string>
|
||||
|
||||
<string name="no_streams_available_download">No hi ha vídeos que es puguin baixar</string>
|
||||
|
||||
<string name="caption_setting_title">Subtítols</string>
|
||||
<string name="caption_setting_description">Modifica la mida del text i el fons dels subtítols. Cal reiniciar l\'aplicació per aplicar els canvis.</string>
|
||||
|
||||
<string name="toast_no_player">No s\'ha trobat cap aplicació que pugui reproduir aquest fitxer</string>
|
||||
|
||||
<string name="clear_views_history_title">Esborra l\'historial de reproduccions</string>
|
||||
<string name="clear_views_history_summary">Esborra l\'historial dels vídeos que s\'han reproduït</string>
|
||||
<string name="delete_view_history_alert">Voleu esborrar tot l\'historial de reproduccions\?</string>
|
||||
|
@ -436,10 +383,8 @@
|
|||
<string name="delete_search_history_alert">Voleu esborrar tot l\'historial de cerca\?</string>
|
||||
<string name="search_history_deleted">S\'ha esborrat l\'historial de cerca.</string>
|
||||
<string name="one_item_deleted">S\'ha esborrat 1 element.</string>
|
||||
|
||||
<string name="app_license">NewPipe és programari lliure sota llicència copyleft: podeu fer-lo servir, estudiar-lo, compartir-lo i millorar-lo al vostre gust. En concret, podeu redistribuir-lo i/o modificar-lo d\'acord amb els termes de la llicència GNU GPL publicada per la Free Software Foundation, ja sigui la versió 3 o (segons vulgueu) qualsevol altra versió posterior.</string>
|
||||
<string name="import_settings">Voleu importar també la configuració?</string>
|
||||
|
||||
<string name="privacy_policy_title">Política de privacitat del NewPipe</string>
|
||||
<string name="privacy_policy_encouragement">El projecte NewPipe es pren molt seriosament la vostra privacitat. Per aquesta raó, l\'aplicació no emmagatzema cap mena de dades sense el vostre consentiment.
|
||||
\nLa política de privacitat del NewPipe descriu detalladament quines dades s\'envien i s\'emmagatzemen quan envieu un informe d\'error.</string>
|
||||
|
@ -448,18 +393,16 @@
|
|||
\nSi voleu enviar-nos un informe d\'error, l\'haureu d\'acceptar.</string>
|
||||
<string name="accept">Accepta</string>
|
||||
<string name="decline">Rebutja</string>
|
||||
<string name="limit_data_usage_none_description">Sense restriccions</string>
|
||||
<string name="limit_data_usage_none_description">Sense restriccions</string>
|
||||
<string name="limit_mobile_data_usage_title">Restringeix la resolució quan es facin servir dades mòbils</string>
|
||||
<string name="minimize_on_exit_title">Minimitza en canviar d\'aplicació</string>
|
||||
<string name="minimize_on_exit_summary">Acció en canviar a una altra aplicació des del reproductor de vídeo principal — %s</string>
|
||||
<string name="minimize_on_exit_none_description">Cap</string>
|
||||
<string name="minimize_on_exit_background_description">Minimitza al reproductor en segon pla</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimitza al reproductor emergent</string>
|
||||
|
||||
<string name="skip_silence_checkbox">Avança ràpid durant el silenci</string>
|
||||
<string name="skip_silence_checkbox">Avança ràpid durant el silenci</string>
|
||||
<string name="playback_step">Pas</string>
|
||||
<string name="playback_reset">Reinicialitza</string>
|
||||
|
||||
<string name="channels">Canals</string>
|
||||
<string name="playlists">Llistes de reproducció</string>
|
||||
<string name="tracks">Pistes</string>
|
||||
|
@ -482,14 +425,37 @@
|
|||
<string name="auto">Automàtic</string>
|
||||
<string name="switch_view">Canvia la vista</string>
|
||||
<string name="app_update_notification_content_title">Està disponible una nova actualització del NewPipe!</string>
|
||||
<string name="missions_header_pending">A la cua</string>
|
||||
<string name="missions_header_pending">Pendent</string>
|
||||
<string name="paused">en pausa</string>
|
||||
<string name="queued">a la cua</string>
|
||||
<string name="enqueue">Afegeix a la cua</string>
|
||||
<string name="generate_unique_name">Genera un nom únic</string>
|
||||
<string name="show_error">Mostra l\'error</string>
|
||||
<string name="label_code">Codi</string>
|
||||
<string name="error_path_creation">No es pot crear el fitxer</string>
|
||||
<string name="error_file_creation">No es pot crear la carpeta de destinació</string>
|
||||
<string name="error_file_creation">No es pot crear el fitxer</string>
|
||||
<string name="error_path_creation">No es pot crear la carpeta de destinació</string>
|
||||
<string name="stop">Atura</string>
|
||||
<string name="events">Esdeveniments</string>
|
||||
<string name="app_update_notification_channel_description">Notificacions de noves versions del NewPipe</string>
|
||||
<string name="subscribers_count_not_available">El nombre de subscriptors no està disponible</string>
|
||||
<string name="main_page_content_summary">Quines pestanyes es mostren a la pàgina principal</string>
|
||||
<string name="conferences">Conferències</string>
|
||||
<string name="list_view_mode">Mode de vista de llista</string>
|
||||
<string name="missions_header_finished">Finalitzades</string>
|
||||
<string name="post_processing">post-processament</string>
|
||||
<string name="download_failed">Ha fallat la baixada</string>
|
||||
<string name="download_finished">Baixada finalitzada</string>
|
||||
<string name="download_finished_more">%s baixades finalitzades</string>
|
||||
<string name="overwrite_finished_warning">Ja existeix un fitxer baixat amb aquest nom</string>
|
||||
<string name="overwrite_unrelated_warning">Ja existeix un fitxer amb aquest nom</string>
|
||||
<string name="download_already_running">Hi ha una baixada en curs amb aquest nom</string>
|
||||
<string name="error_ssl_exception">Ha fallat la connexió segura</string>
|
||||
<string name="error_unknown_host">No s\'ha pogut trobar el servidor</string>
|
||||
<string name="error_connect_host">No s\'ha pogut connectar amb el servidor</string>
|
||||
<string name="error_postprocessing_failed">Ha fallat el post-processament</string>
|
||||
<string name="clear_finished_download">Neteja les baixades finalitzades</string>
|
||||
<string name="max_retry_msg">Intents màxims</string>
|
||||
<string name="max_retry_desc">Nombre màxim d\'intents abans de cancel·lar la baixada</string>
|
||||
<string name="pause_downloads_on_mobile">Pausa en canviar a dades mòbils</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Les baixades que no es puguin pausar es tornaran a iniciar</string>
|
||||
</resources>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources><string name="main_bg_subtitle">点击搜索按钮即可开始使用</string>
|
||||
<resources>
|
||||
<string name="main_bg_subtitle">点击搜索按钮即可开始使用</string>
|
||||
<string name="view_count_text">%1$s 次观看</string>
|
||||
<string name="upload_date_text">发布于 %1$s</string>
|
||||
<string name="no_player_found">找不到媒体播放器。您要安装 VLC 吗?</string>
|
||||
|
@ -26,26 +27,20 @@
|
|||
<string name="channel_unsubscribed">退订成功</string>
|
||||
<string name="subscription_change_failed">无法更改订阅</string>
|
||||
<string name="subscription_update_failed">无法更新订阅</string>
|
||||
<string name="show_info">显示详情</string>
|
||||
|
||||
<string name="show_info">显示信息</string>
|
||||
<string name="tab_main">主页</string>
|
||||
<string name="tab_subscriptions">订阅</string>
|
||||
<string name="tab_bookmarks">已添加书签到播放列表</string>
|
||||
|
||||
<string name="fragment_whats_new">新功能</string>
|
||||
|
||||
<string name="controls_background_title">转到后台</string>
|
||||
<string name="controls_popup_title">悬浮窗</string>
|
||||
<string name="controls_add_to_playlist_title">添加到</string>
|
||||
|
||||
<string name="download_path_title">视频下载路径</string>
|
||||
<string name="download_path_summary">储存视频文件的路径</string>
|
||||
<string name="download_path_dialog_title">输入视频的下载地址</string>
|
||||
|
||||
<string name="download_path_audio_title">音频下载的路径</string>
|
||||
<string name="download_path_audio_summary">下载音频的储存路径</string>
|
||||
<string name="download_path_audio_dialog_title">输入音频的下载路径</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">自动播放</string>
|
||||
<string name="autoplay_by_calling_app_summary">NewPipes被其它程序调用时播放视频</string>
|
||||
<string name="default_resolution_title">默认分辨率</string>
|
||||
|
@ -55,7 +50,7 @@
|
|||
<string name="play_with_kodi_title">用 Kodi 播放</string>
|
||||
<string name="kore_not_found">没找到 Kore 应用,需要安装它吗?</string>
|
||||
<string name="show_play_with_kodi_title">显示“用 Kodi 播放”选项</string>
|
||||
<string name="show_play_with_kodi_summary">显示用 Kodi媒体中心 播放视频的选项</string>
|
||||
<string name="show_play_with_kodi_summary">显示以 Kodi 媒体中心播放视频的选项</string>
|
||||
<string name="play_audio">音频</string>
|
||||
<string name="default_audio_format_title">默认音频格式</string>
|
||||
<string name="default_video_format_title">默认视频格式</string>
|
||||
|
@ -64,14 +59,11 @@
|
|||
<string name="dark_theme_title">酷黑</string>
|
||||
<string name="black_theme_title">黑色</string>
|
||||
<string name="popup_remember_size_pos_title">记住悬浮窗的尺寸与位置</string>
|
||||
<string name="m4a_description">M4A — 更好的音质</string>
|
||||
<string name="popup_remember_size_pos_summary">记住上一次悬浮窗的位置以及大小</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">已清除图像缓存</string>
|
||||
<string name="minimize_on_exit_popup_description">最小化悬浮窗播放器</string>
|
||||
|
||||
|
||||
<string name="clear_views_history_title">清除观看历史</string>
|
||||
<string name="search_history_deleted">已删除搜索历史</string>
|
||||
<string name="clear_views_history_title">清除观看历史</string>
|
||||
<string name="search_history_deleted">搜索记录已删除。</string>
|
||||
<string name="general_error">错误</string>
|
||||
<string name="network_error">网络错误</string>
|
||||
<string name="report_error">举报错误</string>
|
||||
|
@ -85,7 +77,6 @@
|
|||
<string name="add">新任务</string>
|
||||
<string name="finish">好
|
||||
\n</string>
|
||||
|
||||
<string name="msg_error">错误
|
||||
\n</string>
|
||||
<string name="msg_server_unsupported">不支持的服务器</string>
|
||||
|
@ -94,34 +85,28 @@
|
|||
<string name="msg_wait">请稍等…</string>
|
||||
<string name="charset_letters_and_digits">字母与数字</string>
|
||||
<string name="charset_most_special_characters">最特别的字符</string>
|
||||
|
||||
<string name="toast_no_player">这个文件里没有已下载应用程式</string>
|
||||
|
||||
<string name="title_activity_about">关于NewPipe</string>
|
||||
<string name="action_settings">设置</string>
|
||||
<string name="action_about">关于</string>
|
||||
<string name="title_licenses">第三方执照</string>
|
||||
<string name="action_open_website">打开网页</string>
|
||||
<string name="unbookmark_playlist">删除书签</string>
|
||||
|
||||
<string name="delete_playlist_prompt">确定要删除该播放列表吗?</string>
|
||||
<string name="playlist_creation_success">已创建播放列表</string>
|
||||
<string name="playlist_add_stream_success">播放列表</string>
|
||||
<string name="playback_step">步骤</string>
|
||||
<string name="playback_reset">重置</string>
|
||||
|
||||
<string name="start_accept_privacy_policy">为了遵守欧洲通用数据保护法规(GDPR,我们请你注意NewPipe的隐私政策.请仔细阅读.
|
||||
\n你必须接受它才能将错误报告发送给我们.</string>
|
||||
<string name="accept">接受</string>
|
||||
<string name="decline">拒绝</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">没有限制</string>
|
||||
<string name="limit_mobile_data_usage_title">使用移动数据时的解析度限制</string>
|
||||
<string name="minimize_on_exit_title">最小化应用程序切换</string>
|
||||
<string name="minimize_on_exit_summary">从主视频播放器切换到其他应用时的操作 - %s</string>
|
||||
<string name="minimize_on_exit_none_description">没有</string>
|
||||
<string name="minimize_on_exit_background_description">最小化后台播放</string>
|
||||
<string name="webm_description">WebM — 自由视频格式</string>
|
||||
<string name="use_inexact_seek_title">使用快速粗略定位</string>
|
||||
<string name="use_inexact_seek_summary">粗略定位功能允许播放器以略低的精确度为代价换取更快的定位速度</string>
|
||||
<string name="download_thumbnail_title">下载缩略图</string>
|
||||
|
@ -256,26 +241,24 @@
|
|||
<string name="audio">音频</string>
|
||||
<string name="retry">重试</string>
|
||||
<string name="storage_permission_denied">手机存储访问权限被拒绝</string>
|
||||
<string name="use_old_player_title">使用旧的播放器</string>
|
||||
<string name="use_old_player_summary">旧的内置 Mediaframework 播放器</string>
|
||||
<string name="short_thousand">千</string>
|
||||
<string name="short_million">万</string>
|
||||
<string name="short_billion">亿</string>
|
||||
<string name="no_subscribers">没有订阅者</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s 位订阅者</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<item quantity="one">%s 位订阅者</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<string name="no_views">无观看次数</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s 次观看</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<item quantity="one">%s 次观看</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<string name="no_videos">没有视频</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">部视频</item>
|
||||
<item quantity="other"></item>
|
||||
</plurals>
|
||||
<item quantity="one">部视频</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<string name="delete_one">删除</string>
|
||||
<string name="checksum">校验</string>
|
||||
<string name="dismiss">退出</string>
|
||||
|
@ -289,7 +272,7 @@
|
|||
<string name="msg_popup_permission">在悬浮窗模式打开
|
||||
\n需要此权限</string>
|
||||
<string name="one_item_deleted">已删除一个项目。</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA 验证</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA 验证</string>
|
||||
<string name="recaptcha_request_toast">需完成 reCAPTCHA 验证</string>
|
||||
<string name="settings_category_downloads_title">下载</string>
|
||||
|
@ -412,7 +395,7 @@
|
|||
\n2.移至该网址:%1$s
|
||||
\n3.当被询问时登入帐号
|
||||
\n4.复制您重定向的配置文件到网址。</string>
|
||||
<string name="import_soundcloud_instructions_hint">yourID, soundcloud.com/yourid</string>
|
||||
<string name="import_soundcloud_instructions_hint">您的 ID,soundcloud.com/yourid</string>
|
||||
<string name="import_network_expensive_warning">请记住,此操作可能造成昂贵的网络花费。
|
||||
\n
|
||||
\n您是否要继续?</string>
|
||||
|
@ -443,7 +426,7 @@
|
|||
<string name="auto">自动</string>
|
||||
<string name="app_update_notification_content_text">轻按以下载</string>
|
||||
<string name="missions_header_finished">已完成</string>
|
||||
<string name="missions_header_pending">于队列中</string>
|
||||
<string name="missions_header_pending">有待</string>
|
||||
<string name="paused">已暂停</string>
|
||||
<string name="queued">已加入队列</string>
|
||||
<string name="post_processing">后处理</string>
|
||||
|
@ -451,14 +434,14 @@
|
|||
<string name="permission_denied">系统拒绝该行动</string>
|
||||
<string name="download_failed">下载失败</string>
|
||||
<string name="download_finished">下载完成</string>
|
||||
<string name="download_finished_more">%已下载完毕</string>
|
||||
<string name="download_finished_more">%s已下载完毕</string>
|
||||
<string name="generate_unique_name">生成独特的名字</string>
|
||||
<string name="overwrite">覆写</string>
|
||||
<string name="overwrite_warning">同名的已下载文件已经存在</string>
|
||||
<string name="overwrite_finished_warning">同名的已下载文件已经存在</string>
|
||||
<string name="download_already_running">同名下载进行中</string>
|
||||
<string name="show_error">显示错误</string>
|
||||
<string name="label_code">代码</string>
|
||||
<string name="error_path_creation">无法创建该文件</string>
|
||||
<string name="error_file_creation">无法创建该文件</string>
|
||||
<string name="error_permission_denied">系统拒绝此批准</string>
|
||||
<string name="error_ssl_exception">安全连接失败</string>
|
||||
<string name="error_unknown_host">找不到服务器</string>
|
||||
|
@ -481,9 +464,9 @@
|
|||
<string name="grid">网格</string>
|
||||
<string name="switch_view">切换视图</string>
|
||||
<string name="app_update_notification_content_title">NewPipe 更新可用!</string>
|
||||
<string name="error_file_creation">无法创建目标文件夹</string>
|
||||
<string name="error_path_creation">无法创建目标文件夹</string>
|
||||
<string name="error_http_unsupported_range">服务器不接受多线程下载, 请重试使用 @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">请求的范围不满足</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">请求范围无法满足</string>
|
||||
<string name="msg_pending_downloads">继续进行%s个待下载转移</string>
|
||||
<string name="pause_downloads_on_mobile_desc">将重新启动无法暂停的下载</string>
|
||||
<string name="pause_downloads_on_mobile_desc">无法暂停的下载将重新开始</string>
|
||||
</resources>
|
|
@ -15,10 +15,8 @@
|
|||
<string name="screen_rotation">otočení</string>
|
||||
<string name="use_external_video_player_title">Použít externí video přehrávač</string>
|
||||
<string name="use_external_audio_player_title">Použít externí audio přehrávač</string>
|
||||
|
||||
<string name="download_path_audio_summary">Stažené audio je uloženo zde</string>
|
||||
<string name="download_path_audio_dialog_title">Zadejte umístění pro stažené audio soubory</string>
|
||||
|
||||
<string name="download_path_audio_title">Složka pro stažené audio</string>
|
||||
<string name="default_resolution_title">Výchozí rozlišení</string>
|
||||
<string name="play_with_kodi_title">Přehrát pomocí Kodi</string>
|
||||
|
@ -27,7 +25,6 @@
|
|||
<string name="download_path_title">Umístění pro stažené video</string>
|
||||
<string name="download_path_summary">Cesta, kam se uloží stažené video</string>
|
||||
<string name="download_path_dialog_title">Zadejte umístění pro stažená videa</string>
|
||||
|
||||
<string name="show_play_with_kodi_title">Zobrazit možnost \"Přehrát pomocí Kodi\"</string>
|
||||
<string name="show_play_with_kodi_summary">Zobrazit možnost přehrání videa pomocí multimediálního centra Kodi</string>
|
||||
<string name="play_audio">Zvuk</string>
|
||||
|
@ -35,7 +32,6 @@
|
|||
<string name="theme_title">Téma</string>
|
||||
<string name="dark_theme_title">Tmavé</string>
|
||||
<string name="light_theme_title">Světlé</string>
|
||||
|
||||
<string name="download_dialog_title">Stáhnout</string>
|
||||
<string name="next_video_title">Další videa</string>
|
||||
<string name="show_next_and_similar_title">Zobrazovat \'další\' a \'podobná\' videa</string>
|
||||
|
@ -53,7 +49,6 @@
|
|||
<string name="parsing_error">Nebylo možné analyzovat stránku</string>
|
||||
<string name="content_not_available">Obsah není k dispozici</string>
|
||||
<string name="blocked_by_gema">Obsah blokuje GEMA</string>
|
||||
|
||||
<string name="list_thumbnail_view_description">Náhled videa</string>
|
||||
<string name="detail_thumbnail_view_description">Náhled videa</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Náhled avataru uploadera</string>
|
||||
|
@ -61,7 +56,6 @@
|
|||
<string name="detail_dislikes_img_view_description">To se mi nelíbí</string>
|
||||
<string name="use_tor_title">Použít Tor</string>
|
||||
<string name="use_tor_summary">(Experimentální) Vynutit stahování skrz Tor pro zvýšené soukromí (streamovaná videa zatím nepodporována).</string>
|
||||
|
||||
<string name="err_dir_create">Nebylo možné vytvořit složku pro stažené soubory \'%1$s\'</string>
|
||||
<string name="info_dir_created">Vytvořena složka pro stažené soubory \'%1$s\'</string>
|
||||
<string name="autoplay_by_calling_app_title">Automaticky přehrávat</string>
|
||||
|
@ -70,7 +64,6 @@
|
|||
<string name="show_age_restricted_content_title">Věkově omezený obsah</string>
|
||||
<string name="video_is_age_restricted">Zobrazit video s věkovým omezením. Povolit tento obsah lze v \"Nastavení\".</string>
|
||||
<string name="duration_live">ŽIVĚ</string>
|
||||
|
||||
<string name="light_parsing_error">Nebylo možné kompletně analyzovat stránku</string>
|
||||
<string name="main_bg_subtitle">Začni stiskem hledat</string>
|
||||
<string name="msg_copied">Zkopírováno do schránky</string>
|
||||
|
@ -85,15 +78,12 @@
|
|||
<string name="msg_threads">Vlákna</string>
|
||||
<string name="pause">Zastavit</string>
|
||||
<string name="delete">Smazat</string>
|
||||
|
||||
<string name="start">Start</string>
|
||||
<string name="retry">Zkusit znovu</string>
|
||||
<string name="video">Video</string>
|
||||
<string name="audio">Zvuk</string>
|
||||
<string name="report_error">Nahlásit chybu</string>
|
||||
<string name="error_details_headline">Podrobnosti:</string>
|
||||
|
||||
|
||||
<string name="what_happened_headline">Co se stalo:</string>
|
||||
<string name="error_snackbar_action">NAHLÁSIT</string>
|
||||
<string name="sorry_string">Omlouváme se, tohle se nemělo stát.</string>
|
||||
|
@ -105,7 +95,6 @@
|
|||
<string name="could_not_get_stream">Nepodařilo se dostat žádný stream</string>
|
||||
<string name="could_not_setup_download_menu">Nepodařilo se nastavit menu stahování</string>
|
||||
<string name="error_report_title">Nahlásit chybu</string>
|
||||
|
||||
<string name="downloads">Stažené soubory</string>
|
||||
<string name="downloads_title">Stažené soubory</string>
|
||||
<string name="what_device_headline">Info:</string>
|
||||
|
@ -114,35 +103,24 @@
|
|||
<string name="view">Přehrát</string>
|
||||
<string name="add">Nová mise</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">Výzva reCAPTCHA</string>
|
||||
<string name="recaptcha_request_toast">Požadována výzva reCAPTCHA</string>
|
||||
|
||||
<string name="black_theme_title">Černé</string>
|
||||
|
||||
<string name="checksum">Kontrolní součet</string>
|
||||
|
||||
<string name="no_available_dir">Prosím vyberte dostupnou složku pro stahování</string>
|
||||
|
||||
<string name="user_report">Hlášení uživatele</string>
|
||||
|
||||
<string name="info_labels">Co:\\nŽádost:\\nJazyk obsahu:\\nSlužba:\\nČas GMT:\\nBalíček:\\nVerze:\\nVerze OS:</string>
|
||||
<string name="all">Vše</string>
|
||||
<string name="channel">Kanál</string>
|
||||
<string name="yes">Ano</string>
|
||||
<string name="later">Později</string>
|
||||
|
||||
|
||||
<string name="short_thousand">tis.</string>
|
||||
|
||||
<string name="open_in_popup_mode">Otevřít ve vyskakovacím okně</string>
|
||||
<string name="short_million">mil.</string>
|
||||
<string name="msg_popup_permission">Toto oprávnění je vyžadováno pro
|
||||
otevření ve vyskakovacím okně</string>
|
||||
|
||||
<string name="use_old_player_title">Použít starý přehrávač</string>
|
||||
<string name="use_external_video_player_summary">Odstraňuje zvuk v některých rozlišeních</string>
|
||||
<string name="use_external_video_player_summary">Odstraňuje zvuk v některých rozlišeních</string>
|
||||
<string name="show_higher_resolutions_title">Zobrazovat vyšší rozlišení</string>
|
||||
<string name="show_higher_resolutions_summary">Pouze některá zařízení podporují přehrávání 2K/4K videí</string>
|
||||
<string name="default_video_format_title">Výchozí formát videa</string>
|
||||
|
@ -154,15 +132,11 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="channel_unsubscribed">Odběr zrušen</string>
|
||||
<string name="subscription_change_failed">Nelze změnit odběr</string>
|
||||
<string name="subscription_update_failed">Nelze aktualizovat odběr</string>
|
||||
|
||||
<string name="tab_main">Hlavní</string>
|
||||
<string name="tab_subscriptions">Odběry</string>
|
||||
|
||||
<string name="fragment_whats_new">Co je nového</string>
|
||||
|
||||
<string name="controls_background_title">Na pozadí</string>
|
||||
<string name="controls_popup_title">V okně</string>
|
||||
|
||||
<string name="default_popup_resolution_title">Výchozí rozlišení vyskakovacího okna</string>
|
||||
<string name="player_gesture_controls_title">Ovládání přehrávače gesty</string>
|
||||
<string name="player_gesture_controls_summary">Používat gesta pro nastavení jasu a hlasitosti přehrávače</string>
|
||||
|
@ -187,46 +161,35 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="popup_resizing_indicator_title">Změna velikosti</string>
|
||||
<string name="best_resolution">Nejlepší rozlišení</string>
|
||||
<string name="undo">Vrátit</string>
|
||||
|
||||
<string name="notification_channel_name">NewPipe notifikace</string>
|
||||
<string name="notification_channel_description">Notifikace pro NewPipe přehrávače v pozadí a v okně</string>
|
||||
|
||||
<string name="search_no_results">Žádné výsledky</string>
|
||||
<string name="empty_subscription_feed_subtitle">Je tu sranda jak v márnici</string>
|
||||
|
||||
<string name="use_old_player_summary">Starý zabudovaný Mediaframework přehrávač</string>
|
||||
|
||||
<string name="short_billion">mld.</string>
|
||||
|
||||
<string name="no_subscribers">Žádní odběratelé</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s odběratel</item>
|
||||
<item quantity="few">%s odběratelé</item>
|
||||
<item quantity="other">%s odběratelů</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s odběratel</item>
|
||||
<item quantity="few">%s odběratelé</item>
|
||||
<item quantity="other">%s odběratelů</item>
|
||||
</plurals>
|
||||
<string name="no_views">Žádná zhlédnutí</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s zhlédnutí</item>
|
||||
<item quantity="few">%s zhlédnutí</item>
|
||||
<item quantity="other">%s zhlédnutí</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s zhlédnutí</item>
|
||||
<item quantity="few">%s zhlédnutí</item>
|
||||
<item quantity="other">%s zhlédnutí</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Žádná videa</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s video</item>
|
||||
<item quantity="few">%s videa</item>
|
||||
<item quantity="other">%s videí</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s video</item>
|
||||
<item quantity="few">%s videa</item>
|
||||
<item quantity="other">%s videí</item>
|
||||
</plurals>
|
||||
<string name="settings_category_downloads_title">Stahování</string>
|
||||
<string name="settings_file_charset_title">Povolené znaky v názvech souborů</string>
|
||||
<string name="settings_file_replacement_character_summary">Neplatné znaky budou nahrazeny těmito</string>
|
||||
<string name="settings_file_replacement_character_title">Náhradní znak</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Písmena a číslice</string>
|
||||
<string name="charset_most_special_characters">Většina speciálních znaků</string>
|
||||
|
||||
<string name="title_activity_about">O NewPipe</string>
|
||||
<string name="action_settings">Nastavení</string>
|
||||
<string name="action_about">O aplikaci</string>
|
||||
|
@ -243,7 +206,6 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="contribution_encouragement">Pokud máte nápady na zlepšení jako; překlad, změny designu, vylepšování kódu nebo opravdu velké změny kódu - pomoc je vždy vítána. Čím více se udělá, tím lepší to bude!</string>
|
||||
<string name="read_full_license">Přečíst licenci</string>
|
||||
<string name="contribution_title">Podílet se</string>
|
||||
|
||||
<string name="title_activity_history">Historie</string>
|
||||
<string name="title_history_search">Vyhledáváno</string>
|
||||
<string name="title_history_view">Zhlédnuto</string>
|
||||
|
@ -252,18 +214,15 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="history_empty">Historie je prázdná</string>
|
||||
<string name="history_cleared">Historie vymazána</string>
|
||||
<string name="item_deleted">Položka byla odstraněna</string>
|
||||
<string name="show_hold_to_append_title">Zobrazovat tip \"Podržet pro přidání\"</string>
|
||||
<string name="show_hold_to_append_title">Zobrazovat tip \"Podržet pro přidání\"</string>
|
||||
<string name="show_hold_to_append_summary">Zobrazí se po stisku tlačítek přehrát na pozadí nebo přehrát v okně na stránce s videem</string>
|
||||
<string name="background_player_append">Ve frontě přehrávače na pozadí</string>
|
||||
<string name="popup_playing_append">Ve frontě přehrávače v okně</string>
|
||||
<string name="play_all">Přehrát vše</string>
|
||||
|
||||
<string name="player_stream_failure">Tento stream nelze přehrát</string>
|
||||
<string name="player_unrecoverable_failure">Došlo k neobnovitelné chybě přehrávače</string>
|
||||
<string name="player_recoverable_failure">Obnovování z chyby přehrávače</string>
|
||||
|
||||
<string name="delete_item_search_history">Odstranit tuto položku z historie vyhledávání?</string>
|
||||
|
||||
<string name="main_page_content">Obsah úvodní obrazovky</string>
|
||||
<string name="blank_page_summary">Prázdná stránka</string>
|
||||
<string name="kiosk_page_summary">Kiosek</string>
|
||||
|
@ -273,7 +232,6 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="select_a_channel">Zvolte kanál</string>
|
||||
<string name="no_channel_subscribed_yet">Žádný kanál dosud neodebírán</string>
|
||||
<string name="select_a_kiosk">Zvolte kiosek</string>
|
||||
|
||||
<string name="kiosk">Kiosek</string>
|
||||
<string name="trending">Trendy</string>
|
||||
<string name="top_50">Top 50</string>
|
||||
|
@ -284,14 +242,13 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="play_queue_stream_detail">Podrobnosti</string>
|
||||
<string name="play_queue_audio_settings">Nastavení zvuku</string>
|
||||
<string name="hold_to_append">Podrž pro zařazení do fronty</string>
|
||||
<string name="unknown_content">[Neznámý]</string>
|
||||
|
||||
<string name="unknown_content">[Neznámý]</string>
|
||||
<string name="enqueue_on_background">Do fronty na pozadí</string>
|
||||
<string name="enqueue_on_popup">Do fronty v okně</string>
|
||||
<string name="start_here_on_main">Začne hrát zde</string>
|
||||
<string name="start_here_on_background">Začne zde, když na pozadí</string>
|
||||
<string name="start_here_on_popup">Začne zde v okně</string>
|
||||
<string name="donation_title">Donate</string>
|
||||
<string name="donation_title">Donate</string>
|
||||
<string name="donation_encouragement">NewPipe je vyvíjen dobrovolníky, kteří tráví svůj čas, aby vaše zkušenost s aplikací byla co nejlepší. Vraťte vývojářům něco zpět, aby mohli NewPipe dále zlepšovat a zároveň si vychutnat šálek kávy.</string>
|
||||
<string name="give_back">Daruj</string>
|
||||
<string name="website_title">Webová stránka</string>
|
||||
|
@ -302,13 +259,11 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="switch_to_background">Na pozadí</string>
|
||||
<string name="switch_to_popup">Do okna</string>
|
||||
<string name="switch_to_main">Přepnout na hlavní</string>
|
||||
|
||||
<string name="drawer_open">Otevřít Drawer</string>
|
||||
<string name="drawer_close">Zavřít Drawer</string>
|
||||
<string name="no_player_found_toast">Nenalezen přehrávač streamu (pro přehrání můžete nainstalovat např. VLC).</string>
|
||||
<string name="always">Vždy</string>
|
||||
<string name="just_once">Pouze jednou</string>
|
||||
|
||||
<string name="import_data_title">Importovat databázi</string>
|
||||
<string name="export_data_title">Exportovat databázi</string>
|
||||
<string name="import_data_summary">Přepíše vaši dosavadní historii a odběry</string>
|
||||
|
@ -317,67 +272,49 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="invalid_url_toast">Neplatná URL</string>
|
||||
<string name="video_streams_empty">Nenalezeny žádné video streamy</string>
|
||||
<string name="audio_streams_empty">Nenalezeny žádné audio streamy</string>
|
||||
|
||||
<string name="export_complete_toast">Exportováno</string>
|
||||
<string name="import_complete_toast">Importováno</string>
|
||||
<string name="no_valid_zip_file">Žádný platný soubor ZIP</string>
|
||||
<string name="could_not_import_all_files">Upozornění: Nelze importovat všechny soubory.</string>
|
||||
<string name="override_current_data">Tímto se anuluje vaše aktuální nastavení.</string>
|
||||
|
||||
<string name="video_player">Video přehrávač</string>
|
||||
<string name="background_player">Přehrávač na pozadí</string>
|
||||
<string name="popup_player">Přehrávač v okně</string>
|
||||
<string name="always_ask_player">Vždy se ptát</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Získávám informace…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Načítání požadovaného obsahu</string>
|
||||
<string name="controls_download_desc">Stáhnout soubor streamu</string>
|
||||
<string name="controls_download_desc">Stáhnout soubor streamu</string>
|
||||
<string name="show_info">Ukázat informace</string>
|
||||
|
||||
<string name="tab_bookmarks">Uložené playlisty</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">Přidat do</string>
|
||||
|
||||
<string name="detail_drag_description">Táhnout pro přeskupení</string>
|
||||
|
||||
<string name="create">Vytvořit</string>
|
||||
<string name="delete_one">Smazat jeden</string>
|
||||
<string name="delete_all">Smazat vše</string>
|
||||
<string name="dismiss">Zahodit</string>
|
||||
<string name="rename">Přejmenovat</string>
|
||||
|
||||
<string name="delete_stream_history_prompt">Přejete si smazat tuto položku z historie shlédnutí?</string>
|
||||
<string name="delete_all_history_prompt">Jste si jisti, že chcete odstranit všechny položky z historie?</string>
|
||||
<string name="title_last_played">Poslední přehráno</string>
|
||||
<string name="title_most_played">Nejvíce přehráno</string>
|
||||
|
||||
<string name="drawer_header_action_paceholder_text">Zde se brzy něco objeví ;D</string>
|
||||
|
||||
|
||||
<string name="always_ask_open_action">Vždy se zeptat</string>
|
||||
|
||||
<string name="create_playlist">Nový playlist</string>
|
||||
<string name="delete_playlist">Vymazat</string>
|
||||
<string name="rename_playlist">Přejmenovat</string>
|
||||
<string name="playlist_name_input">Jméno</string>
|
||||
<string name="append_playlist">Přidat do playlistu</string>
|
||||
<string name="set_as_playlist_thumbnail">Nastavit jako náhled playlistu</string>
|
||||
|
||||
<string name="bookmark_playlist">Založit playlist</string>
|
||||
<string name="bookmark_playlist">Přidat playlist do záložek</string>
|
||||
<string name="unbookmark_playlist">Smazat záložku</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Smazat tento playlist\?</string>
|
||||
<string name="playlist_creation_success">Playlist vytvořen</string>
|
||||
<string name="playlist_add_stream_success">V playlistu</string>
|
||||
<string name="playlist_thumbnail_change_success">Náhled playlistu změněn.</string>
|
||||
<string name="playlist_delete_failure">Playlist nelze smazat.</string>
|
||||
|
||||
<string name="caption_none">Žádné titulky</string>
|
||||
|
||||
<string name="caption_none">Bez titulků</string>
|
||||
<string name="resize_fit">Přizpůsobit</string>
|
||||
<string name="resize_fill">Vyplnit</string>
|
||||
<string name="resize_zoom">Zvětšit</string>
|
||||
|
||||
<string name="caption_font_size_settings_title">Velikost písma nadpisu</string>
|
||||
<string name="smaller_caption_font_size">Menší písmo</string>
|
||||
<string name="normal_caption_font_size">Normální písmo</string>
|
||||
|
@ -385,19 +322,17 @@ otevření ve vyskakovacím okně</string>
|
|||
|
||||
<string name="toggle_leak_canary">Sledovat únik paměti</string>
|
||||
<string name="disable_leak_canary_notice">Sledování úniku paměti vypnuto</string>
|
||||
<string name="enable_leak_canary_notice">Sledování úniku paměti povoleno, aplikace může při zátěži přestat reagovat</string>
|
||||
<string name="enable_leak_canary_notice">Sledování úniku paměti povoleno, aplikace může při zátěži přestat reagovat</string>
|
||||
<string name="settings_category_debug_title">Ladění</string>
|
||||
<string name="caption_auto_generated">"Automaticky generováno "</string>
|
||||
<string name="enable_leak_canary_title">Povolit službu LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">Monitoring úniku paměti může způsobit nereagování aplikace při heap dumpingu</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Nahlásit mimo-cyklické chyby</string>
|
||||
<string name="enable_disposed_exceptions_summary">Vynutit vykazování výjimek Rx mimo fragment nebo životnost cyklu po odstranění</string>
|
||||
|
||||
<string name="use_inexact_seek_title">Použít rychlé nepřesné hledání</string>
|
||||
<string name="use_inexact_seek_title">Použít rychlé nepřesné hledání</string>
|
||||
<string name="use_inexact_seek_summary">Nepřesné hledání umožní přehrávači posouvat se rychleji, ale se sníženou přesností</string>
|
||||
<string name="download_thumbnail_title">Načítat náhledy</string>
|
||||
<string name="download_thumbnail_summary">Po vypnutí se nestahují náhledy a tím se šetří data a využití paměti. Změna tohoto nastavení vyčistí mezipamět obrázků.</string>
|
||||
<string name="download_thumbnail_summary">Vypnout, aby se zabránilo načítání náhledů a tím se ušetřily data a používání paměti. Změna tohoto nastavení vyčistí mezipamět obrázků v paměti i na disku.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Mezipaměť obrázků vymazána</string>
|
||||
<string name="metadata_cache_wipe_title">Vymazat metadata v mezipaměti</string>
|
||||
<string name="metadata_cache_wipe_summary">Odebrat všechna data uložená v mezipaměti</string>
|
||||
|
@ -405,13 +340,11 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="auto_queue_title">Automatická fronta dalšího streamu</string>
|
||||
<string name="auto_queue_summary">Automaticky připojí související stream při přehrávání posledního streamu v neopakující se frontě.</string>
|
||||
<string name="file">Soubor</string>
|
||||
|
||||
<string name="invalid_directory">Neexistující složka</string>
|
||||
<string name="invalid_source">Neexistující zdroj souboru/obsahu</string>
|
||||
<string name="invalid_file">Soubor neexistuje nebo chybí oprávnění k jeho čtení či zápisu</string>
|
||||
<string name="file_name_empty_error">Název souboru nesmí být prázdný</string>
|
||||
<string name="error_occurred_detail">Došlo k chybě: %1$s</string>
|
||||
|
||||
<string name="import_export_title">Import/export
|
||||
\n</string>
|
||||
<string name="import_title">Importovat
|
||||
|
@ -419,16 +352,12 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="import_from">Importovat z
|
||||
\n</string>
|
||||
<string name="export_to">Exportovat do</string>
|
||||
|
||||
<string name="import_ongoing">Importuji…</string>
|
||||
<string name="export_ongoing">Exportuji…</string>
|
||||
|
||||
<string name="import_file_title">Import souboru</string>
|
||||
<string name="previous_export">Předchozí export</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Odběry nelze importovat</string>
|
||||
<string name="subscriptions_export_unsuccessful">Odběry nelze exportovat</string>
|
||||
|
||||
<string name="import_youtube_instructions">Importovat YouTube odběry stáhnutím exportního souboru:
|
||||
\n
|
||||
\n1. Přejděte na tuto URL adresu: %1$s
|
||||
|
@ -441,27 +370,21 @@ otevření ve vyskakovacím okně</string>
|
|||
\n3. Na vyžádání se přihlašte
|
||||
\n4. Zkopírujte URL adresu profilu, na kterou jste byli přesměrováni.</string>
|
||||
<string name="import_soundcloud_instructions_hint">vašeID, soundcloud.com/yourid</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Pamatujte, že tato operace může být náročná na data.
|
||||
\n
|
||||
\nChcete pokračovat?</string>
|
||||
|
||||
<string name="playback_speed_control">Ovládání rychlosti přehrávání</string>
|
||||
<string name="playback_tempo">Rychlost</string>
|
||||
<string name="playback_pitch">Stupeň tónu</string>
|
||||
<string name="playback_pitch">Výška tónu</string>
|
||||
<string name="unhook_checkbox">Rozpojit (může způsobit zkreslení)</string>
|
||||
<string name="playback_nightcore">Nightcore mód</string>
|
||||
<string name="playback_default">Výchozí nastavení</string>
|
||||
<string name="no_streams_available_download">Ke stažení nejsou dostupné žádné streamy</string>
|
||||
|
||||
<string name="no_streams_available_download">Ke stažení nejsou dostupné žádné streamy</string>
|
||||
<string name="preferred_open_action_settings_title">Preferovaná \'otevřít\' akce</string>
|
||||
<string name="preferred_open_action_settings_summary">Výchozí chování při otevírání obsahu — %s</string>
|
||||
|
||||
<string name="caption_setting_title">Titulky</string>
|
||||
<string name="caption_setting_description">Upravuje velikost textu titulků a styly pozadí. Změny se projeví po restartu aplikace.</string>
|
||||
|
||||
<string name="toast_no_player">K přehrání tohoto souboru chybí vhodná aplikace</string>
|
||||
|
||||
<string name="clear_views_history_title">Vymazat historii sledování</string>
|
||||
<string name="clear_views_history_summary">Vymaže historii přehrávaných streamů</string>
|
||||
<string name="delete_view_history_alert">Vymazat celkovou historii sledování\?</string>
|
||||
|
@ -471,7 +394,6 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="delete_search_history_alert">Vymazat celkovou historii vyhledávání\?</string>
|
||||
<string name="search_history_deleted">Historie vyhledávání smazána.</string>
|
||||
<string name="one_item_deleted">Jedna položka smazána.</string>
|
||||
|
||||
<string name="app_license">NewPipe je copyleft libre software: Můžete jej používat, sdílet a vylepšovat dle vaší vůle. Redistribuovat a/nebo upravovat lze za podmínek GNU General Public Licence zveřejňované nadací Free Software Foundation, a to buď za podmínek licence verze 3 nebo (dle vaší volby) jakékoli pozdější verze.</string>
|
||||
<string name="channels">kanály</string>
|
||||
<string name="playlists">Playlisty</string>
|
||||
|
@ -482,16 +404,13 @@ otevření ve vyskakovacím okně</string>
|
|||
\nZásady ochrany soukromí NewPipe podrobně vysvětlují, jaké údaje jsou odesílány a ukládány, když odešlete zprávu o pádu aplikace.</string>
|
||||
<string name="read_privacy_policy">Přečíst zásady ochrany soukromí</string>
|
||||
<string name="import_settings">Chcete také přenést nastavení?</string>
|
||||
|
||||
<string name="skip_silence_checkbox">Zrychleně vpřed během ticha</string>
|
||||
<string name="playback_step">Krok</string>
|
||||
<string name="playback_reset">Reset</string>
|
||||
|
||||
<string name="start_accept_privacy_policy">Abychom vyhověli Obecnému nařízení o ochraně osobních údajů (GDPR), upozorňujeme vás na zásady ochrany soukromí v NewPipe. Přečtěte si je prosím pozorně.
|
||||
\nJe potřeba je odsouhlasit, abyste nám mohli odeslat hlášení chyb.</string>
|
||||
<string name="accept">Přijmout</string>
|
||||
<string name="decline">Odmítnout</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Bez omezení</string>
|
||||
<string name="limit_mobile_data_usage_title">Omezit rozlišení při použití mobilních dat</string>
|
||||
<string name="minimize_on_exit_title">Minimalizovat při přepínání aplikací</string>
|
||||
|
@ -511,4 +430,56 @@ otevření ve vyskakovacím okně</string>
|
|||
<string name="app_update_notification_channel_name">Notifikace aktualizace aplikace</string>
|
||||
<string name="app_update_notification_channel_description">Notifikace pro novou verzi NewPipe</string>
|
||||
<string name="download_to_sdcard_error_title">Externí úložiště není k dispozici</string>
|
||||
<string name="saved_tabs_invalid_json">Chyba při načítání uložených karet, použijí se výchozí karty</string>
|
||||
<string name="restore_defaults">Obnovit do výchozího nastavení</string>
|
||||
<string name="restore_defaults_confirmation">Chcete obnovit výchozí nastavení\?</string>
|
||||
<string name="subscribers_count_not_available">Počet odběratelů není k dispozici</string>
|
||||
<string name="main_page_content_summary">Karty, které jsou zobrazeny na hlavní stránce</string>
|
||||
<string name="selection">Výběr</string>
|
||||
<string name="updates_setting_title">Aktualizace</string>
|
||||
<string name="events">Události</string>
|
||||
<string name="conferences">Konference</string>
|
||||
<string name="updates_setting_description">Zobrazit oznámení s výzvou k aktualizaci aplikace, když je k dispozici nová verze</string>
|
||||
<string name="list_view_mode">Režim zobrazení seznamu</string>
|
||||
<string name="list">Seznam</string>
|
||||
<string name="grid">Mřížka</string>
|
||||
<string name="auto">Automaticky</string>
|
||||
<string name="switch_view">Přepnout zobrazení</string>
|
||||
<string name="app_update_notification_content_title">K dispozici je aktualizace aplikace NewPipe!</string>
|
||||
<string name="app_update_notification_content_text">Klepněte pro stažení</string>
|
||||
<string name="missions_header_finished">Hotovo</string>
|
||||
<string name="missions_header_pending">Ve frontě</string>
|
||||
<string name="paused">Pozastaveno</string>
|
||||
<string name="queued">ve frontě</string>
|
||||
<string name="post_processing">post-processing</string>
|
||||
<string name="enqueue">Fronta</string>
|
||||
<string name="permission_denied">Akce odmítnuta systémem</string>
|
||||
<string name="download_failed">Stahování se nezdařilo</string>
|
||||
<string name="download_finished">Stahování dokončeno</string>
|
||||
<string name="download_finished_more">% s stahování dokončeno</string>
|
||||
<string name="generate_unique_name">Vytvořit jedinečný název</string>
|
||||
<string name="overwrite">Přepsat</string>
|
||||
<string name="overwrite_unrelated_warning">Stažený soubor s tímto názvem již existuje</string>
|
||||
<string name="overwrite_finished_warning">Stažený soubor s tímto názvem již existuje</string>
|
||||
<string name="download_already_running">Stahování s tímto názvem již probíhá</string>
|
||||
<string name="show_error">Zobrazit chybu</string>
|
||||
<string name="label_code">Kód</string>
|
||||
<string name="error_path_creation">Soubor nelze vytvořit</string>
|
||||
<string name="error_file_creation">Cílovou složku nelze vytvořit</string>
|
||||
<string name="error_permission_denied">Oprávnění odepřeno systémem</string>
|
||||
<string name="error_ssl_exception">Zabezpečené připojení selhalo</string>
|
||||
<string name="error_unknown_host">Server se nepodařilo najít</string>
|
||||
<string name="error_connect_host">Nelze se připojit k serveru</string>
|
||||
<string name="error_http_no_content">Server neposílá data</string>
|
||||
<string name="error_http_unsupported_range">Server neakceptuje vícevláknové stahování, opakujte akci s @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Požadovaný rozsah nelze splnit</string>
|
||||
<string name="error_http_not_found">Nenalezeno</string>
|
||||
<string name="error_postprocessing_failed">Post-processing selhal</string>
|
||||
<string name="clear_finished_download">Vyčistit dokončená stahování</string>
|
||||
<string name="msg_pending_downloads">Pokračovat ve stahování %s souborů, čekajících na stažení</string>
|
||||
<string name="stop">Zastavit</string>
|
||||
<string name="max_retry_msg">Maximální počet pokusů o opakování</string>
|
||||
<string name="max_retry_desc">Maximální počet pokusů před zrušením stahování</string>
|
||||
<string name="pause_downloads_on_mobile">Pozastavit při přepnutí na mobilní data</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Stahování, která nelze pozastavit, budou restartována</string>
|
||||
</resources>
|
|
@ -1,16 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources><string name="main_bg_subtitle">Tryk søg for at komme i gang</string>
|
||||
<resources>
|
||||
<string name="main_bg_subtitle">Tryk søg for at komme i gang</string>
|
||||
<string name="view_count_text">%1$s visninger</string>
|
||||
<string name="upload_date_text">Udgivet den %1$s</string>
|
||||
<string name="upload_date_text">Udgivet %1$s</string>
|
||||
<string name="no_player_found">Ingen streamafspiller blev fundet. Vil du installere VLC\?</string>
|
||||
<string name="no_player_found_toast">Ingen streamafspiller blev fundet (du kan installere VLC for at afspille den).</string>
|
||||
<string name="no_player_found_toast">Ingen streamafspiller fundet (du kan installere VLC for at afspille den).</string>
|
||||
<string name="install">Installer</string>
|
||||
<string name="cancel">Annuller</string>
|
||||
<string name="open_in_browser">åben i browser</string>
|
||||
<string name="open_in_popup_mode">Åben i popup tilstand</string>
|
||||
<string name="open_in_browser">Åbn i browser</string>
|
||||
<string name="open_in_popup_mode">Åbn i pop op-tilstand</string>
|
||||
<string name="share">Del</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="controls_download_desc">Download stream fil</string>
|
||||
<string name="controls_download_desc">Download stream-fil</string>
|
||||
<string name="search">Søg</string>
|
||||
<string name="settings">Indstillinger</string>
|
||||
<string name="did_you_mean">Mente du: %1$s\?</string>
|
||||
|
@ -18,101 +19,100 @@
|
|||
<string name="choose_browser">Vælg browser</string>
|
||||
<string name="screen_rotation">rotation</string>
|
||||
<string name="use_external_video_player_title">Benyt ekstern videoafspiller</string>
|
||||
<string name="use_external_video_player_summary">Fjerner lyd ved nogle opløsninger</string>
|
||||
<string name="use_external_video_player_summary">Fjerner lyd ved NOGLE opløsninger</string>
|
||||
<string name="use_external_audio_player_title">Brug ekstern lydafspiller</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe popup tilstand</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe pop op-tilstand</string>
|
||||
<string name="subscribe_button_title">Abonner</string>
|
||||
<string name="subscribed_button_title">Abonneret</string>
|
||||
<string name="unsubscribe">Afmeld Abonnement</string>
|
||||
<string name="channel_unsubscribed">Abonnement afmeldt for kanal</string>
|
||||
<string name="unsubscribe">Afmeld abonnement</string>
|
||||
<string name="channel_unsubscribed">Abonnement afmeldt</string>
|
||||
<string name="subscription_change_failed">Kunne ikke ændre abonnement</string>
|
||||
<string name="subscription_update_failed">Kunne ikke opdatere abonnoment</string>
|
||||
<string name="subscription_update_failed">Kunne ikke opdatere abonnement</string>
|
||||
<string name="show_info">Vis info</string>
|
||||
<string name="tab_main">Forside</string>
|
||||
<string name="tab_subscriptions">Abbonnomenter</string>
|
||||
<string name="tab_bookmarks">Gemte Playlister</string>
|
||||
<string name="tab_new">Ny Tab</string>
|
||||
<string name="tab_choose">Vælg Tab</string>
|
||||
<string name="tab_main">Primær</string>
|
||||
<string name="tab_subscriptions">Abonnementer</string>
|
||||
<string name="tab_bookmarks">Gemte spillelister</string>
|
||||
<string name="tab_new">Ny fane</string>
|
||||
<string name="tab_choose">Vælg fane</string>
|
||||
<string name="fragment_whats_new">Nyheder</string>
|
||||
<string name="controls_background_title">Baggrund</string>
|
||||
<string name="controls_popup_title">Popup</string>
|
||||
<string name="controls_add_to_playlist_title">Tilføj Til</string>
|
||||
<string name="download_path_title">Video download sti</string>
|
||||
<string name="download_path_summary">Sti til gemme downloade videoer</string>
|
||||
<string name="download_path_dialog_title">Indtast download mappe for videoer</string>
|
||||
<string name="download_path_audio_title">Lyd download mappe</string>
|
||||
<string name="controls_popup_title">Pop op</string>
|
||||
<string name="controls_add_to_playlist_title">Føj til</string>
|
||||
<string name="download_path_title">Placering af videodownloads</string>
|
||||
<string name="download_path_summary">Mappe som videoer skal downloades til</string>
|
||||
<string name="download_path_dialog_title">Angiv downloadmappe for videoer</string>
|
||||
<string name="download_path_audio_title">Downloadmappe for lydfiler</string>
|
||||
<string name="download_path_audio_summary">Downloadede lydfiler bliver gemt her</string>
|
||||
<string name="download_path_audio_dialog_title">Indtast download mappe for lydfiler</string>
|
||||
<string name="download_path_audio_dialog_title">Angiv downloadmappe for lydfiler</string>
|
||||
<string name="autoplay_by_calling_app_title">Afspil automatisk</string>
|
||||
<string name="autoplay_by_calling_app_summary">Afspil en video ny NewPipe bliver åbnet fra en anden app</string>
|
||||
<string name="default_resolution_title">Standard opløsning</string>
|
||||
<string name="default_popup_resolution_title">Stadard popup opløsning</string>
|
||||
<string name="autoplay_by_calling_app_summary">Afspiller video automatisk når NewPipe bliver åbnet fra en anden app</string>
|
||||
<string name="default_resolution_title">Standardopløsning</string>
|
||||
<string name="default_popup_resolution_title">Standardopløsning for pop op</string>
|
||||
<string name="show_higher_resolutions_title">Vis højere opløsninger</string>
|
||||
<string name="show_higher_resolutions_summary">Ikke alle enheder understøtter afspilning af 2K/4K videoer</string>
|
||||
<string name="show_higher_resolutions_summary">Ikke alle enheder understøtter afspilning af 2K/4K-videoer</string>
|
||||
<string name="play_with_kodi_title">Afspil med Kodi</string>
|
||||
<string name="kore_not_found">Kore appen kunne ikke findes. Installer den\?</string>
|
||||
<string name="show_play_with_kodi_title">Vis \"Afspil med Kodi\" valgmulighed</string>
|
||||
<string name="show_play_with_kodi_summary">Vis en knap til at afspille en video via Kode Media Center</string>
|
||||
<string name="kore_not_found">Kore-appen ikke fundet. Installer den\?</string>
|
||||
<string name="show_play_with_kodi_title">Vis valgmuligheden \"Afspil med Kodi\"</string>
|
||||
<string name="show_play_with_kodi_summary">Vis en knap til at afspille en video via Kodi</string>
|
||||
<string name="play_audio">Lyd</string>
|
||||
<string name="default_audio_format_title">Standard lydfilformat</string>
|
||||
<string name="default_video_format_title">Standard videofilformat</string>
|
||||
<string name="default_audio_format_title">Standardformat for lydfiler</string>
|
||||
<string name="default_video_format_title">Standardformat for videofiler</string>
|
||||
<string name="theme_title">Tema</string>
|
||||
<string name="light_theme_title">Lys</string>
|
||||
<string name="dark_theme_title">Mørk</string>
|
||||
<string name="light_theme_title">Lyst</string>
|
||||
<string name="dark_theme_title">Mørkt</string>
|
||||
<string name="black_theme_title">Sort</string>
|
||||
<string name="popup_remember_size_pos_title">Husk popup størrelse og position</string>
|
||||
<string name="popup_remember_size_pos_summary">Husk sidste størelse og position for popup afspiller</string>
|
||||
<string name="popup_remember_size_pos_title">Husk størrelse og placering af pop op</string>
|
||||
<string name="popup_remember_size_pos_summary">Husk sidste størrelse og placering af pop op-afspiller</string>
|
||||
<string name="use_inexact_seek_title">Brug hurtig og upræcis søgning</string>
|
||||
<string name="use_inexact_seek_summary">Upræcis søgning gør det hurtigere at søge i afspilningen, men med dårligere præcision</string>
|
||||
<string name="download_thumbnail_title">Indlæs billeder</string>
|
||||
<string name="download_thumbnail_summary">Når slået fra indlæses billeder ikke, derved spares der på netværks og hukommelses forbrug. Ændringer sletter både cachen i ram og på disk.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Billed cache slettet</string>
|
||||
<string name="metadata_cache_wipe_title">Slet cached metadata</string>
|
||||
<string name="metadata_cache_wipe_summary">Slet alt cached webside data</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">Metadata cache slettet</string>
|
||||
<string name="auto_queue_title">Tilføj automatisk næste stream til køen</string>
|
||||
<string name="auto_queue_summary">Tilføj relaterede streams til køen automatisk når den sidste stream i køen afspilles. Gælder ikke hvis køen er gentagene.</string>
|
||||
<string name="volume_gesture_control_title">Juster lydstyrke ved hjælp af fingerkontrol</string>
|
||||
<string name="volume_gesture_control_summary">Brug håndbevægelser til at kontrollere lydstyrke</string>
|
||||
<string name="brightness_gesture_control_title">Lysstyrke håndbævegesleskontorl</string>
|
||||
<string name="brightness_gesture_control_summary">Burg håndbevægelser til at justere lysstyrke</string>
|
||||
<string name="player_gesture_controls_title">Afspiller håndbevægelseskontol</string>
|
||||
<string name="player_gesture_controls_summary">Brug håndbevægelser til at justere lysstyrke og lydstyrke</string>
|
||||
<string name="show_search_suggestions_title">Søg i foreslag</string>
|
||||
<string name="show_search_suggestions_summary">Vis foreslag når der søges</string>
|
||||
<string name="use_inexact_seek_summary">Upræcis søgning lader afspilleren finde placeringer hurtigere, men mindre præcist</string>
|
||||
<string name="download_thumbnail_title">Indlæs miniaturebilleder</string>
|
||||
<string name="download_thumbnail_summary">Slå fra for at undgå indlæsning af billeder, hvorved der spares data og hukommelse. Ændringer sletter billedcachen i både ram og lager.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Billedcache slettet</string>
|
||||
<string name="metadata_cache_wipe_title">Slet metadata-cachen</string>
|
||||
<string name="metadata_cache_wipe_summary">Slet alle websidedata fra cachen</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">Metadata-cache slettet</string>
|
||||
<string name="auto_queue_title">Føj automatisk næste stream til køen</string>
|
||||
<string name="auto_queue_summary">Føj automatisk relaterede streams til køen når den sidste stream i en ikke-repeterende kø afspilles.</string>
|
||||
<string name="volume_gesture_control_title">Juster lydstyrke ved hjælp af fingerbevægelser</string>
|
||||
<string name="volume_gesture_control_summary">Brug fingerbevægelser til at kontrollere lydstyrke</string>
|
||||
<string name="brightness_gesture_control_title">Styr lysstyrken med fingerbevægelser</string>
|
||||
<string name="brightness_gesture_control_summary">Brug fingerbevægelser til at justere afspillerens lysstyrke</string>
|
||||
<string name="player_gesture_controls_title">Fingerbevægelsesstyring af afspiller</string>
|
||||
<string name="player_gesture_controls_summary">Brug fingerbevægelser til at justere lysstyrke og lydstyrke</string>
|
||||
<string name="show_search_suggestions_title">Søgeforslag</string>
|
||||
<string name="show_search_suggestions_summary">Vis forslag når der søges</string>
|
||||
<string name="enable_search_history_title">Søgehistorik</string>
|
||||
<string name="enable_search_history_summary">Gem søgninger lokalt</string>
|
||||
<string name="enable_watch_history_title">Historie & Cache</string>
|
||||
<string name="enable_watch_history_summary">Hold styr på sete videoer</string>
|
||||
<string name="resume_on_audio_focus_gain_title">Forsæt når appen kommer i focus</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Foresæt afspilning efter afbrydelse (fks. telefon opkald)</string>
|
||||
<string name="enable_watch_history_title">Historik og cache</string>
|
||||
<string name="enable_watch_history_summary">Husk sete videoer</string>
|
||||
<string name="resume_on_audio_focus_gain_title">Fortsæt når appen kommer i fokus</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Fortsæt afspilning efter afbrydelser (fx telefonopkald)</string>
|
||||
<string name="download_dialog_title">Download</string>
|
||||
<string name="next_video_title">Næste</string>
|
||||
<string name="show_next_and_similar_title">Vis \'Næste\' og \'Lignende\' videoer</string>
|
||||
<string name="show_hold_to_append_title">Vis \"Hold for at tiljøje\" tip</string>
|
||||
<string name="show_hold_to_append_summary">Vis et tip når baggrunds eller popup knappen trykkes</string>
|
||||
<string name="url_not_supported_toast">Dette URL er ikke understøttet</string>
|
||||
<string name="default_content_country_title">Standard land for indhold</string>
|
||||
<string name="service_title">Service</string>
|
||||
<string name="content_language_title">Standard sprog for indhold</string>
|
||||
<string name="show_hold_to_append_title">Vis \"Hold for at tilføje\"-tip</string>
|
||||
<string name="show_hold_to_append_summary">Vis et tip når der trykkes på baggrunds- eller pop op-knappen på siden med videodetaljer</string>
|
||||
<string name="url_not_supported_toast">Denne webadresse er ikke understøttet</string>
|
||||
<string name="default_content_country_title">Standardland for indhold</string>
|
||||
<string name="service_title">Tjeneste</string>
|
||||
<string name="content_language_title">Standardsprog for indhold</string>
|
||||
<string name="settings_category_player_title">Afspiller</string>
|
||||
<string name="settings_category_player_behavior_title">Opførsel</string>
|
||||
<string name="settings_category_video_audio_title">Video & Lyd</string>
|
||||
<string name="settings_category_history_title">Historie & Cache</string>
|
||||
<string name="settings_category_popup_title">Popup</string>
|
||||
<string name="settings_category_appearance_title">"Udseende "</string>
|
||||
<string name="settings_category_video_audio_title">Video og lyd</string>
|
||||
<string name="settings_category_history_title">Historik og cache</string>
|
||||
<string name="settings_category_popup_title">Pop op</string>
|
||||
<string name="settings_category_appearance_title">Udseende</string>
|
||||
<string name="settings_category_other_title">Andet</string>
|
||||
<string name="settings_category_debug_title">Debug</string>
|
||||
<string name="settings_category_debug_title">Fejlretning</string>
|
||||
<string name="settings_category_updates_title">Opdateringer</string>
|
||||
<string name="background_player_playing_toast">Afspiller i baggrunden</string>
|
||||
<string name="popup_playing_toast">Afspiller i popup tilstand
|
||||
\n</string>
|
||||
<string name="background_player_append">Tilføjet til køen i baggrundsafspilleren</string>
|
||||
<string name="popup_playing_append">Tilføjet til afspilningskøen</string>
|
||||
<string name="popup_playing_toast">Afspiller i pop op-tilstand</string>
|
||||
<string name="background_player_append">Føjet til køen i baggrundsafspilleren</string>
|
||||
<string name="popup_playing_append">Føjet til pop op-afspilningskøen</string>
|
||||
<string name="play_btn_text">Afspil</string>
|
||||
<string name="content">Inhold</string>
|
||||
<string name="show_age_restricted_content_title">Aldersbegrænset inhold</string>
|
||||
<string name="video_is_age_restricted">Vis aldersbegrænset video. Det er er muligt at tillade sådanne video under indstillinger.</string>
|
||||
<string name="content">Indhold</string>
|
||||
<string name="show_age_restricted_content_title">Aldersbegrænset indhold</string>
|
||||
<string name="video_is_age_restricted">Vis aldersbegrænsede videoer. Du kan tillade denne type videoer under Indstillinger.</string>
|
||||
<string name="duration_live">LIVE</string>
|
||||
<string name="downloads">Downloads</string>
|
||||
<string name="downloads_title">Downloads</string>
|
||||
|
@ -123,9 +123,9 @@
|
|||
<string name="playlist">Playliste</string>
|
||||
<string name="playlists">Playlister</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">Videoer</item>
|
||||
<item quantity="other"></item>
|
||||
</plurals>
|
||||
<item quantity="one">Video</item>
|
||||
<item quantity="other">Videoer</item>
|
||||
</plurals>
|
||||
<string name="tracks">Numre</string>
|
||||
<string name="users">Brugere</string>
|
||||
<string name="yes">Ja</string>
|
||||
|
@ -134,239 +134,233 @@
|
|||
<string name="filter">Filtrer</string>
|
||||
<string name="refresh">Genindlæs</string>
|
||||
<string name="clear">Slet</string>
|
||||
<string name="popup_resizing_indicator_title">Ændrer Størrelse</string>
|
||||
<string name="popup_resizing_indicator_title">Ændrer størrelse</string>
|
||||
<string name="best_resolution">Bedste opløsning</string>
|
||||
<string name="undo">Fortryd</string>
|
||||
<string name="file_deleted">Fil slettet</string>
|
||||
<string name="play_all">Afspil Alle</string>
|
||||
<string name="play_all">Afspil alle</string>
|
||||
<string name="always">Altid</string>
|
||||
<string name="just_once">Kun én gang</string>
|
||||
<string name="file">Fil</string>
|
||||
<string name="notification_channel_name">NewPipe Notifikation
|
||||
\n</string>
|
||||
<string name="notification_channel_description">Notifikationer for NewPipe backgrunds og popup afspillere
|
||||
\n</string>
|
||||
<string name="app_update_notification_channel_name">App Opdaterings Notifikation</string>
|
||||
<string name="app_update_notification_channel_description">Notifikationer for nye NewPipe versioner
|
||||
\n</string>
|
||||
<string name="notification_channel_name">NewPipe-notifikation</string>
|
||||
<string name="notification_channel_description">Notifikationer for NewPipes baggrunds- og pop op-afspillere</string>
|
||||
<string name="app_update_notification_channel_name">Notifikation om opdatering af app</string>
|
||||
<string name="app_update_notification_channel_description">Notifikationer for nye NewPipe-versioner</string>
|
||||
<string name="unknown_content">[Ukendt]</string>
|
||||
<string name="toggle_orientation">Instill Retning</string>
|
||||
<string name="switch_to_background">Skift til Bagrund</string>
|
||||
<string name="switch_to_popup">Skift til Popup</string>
|
||||
<string name="switch_to_main">Skift til Forside</string>
|
||||
<string name="toggle_orientation">Skift skærmretning</string>
|
||||
<string name="switch_to_background">Skift til baggrund</string>
|
||||
<string name="switch_to_popup">Skift til pop op</string>
|
||||
<string name="switch_to_main">Skift til hovedafspiller</string>
|
||||
<string name="import_data_title">Importer database</string>
|
||||
<string name="export_data_title">Eksporter database</string>
|
||||
<string name="import_data_summary">Overskriver din nuværende historie og abebonomenter</string>
|
||||
<string name="export_data_summary">Eksporter historie, abebonomenter and playlister</string>
|
||||
<string name="import_data_summary">Overskriver din nuværende historik og abonnementer</string>
|
||||
<string name="export_data_summary">Eksporter historik, abonnementer og spillelister</string>
|
||||
<string name="clear_views_history_title">Slet visningshistorik</string>
|
||||
<string name="clear_views_history_summary">Sletter historien af viste videoer</string>
|
||||
<string name="clear_views_history_summary">Sletter historikken for viste videoer</string>
|
||||
<string name="delete_view_history_alert">Slet hele visningshistorikken\?</string>
|
||||
<string name="view_history_deleted">Visningshistorikken blev slettet.</string>
|
||||
<string name="clear_search_history_title">Slet søgehistorik</string>
|
||||
<string name="clear_search_history_summary">Sletter gemte søge ord</string>
|
||||
<string name="clear_search_history_summary">Sletter historikken for søgeord</string>
|
||||
<string name="delete_search_history_alert">Slet hele søgehistorikken\?</string>
|
||||
<string name="search_history_deleted">Søgehistorik slettet.</string>
|
||||
<string name="general_error">Fejl</string>
|
||||
<string name="download_to_sdcard_error_title">Ekstern lagring utilgængelig</string>
|
||||
<string name="download_to_sdcard_error_message">Download til til eksternt SD kort er ikke muligt i øjeblikket. Genskab download mappe indstilinning\?</string>
|
||||
<string name="network_error">Netwærksfejl</string>
|
||||
<string name="could_not_load_thumbnails">Kunne indlæse alle billeder</string>
|
||||
<string name="youtube_signature_decryption_error">Kunne ikke dekryptere video URL signatur</string>
|
||||
<string name="parsing_error">Kunne ikke indlæse webside</string>
|
||||
<string name="light_parsing_error">Kunne ikke indlæse hele websiden</string>
|
||||
<string name="content_not_available">Indhold utilgængeligt</string>
|
||||
<string name="download_to_sdcard_error_title">Eksternt lager utilgængeligt</string>
|
||||
<string name="download_to_sdcard_error_message">Download til eksternt SD-kort er endnu ikke muligt. Nulstil placering af download-mappe\?</string>
|
||||
<string name="network_error">Netværksfejl</string>
|
||||
<string name="could_not_load_thumbnails">Kunne ikke indlæse alle miniaturebilleder</string>
|
||||
<string name="youtube_signature_decryption_error">Kunne ikke dekryptere URL-signatur for video</string>
|
||||
<string name="parsing_error">Kunne ikke analysere websted</string>
|
||||
<string name="light_parsing_error">Kunne ikke analysere webstedet fuldstændig</string>
|
||||
<string name="content_not_available">Indhold ikke tilgængeligt</string>
|
||||
<string name="blocked_by_gema">Blokeret af GEMA</string>
|
||||
<string name="could_not_setup_download_menu">Kunne ikke oprette download menu</string>
|
||||
<string name="live_streams_not_supported">"Livestreams er ikke undestøttet endnu "</string>
|
||||
<string name="could_not_get_stream">Kunne ikke hente nogen streams</string>
|
||||
<string name="could_not_load_image">Kunne ikke hente billede</string>
|
||||
<string name="app_ui_crash">App/Brugergrænseflade crashede</string>
|
||||
<string name="could_not_setup_download_menu">Kunne ikke oprette downloadmenu</string>
|
||||
<string name="live_streams_not_supported">Livestreams er endnu ikke understøttet</string>
|
||||
<string name="could_not_get_stream">Kunne ikke hente nogen stream</string>
|
||||
<string name="could_not_load_image">Kunne ikke indlæse billede</string>
|
||||
<string name="app_ui_crash">App/brugergrænseflade gik ned</string>
|
||||
<string name="player_stream_failure">Kunne ikke afspille denne stream</string>
|
||||
<string name="player_unrecoverable_failure">"Uoprettelig fejl ved opstod ved afspilning "</string>
|
||||
<string name="player_recoverable_failure">Prøver at genoprette efter fejl ved afspilning</string>
|
||||
<string name="external_player_unsupported_link_type">Eksterne afspillere undestøtter ikke disse typer af links</string>
|
||||
<string name="player_unrecoverable_failure">Uoprettelig afspillerfejl opstod</string>
|
||||
<string name="player_recoverable_failure">Prøver at genoprette efter afspillerfejl</string>
|
||||
<string name="external_player_unsupported_link_type">Eksterne afspillere understøtter ikke disse typer af links</string>
|
||||
<string name="invalid_url_toast">Ugyldig adresse</string>
|
||||
<string name="video_streams_empty">Ingen video streams blev fundet</string>
|
||||
<string name="audio_streams_empty">Ingen lyd streams blev fundet</string>
|
||||
<string name="invalid_directory">Kunne ikke finde mappe</string>
|
||||
<string name="invalid_source">Kunne ikke finde file/kilde</string>
|
||||
<string name="invalid_file">Filen eksister ikke eller også der er manglende rettigheder til at læse og skrive til den</string>
|
||||
<string name="video_streams_empty">Ingen videostreams fundet</string>
|
||||
<string name="audio_streams_empty">Ingen lydstreams fundet</string>
|
||||
<string name="invalid_directory">Mappen findes ikke</string>
|
||||
<string name="invalid_source">Fil eller indholdskilde findes ikke</string>
|
||||
<string name="invalid_file">Filen eksister ikke eller der mangler rettigheder til at læse eller skrive til den</string>
|
||||
<string name="file_name_empty_error">Filavnet kan ikke være tomt</string>
|
||||
<string name="error_occurred_detail">Der skete en fejl: %1$s</string>
|
||||
<string name="no_streams_available_download">Ingen streams er tilgængelige til at downloade</string>
|
||||
<string name="saved_tabs_invalid_json">Bruger standard tabs, fejl ved indlæsning af gemte tabs</string>
|
||||
<string name="error_occurred_detail">Der opstod en fejl: %1$s</string>
|
||||
<string name="no_streams_available_download">Ingen streams er tilgængelige for download</string>
|
||||
<string name="saved_tabs_invalid_json">Bruger standardfaner pga. fejl ved indlæsning af gemte faner</string>
|
||||
<string name="restore_defaults">Genskab standardindstillinger</string>
|
||||
<string name="restore_defaults_confirmation">Vil du genskabe standardindstillingerne\?</string>
|
||||
<string name="sorry_string">Undskyld, dette skulle ikke have været sket.</string>
|
||||
<string name="error_report_button_text">Rappoter dette via e-mail</string>
|
||||
<string name="error_snackbar_message">Undskyld, der opstod nogle fejl.</string>
|
||||
<string name="sorry_string">Undskyld, dette skulle ikke være sket.</string>
|
||||
<string name="error_report_button_text">Rapporter fejl via e-mail</string>
|
||||
<string name="error_snackbar_message">Undskyld, nogle fejl opstod.</string>
|
||||
<string name="error_snackbar_action">RAPPORTER</string>
|
||||
<string name="what_device_headline">Information:</string>
|
||||
<string name="what_happened_headline">Hvad skete der:</string>
|
||||
<string name="your_comment">Din kommentar (på engelsk):</string>
|
||||
<string name="error_details_headline">Detaljer:</string>
|
||||
<string name="list_thumbnail_view_description">Video billede</string>
|
||||
<string name="detail_thumbnail_view_description">Video billede</string>
|
||||
<string name="list_thumbnail_view_description">Videominiaturebillede</string>
|
||||
<string name="detail_thumbnail_view_description">Videominiaturebillede</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Uploaders profilbillede</string>
|
||||
<string name="detail_likes_img_view_description">Synes godt om</string>
|
||||
<string name="detail_dislikes_img_view_description">Kan ikke lide</string>
|
||||
<string name="use_tor_title">Brug TOR</string>
|
||||
<string name="use_tor_summary">(Eksperimentelt) Tving downloads til at bruge TOR (streaming er ikke understøttet endnu).</string>
|
||||
<string name="report_error">Rappoter en Fejl</string>
|
||||
<string name="use_tor_title">Brug Tor</string>
|
||||
<string name="use_tor_summary">(Eksperimentelt) Send downloadtrafik gennem Tor for øget privatliv (videostreaming endnu ikke understøttet).</string>
|
||||
<string name="report_error">Rapporter en fejl</string>
|
||||
<string name="search_no_results">Ingen resultater</string>
|
||||
<string name="detail_drag_description">Træk for at omarrangere</string>
|
||||
<string name="err_dir_create">Kan ikke oprette download mappe \'%1$s\'</string>
|
||||
<string name="info_dir_created">Oprettede download mappe \'%1$s\'</string>
|
||||
<string name="err_dir_create">Kan ikke oprette downloadmappe \'%1$s\'</string>
|
||||
<string name="info_dir_created">Oprettede downloadmappe \'%1$s\'</string>
|
||||
<string name="video">Video</string>
|
||||
<string name="audio">Lyd</string>
|
||||
<string name="retry">Prøv igen</string>
|
||||
<string name="storage_permission_denied">Adgang til hulkomekse nægtet</string>
|
||||
<string name="no_subscribers">Ingen abbonenter</string>
|
||||
<string name="subscribers_count_not_available">Antal af abonnementer er ikke tilgængeligt</string>
|
||||
<string name="storage_permission_denied">Adgang til lager nægtet</string>
|
||||
<string name="no_subscribers">Ingen abonnenter</string>
|
||||
<string name="subscribers_count_not_available">Antallet af abonnenter er ikke tilgængeligt</string>
|
||||
<string name="no_views">Ingen visninger</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s visning</item>
|
||||
<item quantity="other">%s visninger</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Ingen Videoer</string>
|
||||
<item quantity="one">%s visning</item>
|
||||
<item quantity="other">%s visninger</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Ingen videoer</string>
|
||||
<string name="start">Start</string>
|
||||
<string name="view">Afspil</string>
|
||||
<string name="create">Opret</string>
|
||||
<string name="delete">Slet</string>
|
||||
<string name="delete_one">Slet én</string>
|
||||
<string name="delete_all">Slet Alle</string>
|
||||
<string name="checksum">Checksum</string>
|
||||
<string name="delete_all">Slet alle</string>
|
||||
<string name="checksum">Kontrolsum</string>
|
||||
<string name="dismiss">Afvis</string>
|
||||
<string name="rename">Omdøb</string>
|
||||
<string name="add">Ny mission</string>
|
||||
<string name="finish">Ok</string>
|
||||
<string name="finish">OK</string>
|
||||
<string name="msg_name">Filnavn</string>
|
||||
<string name="msg_threads">Tråde</string>
|
||||
<string name="msg_error">Fejl</string>
|
||||
<string name="msg_server_unsupported">Server ikke understøttet</string>
|
||||
<string name="msg_exists">Filen eksisterer allerede</string>
|
||||
<string name="msg_url_malform">Forkert URL formatering eller manglende internet forbindelse</string>
|
||||
<string name="msg_running">NewPiper Downloader</string>
|
||||
<string name="msg_url_malform">Ugyldig webadresse eller manglende internetforbindelse</string>
|
||||
<string name="msg_running">NewPiper downloader</string>
|
||||
<string name="msg_running_detail">Tryk for detaljer</string>
|
||||
<string name="msg_wait">Vent venligst…</string>
|
||||
<string name="msg_copied">Kopieret til udklipsholderen</string>
|
||||
<string name="no_available_dir">Vælg venligst en ledig download mappe</string>
|
||||
<string name="msg_popup_permission">Denne tilladelse er nødvendig for at kunne åbne i popup tilstand</string>
|
||||
<string name="one_item_deleted">Et element slettet.</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA
|
||||
\n</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA udfordring</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA udfordring anmodet</string>
|
||||
<string name="no_available_dir">Vælg venligst en tilgængelig downloadmappe</string>
|
||||
<string name="msg_popup_permission">Denne tilladelse er nødvendig for at kunne åbne i pop op-tilstand</string>
|
||||
<string name="one_item_deleted">1 element slettet.</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA-udfordring</string>
|
||||
<string name="recaptcha_request_toast">Der blev anmodet om en reCAPTCHA-udfordring</string>
|
||||
<string name="settings_category_downloads_title">Download</string>
|
||||
<string name="settings_file_charset_title">Lovlige tegn i filnavne</string>
|
||||
<string name="settings_file_replacement_character_summary">Ugyldige tegn bliver erstattet med dette tegn</string>
|
||||
<string name="settings_file_replacement_character_title">Erstatningskarakter</string>
|
||||
<string name="charset_letters_and_digits">Bogstaver og tal</string>
|
||||
<string name="settings_file_charset_title">Tilladte tegn i filnavne</string>
|
||||
<string name="settings_file_replacement_character_summary">Ugyldige tegn bliver erstattet med denne værdi</string>
|
||||
<string name="settings_file_replacement_character_title">Erstatningstegn</string>
|
||||
<string name="charset_letters_and_digits">Bogstaver og cifre</string>
|
||||
<string name="charset_most_special_characters">De fleste specialtegn</string>
|
||||
<string name="toast_no_player">Der ingen app installeret der kan afspille denne fil</string>
|
||||
<string name="title_activity_about">Om NewPipe</string>
|
||||
<string name="action_settings">Indstillinger</string>
|
||||
<string name="action_about">Om</string>
|
||||
<string name="title_licenses">Tredjepartslicenser</string>
|
||||
<string name="copyright" formatted="true">© %1$s by %2$s under %3$s
|
||||
\n</string>
|
||||
<string name="copyright" formatted="true">© %1$s af %2$s under %3$s</string>
|
||||
<string name="error_unable_to_load_license">Kunne ikke indlæse licens</string>
|
||||
<string name="action_open_website">Åben webside</string>
|
||||
<string name="action_open_website">Åbn websted</string>
|
||||
<string name="tab_about">Om</string>
|
||||
<string name="tab_contributors">Bidragsydere</string>
|
||||
<string name="tab_licenses">Licenser</string>
|
||||
<string name="app_description">Libre letvægts streaming på Android.</string>
|
||||
<string name="app_description">Åben letvægtsstreaming på Android.</string>
|
||||
<string name="contribution_title">Bidrag til projektet</string>
|
||||
<string name="contribution_encouragement">Hvad enten du har idéer til, oversæting, design ændringer, kode refaktorering eller større kode ændringer, så er hjælp altid velkommen. Jo mere der bliver gjort jo bedre bliver det!</string>
|
||||
<string name="view_on_github">Se på Github</string>
|
||||
<string name="contribution_encouragement">Hvad enten du har idéer til oversættelse, designændringer, kodeoprydning eller virkelig tunge kodeændringer, så er hjælp altid velkommen. Jo mere der bliver gjort, jo bedre bliver det!</string>
|
||||
<string name="view_on_github">Se på GitHub</string>
|
||||
<string name="donation_title">Doner</string>
|
||||
<string name="donation_encouragement">NewPipe er udviklet af frivillige der bruger tid på at give dig den bedste oplevelse. Giv noget tilbage til NewPipes udviklere så de kan gøre appen endnu bedre, mens de nyder en kop kaffe.</string>
|
||||
<string name="donation_encouragement">NewPipe er udviklet af frivillige der bruger tid på at give dig den bedste oplevelse. Giv noget tilbage for at hjælpe NewPipes udviklere til at gøre appen endnu bedre, mens de nyder en kop kaffe.</string>
|
||||
<string name="give_back">Giv noget tilbage</string>
|
||||
<string name="website_title">Webside</string>
|
||||
<string name="website_encouragement">Besøg NewPipes webside for mere information og nyheder.</string>
|
||||
<string name="privacy_policy_title">NewPipes Fortrolighedspolitik
|
||||
\n</string>
|
||||
<string name="website_title">Websted</string>
|
||||
<string name="website_encouragement">Besøg NewPipes websted for mere information og nyheder.</string>
|
||||
<string name="privacy_policy_title">NewPipes fortrolighedspolitik</string>
|
||||
<string name="read_privacy_policy">Læs fortrolighedspolitik</string>
|
||||
<string name="app_license_title">NewPipe\'s Licens</string>
|
||||
<string name="app_license">NewPipe er copyleft libre software: Du kan bruge, studere, dele og forbedre det som du vi.l Specifikt kan du redistribuere og/eller modificere det under betingelserne i GNU General Public License som udgivet af The Free Software Foundation, version 3 af licensen, eller (efter dit valg) en senere version.</string>
|
||||
<string name="app_license_title">NewPipes licens</string>
|
||||
<string name="app_license">NewPipe er copyleft, fri software: Du kan bruge, studere, dele og forbedre den som du vil. Specifikt kan du redistribuere og/eller ændre den under betingelserne i GNU General Public License som udgivet af Free Software Foundation, enten version 3 af licensen eller (efter dit ønske) en vilkårlig senere version.</string>
|
||||
<string name="read_full_license">Læs licens</string>
|
||||
<string name="title_activity_history">Historie</string>
|
||||
<string name="title_activity_history">Historik</string>
|
||||
<string name="title_history_search">Søgte</string>
|
||||
<string name="title_history_view">Sete</string>
|
||||
<string name="history_disabled">Historie er slået fra</string>
|
||||
<string name="action_history">Historie</string>
|
||||
<string name="history_empty">Historien er tom</string>
|
||||
<string name="history_cleared">Historie slettet</string>
|
||||
<string name="history_disabled">Historik er slået fra</string>
|
||||
<string name="action_history">Historik</string>
|
||||
<string name="history_empty">Historikken er tom</string>
|
||||
<string name="history_cleared">Historik slettet</string>
|
||||
<string name="item_deleted">Element slettet</string>
|
||||
<string name="delete_item_search_history">Vil du slette dette element fra søgehistorikken\?</string>
|
||||
<string name="delete_stream_history_prompt">Vil du slette dette element fra visningshistorikken\?</string>
|
||||
<string name="delete_all_history_prompt">Er du sikker på at vil slette alle elementer i historikken\?</string>
|
||||
<string name="title_last_played">Sidst Afspillet</string>
|
||||
<string name="title_most_played">Mest Spillede</string>
|
||||
<string name="main_page_content">Indhold af forsiden</string>
|
||||
<string name="main_page_content_summary">Hvilke tabs vises på forsiden</string>
|
||||
<string name="title_last_played">Sidst afspillet</string>
|
||||
<string name="title_most_played">Mest spillede</string>
|
||||
<string name="main_page_content">Indhold af hovedsiden</string>
|
||||
<string name="main_page_content_summary">Hvilke faner vises på hovedsiden</string>
|
||||
<string name="selection">Udvalg</string>
|
||||
<string name="blank_page_summary">Blank Side</string>
|
||||
<string name="kiosk_page_summary">Kiosk Side</string>
|
||||
<string name="subscription_page_summary">Abonnement Side</string>
|
||||
<string name="blank_page_summary">Tom side</string>
|
||||
<string name="kiosk_page_summary">Kioskside</string>
|
||||
<string name="subscription_page_summary">Abonnementsside</string>
|
||||
<string name="channel_page_summary">Kanalside</string>
|
||||
<string name="select_a_channel">Vælg en kanal</string>
|
||||
<string name="no_channel_subscribed_yet">Ingen kanal abebonomenter endnu</string>
|
||||
<string name="no_channel_subscribed_yet">Ingen kanalabonnementer endnu</string>
|
||||
<string name="select_a_kiosk">Vælg en kiosk</string>
|
||||
<string name="export_complete_toast">Eksporteret</string>
|
||||
<string name="import_complete_toast">Importeret</string>
|
||||
<string name="no_valid_zip_file">Ikke en gyldig ZIP fil</string>
|
||||
<string name="no_valid_zip_file">Ikke en gyldig ZIP-fil</string>
|
||||
<string name="could_not_import_all_files">Advarsel: Kunne ikke importere alle filer.</string>
|
||||
<string name="override_current_data">Dette vil overskrive dine nuværende indstillinger.</string>
|
||||
<string name="import_settings">Vil du også importere indstillinger\?</string>
|
||||
<string name="kiosk">Kiosk</string>
|
||||
<string name="trending">Populært Lige Nu</string>
|
||||
<string name="trending">Populært lige nu</string>
|
||||
<string name="top_50">Top 50</string>
|
||||
<string name="new_and_hot">Nyt & Populært</string>
|
||||
<string name="new_and_hot">Nyt og populært</string>
|
||||
<string name="title_activity_background_player">Baggrundsafspiller</string>
|
||||
<string name="title_activity_popup_player">Popup afspiller</string>
|
||||
<string name="title_activity_popup_player">Pop op-afspiller</string>
|
||||
<string name="play_queue_remove">Fjern</string>
|
||||
<string name="play_queue_stream_detail">Detaljer</string>
|
||||
<string name="play_queue_audio_settings">Lydindstillinger</string>
|
||||
<string name="hold_to_append">Hold for at tilføje til kø</string>
|
||||
<string name="enqueue_on_background">Tilføj til kø når baggrunds tilstand aktiveres</string>
|
||||
<string name="hold_to_append">Hold for at føje til kø</string>
|
||||
<string name="enqueue_on_background">Føj til kø når baggrundstilstand aktiveres</string>
|
||||
<string name="start_here_on_main">Start afspilning her</string>
|
||||
<string name="drawer_header_action_paceholder_text">Noget vil dukke op her snart ;D</string>
|
||||
<string name="preferred_open_action_settings_title">Foretrukket \'åben\' handling</string>
|
||||
<string name="preferred_open_action_settings_title">Foretrukket \'åbn\'-handling</string>
|
||||
<string name="video_player">Videoafspiller</string>
|
||||
<string name="background_player">baggrundsafspiller</string>
|
||||
<string name="popup_player">Popup-afspiller</string>
|
||||
<string name="background_player">Baggrundsafspiller</string>
|
||||
<string name="popup_player">Pop op-afspiller</string>
|
||||
<string name="always_ask_open_action">Spørg altid</string>
|
||||
<string name="preferred_player_fetcher_notification_title">Henter info…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Indlæser anmodet indhold</string>
|
||||
<string name="create_playlist">Ny Playliste</string>
|
||||
<string name="preferred_player_fetcher_notification_title">Henter info …</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Indlæser det ønskede indhold</string>
|
||||
<string name="create_playlist">Ny spilleliste</string>
|
||||
<string name="delete_playlist">Slet</string>
|
||||
<string name="rename_playlist">Omdøb</string>
|
||||
<string name="playlist_name_input">Navn</string>
|
||||
<string name="append_playlist">Tilføj Til Playliste</string>
|
||||
<string name="delete_playlist_prompt">Slet denne playliste\?</string>
|
||||
<string name="playlist_creation_success">Playliste oprettet</string>
|
||||
<string name="caption_none">Ingen Undertekster</string>
|
||||
<string name="append_playlist">Føj til spilleliste</string>
|
||||
<string name="delete_playlist_prompt">Slet denne spilleliste\?</string>
|
||||
<string name="playlist_creation_success">Spilleliste oprettet</string>
|
||||
<string name="caption_none">Ingen undertekster</string>
|
||||
<string name="resize_fit">Tilpas</string>
|
||||
<string name="resize_fill">Udfyld</string>
|
||||
<string name="resize_zoom">Zoom</string>
|
||||
<string name="caption_auto_generated">Autogeneret</string>
|
||||
<string name="caption_auto_generated">Autogenereret</string>
|
||||
<string name="caption_setting_title">Undertekster</string>
|
||||
<string name="export_to">Eksporter til</string>
|
||||
<string name="playback_reset">Nulstil</string>
|
||||
<string name="accept">Accepter</string>
|
||||
<string name="decline">Afvis</string>
|
||||
<string name="limit_data_usage_none_description">Ingen begrænsning</string>
|
||||
<string name="limit_mobile_data_usage_title">Begeæns opløsning når der bruges mobil data</string>
|
||||
<string name="limit_mobile_data_usage_title">Begræns opløsning når der bruges mobildata</string>
|
||||
<string name="updates_setting_title">Opdateringer</string>
|
||||
<string name="list_view_mode">Liste tilstand</string>
|
||||
<string name="list_view_mode">Listevisning</string>
|
||||
<string name="list">Liste</string>
|
||||
<string name="grid">Gitter</string>
|
||||
<string name="auto">Automatisk</string>
|
||||
<string name="app_update_notification_content_text">Tryk for at downloade</string>
|
||||
<string name="missions_header_finished">Færdig</string>
|
||||
<string name="missions_header_pending">i kø</string>
|
||||
<string name="post_processing">Efterbehandling</string>
|
||||
<string name="missions_header_pending">Afventning</string>
|
||||
<string name="post_processing">efterbehandling</string>
|
||||
<string name="enqueue">Kø</string>
|
||||
<string name="permission_denied">Handling afvist af systemet</string>
|
||||
<string name="download_failed">Download fejlede</string>
|
||||
|
@ -374,21 +368,90 @@
|
|||
<string name="download_finished_more">%s downloads færdige</string>
|
||||
<string name="generate_unique_name">Generer unikt navn</string>
|
||||
<string name="overwrite">Overskriv</string>
|
||||
<string name="overwrite_warning">"En downloadet fil med dette navn eksisterer allerede "</string>
|
||||
<string name="overwrite_unrelated_warning">En fil med dette navn eksisterer allerede</string>
|
||||
<string name="overwrite_finished_warning">En downloadet fil med dette navn eksisterer allerede</string>
|
||||
<string name="download_already_running">Der er en download i gang med dette navn</string>
|
||||
<string name="show_error">Vis fejl</string>
|
||||
<string name="label_code">Kode</string>
|
||||
<string name="error_path_creation">Filen kan ikke oprettes</string>
|
||||
<string name="error_file_creation">Destinations mappen kan ikke oprettes</string>
|
||||
<string name="error_file_creation">Filen kan ikke oprettes</string>
|
||||
<string name="error_path_creation">Destinationsmappen kan ikke oprettes</string>
|
||||
<string name="error_permission_denied">Adgang nægtet af systemet</string>
|
||||
<string name="error_ssl_exception">Sikker forbindelse fejlede</string>
|
||||
<string name="error_unknown_host">Kan ikke finde serveren</string>
|
||||
<string name="error_unknown_host">Kunne ikke finde serveren</string>
|
||||
<string name="error_connect_host">Kan ikke forbinde til serveren</string>
|
||||
<string name="error_http_no_content">Serveren sender ikke data</string>
|
||||
<string name="error_http_unsupported_range">Serveren accepterer ikke multitrådede downloads, prøv igen med @string/msg_threads = 1
|
||||
\n</string>
|
||||
<string name="error_http_unsupported_range">Serveren accepterer ikke multitrådede downloads; prøv igen med @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Det anmodede interval er ikke gyldigt</string>
|
||||
<string name="error_http_not_found">Ikke fundet</string>
|
||||
<string name="error_postprocessing_failed">Efterbehandling fejlede</string>
|
||||
<string name="stop">Stop</string>
|
||||
<string name="events">Hændelser</string>
|
||||
<string name="empty_subscription_feed_subtitle">Intet at se her</string>
|
||||
<string name="short_thousand">T</string>
|
||||
<string name="short_million">mio.</string>
|
||||
<string name="short_billion">mia.</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s abonnent</item>
|
||||
<item quantity="other">%s abonnenter</item>
|
||||
</plurals>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="feed_page_summary">Feed-side</string>
|
||||
<string name="subscriptions_import_unsuccessful">Kunne ikke importere abonnementer</string>
|
||||
<string name="subscriptions_export_unsuccessful">Kunne ikke eksportere abonnementer</string>
|
||||
<string name="user_report">Brugerrapport</string>
|
||||
<string name="conferences">Konferencer</string>
|
||||
<string name="enqueue_on_popup">Føj til kø ved ny pop op</string>
|
||||
<string name="start_here_on_background">Start her når i baggrunden</string>
|
||||
<string name="start_here_on_popup">Start her ved ny pop op</string>
|
||||
<string name="drawer_open">Åbn skuffe</string>
|
||||
<string name="drawer_close">Luk skuffe</string>
|
||||
<string name="info_labels">Hvad:\\nForespørgsel:\\nIndholdssprog:\\nTjeneste:\\nGMT-tid:\\nPakke:\\nVersion:\\nOS-version:</string>
|
||||
<string name="preferred_open_action_settings_summary">Standardhandling ved åbning af indhold — %s</string>
|
||||
<string name="set_as_playlist_thumbnail">Angiv som miniaturebillede for spilleliste</string>
|
||||
<string name="bookmark_playlist">Bogmærk spilleliste</string>
|
||||
<string name="unbookmark_playlist">Fjern bogmærke</string>
|
||||
<string name="playlist_add_stream_success">Føjet til spillelisten</string>
|
||||
<string name="playlist_thumbnail_change_success">Miniaturebillede for spilleliste ændret.</string>
|
||||
<string name="playlist_delete_failure">Kunne ikke slette spilleliste.</string>
|
||||
<string name="caption_setting_description">Ændr undertekststørrelse og baggrundsstil. Kræver genstart af appen for at træde i kraft.</string>
|
||||
<string name="enable_leak_canary_title">Aktiver LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">Monitorering for hukommelseslækager kan få appen til ikke at svare under heap dumping</string>
|
||||
<string name="enable_disposed_exceptions_title">Rapporter out-of-lifecycle-fejl</string>
|
||||
<string name="import_export_title">Importer/eksporter</string>
|
||||
<string name="import_title">Importer</string>
|
||||
<string name="import_from">Importer fra</string>
|
||||
<string name="import_ongoing">Importerer …</string>
|
||||
<string name="export_ongoing">Eksporterer …</string>
|
||||
<string name="import_file_title">Importer fil</string>
|
||||
<string name="previous_export">Forrige eksport</string>
|
||||
<string name="import_youtube_instructions">Importer YouTube-abonnementer ved at downloade eksportfilen:
|
||||
\n
|
||||
\n1. Gå til denne webadresse: %1$s
|
||||
\n2. Log ind når du bliver bedt om det
|
||||
\n3. En download bør starte (det er eksportfilen)</string>
|
||||
<string name="import_soundcloud_instructions_hint">ditID, soundcloud.com/ditID</string>
|
||||
<string name="import_network_expensive_warning">Bemærk at denne operation kan kræve meget netværkstrafik.
|
||||
\n
|
||||
\nVil du fortsætte\?</string>
|
||||
<string name="playback_speed_control">Knapper for afspilningshastighed</string>
|
||||
<string name="playback_tempo">Tempo</string>
|
||||
<string name="playback_pitch">Tonehøjde</string>
|
||||
<string name="skip_silence_checkbox">Spol forbi stilhed</string>
|
||||
<string name="playback_step">Skridt</string>
|
||||
<string name="updates_setting_description">Vis en notifikation for at foreslå opdatering af appen, når en ny version er tilgængelig</string>
|
||||
<string name="minimize_on_exit_title">Minimer ved appskift</string>
|
||||
<string name="minimize_on_exit_summary">Handling når der skiftes til en anden app fra hovedvideoafspilleren — %s</string>
|
||||
<string name="minimize_on_exit_none_description">Ingen</string>
|
||||
<string name="minimize_on_exit_background_description">Minimer til baggrundsafspiller</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimer til pop op-afspiller</string>
|
||||
<string name="switch_view">Skift visning</string>
|
||||
<string name="app_update_notification_content_title">NewPipe-opdatering tilgængelig!</string>
|
||||
<string name="paused">sat på pause</string>
|
||||
<string name="queued">sat i kø</string>
|
||||
<string name="clear_finished_download">Ryd færdige downloads</string>
|
||||
<string name="msg_pending_downloads">Fortsæt dine %s ventende overførsler fra Downloads</string>
|
||||
<string name="max_retry_msg">Maksimalt antal genforsøg</string>
|
||||
<string name="max_retry_desc">Maksimalt antal forsøg før downloaden opgives</string>
|
||||
<string name="pause_downloads_on_mobile">Sæt på pause ved skift til mobildata</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Downloads som ikke kan sættes på pause vil blive genstartet</string>
|
||||
</resources>
|
|
@ -2,9 +2,10 @@
|
|||
<resources>
|
||||
<string name="view_count_text">%1$s Aufrufe</string>
|
||||
<string name="upload_date_text">Veröffentlicht am %1$s</string>
|
||||
<string name="no_player_found">Keinen Streamplayer gefunden. Möchtest du VLC installieren?</string>
|
||||
<string name="no_player_found">Keinen Stream-Player gefunden. Möchtest Du VLC installieren\?</string>
|
||||
<string name="install">Installieren</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
<string name="cancel">Abbrechen
|
||||
\n</string>
|
||||
<string name="open_in_browser">Im Browser öffnen</string>
|
||||
<string name="share">Teilen</string>
|
||||
<string name="download">Download</string>
|
||||
|
@ -39,19 +40,15 @@
|
|||
<string name="use_external_audio_player_title">Externen Audio-Player verwenden</string>
|
||||
<string name="background_player_playing_toast">Spiele im Hintergrund ab</string>
|
||||
<string name="play_btn_text">Abspielen</string>
|
||||
|
||||
<string name="use_tor_title">Benutze Tor</string>
|
||||
<string name="use_tor_summary">(Experimentell) Erzwinge das Herunterladen über Tor für verbesserte Privatsphäre (Videostream werden noch nicht unterstützt).</string>
|
||||
<string name="network_error">Netzwerkfehler</string>
|
||||
|
||||
<string name="download_path_audio_title">Downloadverzeichnis für Audiodateien</string>
|
||||
<string name="download_path_audio_summary">Heruntergeladene Audiodateien werden hier gespeichert</string>
|
||||
<string name="download_path_audio_dialog_title">Downloadverzeichnis für Audiodateien angeben</string>
|
||||
|
||||
<string name="theme_title">Design</string>
|
||||
<string name="dark_theme_title">Dunkel</string>
|
||||
<string name="light_theme_title">Hell</string>
|
||||
|
||||
<string name="settings_category_appearance_title">Aussehen</string>
|
||||
<string name="settings_category_other_title">Andere</string>
|
||||
<string name="err_dir_create">Kann Downloadverzeichnis \'%1$s\' nicht anlegen</string>
|
||||
|
@ -62,15 +59,11 @@
|
|||
<string name="parsing_error">Konnte Webseite nicht analysieren</string>
|
||||
<string name="content_not_available">Inhalt nicht verfügbar</string>
|
||||
<string name="blocked_by_gema">Durch die GEMA gesperrt</string>
|
||||
|
||||
<string name="content">Inhalt</string>
|
||||
<string name="show_age_restricted_content_title">Altersbeschränkte Inhalte</string>
|
||||
<string name="video_is_age_restricted">Altersbeschränktes Video anzeigen. Das Zulassen dieses Materials ist von den Einstellungen aus möglich.</string>
|
||||
|
||||
<string name="could_not_setup_download_menu">Konnte Download-Menü nicht einrichten</string>
|
||||
<string name="live_streams_not_supported">Live-Streams werden noch nicht unterstützt</string>
|
||||
|
||||
|
||||
<string name="light_parsing_error">Konnte Webseite nicht vollständig analysieren</string>
|
||||
<string name="error_report_button_text">Fehler via E-Mail melden</string>
|
||||
<string name="error_snackbar_action">MELDEN</string>
|
||||
|
@ -78,7 +71,6 @@
|
|||
<string name="what_happened_headline">Dies ist passiert:</string>
|
||||
<string name="info_labels">Was:\\nAnfrage:\\nSprache des Inhalts:\\nDienst:\\nZeit (GMT):\\nPaket:\\nVersion:\\nOS-Version:</string>
|
||||
<string name="error_details_headline">Details:</string>
|
||||
|
||||
<string name="video">Video</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="retry">Wiederholen</string>
|
||||
|
@ -87,34 +79,26 @@
|
|||
<string name="error_snackbar_message">Entschuldigung. Es sind einige Fehler aufgetreten.</string>
|
||||
<string name="your_comment">Dein Kommentar (auf englisch):</string>
|
||||
<string name="could_not_get_stream">Konnte keinen Stream abrufen</string>
|
||||
<string name="autoplay_by_calling_app_title">Autoplay</string>
|
||||
<string name="autoplay_by_calling_app_summary">Spiele ein Video ab, wenn NewPipe von einer anderen App aufgerufen wurde</string>
|
||||
<string name="autoplay_by_calling_app_title">Automatische Wiedergabe</string>
|
||||
<string name="autoplay_by_calling_app_summary">Wiedergabe eines Videos, wenn NewPipe von einer anderen App aufgerufen wurde</string>
|
||||
<string name="report_error">Einen Fehler melden</string>
|
||||
<string name="user_report">Anwenderbericht</string>
|
||||
|
||||
<string name="duration_live">LIVE</string>
|
||||
|
||||
<string name="main_bg_subtitle">„Suchen“ antippen, um zu beginnen</string>
|
||||
<string name="main_bg_subtitle">Suchen antippen, um zu beginnen</string>
|
||||
<string name="downloads">Downloads</string>
|
||||
<string name="downloads_title">Downloads</string>
|
||||
<string name="error_report_title">Fehlerbericht</string>
|
||||
|
||||
<string name="delete">Löschen</string>
|
||||
<string name="checksum">Prüfsumme</string>
|
||||
|
||||
|
||||
|
||||
<string name="short_thousand">Tsd.</string>
|
||||
<string name="short_million">Mio.</string>
|
||||
<string name="short_billion">Mrd.</string>
|
||||
|
||||
<string name="msg_name">Dateiname</string>
|
||||
<string name="msg_error">Fehler</string>
|
||||
<string name="msg_exists">Datei existiert bereits</string>
|
||||
<string name="msg_wait">Bitte warten…</string>
|
||||
<string name="msg_copied">In Zwischenablage kopiert</string>
|
||||
<string name="no_available_dir">Bitte wähle ein verfügbares Downloadverzeichnis</string>
|
||||
|
||||
<string name="start">Starten</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="view">Abspielen</string>
|
||||
|
@ -126,53 +110,39 @@
|
|||
<string name="msg_threads">Threads</string>
|
||||
<string name="msg_running">NewPipe lädt herunter</string>
|
||||
<string name="msg_running_detail">Für Details antippen</string>
|
||||
|
||||
<string name="msg_url_malform">Ungültige URL oder Internet nicht verfügbar</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="black_theme_title">Schwarz</string>
|
||||
|
||||
<string name="reCaptcha_title">reCAPTCHA-Aufgabe</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA-Aufgabe angefordert</string>
|
||||
|
||||
<string name="later">Später</string>
|
||||
|
||||
<string name="yes">Ja</string>
|
||||
<string name="all">Alle</string>
|
||||
<string name="channel">Kanal</string>
|
||||
|
||||
<string name="disabled">Deaktiviert</string>
|
||||
|
||||
<string name="use_old_player_title">Alten Player benutzen</string>
|
||||
<string name="open_in_popup_mode">Im Pop-up-Modus öffnen</string>
|
||||
<string name="default_video_format_title">Bevorzugtes Videoformat</string>
|
||||
<string name="popup_playing_toast">Spiele im Pop-up Modus ab</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe-Pop-up-Modus</string>
|
||||
|
||||
|
||||
<string name="msg_popup_permission">Diese Berechtigung ist für das Öffnen im Pop-up-Modus erforderlich</string>
|
||||
|
||||
<string name="use_old_player_summary">Alter eingebauter Mediaframework-Player</string>
|
||||
<string name="default_popup_resolution_title">Standardauflösung des Pop-ups</string>
|
||||
<string name="show_higher_resolutions_title">Höhere Auflösungen anzeigen</string>
|
||||
<string name="show_higher_resolutions_summary">Nur manche Geräte unterstützen das Abspielen von 2K-/4K-Videos</string>
|
||||
<string name="controls_background_title">Hintergrund</string>
|
||||
<string name="controls_popup_title">Pop-up</string>
|
||||
|
||||
<string name="popup_remember_size_pos_title">Größe und Position des Pop-ups merken</string>
|
||||
<string name="use_external_video_player_summary">Entfernt Tonspur bei manchen Auflösungen</string>
|
||||
<string name="use_external_video_player_summary">Entfernt Tonspur bei manchen Auflösungen</string>
|
||||
<string name="popup_remember_size_pos_summary">Letzte Größe und Position des Pop-ups merken</string>
|
||||
<string name="player_gesture_controls_title">Gestensteuerung</string>
|
||||
<string name="player_gesture_controls_summary">Helligkeit und Lautstärke mittels Gesten einstellen</string>
|
||||
<string name="show_search_suggestions_title">Suchvorschläge</string>
|
||||
<string name="show_search_suggestions_summary">Beim Suchen Vorschläge anzeigen</string>
|
||||
|
||||
<string name="settings_category_popup_title">Pop-up</string>
|
||||
<string name="filter">Filter</string>
|
||||
<string name="refresh">Aktualisieren</string>
|
||||
<string name="clear">Löschen</string>
|
||||
<string name="popup_resizing_indicator_title">Größenänderung</string>
|
||||
<string name="best_resolution">Beste Auflösung</string>
|
||||
|
||||
<string name="action_about">Über</string>
|
||||
<string name="title_activity_about">Über NewPipe</string>
|
||||
<string name="action_open_website">Website öffnen</string>
|
||||
|
@ -189,19 +159,16 @@
|
|||
<string name="title_licenses">Drittanbieter-Lizenzen</string>
|
||||
<string name="view_on_github">Auf GitHub ansehen</string>
|
||||
<string name="contribution_title">Beitragen</string>
|
||||
<string name="settings_category_downloads_title">Download</string>
|
||||
<string name="settings_category_downloads_title">Download</string>
|
||||
<string name="settings_file_charset_title">Erlaubte Zeichen im Dateinamen</string>
|
||||
<string name="settings_file_replacement_character_summary">Ungültige Zeichen werden durch dieses Zeichen ersetzt</string>
|
||||
<string name="settings_file_replacement_character_title">Ersetzungszeichen</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Buchstaben und Zahlen</string>
|
||||
<string name="subscribe_button_title">Abonnieren</string>
|
||||
<string name="subscribed_button_title">Abonniert</string>
|
||||
<string name="channel_unsubscribed">Abonnement beendet</string>
|
||||
<string name="tab_subscriptions">Abos</string>
|
||||
|
||||
<string name="fragment_whats_new">Neuigkeiten</string>
|
||||
|
||||
<string name="enable_search_history_title">Suchverlauf</string>
|
||||
<string name="enable_search_history_summary">Suchanfragen lokal speichern</string>
|
||||
<string name="enable_watch_history_title">Verlauf & Cache</string>
|
||||
|
@ -213,56 +180,44 @@
|
|||
<string name="action_history">Verlauf</string>
|
||||
<string name="history_empty">Der Verlauf ist leer</string>
|
||||
<string name="history_cleared">Verlauf bereinigt</string>
|
||||
|
||||
<string name="subscription_change_failed">Abonnement konnte nicht geändert werden</string>
|
||||
<string name="subscription_change_failed">Abonnement konnte nicht geändert werden</string>
|
||||
<string name="subscription_update_failed">Abonnement konnte nicht aktualisiert werden</string>
|
||||
|
||||
<string name="resume_on_audio_focus_gain_summary">Nach Unterbrechungen (z.B. Telefonaten) Wiedergabe fortsetzen</string>
|
||||
|
||||
|
||||
<string name="notification_channel_name">NewPipe-Benachrichtigung</string>
|
||||
<string name="notification_channel_description">Benachrichtigungen für NewPipe-Hintergrund- und Pop-up Wiedergabe</string>
|
||||
|
||||
<string name="tab_main">Hauptmenü</string>
|
||||
<string name="settings_category_player_behavior_title">Verhalten</string>
|
||||
<string name="settings_category_history_title">Verlauf & Cache</string>
|
||||
<string name="playlist">Wiedergabeliste</string>
|
||||
<string name="undo">Rückgängig machen</string>
|
||||
|
||||
<string name="search_no_results">Keine Ergebnisse</string>
|
||||
<string name="no_subscribers">Keine Abonnenten</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s Abonnent</item>
|
||||
<item quantity="other">%s Abonnenten</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s Abonnent</item>
|
||||
<item quantity="other">%s Abonnenten</item>
|
||||
</plurals>
|
||||
<string name="no_views">Keine Aufrufe</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s Aufruf</item>
|
||||
<item quantity="other">%s Aufrufe</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s Aufruf</item>
|
||||
<item quantity="other">%s Aufrufe</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Keine Videos</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">Video</item>
|
||||
<item quantity="other">Videos</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Video</item>
|
||||
<item quantity="other">Videos</item>
|
||||
</plurals>
|
||||
<string name="charset_most_special_characters">Die meisten Sonderzeichen</string>
|
||||
|
||||
<string name="item_deleted">Element gelöscht</string>
|
||||
<string name="resume_on_audio_focus_gain_title">Fortsetzen bei erneutem Fokussieren</string>
|
||||
<string name="settings_category_player_title">Player</string>
|
||||
<string name="empty_subscription_feed_subtitle">Nichts hier außer das Zirpen der Grillen</string>
|
||||
|
||||
<string name="delete_item_search_history">Möchtest du dieses Element aus dem Suchverlauf löschen?</string>
|
||||
<string name="blank_page_summary">Leere Seite</string>
|
||||
<string name="blank_page_summary">Leere Seite</string>
|
||||
<string name="select_a_channel">Wähle einen Kanal aus</string>
|
||||
<string name="no_channel_subscribed_yet">Noch keine Kanalabonnements vorhanden</string>
|
||||
<string name="trending">Trends</string>
|
||||
<string name="popup_playing_append">In der Warteschlange der Pop-up-Wiedergabe</string>
|
||||
<string name="play_all">Alles abspielen</string>
|
||||
|
||||
<string name="play_queue_remove">Entfernen</string>
|
||||
<string name="play_queue_audio_settings">Audio-Einstellungen</string>
|
||||
<string name="player_stream_failure">Konnte diesen Stream nicht abspielen</string>
|
||||
|
@ -276,24 +231,21 @@
|
|||
<string name="top_50">Top 50</string>
|
||||
<string name="player_unrecoverable_failure">Nicht behebbarer Wiedergabefehler aufgetreten</string>
|
||||
<string name="player_recoverable_failure">Wiederherstellen nach einem Wiedergabefehler</string>
|
||||
|
||||
<string name="kiosk_page_summary">Kiosk-Seite</string>
|
||||
<string name="select_a_kiosk">Kiosk auswählen</string>
|
||||
|
||||
<string name="kiosk">Kiosk</string>
|
||||
<string name="show_hold_to_append_summary">Tipp anzeigen, wenn der Hintergrundwiedergabe- oder Pop-up-Button auf der Videodetailseite gedrückt gehalten wird</string>
|
||||
<string name="background_player_append">In der Warteschlange der Hintergrundwiedergabe</string>
|
||||
<string name="new_and_hot">Neu & Heiß</string>
|
||||
<string name="hold_to_append">Halten, um zur Wiedergabeliste hinzuzufügen</string>
|
||||
<string name="show_hold_to_append_title">\"Gedrückt halten, um hinzuzufügen\" Tipp anzeigen</string>
|
||||
<string name="show_hold_to_append_title">\"Gedrückt halten, um hinzuzufügen\" Tipp anzeigen</string>
|
||||
<string name="unknown_content">[Unbekannt]</string>
|
||||
|
||||
<string name="enqueue_on_background">In Warteschlange für Hintergrundwiedergabe</string>
|
||||
<string name="enqueue_on_popup">In Warteschlange für Pop-up</string>
|
||||
<string name="start_here_on_main">Ab hier wiedergeben</string>
|
||||
<string name="start_here_on_background">Ab hier im Hintergrundmodus</string>
|
||||
<string name="start_here_on_popup">Ab hier im Pop-up</string>
|
||||
<string name="donation_title">Spenden</string>
|
||||
<string name="donation_title">Spenden</string>
|
||||
<string name="give_back">Zurückgeben</string>
|
||||
<string name="website_title">Website</string>
|
||||
<string name="website_encouragement">Besuche die NewPipe Website für weitere Informationen und Neuigkeiten.</string>
|
||||
|
@ -303,71 +255,53 @@
|
|||
<string name="default_content_country_title">Bevorzugtes Land des Inhalts</string>
|
||||
<string name="always">Immer</string>
|
||||
<string name="just_once">Nur einmal</string>
|
||||
|
||||
<string name="toggle_orientation">Ausrichtung umschalten</string>
|
||||
<string name="switch_to_background">In den Hintergrund wechseln</string>
|
||||
<string name="switch_to_popup">Zum Pop-up wechseln</string>
|
||||
<string name="switch_to_main">Zur normalen Wiedergabe wechseln</string>
|
||||
|
||||
<string name="external_player_unsupported_link_type">Externe Player unterstützen diese Art von Links nicht</string>
|
||||
<string name="invalid_url_toast">Ungültige URL</string>
|
||||
<string name="video_streams_empty">Keine Video-Streams gefunden</string>
|
||||
<string name="audio_streams_empty">Keine Audio-Streams gefunden</string>
|
||||
|
||||
<string name="drawer_open">Navigationsleiste öffnen</string>
|
||||
<string name="drawer_close">Navigationsleiste schließen</string>
|
||||
|
||||
<string name="video_player">Video-Player</string>
|
||||
<string name="background_player">Hintergrund-Player</string>
|
||||
<string name="popup_player">Popup-Player</string>
|
||||
<string name="always_ask_player">Immer fragen</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Informationen werden abgerufen…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Gewünschten Inhalt laden</string>
|
||||
<string name="import_data_title">Datenbank importieren</string>
|
||||
<string name="import_data_title">Datenbank importieren</string>
|
||||
<string name="export_data_title">Datenbank exportieren</string>
|
||||
<string name="import_data_summary">Überschreibt deinen aktuellen Verlauf und deine Abonnements</string>
|
||||
<string name="export_data_summary">Verlauf, Abonnements und Wiedergabelisten exportieren</string>
|
||||
<string name="no_valid_zip_file">Keine gültige ZIP-Datei</string>
|
||||
<string name="could_not_import_all_files">Warnung: Nicht alle Dateien konnten importiert werden.</string>
|
||||
<string name="override_current_data">Dies wird deine aktuellen Einstellungen überschreiben.</string>
|
||||
|
||||
<string name="show_info">Info anzeigen</string>
|
||||
|
||||
<string name="tab_bookmarks">Lesezeichen für Wiedergabelisten</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">Hinzufügen zu</string>
|
||||
|
||||
<string name="detail_drag_description">Zum Neuordnen ziehen</string>
|
||||
|
||||
<string name="create">Erstellen</string>
|
||||
<string name="delete_one">Einen löschen</string>
|
||||
<string name="delete_all">Alle löschen</string>
|
||||
<string name="rename">Umbenennen</string>
|
||||
|
||||
<string name="delete_stream_history_prompt">Möchtest du dieses Element aus dem Wiedergabeverlauf löschen?</string>
|
||||
<string name="delete_all_history_prompt">Bist du sicher, dass du alle Elemente aus dem Verlauf löschen möchtest?</string>
|
||||
<string name="title_last_played">Zuletzt wiedergegeben</string>
|
||||
<string name="title_most_played">Am häufigsten wiedergegeben</string>
|
||||
|
||||
<string name="always_ask_open_action">Immer fragen</string>
|
||||
|
||||
<string name="create_playlist">Neue Wiedergabeliste</string>
|
||||
<string name="delete_playlist">Löschen</string>
|
||||
<string name="rename_playlist">Umbenennen</string>
|
||||
<string name="append_playlist">Zur Wiedergabeliste hinzufügen</string>
|
||||
<string name="set_as_playlist_thumbnail">Als Vorschaubild der Wiedergabeliste festlegen</string>
|
||||
|
||||
<string name="unbookmark_playlist">Lesezeichen entfernen</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Diese Wiedergabeliste löschen?</string>
|
||||
<string name="playlist_creation_success">Wiedergabeliste erstellt</string>
|
||||
<string name="playlist_add_stream_success">Zur Wiedergabeliste hinzugefügt</string>
|
||||
<string name="playlist_thumbnail_change_success">Vorschaubild der Wiedergabeliste geändert.</string>
|
||||
<string name="playlist_delete_failure">Konnte Wiedergabeliste nicht löschen.</string>
|
||||
|
||||
<string name="caption_none">Keine Untertitel</string>
|
||||
|
||||
<string name="caption_font_size_settings_title">Schriftgröße der Untertitel</string>
|
||||
<string name="dismiss">Abbrechen</string>
|
||||
<string name="normal_caption_font_size">Normale Schriftgröße</string>
|
||||
|
@ -375,30 +309,24 @@
|
|||
<string name="use_inexact_seek_title">Schnelle, ungenaue Suche verwenden</string>
|
||||
<string name="use_inexact_seek_summary">Mit ungenauem Suchen kann die Abspielposition schneller erreicht werden, aber auf Kosten der Genauigkeit</string>
|
||||
<string name="file">Datei</string>
|
||||
|
||||
<string name="invalid_directory">Verzeichnis existiert nicht</string>
|
||||
<string name="invalid_file">Die Datei existiert nicht oder die Rechte zum Lesen oder Schreiben fehlen</string>
|
||||
<string name="file_name_empty_error">Dateiname darf nicht leer sein</string>
|
||||
<string name="error_occurred_detail">Ein Fehler ist aufgetreten: %1$s</string>
|
||||
|
||||
<string name="caption_auto_generated">Automatisch erzeugt</string>
|
||||
<string name="smaller_caption_font_size">Kleinere Schrift</string>
|
||||
<string name="larger_caption_font_size">Größere Schrift</string>
|
||||
|
||||
<string name="enable_leak_canary_title">LeakCanary aktivieren</string>
|
||||
<string name="import_from">Import von</string>
|
||||
<string name="export_to">Export nach</string>
|
||||
|
||||
<string name="import_ongoing">Importiere…</string>
|
||||
<string name="export_ongoing">Exportiere…</string>
|
||||
|
||||
<string name="import_file_title">Datei importieren</string>
|
||||
<string name="previous_export">Vorheriger Export</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Beachte, dass diese Aktion das Netzwerk stark belasten kann.
|
||||
\n
|
||||
\nMöchtest du fortfahren?</string>
|
||||
<string name="download_thumbnail_title">Vorschaubilder laden</string>
|
||||
<string name="download_thumbnail_title">Vorschaubilder laden</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Bilder-Cache gelöscht</string>
|
||||
<string name="metadata_cache_wipe_title">Zwischengespeicherte Metadaten löschen</string>
|
||||
<string name="metadata_cache_wipe_summary">Alle zwischengespeicherten Website-Daten entfernen</string>
|
||||
|
@ -412,29 +340,23 @@
|
|||
<string name="import_title">Import</string>
|
||||
<string name="subscriptions_import_unsuccessful">Abonnements konnten nicht importiert werden</string>
|
||||
<string name="subscriptions_export_unsuccessful">Abonnements konnten nicht exportiert werden</string>
|
||||
|
||||
<string name="playback_speed_control">Wiedergabegeschwindigkeitsregler</string>
|
||||
<string name="playback_tempo">Geschwindigkeit</string>
|
||||
<string name="playback_pitch">Tonhöhe</string>
|
||||
<string name="unhook_checkbox">Verknüpfung aufheben (kann zu Verzerrungen führen)</string>
|
||||
<string name="playback_nightcore">Nightcore</string>
|
||||
<string name="playback_default">Standard</string>
|
||||
<string name="download_thumbnail_summary">Abschalten, um das Laden von Miniaturansichten zu verhindern, was Daten- und Speicherverbrauch spart. Änderungen löschen den Bildzwischenspeicher sowohl im Arbeitsspeicher als auch auf der Festplatte.</string>
|
||||
<string name="download_thumbnail_summary">Abschalten, um das Laden von Miniaturansichten zu verhindern, was Daten- und Speicherverbrauch spart. Änderungen löschen den Bildzwischenspeicher sowohl im Arbeitsspeicher als auch auf dem internen Speicher.</string>
|
||||
<string name="auto_queue_title">Nächsten Stream automatisch einreihen</string>
|
||||
<string name="auto_queue_summary">Automatisches Anhängen eines verwandten Streams beim Abspielen des letzten Streams in einer nicht wiederholten Warteschlange.</string>
|
||||
<string name="auto_queue_summary">Automatisches Anhängen eines verwandten Streams beim Abspielen des letzten Streams in einer nicht wiederholten Warteschlange</string>
|
||||
<string name="drawer_header_action_paceholder_text">Hier wird bald etwas stehen ;D</string>
|
||||
|
||||
|
||||
<string name="bookmark_playlist">Wiedergabeliste mit Lesezeichen versehen</string>
|
||||
<string name="resize_fit">Anpassen</string>
|
||||
<string name="resize_fill">Füllen</string>
|
||||
<string name="resize_zoom">Vergrößern</string>
|
||||
|
||||
<string name="enable_leak_canary_summary">Speicherlecküberwachung kann dazu führen, dass die App beim Heap-Dumping nicht mehr reagiert</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Fehler außerhalb des Lebenszyklus melden</string>
|
||||
<string name="enable_disposed_exceptions_summary">Erzwingen der Meldung unzustellbarer Rx-Ausnahmen außerhalb des Lebenszyklus von Fragmenten oder Aktivitäten nach der Entsorgung</string>
|
||||
|
||||
<string name="import_youtube_instructions">Importiere YouTube-Abonnements, indem du die Exportdatei herunterlädst:
|
||||
\n
|
||||
\n1. Gehe zu dieser URL: %1$s
|
||||
|
@ -447,17 +369,12 @@
|
|||
\n3. Melden dich an, falls du dazu aufgefordert wirst
|
||||
\n4. Kopiere die Profil-URL, zu der du weitergeleitet wurdest.</string>
|
||||
<string name="import_soundcloud_instructions_hint">yourID, soundcloud.com/yourid</string>
|
||||
|
||||
<string name="no_streams_available_download">Keine Streams zum Download verfügbar</string>
|
||||
|
||||
<string name="preferred_open_action_settings_title">Bevorzugte \'Öffnen\' Aktion</string>
|
||||
<string name="preferred_open_action_settings_summary">Standardaktion beim Öffnen von Inhalten - %s</string>
|
||||
|
||||
<string name="caption_setting_title">Untertitel</string>
|
||||
<string name="caption_setting_description">Textgröße und Hintergrund der Untertitel im Player anpassen. Wird erst nach Neustart der App wirksam.</string>
|
||||
|
||||
<string name="toast_no_player">Keine App zum Abspielen dieser Datei installiert</string>
|
||||
|
||||
<string name="clear_views_history_title">Wiedergabeverlauf löschen</string>
|
||||
<string name="clear_views_history_summary">Löscht den Verlauf der abgespielten Streams</string>
|
||||
<string name="delete_view_history_alert">Den ganzen Wiedergabeverlauf löschen\?</string>
|
||||
|
@ -467,17 +384,15 @@
|
|||
<string name="delete_search_history_alert">Den gesamten Suchverlauf löschen\?</string>
|
||||
<string name="search_history_deleted">Suchverlauf gelöscht.</string>
|
||||
<string name="one_item_deleted">1 Element gelöscht.</string>
|
||||
|
||||
<string name="app_license">NewPipe ist freie Copyleft-Software: Du kannst sie nach Belieben benutzen, untersuchen, mit anderen teilen und verbessern. Insbesondere kannst du sie unter den von der Free Software Foundation veröffentlichten Bedingungen der GNU General Public License, in der Version 3 der Lizenz oder (nach deiner Wahl) jeder späteren Version, weitergeben und/oder verändern.</string>
|
||||
<string name="import_settings">Möchtest du auch Einstellungen importieren?</string>
|
||||
|
||||
<string name="privacy_policy_title">NewPipe-Datenschutzbestimmungen</string>
|
||||
<string name="privacy_policy_encouragement">Dem NewPipe-Projekt ist Datenschutz sehr wichtig. Deshalb sammelt diese App keine Daten ohne deine Zustimmung.
|
||||
\nNewPipes Datenschutzbestimmungen erklären im Detail, welche Daten beim Absenden eines Absturzberichtes verschickt und gespeichert werden.</string>
|
||||
<string name="read_privacy_policy">Datenschutzbestimmungen lesen</string>
|
||||
<string name="accept">Akzeptieren</string>
|
||||
<string name="decline">Ablehnen</string>
|
||||
<string name="start_accept_privacy_policy">Um der europäischen Datenschutz-Grundverordnung (DSGVO) gerecht zu werden, weisen wir hiermit auf NewPipe\'s Datenschutzerklärung hin. Bitte lies sie sorgfältig durch.
|
||||
<string name="start_accept_privacy_policy">Um der europäischen Datenschutz-Grundverordnung (DSGVO) gerecht zu werden, weisen wir hiermit auf NewPipe\'s Datenschutzerklärung hin. Bitte lies sie sorgfältig durch.
|
||||
\nDu musst den Datenschutzrichtlinien zustimmen, um den Fehlerbericht an uns zu senden.</string>
|
||||
<string name="limit_data_usage_none_description">Unbegrenzt</string>
|
||||
<string name="limit_mobile_data_usage_title">Auflösung bei Verwendung mobiler Daten begrenzen</string>
|
||||
|
@ -486,15 +401,13 @@
|
|||
<string name="minimize_on_exit_none_description">Keine</string>
|
||||
<string name="minimize_on_exit_background_description">Zum Hintergrund-Player minimieren</string>
|
||||
<string name="minimize_on_exit_popup_description">Zum Popup-Player minimieren</string>
|
||||
|
||||
<string name="skip_silence_checkbox">Vorspulen während der Stille</string>
|
||||
<string name="skip_silence_checkbox">Vorspulen während der Stille</string>
|
||||
<string name="playback_step">Schritt</string>
|
||||
<string name="playback_reset">Zurücksetzen</string>
|
||||
|
||||
<string name="channels">Kanäle</string>
|
||||
<string name="playlists">Wiedergabelisten</string>
|
||||
<string name="tracks">Titel</string>
|
||||
<string name="users">Nutzer</string>
|
||||
<string name="users">Benutzer</string>
|
||||
<string name="unsubscribe">Deabonnieren</string>
|
||||
<string name="tab_new">Neuer Tab</string>
|
||||
<string name="tab_choose">Tab wählen</string>
|
||||
|
@ -524,7 +437,7 @@
|
|||
<string name="app_update_notification_content_title">NewPipe-Aktualisierung verfügbar!</string>
|
||||
<string name="app_update_notification_content_text">Zum Herunterladen antippen</string>
|
||||
<string name="missions_header_finished">Fertig</string>
|
||||
<string name="missions_header_pending">In der Warteschlange</string>
|
||||
<string name="missions_header_pending">Ausstehend</string>
|
||||
<string name="paused">pausiert</string>
|
||||
<string name="queued">eingereiht</string>
|
||||
<string name="post_processing">Nachbearbeitung</string>
|
||||
|
@ -535,19 +448,19 @@
|
|||
<string name="download_finished_more">%s heruntergeladen</string>
|
||||
<string name="generate_unique_name">Eindeutigen Namen erzeugen</string>
|
||||
<string name="overwrite">Überschreiben</string>
|
||||
<string name="overwrite_warning">Eine heruntergeladene Datei dieses Namens existiert bereits</string>
|
||||
<string name="download_already_running">Eine Datei dieses Namens wird gerade heruntergeladen</string>
|
||||
<string name="overwrite_unrelated_warning">Eine Datei mit diesem Namen existiert bereits</string>
|
||||
<string name="download_already_running">Eine heruntergeladene Datei mit diesem Namen existiert bereits</string>
|
||||
<string name="show_error">Fehler anzeigen</string>
|
||||
<string name="label_code">Code</string>
|
||||
<string name="error_path_creation">Die Datei kann nicht erstellt werden</string>
|
||||
<string name="error_file_creation">Der Zielordner kann nicht erstellt werden</string>
|
||||
<string name="error_file_creation">Die Datei kann nicht erstellt werden</string>
|
||||
<string name="error_path_creation">Der Zielordner kann nicht erstellt werden</string>
|
||||
<string name="error_permission_denied">System verweigert den Zugriff</string>
|
||||
<string name="error_ssl_exception">Sichere Verbindung fehlgeschlagen</string>
|
||||
<string name="error_unknown_host">Der Server konnte nicht gefunden werden</string>
|
||||
<string name="error_connect_host">Kann nicht mit dem Server verbinden</string>
|
||||
<string name="error_http_no_content">Der Server sendet keine Daten</string>
|
||||
<string name="error_http_unsupported_range">Der Server erlaubt kein mehrfädiges Herunterladen – wiederhole mit @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Angefragter Bereich nicht bedienbar</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Gewünschter Bereich ist nicht verfügbar</string>
|
||||
<string name="error_http_not_found">Nicht gefunden</string>
|
||||
<string name="error_postprocessing_failed">Nachbearbeitung fehlgeschlagen</string>
|
||||
<string name="clear_finished_download">Um fertige Downloads bereinigen</string>
|
||||
|
@ -559,4 +472,5 @@
|
|||
<string name="pause_downloads_on_mobile_desc">Downloads, die nicht pausiert werden können, werden wiederholt</string>
|
||||
<string name="conferences">Konferenzen</string>
|
||||
<string name="events">Ereignisse</string>
|
||||
<string name="error_timeout">Verbindungszeitüberschreitung</string>
|
||||
</resources>
|
|
@ -16,15 +16,12 @@
|
|||
<string name="screen_rotation">περιστροφή</string>
|
||||
<string name="use_external_video_player_title">Χρήση εξωτερικής εφαρμογής αναπαραγωγής βίντεο</string>
|
||||
<string name="use_external_audio_player_title">Χρήση εξωτερικής συσκευής αναπαραγωγής ήχου</string>
|
||||
|
||||
<string name="download_path_title">Διαδρομή λήψης βίντεο</string>
|
||||
<string name="download_path_summary">Διαδρομή για αποθήκευση των βίντεο</string>
|
||||
<string name="download_path_dialog_title">Εισάγετε διαδρομή για λήψη των βίντεο</string>
|
||||
|
||||
<string name="download_path_audio_title">Διαδρομή λήψης αρχείων ήχου</string>
|
||||
<string name="download_path_audio_summary">Αυτή είναι η διαδρομή για την αποθήκευση αρχείων ήχου</string>
|
||||
<string name="download_path_audio_dialog_title">Εισάγετε διαδρομή για λήψη αρχείων ήχου</string>
|
||||
|
||||
<string name="default_resolution_title">Προεπιλεγμένη ανάλυση</string>
|
||||
<string name="play_with_kodi_title">Αναπαραγωγή με το Kodi</string>
|
||||
<string name="kore_not_found">Η εφαρμογή Kore δεν βρέθηκε. Εγκατάσταση της;</string>
|
||||
|
@ -32,12 +29,9 @@
|
|||
<string name="show_play_with_kodi_summary">Προβολή μιας επιλογής για αναπαραγωγή με το Kodi media center</string>
|
||||
<string name="play_audio">Ήχος</string>
|
||||
<string name="default_audio_format_title">Προεπιλεγμένη μορφή ήχου</string>
|
||||
<string name="webm_description">WebM — δωρεάν μορφή</string>
|
||||
<string name="m4a_description">Μ4Α — καλύτερη ποιότητα</string>
|
||||
<string name="theme_title">Θέμα</string>
|
||||
<string name="dark_theme_title">Σκοτεινό</string>
|
||||
<string name="light_theme_title">Φωτεινό</string>
|
||||
|
||||
<string name="download_dialog_title">Λήψη</string>
|
||||
<string name="next_video_title">Επόμενο</string>
|
||||
<string name="show_next_and_similar_title">Εμφάνιση \"Επόμενου\" και \"Σχετικών\" βίντεο</string>
|
||||
|
@ -49,7 +43,6 @@
|
|||
<string name="background_player_playing_toast">Αναπαραγωγή στο υπόβαθρο</string>
|
||||
<string name="play_btn_text">Αναπαραγωγή</string>
|
||||
<string name="network_error">Σφάλμα δικτύου</string>
|
||||
|
||||
<string name="list_thumbnail_view_description">Μικρογραφία προεπισκόπισης βίντεο</string>
|
||||
<string name="detail_thumbnail_view_description">Μικρογραφία προεπισκόπησης βίντεο</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Μικρογραφία εικόνας προφίλ του χρήστη</string>
|
||||
|
@ -57,11 +50,9 @@
|
|||
<string name="detail_dislikes_img_view_description">Dislike</string>
|
||||
<string name="use_tor_title">Χρήση του Tor</string>
|
||||
<string name="use_tor_summary">(Πειραματικό) Αναγκάζει την κίνηση λήψης μέσω Tor για αυξημένη προστασία προσωπικών δεδομένων (η αναπαραγωγή δεν υποστηρίζεται ακόμη).</string>
|
||||
|
||||
<string name="err_dir_create">Δεν μπόρεσε να δημιουργηθεί ο φάκελος \'%1$s\'</string>
|
||||
<string name="info_dir_created">Δημιουργήθηκε ο φάκελος \'%1$s\'</string>
|
||||
<string name="short_billion">Δ</string>
|
||||
|
||||
<string name="short_billion">Δις</string>
|
||||
<string name="open_in_popup_mode">Άνοιγμα σε αναδυόμενο παράθυρο</string>
|
||||
<string name="subscribe_button_title">Εγγραφή</string>
|
||||
<string name="subscribed_button_title">Εγγεγραμμένος</string>
|
||||
|
@ -82,8 +73,6 @@
|
|||
<string name="what_happened_headline">Τι συνέβη:</string>
|
||||
<string name="your_comment">Το σχόλιό σας (στα Αγγλικά):</string>
|
||||
<string name="error_details_headline">Λεπτομέρειες:</string>
|
||||
|
||||
|
||||
<string name="report_error">Αναφορά Σφάλματος</string>
|
||||
<string name="video">Βίντεο</string>
|
||||
<string name="audio">Ήχος</string>
|
||||
|
@ -100,8 +89,7 @@
|
|||
<string name="title_activity_history">Ιστορικό</string>
|
||||
<string name="action_history">Ιστορικό</string>
|
||||
<string name="show_info">Εμφάνιση πληροφοριών</string>
|
||||
|
||||
<string name="main_bg_subtitle">Πατήστε στην αναζήτηση για να ξεκινήσετε</string>
|
||||
<string name="main_bg_subtitle">Πατήστε αναζήτηση για να ξεκινήσετε</string>
|
||||
<string name="no_player_found_toast">Δε βρέθηκε πρόγραμμα αναπαραγωγής ροής δεδομένων (μπορείτε να εγκαταστήσετε το VLC για να κάνετε αναπαραγωγή).</string>
|
||||
<string name="controls_download_desc">Κατέβασμα του αρχείου ροής</string>
|
||||
<string name="use_external_video_player_summary">Αφαίρεση του ήχου από κάποιες αναλύσεις</string>
|
||||
|
@ -110,15 +98,12 @@
|
|||
<string name="subscription_change_failed">Αδύνατη η αλλαγή της εγγραφής</string>
|
||||
<string name="subscription_update_failed">Αδύνατη η ενημέρωση της εγγραφής</string>
|
||||
<string name="tab_main">Κύριο</string>
|
||||
<string name="tab_subscriptions">Εγγραφές</string>
|
||||
<string name="tab_subscriptions">Συνδρομές</string>
|
||||
<string name="tab_bookmarks">Αγαπημένες λίστες αναπαραγωγής</string>
|
||||
|
||||
<string name="fragment_whats_new">Νέα</string>
|
||||
|
||||
<string name="controls_background_title">Στο παρασκήνιο</string>
|
||||
<string name="controls_popup_title">Αναδυόμενο παράθυρο</string>
|
||||
<string name="controls_add_to_playlist_title">Προσθήκη σε</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">Αυτόματη αναπαραγωγή</string>
|
||||
<string name="autoplay_by_calling_app_summary">Αναπαραγωγή του βίντεο όταν το NewPipe καλείται από άλλη εφαρμογή</string>
|
||||
<string name="default_popup_resolution_title">Προεπιλεγμένη ανάλυση αναδυόμενου παραθύρου</string>
|
||||
|
@ -129,7 +114,7 @@
|
|||
<string name="use_inexact_seek_title">Χρήση γρήγορης μη-ακριβούς αναζήτησης</string>
|
||||
<string name="use_inexact_seek_summary">Η μη-ακριβής αναζήτηση επιτρέπει στην εφαρμογή να αναζητεί θέσεις στο βίντεο γρηγορότερα με μειωμένη ακρίβεια</string>
|
||||
<string name="download_thumbnail_title">Φόρτωση thumbnails</string>
|
||||
<string name="download_thumbnail_summary">Αν η επιλογή είναι απενεργοποιημένη δεν φορτώνονται οι μικρογραφίες, χρησιμοποιώντας λιγότερα δεδομένα και μνήμη. Οι αλλαγές σβήνουν την προσωρινή μνήμη των εικόνων.</string>
|
||||
<string name="download_thumbnail_summary">Με την απενεργοποίηση δεν φορτώνονται οι μικρογραφίες, χρησιμοποιώντας λιγότερα δεδομένα και μνήμη. Οι αλλαγές σβήνουν τις προσωρινά αποθηκευμένες εικόνες στην μνήμη.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Εκκαθαρίστηκε η προσωρινή μνήμη εικονών</string>
|
||||
<string name="metadata_cache_wipe_title">Εκκαθάριση προσωρινά αποθηκευμένων μεταδεδομένων</string>
|
||||
<string name="metadata_cache_wipe_summary">Αφαίρεση όλων των προσωρινά αποθηκευμένων δεδομένων ιστοσελίδων</string>
|
||||
|
@ -158,7 +143,7 @@
|
|||
<string name="popup_playing_append">Προστέθηκε στη λίστα αναπαραγωγής αναδυόμενου παραθύρου</string>
|
||||
<string name="content">Περιεχόμενο</string>
|
||||
<string name="show_age_restricted_content_title">Περιεχόμενο περιορισμένης ηλικίας</string>
|
||||
<string name="video_is_age_restricted">Βίντεο περιορισμένης πρόσβασης. Για να επιτρέπετε περιερχόμενο τέτοιου είδους, ενεργοποιήστε το στις \"Ρυθμίσεις\".</string>
|
||||
<string name="video_is_age_restricted">Βίντεο ηλικιακά περιορισμένης πρόσβασης. Για να επιτρέπετε περιερχόμενο τέτοιου είδους, ενεργοποιήστε το στις \"Ρυθμίσεις\".</string>
|
||||
<string name="duration_live">ΖΩΝΤΑΝΑ</string>
|
||||
<string name="error_report_title">Αναφορά σφαλμάτων</string>
|
||||
<string name="channels">Κανάλια</string>
|
||||
|
@ -176,17 +161,13 @@
|
|||
<string name="always">Πάντα</string>
|
||||
<string name="just_once">Μόνο μία φορά</string>
|
||||
<string name="file">Αρχείο</string>
|
||||
|
||||
<string name="notification_channel_name">Ειδοποίηση NewPipe</string>
|
||||
<string name="notification_channel_description">Ειδοποιήσεις για την αναπαραγωγή Παρασκηνίου και Αναδυόμενου Παραθύρου</string>
|
||||
|
||||
<string name="unknown_content">[Άγνωστο]</string>
|
||||
|
||||
<string name="toggle_orientation">Αλλαγή προσανατολισμού</string>
|
||||
<string name="switch_to_background">Αλλαγή σε Παρασκήνιο</string>
|
||||
<string name="switch_to_popup">Αλλαγή σε Αναδυόμενο Παράθυρο</string>
|
||||
<string name="switch_to_main">Αλλαγή σε Κύριο</string>
|
||||
|
||||
<string name="import_data_title">Εισαγωγή βάσης δεδομένων</string>
|
||||
<string name="export_data_title">Εξαγωγή βάσης δεδομένων</string>
|
||||
<string name="import_data_summary">Θα παρακάμψει το τρέχον ιστορικό και εγγραφές σας</string>
|
||||
|
@ -223,7 +204,6 @@
|
|||
<string name="file_name_empty_error">Το όνομα αρχείου δεν μπορεί να είναι κενό</string>
|
||||
<string name="error_occurred_detail">Προέκυψε ένα σφάλμα: %1$s</string>
|
||||
<string name="no_streams_available_download">Δεν υπάρχουν διαθέσιμες ροές για λήψη</string>
|
||||
|
||||
<string name="sorry_string">Λυπούμαστε, αυτό δεν έπρεπε να έχει συμβεί.</string>
|
||||
<string name="error_report_button_text">Αναφορά σφάλματος με ηλεκτρονικό ταχυδρομίο</string>
|
||||
<string name="error_snackbar_message">Λυπούμαστε, συνέβησαν κάποια σφάλματα.</string>
|
||||
|
@ -232,32 +212,25 @@
|
|||
<string name="search_no_results">Κανένα αποτέλεσμα</string>
|
||||
<string name="empty_subscription_feed_subtitle">Δεν υπάρχει τίποτα εδώ</string>
|
||||
<string name="detail_drag_description">Σύρετε για ταξινόμηση</string>
|
||||
|
||||
<string name="retry">Προσπάθεια εκ νέου</string>
|
||||
<string name="storage_permission_denied">Δεν δώθηκε άδεια εγγραφής στην εσωτερική μνήμη</string>
|
||||
<string name="use_old_player_title">Χρήση παλαιάς συσκευής αναπαραγωγής</string>
|
||||
<string name="use_old_player_summary">Παλαιά συσκευή αναπαραγωγής Mediaframework</string>
|
||||
|
||||
<string name="short_thousand">Κ</string>
|
||||
<string name="short_million">Μ</string>
|
||||
<string name="short_thousand">χιλ</string>
|
||||
<string name="short_million">Εκ</string>
|
||||
<string name="no_subscribers">Κανένας εγγεγραμένος χρήστης</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s εγγεγραμένος χρήστης</item>
|
||||
<item quantity="other">%s εγγεγραμένοι χρήστες</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s εγγεγραμένος χρήστης</item>
|
||||
<item quantity="other">%s εγγεγραμένοι χρήστες</item>
|
||||
</plurals>
|
||||
<string name="no_views">Καμία προβολή</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s προβολή</item>
|
||||
<item quantity="other">%s προβολές</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s προβολή</item>
|
||||
<item quantity="other">%s προβολές</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Κανένα βίντεο</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s βίντεο</item>
|
||||
<item quantity="other">"%s βίντεο "</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Βίντεο</item>
|
||||
<item quantity="other">Βίντεο</item>
|
||||
</plurals>
|
||||
<string name="start">Εκκίνηση</string>
|
||||
<string name="view">Αναπαραγωγή</string>
|
||||
<string name="create">Δημιουργία</string>
|
||||
|
@ -266,10 +239,8 @@
|
|||
<string name="checksum">Άθροισμα ελέγχου</string>
|
||||
<string name="dismiss">Αγνόηση</string>
|
||||
<string name="rename">Μετονομασία</string>
|
||||
|
||||
<string name="add">Νέα αποστολη</string>
|
||||
<string name="finish">ΟΚ</string>
|
||||
|
||||
<string name="msg_name">Όνομα αρχείου</string>
|
||||
<string name="msg_threads">Νήματα</string>
|
||||
<string name="msg_server_unsupported">Ο εξυπηρετητής δεν υποστηρίζεται</string>
|
||||
|
@ -281,19 +252,14 @@
|
|||
<string name="msg_popup_permission">Αυτή η άδεια είναι απαραίτητη για
|
||||
\nτο άνοιγμα αναδυόμενων παραθύρων</string>
|
||||
<string name="one_item_deleted">1 αντικείμενο διαγράφηκε.</string>
|
||||
|
||||
<string name="reCaptchaActivity">Αυτόματο τεστ</string>
|
||||
<string name="reCaptcha_title">Πρόκληση reCAPTCHA</string>
|
||||
<string name="recaptcha_request_toast">Ζητήθηκε πρόκληση reCAPTCHA</string>
|
||||
|
||||
<string name="settings_file_charset_title">Επιτρεπτοί χαρακτήρες σε ονόματα αρχείων</string>
|
||||
<string name="settings_file_charset_title">Επιτρεπόμενοι χαρακτήρες σε ονόματα αρχείων</string>
|
||||
<string name="settings_file_replacement_character_summary">Οι μη έγκυροι χαρακτήρες αντικαθίστανται με αυτήν την τιμή</string>
|
||||
<string name="settings_file_replacement_character_title">Αντικαταστάτης χαρακτήρας</string>
|
||||
|
||||
<string name="charset_most_special_characters">Οι περισσότεροι ειδικοί χαρακτήρες</string>
|
||||
|
||||
<string name="toast_no_player">Δεν υπάρχει εφαρμογή εγκατεστημένη για την αναπαραγωγή αυτού του αρχείου</string>
|
||||
|
||||
<string name="title_activity_about">Σχετικά με το NewPipe</string>
|
||||
<string name="action_about">Περί</string>
|
||||
<string name="title_licenses">Άδειες Τρίτων</string>
|
||||
|
@ -317,10 +283,8 @@
|
|||
<string name="app_license_title">Η άδεια του NewPipe</string>
|
||||
<string name="app_license">Το NewPipe είναι copylelft ελεύθερο λογισμικό: Μπορείτε να το χρησιμοποιήσετε, να το μελετήσετε, να το μοιραστείτε και να το βελτιώσετε κατά βούληση. Ειδικότερα, μπορείτε να το αναδιανείμετε ή/και να το τροποποιήσετε υπό την άδεια GNU General Public Licence όπως αυτή εκδόθηκε από το Free Software Foundation, είτε υπό την έκδοση 3 της Άδειας είτε (προεραιτικά) υπό οποιαδήποτε μεταγενέστερη άδεια.</string>
|
||||
<string name="read_full_license">Διαβάστε την άδεια</string>
|
||||
|
||||
|
||||
<string name="title_history_search">Αναζητημένα</string>
|
||||
<string name="title_history_view">Έχει γίνει προβολή</string>
|
||||
<string name="title_history_search">Αναζητήθηκαν</string>
|
||||
<string name="title_history_view">Προβλήθηκαν</string>
|
||||
<string name="history_disabled">Το ιστορικό έχει απενεργοποιηθεί</string>
|
||||
<string name="history_empty">Το ιστορικό είναι κενό</string>
|
||||
<string name="history_cleared">Το ιστορικό εκκαθαρίστηκε</string>
|
||||
|
@ -330,7 +294,6 @@
|
|||
<string name="delete_all_history_prompt">Είστε σίγουροι ότι θέλετε να σβήσετε όλα τα αντικείμενα από το ιστορικό;</string>
|
||||
<string name="title_last_played">Τελευταία αναπαραγωγή</string>
|
||||
<string name="title_most_played">Αναπαράχθηκε περισσότερο</string>
|
||||
|
||||
<string name="main_page_content">Περιεχόμενο της κεντρικής σελίδας</string>
|
||||
<string name="blank_page_summary">Κενή σελίδα</string>
|
||||
<string name="kiosk_page_summary">Σελίδα περιπτέρου</string>
|
||||
|
@ -345,7 +308,6 @@
|
|||
<string name="could_not_import_all_files">Προσοχή: Δεν ήταν δυνατή η εισαγωγή όλων των αρχείων.</string>
|
||||
<string name="override_current_data">Αυτό θα παρακάμψει τις τρέχουσες ρυθμίσεις σας.</string>
|
||||
<string name="import_settings">Θέλετε επίσης να εισάγετε ρυθμίσεις;</string>
|
||||
|
||||
<string name="kiosk">Περίπτερο</string>
|
||||
<string name="title_activity_background_player">Συσκευή αναπαραγωγής Παρασκηνίου</string>
|
||||
<string name="title_activity_popup_player">Συσκευή αναπαραγωγής Αναδυόμενου παραθύρου</string>
|
||||
|
@ -358,71 +320,52 @@
|
|||
<string name="start_here_on_main">Εκκίνηση Αναπαραγωγής εδώ</string>
|
||||
<string name="start_here_on_background">Εκκίνηση εδώ όταν είναι στο Παρασκήνιο</string>
|
||||
<string name="start_here_on_popup">Εκκίνηση εδώ όταν είναι στο Αναδυόμενο Παράθυρο</string>
|
||||
|
||||
<string name="drawer_open">Άνοιγμα Συρταριού</string>
|
||||
<string name="drawer_close">Κλείσιμο Συρταριού</string>
|
||||
<string name="drawer_header_action_paceholder_text">Κάτι θα παιχτεί εδω σύντομα ;D</string>
|
||||
|
||||
|
||||
<string name="top_50">Τοπ 50</string>
|
||||
<string name="new_and_hot">Καινούρια & δημοφιλή</string>
|
||||
<string name="preferred_open_action_settings_title">Προτιμώμενη ενέργεια ανοίγματος</string>
|
||||
<string name="preferred_open_action_settings_summary">Προεπιλεγμένη ενέργεια για το άνοιγμα περιεχομένου — %s</string>
|
||||
|
||||
<string name="video_player">Συσκευή αναπαραγωγής βίντεο</string>
|
||||
<string name="background_player">Αναπαραγωγή Παρασκηνίου</string>
|
||||
<string name="popup_player">Αναπαραγωγή σε Αναδυόμενο Παράθυρο</string>
|
||||
<string name="always_ask_open_action">Πάντα ερώτηση</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Γίνεται λήψη πληροφοριών…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Γίνεται φόρτωση του ζητούμενου περιεχομένου</string>
|
||||
|
||||
<string name="create_playlist">Νέα Λίστα Αναπαραγωγής</string>
|
||||
<string name="delete_playlist">Διαγραφή</string>
|
||||
<string name="rename_playlist">Μετονομασία</string>
|
||||
<string name="playlist_name_input">Όνομα</string>
|
||||
<string name="append_playlist">Προσθήκη στη Λίστα</string>
|
||||
<string name="set_as_playlist_thumbnail">Ορισμός ως μικρογραφία λίστας αναπαραγωγής</string>
|
||||
|
||||
<string name="bookmark_playlist">Προσθήκη Σελιδοδείκτη στη Λίστα</string>
|
||||
<string name="unbookmark_playlist">Διαγραφή Σελιδοδείκτη</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Διαγραφή αυτής της λίστας αναπαραγωγής;</string>
|
||||
<string name="playlist_creation_success">Η λίστα αναπαραγωγής δημιουργήθηκε</string>
|
||||
<string name="playlist_add_stream_success">Προστέθηκε στη λίστα αναπαραγωγής</string>
|
||||
<string name="playlist_thumbnail_change_success">Η μικρογραφία της λίστας αναπαραγωγής άλλαξε.</string>
|
||||
<string name="playlist_delete_failure">Δεν ήταν δυνατή η διαγραφή της λίστας.</string>
|
||||
|
||||
<string name="caption_none">Δεν υπάρχουν υπότιτλοι</string>
|
||||
|
||||
<string name="caption_none">Χωρίς υπότιτλους</string>
|
||||
<string name="resize_fit">Προσαρμογή</string>
|
||||
<string name="resize_fill">Γέμισμα</string>
|
||||
<string name="resize_zoom">Μεγέθυνση</string>
|
||||
|
||||
<string name="caption_auto_generated">Αυτόματοι</string>
|
||||
|
||||
<string name="caption_setting_title">Υπότιτλοι</string>
|
||||
<string name="caption_setting_description">Τροποποίηση του μεγέθους και του φόντου των υπότιτλων. Απαιτεί επανεκκίνηση της εφαρμογής.</string>
|
||||
|
||||
<string name="enable_leak_canary_title">Ενεργοποίηση του LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">Η παρακολούθηση των διαρροών μνήμης μπορεί να προκαλέσει την διακοπή της εφαρμογής</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_summary">Υποχρεωτική αναφορά μη παραδοτέων Rx εξαιρέσεων έξω από το κομμάτι ή τον κύκλο δραστηριότητας μετά από απόρριψη</string>
|
||||
|
||||
<string name="import_export_title">Εισαγωγή/Εξαγωγή</string>
|
||||
<string name="import_title">Εισαγωγή</string>
|
||||
<string name="import_from">Εισαγωγή από</string>
|
||||
<string name="export_to">Εξαγωγή σε</string>
|
||||
|
||||
<string name="import_ongoing">Γίνεται εισαγωγή…</string>
|
||||
<string name="export_ongoing">Γίνεται εξαγωγή…</string>
|
||||
|
||||
<string name="import_file_title">Εισαγωγή αρχείου</string>
|
||||
<string name="previous_export">Προηγούμενη εξαγωγή</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Δεν ήταν δυνατή η εισαγωγή των εγγραφών</string>
|
||||
<string name="subscriptions_export_unsuccessful">Δεν ήταν δυνατή η εισαγωγή των εγγραφών</string>
|
||||
|
||||
<string name="import_youtube_instructions">Κάντε εισαγωγή των εγγραφών σας στο YouTube κατεβάζοντας το εξής αρχείο:
|
||||
\n
|
||||
\n1. Πλοηγηθήτε στο: %1$s
|
||||
|
@ -437,7 +380,6 @@
|
|||
<string name="import_network_expensive_warning">Αυτή η διαδικασία μπορεί να χρησιμοποιήσει μεγάλο όγκο δεδομένων.
|
||||
\n
|
||||
\nΕπιθυμείτε να συνεχίσετε;</string>
|
||||
|
||||
<string name="playback_speed_control">Έλεγχος ταχύτητας αναπαραγωγής</string>
|
||||
<string name="playback_tempo">Τέμπο</string>
|
||||
<string name="playback_pitch">Τόνος</string>
|
||||
|
@ -446,22 +388,83 @@
|
|||
<string name="trending">Δημοφιλή</string>
|
||||
<string name="enable_disposed_exceptions_title">Αναφορά σφαλμάτων εκτός κύκλου ζωής</string>
|
||||
<string name="import_soundcloud_instructions_hint">Το όνομα χρήστη σας, soundcloud.com/όνομαχρήστη</string>
|
||||
|
||||
<string name="unhook_checkbox">Αποσύνδεση (μπορεί να προκαλέσει παραμόρφωση)</string>
|
||||
<string name="skip_silence_checkbox">Επιτάχυνση αναπαραγωγής κατά τη διάρκεια σιωπής</string>
|
||||
<string name="playback_step">Βήμα</string>
|
||||
<string name="playback_reset">Επαναφορά</string>
|
||||
|
||||
<string name="start_accept_privacy_policy">Προς συμμόρφωση με τον Ευρωπαϊκό Γενικό Κανονισμό για την Προστασία Δεδομένων (GDPR), σας επιστούμε την προσοχή στην πολιτική προστασίας προσωπικών δεδομένων του NewPipe. Παραλούμε, διαβάστε την προσεκτικά.
|
||||
\nΘα πρέπει να την αποδεχτέιτε προκειμένου να μας αποστείλετε την αναφορά σφάλματος.</string>
|
||||
<string name="accept">Αποδοχή</string>
|
||||
<string name="decline">Απόρριψη</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Χωρίς όριο</string>
|
||||
<string name="limit_mobile_data_usage_title">Περιορισμός της ανάλυσης όταν γίνεται χρήση δεδομένων</string>
|
||||
<string name="minimize_on_exit_title">Ελαχιστοποίηση κατά την εναλλαγή εφαρμογών</string>
|
||||
<string name="minimize_on_exit_none_description">Καμία</string>
|
||||
<string name="minimize_on_exit_background_description">Ελαχιστοποίηση στο παρασκήνιο</string>
|
||||
<string name="minimize_on_exit_popup_description">Ελαχιστοποίηση σε αναδυόμενο παράθυρο</string>
|
||||
|
||||
<string name="unsubscribe">Απεγγραφή</string>
|
||||
<string name="tab_new">Νέα Καρτέλα</string>
|
||||
<string name="tab_choose">Επιλογή Καρτέλας</string>
|
||||
<string name="volume_gesture_control_title">Ρυθμίσεις χειρονομιών ήχου</string>
|
||||
<string name="volume_gesture_control_summary">Χρησιμοποιήστε χειρονομίες για τον έλεγχο της έντασης του ήχου</string>
|
||||
<string name="brightness_gesture_control_title">Ρυθμίσεις χειρονομιών φωτεινότητας</string>
|
||||
<string name="brightness_gesture_control_summary">Χρησιμοποιήστε χειρονομίες για τον έλεγχο της φωτεινότητας</string>
|
||||
<string name="settings_category_updates_title">Ενημερώσεις</string>
|
||||
<string name="events">Συμβάντα</string>
|
||||
<string name="file_deleted">Το αρχείο διαγράφηκε</string>
|
||||
<string name="app_update_notification_channel_name">Ειδοποίηση Ενημέρωσης Εφαρμογής</string>
|
||||
<string name="app_update_notification_channel_description">Ειδοποίηση για νεότερη έκδοση του NewPipe</string>
|
||||
<string name="download_to_sdcard_error_title">Εξωτερική μνήμη αποθήκευσης μη διαθέσιμη</string>
|
||||
<string name="download_to_sdcard_error_message">Η αποθήκευση στην εξωτερική μνήμη απέτυχε. Επαναφορά στην αρχική τοποθεσία λήψης;</string>
|
||||
<string name="saved_tabs_invalid_json">Χρήση προεπιλεγμένων καρτέλων, σφάλμα κατα την ανάγνωση των αποθηκευμένων καρτέλων</string>
|
||||
<string name="restore_defaults">Επαναφορά προεπιλεγμένων ρυθμίσεων</string>
|
||||
<string name="restore_defaults_confirmation">Θέλετε να επαναφέρετε τις προεπιλεγμένες ρυθμίσεις;</string>
|
||||
<string name="subscribers_count_not_available">Το πλήθος των συνδρομητών δεν είναι διαθέσιμο</string>
|
||||
<string name="main_page_content_summary">Ποιές καρτέλες θα εμφανίζονται στην αρχική σελίδα</string>
|
||||
<string name="selection">Επιλογή</string>
|
||||
<string name="conferences">Συνέδρια</string>
|
||||
<string name="updates_setting_title">Ενημερώσεις</string>
|
||||
<string name="updates_setting_description">Εμφάνιση ειδοποίησης όταν μια υπάρχει μια νεότερη έκδοση</string>
|
||||
<string name="list_view_mode">Λειτουργία προβολής ως λίστα</string>
|
||||
<string name="list">Λίστα</string>
|
||||
<string name="grid">Πλέγμα</string>
|
||||
<string name="auto">Αυτόματα</string>
|
||||
<string name="switch_view">Αλλαγή τρόπου προβολής</string>
|
||||
<string name="app_update_notification_content_title">Νεά Έκδοση NewPipe Διαθέσιμη!</string>
|
||||
<string name="app_update_notification_content_text">Πατήστε για λήψη</string>
|
||||
<string name="missions_header_finished">Ολοκληρώθηκε</string>
|
||||
<string name="missions_header_pending">Στην ουρά αναμονής</string>
|
||||
<string name="paused">Παύση</string>
|
||||
<string name="queued">στην ουρά</string>
|
||||
<string name="post_processing">Μετεπεξεργασία</string>
|
||||
<string name="enqueue">Ουρά</string>
|
||||
<string name="permission_denied">Η δράση απορρίφθηκε από το σύστημα</string>
|
||||
<string name="download_failed">Η λήψη απέτυχε</string>
|
||||
<string name="download_finished">Η λήψη ολοκληρώθηκε</string>
|
||||
<string name="download_finished_more">%s λήψεις ολοκρηρώθηκαν</string>
|
||||
<string name="generate_unique_name">Δημιουργία μοναδικού ονόματος</string>
|
||||
<string name="overwrite">Αντικατάσταση</string>
|
||||
<string name="overwrite_unrelated_warning">Ένα αρχείο με αυτό το όνομα υπάρχει ήδη</string>
|
||||
<string name="overwrite_finished_warning">Ένα αρχείο που έχει ληφθεί με αυτό το όνομα υπάρχει ήδη</string>
|
||||
<string name="download_already_running">Υπάρχει μια λήψη σε εξέλιξη με αυτό το όνομα</string>
|
||||
<string name="show_error">Εμφάνιση σφάλματος</string>
|
||||
<string name="label_code">Κωδικός</string>
|
||||
<string name="error_path_creation">Το αρχείο δεν μπορεί να δημιουργηθεί</string>
|
||||
<string name="error_file_creation">Αδυναμία δημιουργίας φάκελου προορισμού</string>
|
||||
<string name="error_permission_denied">Η αδειοδότηση απορρίφθηκε απο το σύστημα</string>
|
||||
<string name="error_ssl_exception">Δημιουργία ασφαλής σύνδεσης απέτυχε</string>
|
||||
<string name="error_unknown_host">Αδυναμία εύρεσης του εξυπηρετητή</string>
|
||||
<string name="error_connect_host">Αδυναμία σύνδεσης με τον εξυπηρετητή</string>
|
||||
<string name="error_http_no_content">Ο εξυπηρετητής δεν μπορεί να στείλει τα δεδομένα</string>
|
||||
<string name="error_http_unsupported_range">Ο εξυπηρετητής δέν υποστηρίζει πολυνηματικές λήψεις, ξαναπροσπαθήστε με @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Το ζητούμενο εύρος δεν μπορεί να εξυπηρετηθεί</string>
|
||||
<string name="error_http_not_found">Δεν βρέθηκε</string>
|
||||
<string name="error_postprocessing_failed">Μετεπεξεργασία απέτυχε</string>
|
||||
<string name="clear_finished_download">Εκκαθάριση ολοκληρωμένων λήψεων</string>
|
||||
<string name="msg_pending_downloads">Συνέχιση των %s εκκρεμών σας λήψεων</string>
|
||||
<string name="stop">Διακοπή</string>
|
||||
<string name="max_retry_msg">Μέγιστες επαναπροσπάθειες</string>
|
||||
<string name="max_retry_desc">Μέγιστος αριθμός προσπαθειών προτού γίνει ακύρωση της λήψης</string>
|
||||
<string name="pause_downloads_on_mobile">Παύση με την εναλλαγή του δικτύου σε δεδομένα</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Οι λήψεις που δεν δέχονται παύση θα επανεκκινηθούν</string>
|
||||
</resources>
|
|
@ -14,7 +14,7 @@
|
|||
<string name="share_dialog_title">Compartir con</string>
|
||||
<string name="choose_browser">Elegir navegador</string>
|
||||
<string name="screen_rotation">rotación</string>
|
||||
<string name="download_path_title">Ruta de descarga de vídeo</string>
|
||||
<string name="download_path_title">Carpeta de descarga de vídeo</string>
|
||||
<string name="download_path_summary">Ruta para almacenar los vídeos descargados</string>
|
||||
<string name="download_path_dialog_title">Introducir directorio de descargas para vídeos</string>
|
||||
<string name="default_resolution_title">Resolución por defecto de vídeo</string>
|
||||
|
@ -29,25 +29,20 @@
|
|||
<string name="url_not_supported_toast">URL no soportada</string>
|
||||
<string name="use_external_video_player_title">Usar reproductor de vídeo externo</string>
|
||||
<string name="use_external_audio_player_title">Usar reproductor de audio externo</string>
|
||||
|
||||
<string name="theme_title">Tema</string>
|
||||
<string name="dark_theme_title">Oscuro</string>
|
||||
<string name="light_theme_title">Claro</string>
|
||||
|
||||
<string name="settings_category_appearance_title">Apariencia</string>
|
||||
<string name="settings_category_other_title">Otros</string>
|
||||
<string name="background_player_playing_toast">Reproduciendo en segundo plano</string>
|
||||
<string name="content_not_available">Contenido no disponible</string>
|
||||
<string name="use_tor_title">Usar Tor</string>
|
||||
<string name="use_tor_summary">(Experimental) Forzar la descarga a través de Tor para una mayor privacidad (transmisión de vídeos aún no compatible).</string>
|
||||
|
||||
<string name="err_dir_create">No se puede crear la carpeta de descarga \'%1$s\'</string>
|
||||
<string name="info_dir_created">Carpeta de descarga creada \'%1$s\'</string>
|
||||
<string name="download_path_audio_summary">Los audios descargados se almacenan aquí</string>
|
||||
<string name="download_path_audio_summary">Ruta para almacenar los audios descargados</string>
|
||||
<string name="download_path_audio_dialog_title">Introducir ruta de descarga para archivos de audio</string>
|
||||
|
||||
<string name="blocked_by_gema">Bloqueado por GEMA</string>
|
||||
|
||||
<string name="download_path_audio_title">Carpeta de descarga de audio</string>
|
||||
<string name="settings_category_video_audio_title">Vídeo y audio</string>
|
||||
<string name="play_btn_text">Reproducir</string>
|
||||
|
@ -64,12 +59,9 @@
|
|||
<string name="detail_dislikes_img_view_description">No me gusta</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Miniatura del avatar del usuario</string>
|
||||
<string name="live_streams_not_supported">Las transmisiones en vivo aún no están soportadas</string>
|
||||
|
||||
|
||||
<string name="content">Contenido</string>
|
||||
<string name="show_age_restricted_content_title">Contenido restringido por edad</string>
|
||||
<string name="video_is_age_restricted">Mostrar vídeo restringido por edad. Permitir este tipo de material es posible desde \"Ajustes\".</string>
|
||||
|
||||
<string name="video_is_age_restricted">Mostrar vídeo restringido por edad. Se puede permitir este tipo de material desde Ajustes.</string>
|
||||
<string name="main_bg_subtitle">Toque en buscar para empezar</string>
|
||||
<string name="autoplay_by_calling_app_title">Reproducción automática</string>
|
||||
<string name="autoplay_by_calling_app_summary">Reproducir un vídeo cuando NewPipe es llamado desde otra app</string>
|
||||
|
@ -77,7 +69,6 @@
|
|||
<string name="downloads">Descargas</string>
|
||||
<string name="downloads_title">Descargas</string>
|
||||
<string name="error_report_title">Reportar error</string>
|
||||
|
||||
<string name="light_parsing_error">No se pudo analizar el sitio web completamente</string>
|
||||
<string name="could_not_setup_download_menu">No se pudo configurar el menú de descarga</string>
|
||||
<string name="could_not_get_stream">No se pudo obtener ninguna transmisión</string>
|
||||
|
@ -89,26 +80,19 @@
|
|||
<string name="what_happened_headline">Qué ha ocurrido:</string>
|
||||
<string name="your_comment">Su comentario (en Inglés):</string>
|
||||
<string name="error_details_headline">Detalles:</string>
|
||||
|
||||
|
||||
<string name="report_error">Reportar un error</string>
|
||||
<string name="user_report">Reporte de usuario</string>
|
||||
|
||||
<string name="video">Vídeo</string>
|
||||
|
||||
<string name="audio">Audio</string>
|
||||
<string name="retry">Reintentar</string>
|
||||
<string name="storage_permission_denied">Permiso de acceso al almacenamiento denegado</string>
|
||||
|
||||
<string name="start">Iniciar</string>
|
||||
<string name="pause">Pausar</string>
|
||||
<string name="view">Reproducir</string>
|
||||
<string name="delete">Eliminar</string>
|
||||
<string name="checksum">Checksum</string>
|
||||
|
||||
<string name="add">Nueva misión</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="msg_name">Nombre del archivo</string>
|
||||
<string name="msg_threads">Hilos</string>
|
||||
<string name="msg_error">Error</string>
|
||||
|
@ -120,60 +104,45 @@
|
|||
<string name="msg_wait">Espere, por favor …</string>
|
||||
<string name="msg_copied">Copiado al portapapeles</string>
|
||||
<string name="no_available_dir">Por favor, seleccione un directorio de descarga disponible</string>
|
||||
|
||||
<string name="could_not_load_image">No se pudo cargar la imagen</string>
|
||||
<string name="app_ui_crash">La interfaz de la app dejó de funcionar</string>
|
||||
<string name="info_labels">Lo sucedido:\\nPetición:\\nIdioma del contenido:\\nServicio:\\nHora GMT:\\nPaquete:\\nVersión:\\nVersión del SO:</string>
|
||||
|
||||
<string name="black_theme_title">Negro</string>
|
||||
|
||||
<string name="all">Todo</string>
|
||||
<string name="channel">Canal</string>
|
||||
<string name="yes">Sí</string>
|
||||
<string name="later">Después</string>
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">MM</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="open_in_popup_mode">Abrir en modo popup</string>
|
||||
<string name="msg_popup_permission">Este permiso es necesario para
|
||||
abrir en modo popup</string>
|
||||
|
||||
<string name="reCaptcha_title">Reto reCAPTCHA</string>
|
||||
<string name="recaptcha_request_toast">Reto reCAPTCHA requerido</string>
|
||||
|
||||
<string name="popup_mode_share_menu_title">Modo popup de NewPipe</string>
|
||||
|
||||
<string name="popup_playing_toast">Reproduciendo en modo popup</string>
|
||||
<string name="default_video_format_title">Formato de vídeo por defecto</string>
|
||||
<string name="disabled">Desactivado</string>
|
||||
|
||||
<string name="show_higher_resolutions_title">Mostrar resoluciones más altas</string>
|
||||
<string name="show_higher_resolutions_summary">Solo algunos dispositivos soportan reproducción de vídeos en 2K/4K</string>
|
||||
<string name="default_popup_resolution_title">Resolución por defecto del popup</string>
|
||||
<string name="controls_background_title">Segundo plano</string>
|
||||
<string name="controls_popup_title">Popup</string>
|
||||
|
||||
<string name="filter">Filtro</string>
|
||||
<string name="refresh">Actualizar</string>
|
||||
<string name="clear">Limpiar</string>
|
||||
|
||||
<string name="popup_remember_size_pos_title">Recordar tamaño y posición del popup</string>
|
||||
<string name="popup_remember_size_pos_summary">Recordar el último tamaño y posición del popup</string>
|
||||
|
||||
<string name="settings_category_popup_title">Popup</string>
|
||||
<string name="popup_resizing_indicator_title">Redimensionando</string>
|
||||
|
||||
<string name="use_external_video_player_summary">Elimina el audio en algunas resoluciones</string>
|
||||
<string name="player_gesture_controls_title">Controles de gestos del reproductor</string>
|
||||
<string name="player_gesture_controls_summary">Usar gestos para controlar el brillo y volumen del reproductor</string>
|
||||
<string name="show_search_suggestions_title">Sugerencias de búsqueda</string>
|
||||
<string name="show_search_suggestions_summary">Mostrar sugerencias cuando esté buscando</string>
|
||||
|
||||
<string name="best_resolution">Mejor resolución</string>
|
||||
|
||||
<string name="best_resolution">Mejor resolución</string>
|
||||
<string name="title_activity_about">Acerca de NewPipe</string>
|
||||
<string name="action_settings">Ajustes</string>
|
||||
<string name="action_about">Acerca de</string>
|
||||
|
@ -190,28 +159,22 @@ abrir en modo popup</string>
|
|||
<string name="contribution_encouragement">Si tienes ideas de; traducción, cambios de diseño, limpieza de código o cambios de código realmente fuertes—la ayuda siempre es bienvenida. Cuanto más se hace, mejor se pone!</string>
|
||||
<string name="read_full_license">Leer licencia</string>
|
||||
<string name="contribution_title">Contribuir</string>
|
||||
<string name="subscribe_button_title">Suscribirse</string>
|
||||
<string name="subscribe_button_title">Suscribirse</string>
|
||||
<string name="subscribed_button_title">Suscrito</string>
|
||||
<string name="channel_unsubscribed">Canal no suscrito</string>
|
||||
<string name="subscription_change_failed">No se pudo cambiar la suscripción</string>
|
||||
<string name="subscription_update_failed">No se pudo actualizar la suscripción</string>
|
||||
|
||||
<string name="tab_main">Principal</string>
|
||||
<string name="tab_subscriptions">Suscripciones</string>
|
||||
|
||||
<string name="fragment_whats_new">Qué hay de nuevo</string>
|
||||
|
||||
<string name="resume_on_audio_focus_gain_title">Reanudar al enfocar</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Continuar reproduciendo después de las interrupciones (ej. llamadas telefónicas)</string>
|
||||
|
||||
<string name="settings_category_downloads_title">Descargar</string>
|
||||
<string name="settings_file_charset_title">Caracteres permitidos en los nombres de archivo</string>
|
||||
<string name="settings_file_replacement_character_summary">Los caracteres no válidos se reemplazan por este valor</string>
|
||||
<string name="settings_file_replacement_character_title">Carácter de reemplazo</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Letras y dígitos</string>
|
||||
<string name="charset_most_special_characters">La mayoría de caracteres especiales</string>
|
||||
|
||||
<string name="enable_search_history_title">Historial de búsqueda</string>
|
||||
<string name="enable_search_history_summary">Almacenar búsquedas localmente</string>
|
||||
<string name="enable_watch_history_title">Historial y caché</string>
|
||||
|
@ -223,40 +186,33 @@ abrir en modo popup</string>
|
|||
<string name="action_history">Historial</string>
|
||||
<string name="history_empty">El historial está vacío</string>
|
||||
<string name="history_cleared">Historial borrado</string>
|
||||
|
||||
<string name="notification_channel_name">Notificación de NewPipe</string>
|
||||
<string name="notification_channel_name">Notificación de NewPipe</string>
|
||||
<string name="notification_channel_description">Notificaciones para NewPipe en segundo plano y reproductores popup</string>
|
||||
|
||||
<string name="settings_category_player_title">Reproductor</string>
|
||||
<string name="settings_category_player_behavior_title">Funcionamiento</string>
|
||||
<string name="settings_category_history_title">Historial y caché</string>
|
||||
<string name="playlist">Lista de reproducción</string>
|
||||
<string name="undo">Deshacer</string>
|
||||
|
||||
<string name="search_no_results">No hay resultados</string>
|
||||
<string name="empty_subscription_feed_subtitle">Nada más que grillos</string>
|
||||
|
||||
<string name="no_subscribers">Sin suscriptores</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s suscriptor</item>
|
||||
<item quantity="other">%s suscriptores</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s suscriptor</item>
|
||||
<item quantity="other">%s suscriptores</item>
|
||||
</plurals>
|
||||
<string name="no_views">Sin reproducciones</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s reproducción</item>
|
||||
<item quantity="other">%s reproducciones</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s reproducción</item>
|
||||
<item quantity="other">%s reproducciones</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Sin vídeos</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s vídeo</item>
|
||||
<item quantity="other">%s vídeos</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Vídeo</item>
|
||||
<item quantity="other">Vídeos</item>
|
||||
</plurals>
|
||||
<string name="item_deleted">Elemento eliminado</string>
|
||||
<string name="delete_item_search_history">¿Desea eliminar este elemento del historial de búsqueda?</string>
|
||||
<string name="main_page_content">Contenido de la página principal</string>
|
||||
<string name="delete_item_search_history">¿Desea eliminar este elemento del historial de búsqueda?</string>
|
||||
<string name="main_page_content">Contenido de la página principal</string>
|
||||
<string name="blank_page_summary">Página en blanco</string>
|
||||
<string name="kiosk_page_summary">Página del kiosco</string>
|
||||
<string name="subscription_page_summary">Página de suscripción</string>
|
||||
|
@ -265,32 +221,28 @@ abrir en modo popup</string>
|
|||
<string name="select_a_channel">Seleccione un canal</string>
|
||||
<string name="no_channel_subscribed_yet">No hay canales suscritos todavía</string>
|
||||
<string name="select_a_kiosk">Seleccione un kiosco</string>
|
||||
|
||||
<string name="kiosk">Kiosco</string>
|
||||
<string name="trending">Tendencias</string>
|
||||
<string name="top_50">Top 50</string>
|
||||
<string name="show_hold_to_append_summary">Mostrar sugerencia cuando se presiona el botón de segundo plano o popup en la página de detalles del vídeo</string>
|
||||
<string name="show_hold_to_append_summary">Mostrar sugerencia cuando se presiona el botón de segundo plano o popup en la página de detalles del vídeo</string>
|
||||
<string name="background_player_append">En cola en el reproductor de fondo</string>
|
||||
<string name="popup_playing_append">En cola en el reproductor popup</string>
|
||||
<string name="play_all">Reproducir todo</string>
|
||||
|
||||
<string name="player_stream_failure">No se pudo reproducir este stream</string>
|
||||
<string name="player_unrecoverable_failure">Se produjo un error irrecuperable del reproductor</string>
|
||||
<string name="player_recoverable_failure">Recuperándose del error del reproductor</string>
|
||||
|
||||
<string name="title_activity_background_player">Reproductor en segundo plano</string>
|
||||
<string name="title_activity_popup_player">Reproductor popup</string>
|
||||
<string name="play_queue_remove">Quitar</string>
|
||||
<string name="play_queue_stream_detail">Detalles</string>
|
||||
<string name="play_queue_audio_settings">Ajustes de audio</string>
|
||||
<string name="unknown_content">[Desconocido]</string>
|
||||
|
||||
<string name="enqueue_on_background">Poner en cola de segundo plano</string>
|
||||
<string name="enqueue_on_popup">Poner en cola de popup</string>
|
||||
<string name="start_here_on_main">Comenzar a reproducir aquí</string>
|
||||
<string name="start_here_on_background">Comenzar aquí en segundo plano</string>
|
||||
<string name="start_here_on_popup">Comenzar aquí en popup</string>
|
||||
<string name="show_hold_to_append_title">Mostrar consejo \"Mantener para poner en la cola\"</string>
|
||||
<string name="show_hold_to_append_title">Mostrar consejo \"Mantener para poner en la cola\"</string>
|
||||
<string name="new_and_hot">Nuevo y popular</string>
|
||||
<string name="hold_to_append">Mantener para poner en la cola</string>
|
||||
<string name="donation_title">Donar</string>
|
||||
|
@ -303,27 +255,22 @@ abrir en modo popup</string>
|
|||
<string name="switch_to_background">Cambiar a segundo plano</string>
|
||||
<string name="switch_to_popup">Cambiar a popup</string>
|
||||
<string name="switch_to_main">Cambiar a principal</string>
|
||||
|
||||
<string name="service_title">Servicio</string>
|
||||
<string name="drawer_open">Abrir cajón</string>
|
||||
<string name="drawer_close">Cerrar cajón</string>
|
||||
<string name="no_player_found_toast">No se ha encontrado ningún reproductor de vídeo (puede instalar VLC para reproducirlo).</string>
|
||||
<string name="always">Siempre</string>
|
||||
<string name="just_once">Sólo una vez</string>
|
||||
|
||||
<string name="external_player_unsupported_link_type">Los reproductores externos no soportan este tipo de enlaces</string>
|
||||
<string name="invalid_url_toast">URL no válida</string>
|
||||
<string name="video_streams_empty">No se encontraron transmisiones de vídeo</string>
|
||||
<string name="audio_streams_empty">No se encontraron transmisiones de audio</string>
|
||||
|
||||
<string name="video_player">Reproductor de vídeo</string>
|
||||
<string name="background_player">Reproductor de fondo</string>
|
||||
<string name="popup_player">Reproductor de popup</string>
|
||||
<string name="always_ask_player">Preguntar siempre</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Obteniendo información…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Cargando contenido solicitado</string>
|
||||
<string name="import_data_title">Importar base de datos</string>
|
||||
<string name="import_data_title">Importar base de datos</string>
|
||||
<string name="export_data_title">Exportar base de datos</string>
|
||||
<string name="import_data_summary">Reemplazará su historial actual y sus suscripciones</string>
|
||||
<string name="export_data_summary">Exportar historial, suscripciones y listas de reproducción</string>
|
||||
|
@ -332,90 +279,68 @@ abrir en modo popup</string>
|
|||
<string name="no_valid_zip_file">Archivo ZIP no válido</string>
|
||||
<string name="could_not_import_all_files">ADVERTENCIA: no se pudieron importar todos los archivos.</string>
|
||||
<string name="override_current_data">Esto reemplazará su configuración actual.</string>
|
||||
|
||||
<string name="controls_download_desc">Descargar archivo stream</string>
|
||||
<string name="show_info">Mostrar info</string>
|
||||
|
||||
<string name="tab_bookmarks">"Listas de reproducción en marcadores "</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">Añadir a</string>
|
||||
|
||||
<string name="detail_drag_description">Arrastrar para reordenar</string>
|
||||
|
||||
<string name="create">Crear</string>
|
||||
<string name="delete_one">Eliminar uno</string>
|
||||
<string name="delete_all">Eliminar todos</string>
|
||||
<string name="dismiss">Descartar</string>
|
||||
<string name="rename">Renombrar</string>
|
||||
|
||||
<string name="delete_stream_history_prompt">¿Desea eliminar este elemento del historial de reproducciones?</string>
|
||||
<string name="delete_all_history_prompt">¿Seguro que desea eliminar todos los elementos del historial?</string>
|
||||
<string name="title_last_played">Última reproducción</string>
|
||||
<string name="title_most_played">Más reproducido</string>
|
||||
|
||||
<string name="always_ask_open_action">Preguntar siempre</string>
|
||||
|
||||
<string name="create_playlist">Nueva lista de reproducción</string>
|
||||
<string name="delete_playlist">Eliminar</string>
|
||||
<string name="rename_playlist">Renombrar</string>
|
||||
<string name="playlist_name_input">Nombre</string>
|
||||
<string name="append_playlist">Añadir a la lista de reproducción</string>
|
||||
<string name="set_as_playlist_thumbnail">Definir como miniatura de lista de reproducción</string>
|
||||
|
||||
<string name="bookmark_playlist">Marcar lista de reproducción</string>
|
||||
<string name="unbookmark_playlist">Eliminar marcador</string>
|
||||
|
||||
<string name="delete_playlist_prompt">¿Borrar esta lista de reproducción\?</string>
|
||||
<string name="playlist_creation_success">Lista de reproducción creada</string>
|
||||
<string name="playlist_add_stream_success">Añadido a la lista de reproducción</string>
|
||||
<string name="playlist_thumbnail_change_success">Miniatura de lista de reproducción cambiada.</string>
|
||||
<string name="playlist_delete_failure">No se pudo eliminar la lista de reproducción.</string>
|
||||
|
||||
<string name="drawer_header_action_paceholder_text">Algo aparecerá aquí pronto ;D</string>
|
||||
|
||||
|
||||
<string name="caption_none">Sin subtítulos</string>
|
||||
|
||||
<string name="resize_fit">Ajustar</string>
|
||||
<string name="resize_fill">Rellenar</string>
|
||||
<string name="resize_zoom">Zoom</string>
|
||||
|
||||
<string name="settings_category_debug_title">Depuración</string>
|
||||
<string name="settings_category_debug_title">Depuración</string>
|
||||
<string name="caption_auto_generated">Auto generados</string>
|
||||
<string name="enable_leak_canary_title">Activar LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">La monitorización de fugas de memoria puede causar que la app no responda cuando hay Heap Dump</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Reportar errores fuera del ciclo de duración</string>
|
||||
<string name="enable_disposed_exceptions_summary">Forzar reporte de excepciones no entregables de RX fuera del fragmento o del ciclo de actividad después del descarte</string>
|
||||
|
||||
<string name="use_inexact_seek_title">Usar búsqueda rápida inexacta</string>
|
||||
<string name="use_inexact_seek_title">Usar búsqueda rápida inexacta</string>
|
||||
<string name="use_inexact_seek_summary">La búsqueda inexacta permite al reproductor buscar posiciones más rápido con menor precisión</string>
|
||||
<string name="auto_queue_title">Auto-encolar la siguiente transmisión</string>
|
||||
<string name="auto_queue_summary">Auto-añadir un vídeo relacionado al reproducir el último vídeo en una cola no repetitiva.</string>
|
||||
<string name="live">DIRECTO</string>
|
||||
<string name="live_sync">SINCRONIZAR</string>
|
||||
<string name="file">Archivo</string>
|
||||
|
||||
<string name="file">Archivo</string>
|
||||
<string name="missing_file">Archivo movido o eliminado</string>
|
||||
<string name="invalid_directory">No existe el directorio</string>
|
||||
<string name="invalid_source">No existe la fuente del archivo/contenido</string>
|
||||
<string name="invalid_file">El archivo no existe o insuficientes permisos para leerlo o escribir en él</string>
|
||||
<string name="file_name_empty_error">El nombre del archivo no puede estar vacío</string>
|
||||
<string name="error_occurred_detail">Ocurrió un error: %1$s</string>
|
||||
|
||||
<string name="import_export_title">Importar/exportar</string>
|
||||
<string name="import_title">Importar</string>
|
||||
<string name="import_from">Importar desde</string>
|
||||
<string name="export_to">Exportar a</string>
|
||||
|
||||
<string name="import_ongoing">Importando…</string>
|
||||
<string name="export_ongoing">Exportando…</string>
|
||||
|
||||
<string name="import_file_title">Importar archivo</string>
|
||||
<string name="previous_export">Exportación anterior</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">No se pudo importar suscripciones</string>
|
||||
<string name="subscriptions_export_unsuccessful">No se pudo exportar suscripciones</string>
|
||||
|
||||
<string name="import_youtube_instructions">Importe suscripciones de YouTube descargando el archivo de exportación:
|
||||
\n
|
||||
\n1. Vaya a esta URL: %1$s
|
||||
|
@ -428,12 +353,11 @@ abrir en modo popup</string>
|
|||
\n3. Inicie sesión cuando se le pida
|
||||
\n4. Copie la URL del perfil a la que fue redireccionado.</string>
|
||||
<string name="import_soundcloud_instructions_hint">suID, soundcloud.com/suID</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Tenga en cuenta que esta operación puede ser costosa para la red.
|
||||
\n
|
||||
\n¿Desea continuar?</string>
|
||||
<string name="download_thumbnail_title">Cargar Miniaturas</string>
|
||||
<string name="download_thumbnail_summary">Cuando está desactivado no se cargan miniaturas, economizando el uso de datos y memoria. Los cambios borrarán tanto la caché de imágenes en la memoria como en el disco.</string>
|
||||
<string name="download_thumbnail_title">Cargar miniaturas</string>
|
||||
<string name="download_thumbnail_summary">Desactívalo para evitar la carga de miniaturas, ahorrando datos y uso de memoria. Los cambios borrarán tanto la caché de imágenes en la memoria como en el disco.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Caché de imagen limpiado</string>
|
||||
<string name="metadata_cache_wipe_title">Metadatos eliminados del caché</string>
|
||||
<string name="metadata_cache_wipe_summary">Eliminar todos los datos de la página web en caché</string>
|
||||
|
@ -442,16 +366,12 @@ abrir en modo popup</string>
|
|||
<string name="playback_tempo">Tiempo</string>
|
||||
<string name="playback_pitch">Tono</string>
|
||||
<string name="unhook_checkbox">Desenganchar (puede causar distorsión)</string>
|
||||
<string name="no_streams_available_download">No hay streams disponibles para descargar</string>
|
||||
|
||||
<string name="no_streams_available_download">No hay streams disponibles para descargar</string>
|
||||
<string name="preferred_open_action_settings_title">Acción \'abrir\' preferida</string>
|
||||
<string name="preferred_open_action_settings_summary">Acción por defecto al abrir contenido — %s</string>
|
||||
|
||||
<string name="toast_no_player">No hay ninguna app instalada para reproducir este archivo</string>
|
||||
|
||||
<string name="caption_setting_title">Subtítulos</string>
|
||||
<string name="caption_setting_description">Modificar la escala de texto de los subtítulos y los estilos de fondo del reproductor. Requiere el reinicio de la app para que surta efecto.</string>
|
||||
|
||||
<string name="clear_views_history_title">Borrar historial de reproducciones</string>
|
||||
<string name="clear_views_history_summary">Elimina el historial de las transmisiones reproducidas</string>
|
||||
<string name="delete_view_history_alert">¿Eliminar todo el historial de reproducciones\?</string>
|
||||
|
@ -461,81 +381,113 @@ abrir en modo popup</string>
|
|||
<string name="delete_search_history_alert">¿Eliminar todo el historial de búsqueda\?</string>
|
||||
<string name="search_history_deleted">Historial de búsquedas eliminado.</string>
|
||||
<string name="one_item_deleted">1 elemento eliminado.</string>
|
||||
|
||||
<string name="app_license">NewPipe es software libre copyleft: puedes usarlo, estudiarlo, compartirlo y mejorarlo a tu antojo. Específicamente, puedes redistribuirlo y/o modificarlo bajo los términos de la Licencia Pública General GNU publicada por la Free Software Foundation, ya sea la versión 3 de la Licencia, o (a tu elección) cualquier versión posterior.</string>
|
||||
<string name="import_settings">¿Desea importar también los ajustes?</string>
|
||||
|
||||
<string name="privacy_policy_title">Política de Privacidad de NewPipe</string>
|
||||
<string name="privacy_policy_encouragement">El proyecto NewPipe toma su privacidad muy en serio. Por lo tanto, la aplicación no recopila ningún dato sin su consentimiento. La política de privacidad de NewPipe explica en detalle qué datos se envían y almacenan cuando envía un informe de fallas.</string>
|
||||
<string name="read_privacy_policy">Leer la Política de Privacidad</string>
|
||||
<string name="start_accept_privacy_policy">Para cumplir con el Reglamento general europeo de protección de datos (GDPR), podemos llamar su atención sobre la política de privacidad de NewPipe. Por favor léelo cuidadosamente. Debe aceptarlo para enviarnos el informe de error.</string>
|
||||
<string name="accept">Aceptar</string>
|
||||
<string name="decline">Declinar</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Sin límite</string>
|
||||
<string name="limit_mobile_data_usage_title">Limitar resolución cuando se use Datos Móviles</string>
|
||||
<string name="limit_mobile_data_usage_title">Limitar la resolución cuando se usen datos móviles</string>
|
||||
<string name="minimize_on_exit_title">Mimimizar al cambiar de aplicación</string>
|
||||
<string name="minimize_on_exit_summary">Acción de cambiar a otra aplicación desde el reproductor principal — %s</string>
|
||||
<string name="minimize_on_exit_none_description">Ninguna</string>
|
||||
<string name="minimize_on_exit_background_description">Minimizar al reproductor de fondo</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimizar el reproductor emergente</string>
|
||||
|
||||
<string name="skip_silence_checkbox">Avance rápido durante el silencio</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimizar al reproductor popup</string>
|
||||
<string name="skip_silence_checkbox">Avance rápido durante el silencio</string>
|
||||
<string name="playback_step">Paso</string>
|
||||
<string name="playback_reset">Reiniciar</string>
|
||||
|
||||
<string name="channels">Canales</string>
|
||||
<string name="users">Usuarios</string>
|
||||
<string name="playlists">Listas de reproducción</string>
|
||||
<string name="tracks">Pistas</string>
|
||||
<string name="missions_header_finished">Finalizadas</string>
|
||||
<string name="missions_header_pending">En cola</string>
|
||||
|
||||
<string name="missions_header_pending">Pendientes</string>
|
||||
<string name="paused">pausado</string>
|
||||
<string name="queued">en cola</string>
|
||||
<string name="post_processing">post-procesado</string>
|
||||
|
||||
<string name="enqueue">Encolar</string>
|
||||
|
||||
<string name="permission_denied">Acción denegada por el sistema</string>
|
||||
|
||||
<string name="file_deleted">Archivo borrado</string>
|
||||
|
||||
<!-- download notifications -->
|
||||
<string name="download_failed">Descarga fallida</string>
|
||||
<string name="download_finished">Descarga finalizada</string>
|
||||
<string name="download_finished_more">%s descargas finalizadas</string>
|
||||
|
||||
<!-- dialog about existing downloads -->
|
||||
<string name="generate_unique_name">Generar nombre único</string>
|
||||
<string name="overwrite">Sobrescribir</string>
|
||||
<string name="overwrite_warning">Ya existe un archivo descargado con este nombre</string>
|
||||
<string name="overwrite_unrelated_warning">Ya existe un archivo con este nombre</string>
|
||||
<string name="overwrite_finished_warning">Ya existe un archivo descargado con este nombre</string>
|
||||
<string name="overwrite_failed">No se puede sobrescribir el archivo</string>
|
||||
<string name="download_already_running">Hay una descarga en curso con este nombre</string>
|
||||
|
||||
<string name="download_already_pending">Hay una descarga pendiente con este nombre</string>
|
||||
<string name="grid">Mostrar como grilla</string>
|
||||
<string name="list">Mostrar como lista</string>
|
||||
<string name="clear_finished_download">Limpiar descargas finalizadas</string>
|
||||
<string name="msg_pending_downloads">Tienes %s descargas pendientes, ve a Descargas para continuarlas</string>
|
||||
<string name="confirm_prompt">¿Estas seguro?</string>
|
||||
<string name="stop">Detener</string>
|
||||
<string name="max_retry_msg">Intentos maximos</string>
|
||||
<string name="max_retry_msg">Intentos máximos</string>
|
||||
<string name="max_retry_desc">Cantidad máxima de intentos antes de cancelar la descarga</string>
|
||||
<string name="pause_downloads_on_mobile">Pausar al cambiar a datos moviles</string>
|
||||
<string name="pause_downloads_on_mobile_desc">No todas las descargas se pueden suspender, en esos casos, se reiniciaran</string>
|
||||
<string name="pause_downloads_on_mobile">Interrumpir en redes medidas</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Útil al cambiar a Datos Móviles, solo algunas descargas no se pueden suspender</string>
|
||||
<string name="enable_queue_limit">Limitar cola de descarga</string>
|
||||
<string name="enable_queue_limit_desc">Solo se permitirá una descarga a la vez</string>
|
||||
<string name="start_downloads">Iniciar descargas</string>
|
||||
<string name="pause_downloads">Pausar descargas</string>
|
||||
|
||||
|
||||
<!-- message dialog about download error -->
|
||||
<string name="show_error">Mostrar error</string>
|
||||
<string name="label_code">Codigo</string>
|
||||
<string name="error_path_creation">No se puede crear la carpeta de destino</string>
|
||||
<string name="error_file_creation">No se puede crear el archivo</string>
|
||||
<string name="error_path_creation">No se puede crear la carpeta de destino</string>
|
||||
<string name="error_permission_denied">Permiso denegado por el sistema</string>
|
||||
<string name="error_ssl_exception">Fallo la conexión segura</string>
|
||||
<string name="error_unknown_host">No se puede encontrar el servidor</string>
|
||||
<string name="error_unknown_host">No se pudo encontrar el servidor</string>
|
||||
<string name="error_connect_host">No se puede conectar con el servidor</string>
|
||||
<string name="error_http_no_content">El servidor no devolvio datos</string>
|
||||
<string name="error_http_unsupported_range">El servidor no acepta descargas multi-hilos, intente de nuevo con @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Rango solicitado no satisfactorio</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">No se logro obtener el rango solicitado</string>
|
||||
<string name="error_http_not_found">No encontrado</string>
|
||||
<string name="error_postprocessing_failed">Fallo el post-procesado</string>
|
||||
|
||||
</resources>
|
||||
<string name="error_postprocessing_stopped">NewPipe se cerro mientras se trabajaba en el archivo</string>
|
||||
<string name="error_insufficient_storage">No hay suficiente espacio disponible en el dispositivo</string>
|
||||
<string name="error_progress_lost">Se perdió el progreso porque el archivo fue eliminado</string>
|
||||
<string name="error_timeout">Tiempo de espera excedido</string>
|
||||
|
||||
<string name="download_pick_path">Seleccione los directorios de descarga</string>
|
||||
<string name="downloads_storage_ask_title">Preguntar dónde descargar</string>
|
||||
<string name="downloads_storage_ask_summary">Se preguntará dónde guardar cada descarga</string>
|
||||
<string name="downloads_storage_ask_summary_kitkat">Se preguntará dónde guardar cada descarga.\nHabilita esta opción si quieres descargar en la tarjeta SD externa</string>
|
||||
|
||||
<string name="unsubscribe">Desuscribirse</string>
|
||||
<string name="tab_new">Nueva pestaña</string>
|
||||
<string name="tab_choose">Elige la pestaña</string>
|
||||
<string name="volume_gesture_control_title">Control de volumen por gestos</string>
|
||||
<string name="volume_gesture_control_summary">Usar gestos para controlar el volumen del reproductor</string>
|
||||
<string name="brightness_gesture_control_title">Control de brillo por gestos</string>
|
||||
<string name="brightness_gesture_control_summary">Usar gestos para controlar el brillo del reproductor</string>
|
||||
<string name="settings_category_updates_title">Actualizaciones</string>
|
||||
<string name="events">Eventos</string>
|
||||
<string name="app_update_notification_channel_name">Notificación de actualización de la aplicación</string>
|
||||
<string name="app_update_notification_channel_description">Notificaciones para nueva versión de NewPipe</string>
|
||||
<string name="download_to_sdcard_error_title">Almacenamiento externo no disponible</string>
|
||||
<string name="download_to_sdcard_error_message">No es posible descargar a una tarjeta SD externa. \¿Restablecer la ubicación de la carpeta de descarga\?</string>
|
||||
<string name="saved_tabs_invalid_json">Usando las pestañas por defecto, error al leer las pestañas guardadas</string>
|
||||
<string name="restore_defaults">Restaurar valores por defecto</string>
|
||||
<string name="restore_defaults_confirmation">¿Quieres restaurar los valores por defecto\?</string>
|
||||
<string name="subscribers_count_not_available">Número de suscriptores no disponible</string>
|
||||
<string name="main_page_content_summary">Qué pestañas aparecen en la página principal</string>
|
||||
<string name="selection">Selección</string>
|
||||
<string name="conferences">Conferencias</string>
|
||||
<string name="updates_setting_title">Actualizaciones</string>
|
||||
<string name="updates_setting_description">Mostrar una notificación para solicitar actualizar la aplicación cuando haya una nueva versión disponible</string>
|
||||
<string name="list_view_mode">Modo de vista de lista</string>
|
||||
<string name="auto">Automático</string>
|
||||
<string name="switch_view">Cambiar vista</string>
|
||||
<string name="app_update_notification_content_title">¡Actualización de NewPipe disponible!</string>
|
||||
<string name="app_update_notification_content_text">Pulsa para descargar</string>
|
||||
</resources>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources><string name="main_bg_subtitle">Alustuseks puuduta otsingut</string>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="main_bg_subtitle">Alustuseks puuduta otsingut</string>
|
||||
<string name="view_count_text">%1$s vaatamist</string>
|
||||
<string name="upload_date_text">Avaldatud %1$s</string>
|
||||
<string name="no_player_found">Voogesituseks puudub pleier. Kas paigaldada VLC?</string>
|
||||
|
@ -27,24 +28,18 @@
|
|||
<string name="subscription_change_failed">Tellimust ei saanud muuta</string>
|
||||
<string name="subscription_update_failed">Tellimust ei õnnestunud uuendada</string>
|
||||
<string name="show_info">Kuva info</string>
|
||||
|
||||
<string name="tab_subscriptions">Tellimused</string>
|
||||
<string name="tab_bookmarks">Esitusloendid järjehoidjates</string>
|
||||
|
||||
<string name="fragment_whats_new">Mis on uut</string>
|
||||
|
||||
<string name="controls_background_title">Taust</string>
|
||||
<string name="controls_popup_title">Hüpikaken</string>
|
||||
<string name="controls_add_to_playlist_title">"Lisa "</string>
|
||||
|
||||
<string name="download_path_title">Video allalaadimise kaust</string>
|
||||
<string name="download_path_summary">Kaust allalaetud videote hoiustamiseks</string>
|
||||
<string name="download_path_dialog_title">Sisesta videote allalaadimise rada</string>
|
||||
|
||||
<string name="download_path_audio_title">Audio allalaadimise kaust</string>
|
||||
<string name="download_path_audio_summary">Siia salvestatakse alla laaditud audio</string>
|
||||
<string name="download_path_audio_dialog_title">Sisesta audio allalaadimise rada</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">Automaatesitus</string>
|
||||
<string name="autoplay_by_calling_app_summary">Esita video, kui NewPipe käivitub teise rakenduse kaudu</string>
|
||||
<string name="default_resolution_title">Vaikelahutus</string>
|
||||
|
@ -67,15 +62,15 @@
|
|||
<string name="use_inexact_seek_title">Kasuta ebatäpset kerimist</string>
|
||||
<string name="use_inexact_seek_summary">Ebatäpne kerimine lubab pleieril otsida asukohta kiiremini täpsuse arvel</string>
|
||||
<string name="download_thumbnail_title">Laadi pisipildid</string>
|
||||
<string name="download_thumbnail_summary">Välujalülitatult ei toimu pisipiltide laadimist, salvestamist ja puhverdamist. Muutmine puhastab vahemälu nii kettal kui ka mälus.</string>
|
||||
<string name="download_thumbnail_summary">Lülita välja, et keelata pisipiltide laadimist, andmete salvestamist ja mälu kasutust. Muutmine puhastab vahemälu nii kettal kui ka mälus.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Pildid kustutati vahemälust</string>
|
||||
<string name="metadata_cache_wipe_title">Kustuta metaandmed vahemälust</string>
|
||||
<string name="metadata_cache_wipe_summary">Kustuta veebilehtede andmed vahemälust</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">Metaandmed kustutati vahemälust</string>
|
||||
<string name="auto_queue_title">Järgmine voog automaatselt järjekorda</string>
|
||||
<string name="auto_queue_summary">Lisa seotud voog automaatselt, kui esitusel on viimane voog mittekorduvast järjekorrast.</string>
|
||||
<string name="player_gesture_controls_title">Pleieri juhtimise viiped</string>
|
||||
<string name="player_gesture_controls_summary">Luba viiped helitugevuse ja ereduse juhtimiseks</string>
|
||||
<string name="player_gesture_controls_title">Pleieri juhtimine viibetega</string>
|
||||
<string name="player_gesture_controls_summary">Kasuta helitugevuse ja ereduse reguleerimiseks viipeid</string>
|
||||
<string name="show_search_suggestions_title">Kuva soovitused</string>
|
||||
<string name="show_search_suggestions_summary">Kuva otsingu ajal soovitusi</string>
|
||||
<string name="enable_search_history_title">Otsinguajalugu</string>
|
||||
|
@ -108,7 +103,7 @@
|
|||
<string name="play_btn_text">Esita</string>
|
||||
<string name="content">Sisu</string>
|
||||
<string name="show_age_restricted_content_title">Vanusepiiranguga sisu</string>
|
||||
<string name="video_is_age_restricted">Kuva vanusepiiranguga sisu. Sellise materjali saab lubada \"seadetes\".</string>
|
||||
<string name="video_is_age_restricted">Kuva vanusepiiranguga video. Sellist sisu saab lubada seadetes.</string>
|
||||
<string name="duration_live">OTSE</string>
|
||||
<string name="downloads">Allalaadimised</string>
|
||||
<string name="downloads_title">Allalaadimised</string>
|
||||
|
@ -129,12 +124,9 @@
|
|||
<string name="always">Alati</string>
|
||||
<string name="just_once">Üks kord</string>
|
||||
<string name="file">Fail</string>
|
||||
|
||||
<string name="notification_channel_name">NewPipe teavitus</string>
|
||||
<string name="notification_channel_description">Teavitused NewPipe tausta- ja hüpikpleierile</string>
|
||||
|
||||
<string name="unknown_content">[Tundmatu]</string>
|
||||
|
||||
<string name="toggle_orientation">Vaheta suunda</string>
|
||||
<string name="switch_to_background">Lülita taustale</string>
|
||||
<string name="switch_to_popup">Lülita hüpikpleierile</string>
|
||||
|
@ -176,7 +168,6 @@
|
|||
<string name="file_name_empty_error">Tühi failinimi pole lubatud</string>
|
||||
<string name="error_occurred_detail">Ilmnes viga: %1$s</string>
|
||||
<string name="no_streams_available_download">Allalaaditavaid videovooge pole</string>
|
||||
|
||||
<string name="sorry_string">Vabandust, seda poleks pidanud juhtuma.</string>
|
||||
<string name="error_report_button_text">Teata veast e-posti kaudu</string>
|
||||
<string name="error_snackbar_message">Vabandust, ilmnesid mõned vead.</string>
|
||||
|
@ -186,8 +177,6 @@
|
|||
<string name="info_labels">Mis:\\nPäring:\\nSisu Keel:\\nTeenus:\\nGMT aeg:\\nPakett:\\nVersioon:\\nOS versioon:</string>
|
||||
<string name="your_comment">Oma kommentaar (inglise keeles):</string>
|
||||
<string name="error_details_headline">Üksikasjad:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">Video eelvaate pisipilt</string>
|
||||
<string name="detail_thumbnail_view_description">Video eelvaate pisipilt</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Üleslaadiaja avatari pisipilt</string>
|
||||
|
@ -200,39 +189,30 @@
|
|||
<string name="search_no_results">Tulemusi pole</string>
|
||||
<string name="empty_subscription_feed_subtitle">Siin pole veel midagi</string>
|
||||
<string name="detail_drag_description">Lohista järjestuse muutmiseks</string>
|
||||
|
||||
<string name="err_dir_create">Allalaadimiskataloogi \'%1$s\' loomine nurjus</string>
|
||||
<string name="info_dir_created">Loodi allalaadimiskataloog \'%1$s\'</string>
|
||||
|
||||
<string name="video">Video</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="retry">Proovi uuesti</string>
|
||||
<string name="storage_permission_denied">Pääsuõigused salvestile puuduvad</string>
|
||||
<string name="use_old_player_title">Kasuta vana pleierit</string>
|
||||
<string name="use_old_player_summary">Vana sisseehitatud mediaframework pleier</string>
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">B</string>
|
||||
|
||||
<string name="no_subscribers">Tellijaid pole</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s tellija</item>
|
||||
<item quantity="other">%s tellijat</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s tellija</item>
|
||||
<item quantity="other">%s tellijat</item>
|
||||
</plurals>
|
||||
<string name="no_views">Pole vaadatud</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s vaatamine</item>
|
||||
<item quantity="other">%s vaatamist</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s vaatamine</item>
|
||||
<item quantity="other">%s vaatamist</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Videoid pole</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s video</item>
|
||||
<item quantity="other">%s videot</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s video</item>
|
||||
<item quantity="other">%s videot</item>
|
||||
</plurals>
|
||||
<string name="start">"Start "</string>
|
||||
<string name="pause">Paus</string>
|
||||
<string name="view">Esita</string>
|
||||
|
@ -243,10 +223,8 @@
|
|||
<string name="checksum">Kontrollsumma</string>
|
||||
<string name="dismiss">Loobu</string>
|
||||
<string name="rename">Nimeta ümber</string>
|
||||
|
||||
<string name="add">Uus ülesanne</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="msg_name">Faili nimi</string>
|
||||
<string name="msg_threads">Lõimed</string>
|
||||
<string name="msg_error">Viga</string>
|
||||
|
@ -261,18 +239,14 @@
|
|||
<string name="msg_popup_permission">Need õigused on vajalikud
|
||||
\nhüpikakna avamiseks</string>
|
||||
<string name="one_item_deleted">Kustutati 1 element.</string>
|
||||
|
||||
<string name="reCaptchaActivity">"reCAPTCHA "</string>
|
||||
<string name="settings_category_downloads_title">Laadi alla</string>
|
||||
<string name="settings_file_charset_title">Lubatud tähemärgid failinimedes</string>
|
||||
<string name="settings_file_replacement_character_summary">Vigased tähemärgid asendatakse selle väärtusega</string>
|
||||
<string name="settings_file_replacement_character_title">Asendustähemärk</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Tähed ja numbrid</string>
|
||||
<string name="charset_most_special_characters">Erimärgid</string>
|
||||
|
||||
<string name="toast_no_player">Selle faili esitamiseks puudub rakendus</string>
|
||||
|
||||
<string name="title_activity_about">NewPipe rakendusest</string>
|
||||
<string name="action_settings">Seaded</string>
|
||||
<string name="action_about">Programmist</string>
|
||||
|
@ -291,8 +265,6 @@
|
|||
<string name="read_privacy_policy">Loe privaatsuspoliitikat</string>
|
||||
<string name="app_license_title">NewPipe litsents</string>
|
||||
<string name="read_full_license">Loe litsentsi</string>
|
||||
|
||||
|
||||
<string name="title_activity_history">Ajalugu</string>
|
||||
<string name="title_history_search">Otsitud</string>
|
||||
<string name="title_history_view">Vaadatud</string>
|
||||
|
@ -306,7 +278,6 @@
|
|||
<string name="delete_all_history_prompt">Kas kustutada kõik kirjed ajaloost?</string>
|
||||
<string name="title_last_played">Viimati esitatud</string>
|
||||
<string name="title_most_played">Enim esitatud</string>
|
||||
|
||||
<string name="main_page_content">Avalehe sisu</string>
|
||||
<string name="blank_page_summary">Tühi leht</string>
|
||||
<string name="kiosk_page_summary">Kioski leht</string>
|
||||
|
@ -322,7 +293,6 @@
|
|||
<string name="could_not_import_all_files">Hoiatus: Kõiki faile ei õnnestunud importida.</string>
|
||||
<string name="override_current_data">See alistab praeguse seadistuse.</string>
|
||||
<string name="import_settings">Kas importida ka seadistused?</string>
|
||||
|
||||
<string name="kiosk">"Kiosk "</string>
|
||||
<string name="trending">Trendid</string>
|
||||
<string name="top_50">"Top 50 "</string>
|
||||
|
@ -338,66 +308,48 @@
|
|||
<string name="start_here_on_main">Alusta taasesitust siit</string>
|
||||
<string name="start_here_on_background">Alusta siit olles taustal</string>
|
||||
<string name="start_here_on_popup">Alusta siit uue hüpikaknaga</string>
|
||||
|
||||
<string name="drawer_open">Ava sahtel</string>
|
||||
<string name="drawer_close">Sulge sahtel</string>
|
||||
<string name="drawer_header_action_paceholder_text">Siia ilmub varsti midagi ;D</string>
|
||||
|
||||
|
||||
<string name="preferred_open_action_settings_title">Lingi avamine</string>
|
||||
<string name="preferred_open_action_settings_summary">Vaikimisi tegevus sisu avamisel — %s</string>
|
||||
|
||||
<string name="video_player">Videopleier</string>
|
||||
<string name="background_player">Taustapleier</string>
|
||||
<string name="popup_player">Hüpikpleier</string>
|
||||
<string name="always_ask_open_action">Küsi alati</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Info hankimine…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Soovitud sisu laadimine</string>
|
||||
|
||||
<string name="create_playlist">Uus pleilist</string>
|
||||
<string name="delete_playlist">Kustuta</string>
|
||||
<string name="rename_playlist">Nimeta ümber</string>
|
||||
<string name="playlist_name_input">Nimi</string>
|
||||
<string name="append_playlist">Lisa pleilisti</string>
|
||||
<string name="set_as_playlist_thumbnail">Määra pleilisti pisipildiks</string>
|
||||
|
||||
<string name="bookmark_playlist">Lisa pleilist järjehoidjaks</string>
|
||||
<string name="unbookmark_playlist">Eemalda järjehoidja</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Kas kustutada see pleilist?</string>
|
||||
<string name="playlist_creation_success">Pleilist loodud</string>
|
||||
<string name="playlist_add_stream_success">Lisati pleilisti</string>
|
||||
<string name="playlist_thumbnail_change_success">Pleilisti pisipilt muudetud.</string>
|
||||
<string name="playlist_delete_failure">Pleilisti kustutamine nurjus.</string>
|
||||
|
||||
<string name="caption_none">Subtiitriteta</string>
|
||||
|
||||
<string name="resize_fit">Mahuta</string>
|
||||
<string name="resize_fill">Täida</string>
|
||||
<string name="resize_zoom">Suumi</string>
|
||||
|
||||
<string name="caption_auto_generated">Automaatselt loodud</string>
|
||||
|
||||
<string name="caption_setting_title">Subtiitrid</string>
|
||||
<string name="caption_setting_description">Kohanda pleieri subtiitrite teksti suurust ja tausta. Jõustamiseks tuleb rakendus taaskäivitada.</string>
|
||||
|
||||
<string name="enable_leak_canary_summary">Mälulekke seire võib põhjustada rakenduse hangumise</string>
|
||||
|
||||
<string name="import_export_title">Import/eksport</string>
|
||||
<string name="import_title">Import</string>
|
||||
<string name="import_from">Impordi asukohast</string>
|
||||
<string name="export_to">Ekspordi asukohta</string>
|
||||
|
||||
<string name="import_ongoing">Import…</string>
|
||||
<string name="export_ongoing">Eksport…</string>
|
||||
|
||||
<string name="import_file_title">Impordi fail</string>
|
||||
<string name="previous_export">Eelmine eksport</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Tellimuste import nurjus</string>
|
||||
<string name="subscriptions_export_unsuccessful">Tellimuste eksport nurjus</string>
|
||||
|
||||
<string name="import_youtube_instructions">Impordi YouTube tellimused eksportfaili abil:
|
||||
\n
|
||||
\n1. Ava URL: %1$s
|
||||
|
@ -406,14 +358,11 @@
|
|||
<string name="import_network_expensive_warning">See toiming võib põhjustada suurt võrguliiklust.
|
||||
\n
|
||||
\nKas jätkata?</string>
|
||||
|
||||
<string name="playback_speed_control">Taasesituse kiiruse juhtimine</string>
|
||||
<string name="playback_tempo">"Tempo "</string>
|
||||
<string name="playback_default">Vaikimisi</string>
|
||||
|
||||
<string name="accept">Nõustu</string>
|
||||
<string name="decline">Keeldu</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Piiranguta</string>
|
||||
<string name="limit_mobile_data_usage_title">Piira lahutust mobiilse andmeside kasutamisel</string>
|
||||
<string name="tab_main">Peamenüü</string>
|
||||
|
@ -422,10 +371,8 @@
|
|||
<string name="tracks">Lood</string>
|
||||
<string name="users">Kasutajad</string>
|
||||
<string name="switch_to_main">Lülitu peamisele</string>
|
||||
|
||||
<string name="reCaptcha_title">reCAPTCHA nõue</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA nõude taotlus</string>
|
||||
|
||||
<string name="copyright" formatted="true">© %1$s %2$s %3$s alla</string>
|
||||
<string name="app_description">Vaba kergekaaluline Androidi voogesitus.</string>
|
||||
<string name="contribution_encouragement">Kui sul on ideid kujunduse muutmisest, koodi puhastamisest või suurtest koodi muudatustest - abi on alati teretulnud. Mida rohkem tehtud, seda paremaks läheb!</string>
|
||||
|
@ -443,13 +390,11 @@
|
|||
\n3. Logi sisse
|
||||
\n4. Kopeeri suunatud profiili URL.</string>
|
||||
<string name="import_soundcloud_instructions_hint">sinu_ID, soundcloud.com/sinu_id</string>
|
||||
|
||||
<string name="playback_pitch">Toon</string>
|
||||
<string name="unhook_checkbox">Tühista ühendus (võib põhjustada moonutusi)</string>
|
||||
<string name="skip_silence_checkbox">Keri helitu koht edasi</string>
|
||||
<string name="playback_step">Samm</string>
|
||||
<string name="playback_reset">Lähtesta</string>
|
||||
|
||||
<string name="start_accept_privacy_policy">Selleks, et täita Euroopa Üldist Andmekaitse Määrust (GDPR), juhime tähelepanu NewPipe\'i privaatsuspoliitikale. Palun lugege seda hoolikalt.
|
||||
\nMeile veateate saatmiseks tuleb sellega nõustuda.</string>
|
||||
<string name="minimize_on_exit_title">Minimeeri, kui kasutad teisi rakendusi</string>
|
||||
|
@ -457,7 +402,70 @@
|
|||
<string name="minimize_on_exit_none_description">Pole</string>
|
||||
<string name="minimize_on_exit_background_description">Esita taustal</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimeeri hüpikpleierisse</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_summary">Jõusta väljaspool fragmenti või elutsüklit olevate kättetoimetamatute Rx erindite raporteerimine nende vabastamise järgselt</string>
|
||||
|
||||
</resources>
|
||||
<string name="enable_disposed_exceptions_summary">Jõusta väljaspool fragmenti või elutsüklit olevate kättetoimetamatute Rx erindite raporteerimine nende vabastamise järgselt</string>
|
||||
<string name="unsubscribe">Lõpeta tellimine</string>
|
||||
<string name="tab_new">Uus vahekaart</string>
|
||||
<string name="tab_choose">Vali vahekaart</string>
|
||||
<string name="volume_gesture_control_title">Helitugevuse juhtimine viibetega</string>
|
||||
<string name="volume_gesture_control_summary">Kasuta helitugevuse reguleerimiseks viipeid</string>
|
||||
<string name="brightness_gesture_control_title">Ereduse reguleerimine viibetega</string>
|
||||
<string name="brightness_gesture_control_summary">Kasuta ereduse reguleerimiseks viipeid</string>
|
||||
<string name="settings_category_updates_title">Uuendused</string>
|
||||
<string name="events">Sündmused</string>
|
||||
<string name="file_deleted">Fail kustutati</string>
|
||||
<string name="app_update_notification_channel_name">Rakenduse värskenduse teatis</string>
|
||||
<string name="app_update_notification_channel_description">NewPipe uuest versioonist teavitamine</string>
|
||||
<string name="download_to_sdcard_error_title">Väline andmekandja pole saadaval</string>
|
||||
<string name="download_to_sdcard_error_message">Allalaadimine välisele SD-kaardile ei ole veel võimalik. Kas lähtestada allalaadimiste kataloogi asukoht\?</string>
|
||||
<string name="saved_tabs_invalid_json">Tõrge salvestatud vahekaaride lugemisel. Kasutatakse vaikeväärtusi</string>
|
||||
<string name="restore_defaults">Taasta vaikeväärtused</string>
|
||||
<string name="restore_defaults_confirmation">Kas taastada vaikeväärtused\?</string>
|
||||
<string name="subscribers_count_not_available">Tellijate arv ei ole saadaval</string>
|
||||
<string name="main_page_content_summary">Esilehel kuvatavad vahekaardid</string>
|
||||
<string name="selection">Valik</string>
|
||||
<string name="conferences">Konverentsid</string>
|
||||
<string name="updates_setting_title">Uuendused</string>
|
||||
<string name="updates_setting_description">Kuva teavitus, kui uus versioon on saadaval</string>
|
||||
<string name="list_view_mode">Nimekirjavaate režiim</string>
|
||||
<string name="list">Nimekiri</string>
|
||||
<string name="grid">Võrgustik</string>
|
||||
<string name="auto">Auto</string>
|
||||
<string name="switch_view">Vaheta vaadet</string>
|
||||
<string name="app_update_notification_content_title">NewPipe värskendus on saadaval!</string>
|
||||
<string name="app_update_notification_content_text">Allalaadimiseks puuduta</string>
|
||||
<string name="missions_header_finished">Lõpetatud</string>
|
||||
<string name="missions_header_pending">Järjekorras</string>
|
||||
<string name="paused">peatatud</string>
|
||||
<string name="queued">järjekorras</string>
|
||||
<string name="post_processing">järeltöötlus</string>
|
||||
<string name="enqueue">Järjekord</string>
|
||||
<string name="permission_denied">Tegevus keelati süsteemi poolt</string>
|
||||
<string name="download_failed">Allalaadimine nurjus</string>
|
||||
<string name="download_finished">Allalaadimine lõpetatud</string>
|
||||
<string name="download_finished_more">%s allalaadimist lõppenud</string>
|
||||
<string name="generate_unique_name">Loo kordumatu nimi</string>
|
||||
<string name="overwrite">Kirjuta üle</string>
|
||||
<string name="overwrite_unrelated_warning">Sellise nimega fail on juba olemas</string>
|
||||
<string name="overwrite_finished_warning">Selle nimega allalaaditud fail on juba olemas</string>
|
||||
<string name="download_already_running">Selle nimega allalaadimine on käimas</string>
|
||||
<string name="show_error">Näita viga</string>
|
||||
<string name="label_code">Kood</string>
|
||||
<string name="error_path_creation">Faili ei saa luua</string>
|
||||
<string name="error_file_creation">Sihtkausta ei saa luua</string>
|
||||
<string name="error_permission_denied">Tegevus keelati süsteemi poolt</string>
|
||||
<string name="error_ssl_exception">Turvaline ühendus nurjus</string>
|
||||
<string name="error_unknown_host">Serverit ei leitud</string>
|
||||
<string name="error_connect_host">Serveriga ei saadud ühendust</string>
|
||||
<string name="error_http_no_content">Server ei saada andmeid</string>
|
||||
<string name="error_http_unsupported_range">Server ei toeta mitmelõimelisi allalaadimisi. Proovi uuesti kasutades @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Taotletud vahemik ei ole rahuldatav</string>
|
||||
<string name="error_http_not_found">Ei leitud</string>
|
||||
<string name="error_postprocessing_failed">Järeltöötlemine nurjus</string>
|
||||
<string name="clear_finished_download">Eemalda lõpetatud allalaadimised</string>
|
||||
<string name="msg_pending_downloads">Jätka %s pooleliolevat allalaadimist</string>
|
||||
<string name="stop">Stopp</string>
|
||||
<string name="max_retry_msg">Korduskatseid</string>
|
||||
<string name="max_retry_desc">Suurim katsete arv enne allalaadimise tühistamist</string>
|
||||
<string name="pause_downloads_on_mobile">Paus üleminekul mobiilsele andmesidele</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Allalaadimised, mida ei saa peatada, taaskäivitatakse</string>
|
||||
</resources>
|
|
@ -29,7 +29,6 @@
|
|||
<string name="content_language_title">Edukiaren hizkuntz lehenetsia</string>
|
||||
<string name="settings_category_video_audio_title">Bideoa eta Audioa</string>
|
||||
<string name="play_btn_text">Erreproduzitu</string>
|
||||
|
||||
<string name="list_thumbnail_view_description">Bideoaren aurreikuspen argazkitxoa</string>
|
||||
<string name="detail_thumbnail_view_description">Bideoaren aurreikuspen argazkitxoa</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Igotzailearen abatarraren iruditxoa</string>
|
||||
|
@ -45,20 +44,17 @@
|
|||
<string name="main_bg_subtitle">Ukitu bilaketa hasteko</string>
|
||||
<string name="download_path_audio_title">Audioa deskargatzeko karpeta</string>
|
||||
<string name="download_path_audio_dialog_title">Zehaztu audioa deskargatzeko bide-izena</string>
|
||||
|
||||
<string name="download_path_audio_summary">Deskargatutako audioa hemen gordetzen da</string>
|
||||
<string name="autoplay_by_calling_app_title">Erreprodukzio automatikoa</string>
|
||||
<string name="autoplay_by_calling_app_summary">Bideoa abiatzen du NewPipe beste aplikazio batek deitu badu</string>
|
||||
<string name="dark_theme_title">Iluna</string>
|
||||
<string name="light_theme_title">Argia</string>
|
||||
|
||||
<string name="settings_category_appearance_title">Itxura</string>
|
||||
<string name="open_in_popup_mode">Ireki laster-leiho moduan</string>
|
||||
<string name="open_in_popup_mode">Ireki laster-leiho moduan</string>
|
||||
<string name="use_external_video_player_summary">Audioa kentzen du bereizmen batzuetan</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe laster-leiho modua</string>
|
||||
<string name="controls_background_title">Bigarren planoa</string>
|
||||
<string name="controls_popup_title">Laster-leihoa</string>
|
||||
|
||||
<string name="default_popup_resolution_title">Laster-leihoaren lehenetsitako bereizmena</string>
|
||||
<string name="show_higher_resolutions_title">Erakutsi bereizmen altuagoak</string>
|
||||
<string name="show_higher_resolutions_summary">Gailu batzuk besterik ez dute onartzen 2K/4K bideoak erreproduzitzea</string>
|
||||
|
@ -71,7 +67,6 @@
|
|||
<string name="player_gesture_controls_summary">Erabili keinuak erreproduzigailuaren distira eta bolumena kontrolatzeko</string>
|
||||
<string name="show_search_suggestions_title">Bilaketa-iradokizunak</string>
|
||||
<string name="show_search_suggestions_summary">Erakutsi iradokizunak bilatzean</string>
|
||||
|
||||
<string name="settings_category_popup_title">Laster-leihoa</string>
|
||||
<string name="settings_category_other_title">Besteak</string>
|
||||
<string name="popup_playing_toast">Laster-leiho moduan erreproduzitzen</string>
|
||||
|
@ -92,7 +87,6 @@
|
|||
<string name="clear">Garbitu</string>
|
||||
<string name="popup_resizing_indicator_title">Tamainaz aldatzen</string>
|
||||
<string name="best_resolution">Bereizmen onena</string>
|
||||
|
||||
<string name="general_error">Errorea</string>
|
||||
<string name="network_error">Sare-errorea</string>
|
||||
<string name="could_not_load_thumbnails">Ezin izan dira iruditxo guztiak deskargatu</string>
|
||||
|
@ -115,35 +109,24 @@
|
|||
<string name="info_labels">Zer:\\nEskaria:\\nEdukiaren hizkuntza:\\nZerbitzua:\\nGMT Ordua:\\nPaketea:\\nBertsioa:\\nSE bertsioa:</string>
|
||||
<string name="your_comment">Zure iruzkina (Ingelesez):</string>
|
||||
<string name="error_details_headline">Xehetasunak:</string>
|
||||
|
||||
|
||||
<string name="report_error">Eman errore baten berri</string>
|
||||
<string name="user_report">Erabiltzaile-txostena</string>
|
||||
|
||||
<string name="err_dir_create">Ezin izan da \'%1$s\' karpeta sortu deskargetarako</string>
|
||||
<string name="info_dir_created">\'%1$s\' karpeta sortu da deskargetarako</string>
|
||||
|
||||
<string name="video">Bideoa</string>
|
||||
<string name="audio">Audioa</string>
|
||||
<string name="retry">Saiatu berriro</string>
|
||||
<string name="storage_permission_denied">Biltegia atzitzeko baimena ukatu da</string>
|
||||
<string name="use_old_player_title">Erabili erreproduzigailu zaharra</string>
|
||||
<string name="use_old_player_summary">Barne Media Framework erreproduzigailu zaharra</string>
|
||||
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">MM</string>
|
||||
|
||||
<string name="start">Hasi</string>
|
||||
<string name="pause">Pausatu</string>
|
||||
<string name="view">Jo</string>
|
||||
<string name="delete">Ezabatu</string>
|
||||
<string name="checksum">Egiaztaketa-batura</string>
|
||||
|
||||
<string name="add">Misio berria</string>
|
||||
<string name="finish">Ados</string>
|
||||
|
||||
<string name="msg_name">Fitxategi-izena</string>
|
||||
<string name="msg_threads">Hariak</string>
|
||||
<string name="msg_error">Errorea</string>
|
||||
|
@ -157,11 +140,9 @@
|
|||
<string name="no_available_dir">Aukeratu eskuragarri dagoen karpeta bat deskargetarako</string>
|
||||
<string name="msg_popup_permission">Baimen hau beharrezkoa da
|
||||
\nlaster-leiho moduan irekitzeko</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA erronka</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA erronka eskatu da</string>
|
||||
|
||||
<string name="title_activity_about">NewPipe aplikazioari buruz</string>
|
||||
<string name="action_settings">Ezarpenak</string>
|
||||
<string name="action_about">Honi buruz</string>
|
||||
|
@ -178,28 +159,22 @@
|
|||
<string name="contribution_encouragement">Ideiak, itzulpenak, diseinu aldaketak, kode garbiketak, kode aldaketa sakonak badituzu, laguntza beti da ongi etorria. Eginaz hobetzen da!</string>
|
||||
<string name="read_full_license">Irakurri lizentzia</string>
|
||||
<string name="contribution_title">Hartu parte</string>
|
||||
<string name="subscribe_button_title">Harpidetu</string>
|
||||
<string name="subscribe_button_title">Harpidetu</string>
|
||||
<string name="subscribed_button_title">Harpidetuta</string>
|
||||
<string name="channel_unsubscribed">Kanaletik harpidetza kenduta</string>
|
||||
<string name="subscription_change_failed">Ezin izan da harpidetza aldatu</string>
|
||||
<string name="subscription_update_failed">Ezin izan da harpidetza eguneratu</string>
|
||||
|
||||
<string name="tab_main">Nagusia</string>
|
||||
<string name="tab_subscriptions">Harpidetzak</string>
|
||||
|
||||
<string name="fragment_whats_new">Zer dago berri</string>
|
||||
|
||||
<string name="resume_on_audio_focus_gain_title">Jarraitu fokua irabaztean</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Jarraitu etenaldiak eta gero (adib. telefono deiak)</string>
|
||||
|
||||
<string name="settings_category_downloads_title">Deskargatu</string>
|
||||
<string name="settings_category_downloads_title">Deskargak</string>
|
||||
<string name="settings_file_charset_title">Fitxategi-izenetan baimendutako karaktereak</string>
|
||||
<string name="settings_file_replacement_character_summary">Karaktere baliogabeak balio honekin ordezkatzen dira</string>
|
||||
<string name="settings_file_replacement_character_title">Ordezko karakterea</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Hizkiak eta zenbakiak</string>
|
||||
<string name="charset_most_special_characters">Karaktere berezi gehienak</string>
|
||||
|
||||
<string name="enable_search_history_title">Bilaketa historiala</string>
|
||||
<string name="enable_search_history_summary">Gorde bilaketak lokalki</string>
|
||||
<string name="enable_watch_history_title">Historiala eta katxea</string>
|
||||
|
@ -207,33 +182,27 @@
|
|||
<string name="notification_channel_name">NewPipe jakinarazpena</string>
|
||||
<string name="settings_category_player_title">Erreproduzigailua</string>
|
||||
<string name="settings_category_player_behavior_title">Portaera</string>
|
||||
<string name="settings_category_history_title">Historia eta cache-a</string>
|
||||
<string name="settings_category_history_title">Historia eta cachea</string>
|
||||
<string name="playlist">Erreprodukzio-zerrenda</string>
|
||||
<string name="undo">Desegin</string>
|
||||
|
||||
<string name="notification_channel_description">Atzeko planoko eta laster-leihoko NewPipe erreproduzigailuen jakinarazpenak</string>
|
||||
|
||||
<string name="search_no_results">Emaitzarik ez</string>
|
||||
<string name="empty_subscription_feed_subtitle">Kilkerrak besterik ez daude hemen</string>
|
||||
|
||||
<string name="no_subscribers">Harpidedunik ez</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">Harpidedun %s</item>
|
||||
<item quantity="other">%s harpidedun</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Harpidedun %s</item>
|
||||
<item quantity="other">%s harpidedun</item>
|
||||
</plurals>
|
||||
<string name="no_views">Ikustaldirik ez</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">ikustaldi %s</item>
|
||||
<item quantity="other">%s ikustaldi</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">ikustaldi %s</item>
|
||||
<item quantity="other">%s ikustaldi</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Bideorik ez</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">Bideoa</item>
|
||||
<item quantity="other">Bideoak</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Bideoa</item>
|
||||
<item quantity="other">Bideoak</item>
|
||||
</plurals>
|
||||
<string name="title_activity_history">Historiala</string>
|
||||
<string name="title_history_search">Bilatuta</string>
|
||||
<string name="title_history_view">Ikusita</string>
|
||||
|
@ -242,32 +211,27 @@
|
|||
<string name="history_empty">Historiala hutsik dago</string>
|
||||
<string name="history_cleared">Historiala garbitu da</string>
|
||||
<string name="item_deleted">Elementua ezabatuta</string>
|
||||
<string name="show_hold_to_append_title">Erakutsi \"mantendu eransteko\" aholkua</string>
|
||||
<string name="show_hold_to_append_title">Erakutsi \"mantendu eransteko\" aholkua</string>
|
||||
<string name="show_hold_to_append_summary">Erakutsi aholkua bigarren planoko eta laster-leihoko botoia sakatzean bideoaren xehetasunen orrian</string>
|
||||
<string name="default_content_country_title">Lehenetsitako edukiaren herrialdea</string>
|
||||
<string name="service_title">Zerbitzua</string>
|
||||
<string name="background_player_append">Bigarren planoko erreproduzigailuaren ilaran</string>
|
||||
<string name="popup_playing_append">Laster-leiho erreproduzigailuaren ilaran</string>
|
||||
<string name="play_all">Jo denak</string>
|
||||
|
||||
<string name="unknown_content">[Ezezaguna]</string>
|
||||
|
||||
<string name="toggle_orientation">Txandakatu orientazioa</string>
|
||||
<string name="switch_to_background">Aldatu bigarren planora</string>
|
||||
<string name="switch_to_popup">Aldatu laster-leihora</string>
|
||||
<string name="switch_to_main">Aldatu nagusira</string>
|
||||
|
||||
<string name="player_stream_failure">Ezin izan da jario hau erreproduzitu</string>
|
||||
<string name="player_unrecoverable_failure">Erreproduzigailuaren errore berreskuraezina gertatu da</string>
|
||||
<string name="player_recoverable_failure">Erreproduzigailuaren erroretik berreskuratzen</string>
|
||||
|
||||
<string name="donation_title">Dohaintza</string>
|
||||
<string name="donation_encouragement">NewPipe zuri esperientziarik onena ekartzeko denbora ematen duten boluntarioek garatzen dute. Emaiezu zerbait garatzaileei NewPipe kafe bat hartzen duten bitartean hobetu ahal izan dezaten.</string>
|
||||
<string name="give_back">Egin dohaintza</string>
|
||||
<string name="website_title">Webgunea</string>
|
||||
<string name="website_encouragement">Bisitatu NewPipe webgunea informazio gehiagorako eta berriak irakurtzeko.</string>
|
||||
<string name="delete_item_search_history">Elementu hau bilaketen historialetik ezabatu nahi duzu?</string>
|
||||
|
||||
<string name="main_page_content">Orri nagusiko edukia</string>
|
||||
<string name="blank_page_summary">Orri hutsa</string>
|
||||
<string name="kiosk_page_summary">Kioskoaren orria</string>
|
||||
|
@ -277,7 +241,6 @@
|
|||
<string name="select_a_channel">Hautatu kanal bat</string>
|
||||
<string name="no_channel_subscribed_yet">Ez zara inolako kanalera harpidetu oraindik</string>
|
||||
<string name="select_a_kiosk">Hautatu kiosko bat</string>
|
||||
|
||||
<string name="kiosk">Kioskoa</string>
|
||||
<string name="trending">Joerak</string>
|
||||
<string name="top_50">Lehen 50ak</string>
|
||||
|
@ -293,43 +256,34 @@
|
|||
<string name="start_here_on_main">Hasi hemen erreproduzitzen</string>
|
||||
<string name="start_here_on_background">Hasi hemen bigarren planoan</string>
|
||||
<string name="start_here_on_popup">Hasi hemen laster-leihoan</string>
|
||||
|
||||
<string name="drawer_open">"Ireki tiradera "</string>
|
||||
<string name="drawer_close">Itxi tiradera</string>
|
||||
<string name="no_player_found_toast">Ez da jarioen erreproduzigailurik aurkitu (VLC instalatu dezakezu).</string>
|
||||
<string name="always">Beti</string>
|
||||
<string name="just_once">Behin besterik ez</string>
|
||||
|
||||
<string name="external_player_unsupported_link_type">Kanpo erreproduzigailuek ez dituzte mota honetako estekak onartzen</string>
|
||||
<string name="invalid_url_toast">URL baliogabea</string>
|
||||
<string name="video_streams_empty">Ez da bideo jariorik aurkitu</string>
|
||||
<string name="audio_streams_empty">Ez da audio jariorik aurkitu</string>
|
||||
|
||||
<string name="video_player">Bideo erreproduzigailua</string>
|
||||
<string name="background_player">Bigarren planoko erreproduzigailua</string>
|
||||
<string name="popup_player">Laster-leiho erreproduzigailua</string>
|
||||
<string name="always_ask_player">Galdetu beti</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Informazioa eskuratzen…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Kargatzen eskatutako edukia</string>
|
||||
<string name="controls_download_desc">Deskargatu jario fitxategia</string>
|
||||
<string name="controls_download_desc">Deskargatu jario fitxategia</string>
|
||||
<string name="show_info">Erakutsi informazioa</string>
|
||||
|
||||
<string name="tab_bookmarks">Gogoko erreprodukzio-zerrendak</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">Gehitu hona</string>
|
||||
|
||||
<string name="use_inexact_seek_title">Erabili bilaketa azkar ez zehatza</string>
|
||||
<string name="download_thumbnail_title">Kargatu iruditxoak</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Irudien cache-a ezabatuta</string>
|
||||
<string name="metadata_cache_wipe_title">Ezabatu cache-ko metadatuak</string>
|
||||
<string name="metadata_cache_wipe_summary">Kendu cache-ko wegbuneen datu guztiak</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">Metadatuen cache-a ezabatuta</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Irudien cachea ezabatuta</string>
|
||||
<string name="metadata_cache_wipe_title">Ezabatu cacheko metadatuak</string>
|
||||
<string name="metadata_cache_wipe_summary">Kendu cachetik webguneen datu guztiak</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">Metadatuen cachea ezabatuta</string>
|
||||
<string name="auto_queue_title">Gehitu ilarara hurrengo jarioa</string>
|
||||
<string name="auto_queue_summary">Gehitu erlazionatutako jario bat azken jarioa jo bitartean errepikapenik gabeko ilara batean.</string>
|
||||
<string name="settings_category_debug_title">Arazketa</string>
|
||||
<string name="file">Fitxategia</string>
|
||||
|
||||
<string name="import_data_title">Inportatu datu-basea</string>
|
||||
<string name="export_data_title">Esportatu datu-basea</string>
|
||||
<string name="import_data_summary">Zure uneko historiala eta harpidetzak gainidazten ditu</string>
|
||||
|
@ -348,83 +302,60 @@
|
|||
<string name="file_name_empty_error">Fitxategi izena ezin da hutsik egon</string>
|
||||
<string name="error_occurred_detail">Errore bat gertatu da: %1$s</string>
|
||||
<string name="no_streams_available_download">Ez dago jariorik deskargatzeko eskuragarri</string>
|
||||
|
||||
<string name="detail_drag_description">Arrastatu ordena aldatzeko</string>
|
||||
|
||||
<string name="create">Sortu</string>
|
||||
<string name="delete_one">Ezabatu bat</string>
|
||||
<string name="delete_all">Ezabatu guztiak</string>
|
||||
<string name="dismiss">Baztertu</string>
|
||||
<string name="rename">Aldatu izena</string>
|
||||
|
||||
<string name="one_item_deleted">Elementu 1 ezabatuta.</string>
|
||||
|
||||
<string name="toast_no_player">Ez dago fitxategi hau erreproduzitzeko aplikaziorik instalatuta</string>
|
||||
|
||||
<string name="delete_stream_history_prompt">Elementu hau ikusitakoen historialetik ezabatu nahi duzu?</string>
|
||||
<string name="delete_all_history_prompt">Ziur elementu guztiak ezabatu nahi dituzula historialetik?</string>
|
||||
<string name="title_last_played">Jotako azkena</string>
|
||||
<string name="title_most_played">Ikusiena</string>
|
||||
|
||||
<string name="export_complete_toast">Esportatuta</string>
|
||||
<string name="import_complete_toast">Inportatuta</string>
|
||||
<string name="no_valid_zip_file">Ez da baliozko ZIP fitxategia</string>
|
||||
<string name="could_not_import_all_files">Ebisua: Ezin izan dira fitxategi guztiak inportatu.</string>
|
||||
<string name="override_current_data">Honek oraingo ezarpenak gainidatziko ditu.</string>
|
||||
|
||||
<string name="drawer_header_action_paceholder_text">Laster hemen zerbait egongo da ;D</string>
|
||||
|
||||
|
||||
<string name="preferred_open_action_settings_title">\'Ireki\' ekintza hobetsia</string>
|
||||
<string name="preferred_open_action_settings_summary">Lehenetsitako ekintza edukia irekitzean — %s</string>
|
||||
|
||||
<string name="always_ask_open_action">Galdetu beti</string>
|
||||
|
||||
<string name="create_playlist">Erreprodukzio-zerrenda berria</string>
|
||||
<string name="delete_playlist">Ezabatu</string>
|
||||
<string name="rename_playlist">Aldatu izena</string>
|
||||
<string name="playlist_name_input">Izena</string>
|
||||
<string name="append_playlist">Gehitu erreprodukzio-zerrendara</string>
|
||||
<string name="set_as_playlist_thumbnail">Ezarri erreprodukzio-zerrendaren iruditxo gisa</string>
|
||||
|
||||
<string name="bookmark_playlist">Gogoko erreprodukzio-zerrenda</string>
|
||||
<string name="unbookmark_playlist">Kendu gogokoa</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Erreprodukzio zerrenda hau ezabatu\?</string>
|
||||
<string name="playlist_creation_success">Erreprodukzio-zerrenda sortuta</string>
|
||||
<string name="playlist_add_stream_success">Erreprodukzio-zerrendatua</string>
|
||||
<string name="playlist_thumbnail_change_success">Erreprodukzio zerrendaren iruditxoa aldatuta.</string>
|
||||
<string name="playlist_delete_failure">Ezin izan da erreprodukzio-zerrenda ezabatu.</string>
|
||||
|
||||
<string name="caption_none">Azpititulurik ez</string>
|
||||
|
||||
<string name="resize_fit">Doitu</string>
|
||||
<string name="resize_fill">Bete</string>
|
||||
<string name="resize_zoom">Zoom</string>
|
||||
|
||||
<string name="caption_auto_generated">Automatikoki sortuak</string>
|
||||
|
||||
<string name="caption_setting_title">Azpitituluak</string>
|
||||
<string name="caption_setting_description">Aldatu azpitituluen testuaren eskala eta atzealdeko estiloa. Aplikazioa berrabiarazi behar da aldaketak aplikatzeko.</string>
|
||||
|
||||
<string name="enable_leak_canary_title">Gaitu LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">Memoria galeren monitorizazioa. Aplikazioak agian ez du erantzungo memoriaren aitortza egin bitartean</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Eman bizitza-ziklo kanpoko erroreen berri</string>
|
||||
<string name="import_export_title">Inportatu/esportatu</string>
|
||||
<string name="import_title">Inportatu</string>
|
||||
<string name="import_from">Inportatu hemendik</string>
|
||||
<string name="export_to">Esportatu hona</string>
|
||||
|
||||
<string name="import_ongoing">Inportatzen…</string>
|
||||
<string name="export_ongoing">Esportatzen…</string>
|
||||
|
||||
<string name="import_file_title">Inportatu fitxategia</string>
|
||||
<string name="previous_export">Aurreko esportazioa</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Ezin izan dira harpidetzak inportatu</string>
|
||||
<string name="subscriptions_export_unsuccessful">Ezin izan dira harpidetzak esportatu</string>
|
||||
|
||||
<string name="import_youtube_instructions">Inporttu YouTube harpidetzak esportazio fitxategia deskargatuz:
|
||||
\n
|
||||
\n1. Joan URL honetara: %1$s
|
||||
|
@ -437,24 +368,20 @@
|
|||
\n3. Hasi saioa eskatzen zaizunean
|
||||
\n4. Kopiatu profilaren URL-a eraman zaizun orritik.</string>
|
||||
<string name="import_soundcloud_instructions_hint">zureID,soundcloud.com/zureid</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Eragiketa honek sarearen erabilera handia egin lezake.
|
||||
\n
|
||||
\nJarraitu nahi duzu?</string>
|
||||
|
||||
<string name="playback_speed_control">Erreprodukzio-abiaduraren kontrolak</string>
|
||||
<string name="playback_tempo">Tempoa</string>
|
||||
<string name="playback_pitch">Tonua</string>
|
||||
<string name="unhook_checkbox">Deslotu (distortsioa sor lezake)</string>
|
||||
<string name="playback_nightcore">Nightcore</string>
|
||||
<string name="playback_default">Lehenetsia</string>
|
||||
<string name="import_settings">Ezarpenak ere inportatu nahi dituzu?</string>
|
||||
|
||||
<string name="import_settings">Ezarpenak ere inportatu nahi dituzu?</string>
|
||||
<string name="use_inexact_seek_summary">Bilaketa ez zehatzak posizioak azkarrago baina prezisio gutxiagoz bilatzea ahalbidetzen du</string>
|
||||
<string name="download_thumbnail_summary">Desgaitu koadro txikiak ez kargatzeko, datuak eta memoria aurreztuz. Aldaketak memoria eta diskoko irudien cache-ak garbituko ditu.</string>
|
||||
<string name="download_thumbnail_summary">Desgaitu koadro txikiak ez kargatzeko, datuak eta memoria aurreztuz. Aldaketak memoria eta diskoko irudien cacheak garbituko ditu.</string>
|
||||
<string name="app_license">NewPipe Software Librea eta Copyleft da: Erabili, ikertu, partekatu eta hobetu dezakezu. Zehazki, elkarbanatzea eta aldatzea Free Software Foundation-ek argitaratutako GNU General Public License-ren 3. bertsioa edo berriagoren baten terminoen arabera egiteko baimena duzu.</string>
|
||||
<string name="enable_disposed_exceptions_summary">Behartu aktibitatearen bizitza ziklotik kanpo baztertu eta gero entregatu ezin diren Rx salbuespenen inguruko txostena</string>
|
||||
|
||||
<string name="privacy_policy_title">NewPipe pribatutasun politika</string>
|
||||
<string name="privacy_policy_encouragement">NewPipe proiektuak aintzat hartzen du zure pribatutasuna. Aplikazioak ez du zure baimenik gabe daturik jasotzen.
|
||||
\nNewPipe pribatutasun politikak azaltzen du zehazki bidali eta gordetako informazioa zein den kraskatze txosten bat bidaltzen duzunean.</string>
|
||||
|
@ -463,20 +390,17 @@
|
|||
\nAkats txosten bat bidali ahal izateko onartu behar duzu."</string>
|
||||
<string name="accept">Onartu</string>
|
||||
<string name="decline">Ukatu</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Mugagabea</string>
|
||||
<string name="limit_mobile_data_usage_title">Mugatu bereizmena datu mugikorrak erabiltzean</string>
|
||||
<string name="skip_silence_checkbox">Aurreratu azkar isilunea dagoenean</string>
|
||||
<string name="playback_step">Urratsa</string>
|
||||
<string name="playback_reset">Leheneratu</string>
|
||||
|
||||
<string name="minimize_on_exit_title">Minimizatu app-a aldatzean</string>
|
||||
<string name="minimize_on_exit_summary">Ekintza bideo erreproduzigailu nagusitik beste app batera aldatzean — %s</string>
|
||||
<string name="minimize_on_exit_none_description">Bat ere ez</string>
|
||||
<string name="minimize_on_exit_background_description">Minimizatu bigarren planoko erreproduzigailura</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimizatu laster-liho erreproduzigailura</string>
|
||||
|
||||
<string name="channels">Kanalak</string>
|
||||
<string name="channels">Kanalak</string>
|
||||
<string name="playlists">Erreprodukzio-zerrendak</string>
|
||||
<string name="tracks">Pistak</string>
|
||||
<string name="users">Erabiltzaileak</string>
|
||||
|
@ -511,7 +435,7 @@
|
|||
<string name="app_update_notification_content_title">NewPipe eguneraketa eskuragarri!</string>
|
||||
<string name="app_update_notification_content_text">Sakatu deskargatzeko</string>
|
||||
<string name="missions_header_finished">Amaituta</string>
|
||||
<string name="missions_header_pending">Ilaran</string>
|
||||
<string name="missions_header_pending">Zain</string>
|
||||
<string name="paused">pausatuta</string>
|
||||
<string name="queued">ilaran</string>
|
||||
<string name="post_processing">post-prozesua</string>
|
||||
|
@ -522,12 +446,12 @@
|
|||
<string name="download_finished_more">%s deskarga amaituta</string>
|
||||
<string name="generate_unique_name">Sortu izen bakana</string>
|
||||
<string name="overwrite">Gainidatzi</string>
|
||||
<string name="overwrite_warning">Badago izen bera duen deskargatutako fitxategi bat</string>
|
||||
<string name="overwrite_finished_warning">Badago izen bera duen deskargatutako fitxategi bat</string>
|
||||
<string name="download_already_running">Badago izen bera duen deskarga bat abian</string>
|
||||
<string name="show_error">Erakutsi errorea</string>
|
||||
<string name="label_code">Kodea</string>
|
||||
<string name="error_path_creation">Ezin da fitxategia sortu</string>
|
||||
<string name="error_file_creation">Ezin da helburu karpeta sortu</string>
|
||||
<string name="error_file_creation">Ezin da fitxategia sortu</string>
|
||||
<string name="error_path_creation">Ezin da helburu karpeta sortu</string>
|
||||
<string name="error_permission_denied">Sistemak baimena ukatu du</string>
|
||||
<string name="error_ssl_exception">Konexio seguruak huts egin du</string>
|
||||
<string name="error_unknown_host">Ezin izan da zerbitzaria aurkitu</string>
|
||||
|
@ -540,8 +464,9 @@
|
|||
<string name="clear_finished_download">Garbitu amaitutako deskargak</string>
|
||||
<string name="msg_pending_downloads">Berrekin burutzeke dauden %s transferentzia deskargetatik</string>
|
||||
<string name="stop">Gelditu</string>
|
||||
<string name="max_retry_msg">Saiakerak gehienez</string>
|
||||
<string name="max_retry_msg">Gehienezko saiakerak</string>
|
||||
<string name="max_retry_desc">Deskarga ezeztatu aurretik saiatu beharreko aldi kopurua</string>
|
||||
<string name="pause_downloads_on_mobile">Pausatu datu mugikorretara aldatzean</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Pausatu ezin daitezkeen deskargak berrekingo dira</string>
|
||||
<string name="error_timeout">Konexioaren denbora muga</string>
|
||||
</resources>
|
|
@ -17,15 +17,12 @@
|
|||
<string name="screen_rotation">چرخش</string>
|
||||
<string name="use_external_video_player_title">استفاده از پخشکنندهٔ ویدیوی خارجی</string>
|
||||
<string name="use_external_audio_player_title">استفاده از پخشکنندهٔ صدای خارجی</string>
|
||||
|
||||
<string name="download_path_title">مسیر بارگیری ویدیو</string>
|
||||
<string name="download_path_summary">مسیر ذخیرهٔ ویدیوهای بارگیری شده</string>
|
||||
<string name="download_path_dialog_title">مسیر بارگیری را برای ویدیوها وارد کنید</string>
|
||||
|
||||
<string name="download_path_audio_title">پوشه بارگیری صدا</string>
|
||||
<string name="download_path_audio_summary">صدای بارگیری شده در اینجا نگه داشته میشود</string>
|
||||
<string name="download_path_audio_dialog_title">مسیر بارگیری را برای صداها وارد کنید</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">پخش خودکار</string>
|
||||
<string name="autoplay_by_calling_app_summary">هنگامی که نیوپایپ از کارهٔ دیگری فراخوانی میشود، ویدیوی به طور خودکار پخش شود</string>
|
||||
<string name="default_resolution_title">وضوح پیشگزیده</string>
|
||||
|
@ -35,12 +32,9 @@
|
|||
<string name="show_play_with_kodi_summary">نمایش گزینهای برای پخش ویدیو با مرکز رسانهٔ کودی</string>
|
||||
<string name="play_audio">صدا</string>
|
||||
<string name="default_audio_format_title">قالب صدای پیشگزیده</string>
|
||||
<string name="webm_description">قالب آزاد — WebM</string>
|
||||
<string name="m4a_description">کیفیت بهتر — M4A</string>
|
||||
<string name="theme_title">زمینه</string>
|
||||
<string name="dark_theme_title">تیره</string>
|
||||
<string name="light_theme_title">روشن</string>
|
||||
|
||||
<string name="download_dialog_title">بارگیری</string>
|
||||
<string name="next_video_title">بعدی</string>
|
||||
<string name="show_next_and_similar_title">نماش ویدیوهای «بعدی» و «مشابه»</string>
|
||||
|
@ -58,7 +52,6 @@
|
|||
<string name="downloads">بارگیریها</string>
|
||||
<string name="downloads_title">بارگیریها</string>
|
||||
<string name="error_report_title">گزارش خطا</string>
|
||||
|
||||
<string name="general_error">خطا</string>
|
||||
<string name="network_error">خطای شبکه</string>
|
||||
<string name="could_not_load_thumbnails">نمیتوان تمام بندانگشتیها را بار کرد</string>
|
||||
|
@ -78,8 +71,6 @@
|
|||
<string name="what_happened_headline">چه روی داد:</string>
|
||||
<string name="your_comment">توضیح شما (به انگلیسی):</string>
|
||||
<string name="error_details_headline">جزییات:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">بندانگشتی پیشنمایش ویدیو</string>
|
||||
<string name="detail_thumbnail_view_description">بندانگشتی پیشنمایش ویدیو</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">بندانگشتی کاربر بارگذار</string>
|
||||
|
@ -89,24 +80,19 @@
|
|||
<string name="use_tor_summary">(آزمایشی) اجبار ترافیک بارگیری از مسیر تور برای محرمانگی بیشتر (هنوز پخش جریانی پشتیبانی نمیشود).</string>
|
||||
<string name="report_error">گزارش یک خطا</string>
|
||||
<string name="user_report">گزارش کاربر</string>
|
||||
|
||||
<string name="err_dir_create">نمیتوان شاخهٔ بارگیری «%1$s» را ایجاد کرد</string>
|
||||
<string name="info_dir_created">شاخهٔ بارگیری «%1$s» ایجاد شد</string>
|
||||
|
||||
<string name="video">ویدیو</string>
|
||||
<string name="audio">صدا</string>
|
||||
<string name="retry">تلاش دوباره</string>
|
||||
<string name="storage_permission_denied">اجازهٔ دسترسی به انبار ذخیره رد شد</string>
|
||||
|
||||
<string name="start">شروع</string>
|
||||
<string name="pause">مکث</string>
|
||||
<string name="view">نمایش</string>
|
||||
<string name="delete">حذف</string>
|
||||
<string name="checksum">مجموع مقابلهای</string>
|
||||
|
||||
<string name="add">مآموریت جدید</string>
|
||||
<string name="finish">قبول</string>
|
||||
|
||||
<string name="msg_name">نام پرونده</string>
|
||||
<string name="msg_threads">رشتهها</string>
|
||||
<string name="msg_error">خطا</string>
|
||||
|
@ -118,8 +104,7 @@
|
|||
<string name="msg_wait">لطفاً صبر کنید…</string>
|
||||
<string name="msg_copied">در حافظه رونوشت شد.</string>
|
||||
<string name="no_available_dir">لطفاً یک شاخهٔ بارگیری موجود را برگزینید.</string>
|
||||
|
||||
<string name="no_player_found_toast">هیچ پخش کننده جریانی پیدا نشد (شما میتوانید برنامه ویالسی را برای پخش آن نصب کنید).</string>
|
||||
<string name="no_player_found_toast">هیچ پخش کننده جریانی پیدا نشد (شما میتوانید برنامه ویالسی را برای پخش آن نصب کنید).</string>
|
||||
<string name="controls_download_desc">بارگیری پرونده جریان</string>
|
||||
<string name="use_external_video_player_summary">حذف صدا در برخی کیفیتها</string>
|
||||
<string name="subscribe_button_title">اشتراک</string>
|
||||
|
@ -128,16 +113,12 @@
|
|||
<string name="subscription_change_failed">ناتوانی در تغییر وضعیت اشتراک</string>
|
||||
<string name="subscription_update_failed">ناتوانی در بهروزرسانی اشتراک</string>
|
||||
<string name="show_info">نمایش اطلاعات</string>
|
||||
|
||||
<string name="tab_main">اصلی</string>
|
||||
<string name="tab_subscriptions">اشتراکها</string>
|
||||
<string name="tab_bookmarks">فهرستهای پخش دارای نشانک</string>
|
||||
|
||||
<string name="fragment_whats_new">موارد جدید</string>
|
||||
|
||||
<string name="controls_background_title">پس زمینه</string>
|
||||
<string name="controls_add_to_playlist_title">افزودن به</string>
|
||||
|
||||
<string name="show_higher_resolutions_title">نمایش کیفیت بالاتر</string>
|
||||
<string name="show_higher_resolutions_summary">تنها برخی دستگاهها توانایی پخش ویدئوهای 2K و 4K را دارند</string>
|
||||
<string name="default_video_format_title">قالب ویدئوی پیشفرض</string>
|
||||
|
@ -168,10 +149,8 @@
|
|||
<string name="always">همیشه</string>
|
||||
<string name="just_once">فقط یکبار</string>
|
||||
<string name="file">پرونده</string>
|
||||
|
||||
<string name="notification_channel_name">اعلان نیوپایپ</string>
|
||||
<string name="unknown_content">[ناشناخته]</string>
|
||||
|
||||
<string name="import_data_title">وارد کردن پایگاهداده</string>
|
||||
<string name="export_data_title">"صادرکردن "</string>
|
||||
<string name="import_data_summary">تاریخچه و اشتراکهای شما بازنویسی خواهند شد</string>
|
||||
|
@ -181,17 +160,13 @@
|
|||
<string name="import_title">وارد کردن</string>
|
||||
<string name="import_from">وارد کردن از</string>
|
||||
<string name="export_to">صادر کردن به</string>
|
||||
|
||||
<string name="import_ongoing">در حال وارد کردن…</string>
|
||||
<string name="export_ongoing">در حال صدور…</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">ناتوانی در ورود اشتراکها</string>
|
||||
<string name="subscriptions_export_unsuccessful">ناتوانی در صدور اشتراکها</string>
|
||||
|
||||
<string name="playback_speed_control">کنترلهای سرعت پخش</string>
|
||||
<string name="accept">قبول</string>
|
||||
<string name="decline">رد</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">بدون محدودیت</string>
|
||||
<string name="minimize_on_exit_none_description">هیچ</string>
|
||||
<string name="best_resolution">بهترین وضوح</string>
|
||||
|
@ -211,47 +186,36 @@
|
|||
<string name="file_name_empty_error">نام پرونده نمیتواند خالی باشد</string>
|
||||
<string name="error_occurred_detail">خطایی رخ داد: %1$s</string>
|
||||
<string name="no_streams_available_download">جریانی برای بارگیری در دسترس نیست</string>
|
||||
|
||||
<string name="search_no_results">بدون نتیجه</string>
|
||||
<string name="use_old_player_title">استفاده از پخشکننده قدیمی</string>
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">B</string>
|
||||
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s مشترک</item>
|
||||
<item quantity="other">%s مشترک</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s مشترک</item>
|
||||
<item quantity="other">%s مشترک</item>
|
||||
</plurals>
|
||||
<string name="no_views">بدون بازدید</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s بازدید</item>
|
||||
<item quantity="other">%s بازدید</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s بازدید</item>
|
||||
<item quantity="other">%s بازدید</item>
|
||||
</plurals>
|
||||
<string name="no_videos">بدون ویدئو</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">ویدئو</item>
|
||||
<item quantity="other">ویدئو</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">ویدئو</item>
|
||||
<item quantity="other">ویدئو</item>
|
||||
</plurals>
|
||||
<string name="create">ایجاد</string>
|
||||
<string name="delete_one">پاک کردن یک مورد</string>
|
||||
<string name="delete_all">پاککردن همه</string>
|
||||
<string name="dismiss">صرف نظر</string>
|
||||
<string name="rename">تغییر نام</string>
|
||||
|
||||
<string name="one_item_deleted">یک مورد پاک شد.</string>
|
||||
|
||||
<string name="settings_file_charset_title">نویسههای مجاز در نام پروندهها</string>
|
||||
<string name="settings_file_replacement_character_summary">نویسههای نامعتبر با این مقدار جایگزین شدند</string>
|
||||
<string name="settings_file_replacement_character_title">نویسه جایگزین</string>
|
||||
|
||||
<string name="charset_letters_and_digits">حروف و اعداد</string>
|
||||
<string name="charset_most_special_characters">مهمترین نویسههای خاص</string>
|
||||
|
||||
<string name="toast_no_player">کارهای برای پخش این پرونده نصب نشده است</string>
|
||||
|
||||
<string name="title_activity_about">درباره نیوپایپ</string>
|
||||
<string name="action_settings">تنظیمات</string>
|
||||
<string name="action_about">درباره</string>
|
||||
|
@ -269,8 +233,6 @@
|
|||
<string name="read_privacy_policy">خواندن سیاست حریم خصوصی</string>
|
||||
<string name="app_license_title">پروانه نیوپایپ</string>
|
||||
<string name="read_full_license">خواندن پروانه</string>
|
||||
|
||||
|
||||
<string name="title_activity_history">تاریخچه</string>
|
||||
<string name="title_history_search">جستجو شده</string>
|
||||
<string name="title_history_view">دیدهشده</string>
|
||||
|
@ -284,7 +246,6 @@
|
|||
<string name="delete_all_history_prompt">میخواهید همه موارد را از تاریخچه پاک کنید؟</string>
|
||||
<string name="title_last_played">آخرین پخششده</string>
|
||||
<string name="title_most_played">بیشترین پخششده</string>
|
||||
|
||||
<string name="main_page_content">محتوای صفحه اصلی</string>
|
||||
<string name="blank_page_summary">صفحه خالی</string>
|
||||
<string name="kiosk_page_summary">صفحه کیوسک</string>
|
||||
|
@ -305,25 +266,20 @@
|
|||
<string name="video_player">پخشکننده ویدئو</string>
|
||||
<string name="background_player">پخشکننده پسزمینه</string>
|
||||
<string name="always_ask_open_action">همیشه بپرس</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">در حال دریافت اطلاعات…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">بارگذری محتوای درخواستی</string>
|
||||
|
||||
<string name="create_playlist">فهرست پخش جدید</string>
|
||||
<string name="delete_playlist">پاککردن</string>
|
||||
<string name="rename_playlist">تغییر نام</string>
|
||||
<string name="playlist_name_input">نام</string>
|
||||
<string name="append_playlist">افزودن به فهرست پخش</string>
|
||||
<string name="set_as_playlist_thumbnail">استفاده به عنوان تصویر فهرست پخش</string>
|
||||
|
||||
<string name="delete_playlist_prompt">این فهرست پخش پاک شود؟</string>
|
||||
<string name="playlist_creation_success">فهرست پخش ایجاد شد</string>
|
||||
<string name="playlist_add_stream_success">به فهرست پخش افزوده شد</string>
|
||||
<string name="playlist_thumbnail_change_success">تصویر فهرست پخش تغییر کرد.</string>
|
||||
<string name="playlist_delete_failure">ناتوانی در پاککردن فهرست پخش.</string>
|
||||
|
||||
<string name="caption_none">بدون توضیحات</string>
|
||||
|
||||
<string name="caption_setting_title">توضحیات</string>
|
||||
<string name="unsubscribe">لغو اشتراک</string>
|
||||
<string name="tab_new">زبان جدید</string>
|
||||
|
@ -332,4 +288,12 @@
|
|||
<string name="settings_category_history_title">تاریخچه و حافظه نهان</string>
|
||||
<string name="settings_category_debug_title">اشکالزدایی</string>
|
||||
<string name="settings_category_updates_title">بهروزرسانیها</string>
|
||||
<string name="open_in_popup_mode">در پنجره جداگانه باز شود</string>
|
||||
<string name="popup_mode_share_menu_title">حالت پنجره مجزا</string>
|
||||
<string name="default_popup_resolution_title">اندازه پیش فرض پنجره جداگانه</string>
|
||||
<string name="controls_popup_title">پنجره جداگانه</string>
|
||||
<string name="popup_remember_size_pos_title">به یاد داشتن اندازه و موقعیت پنجره جداگانه</string>
|
||||
<string name="popup_remember_size_pos_summary">به یاد داشتن آخرین اندازه و موقعیت قبلی پنجره جداگانه</string>
|
||||
<string name="use_inexact_seek_title">زمان فعلی پخش کننده را به صورت تقریبی و سریع جلو ببر</string>
|
||||
<string name="use_inexact_seek_summary">این گزینه باعث می شود هنگام جلو/عقب کردن زمان تصویر، به جای زمان دقیق انتخاب شده، به زمان غیر دقیق و نزدیک به مکان انتخاب شده برود که این کار سریع تر انجام می شود</string>
|
||||
</resources>
|
|
@ -148,8 +148,6 @@
|
|||
<string name="audio">Ääni</string>
|
||||
<string name="retry">Toista uudelleen</string>
|
||||
<string name="storage_permission_denied">Oikeus tallennustilan hallintaan evätty</string>
|
||||
<string name="use_old_player_title">Käytä vanhaa soitinta</string>
|
||||
<string name="use_old_player_summary">Käytä vanhaa sisäänrakennettua Mediaframework-soitinta</string>
|
||||
|
||||
<string name="short_thousand">t.</string>
|
||||
<string name="short_million">milj.</string>
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
<string name="url_not_supported_toast">URL non supportée</string>
|
||||
<string name="settings_category_video_audio_title">Vidéo & audio</string>
|
||||
<string name="settings_category_other_title">Autre</string>
|
||||
|
||||
<string name="list_thumbnail_view_description">Miniature d’aperçu vidéo</string>
|
||||
<string name="detail_thumbnail_view_description">Miniature d’aperçu vidéo</string>
|
||||
<string name="detail_dislikes_img_view_description">Je n’aime pas</string>
|
||||
|
@ -41,32 +40,26 @@
|
|||
<string name="use_external_audio_player_title">Utiliser un lecteur audio externe</string>
|
||||
<string name="background_player_playing_toast">Lecture en arrière-plan</string>
|
||||
<string name="play_btn_text">Lire</string>
|
||||
|
||||
<string name="use_tor_title">Utiliser Tor</string>
|
||||
<string name="use_tor_summary">(Expérimental) Rediriger le trafic de téléchargement via Tor pour plus de confidentialité (streaming non supporté pour le moment).</string>
|
||||
<string name="theme_title">Thème</string>
|
||||
<string name="dark_theme_title">Sombre</string>
|
||||
<string name="light_theme_title">Clair</string>
|
||||
|
||||
<string name="settings_category_appearance_title">Apparence</string>
|
||||
<string name="network_error">Erreur réseau</string>
|
||||
|
||||
<string name="download_path_audio_title">Dossier de téléchargement audio</string>
|
||||
<string name="download_path_audio_summary">L\'audio téléchargé est stocké ici</string>
|
||||
<string name="download_path_audio_dialog_title">Entrez le chemin de téléchargement des fichiers audio</string>
|
||||
|
||||
<string name="err_dir_create">Impossible de créer le répertoire de téléchargement « %1$s »</string>
|
||||
<string name="info_dir_created">Répertoire de téléchargement « %1$s » créé</string>
|
||||
<string name="general_error">Erreur</string>
|
||||
<string name="parsing_error">Impossible d\'analyser le site web</string>
|
||||
<string name="content_not_available">Contenu non disponible</string>
|
||||
<string name="blocked_by_gema">Bloqué par GEMA</string>
|
||||
|
||||
<string name="error_snackbar_message">Désolé, des erreurs se sont produites.</string>
|
||||
<string name="content">Contenu</string>
|
||||
<string name="show_age_restricted_content_title">Contenu avec limite d\'âge</string>
|
||||
<string name="duration_live">EN DIRECT</string>
|
||||
|
||||
<string name="could_not_load_thumbnails">Impossible de charger toutes les miniatures</string>
|
||||
<string name="youtube_signature_decryption_error">Impossible de déchiffrer la signature URL de la vidéo</string>
|
||||
<string name="light_parsing_error">Impossible d\'analyser complètement le site web</string>
|
||||
|
@ -78,8 +71,6 @@
|
|||
<string name="what_happened_headline">Ce qui s\'est passé :</string>
|
||||
<string name="your_comment">Votre commentaire (en anglais) :</string>
|
||||
<string name="error_details_headline">Détails :</string>
|
||||
|
||||
|
||||
<string name="report_error">Signaler une erreur</string>
|
||||
<string name="video">Vidéo</string>
|
||||
<string name="audio">Audio</string>
|
||||
|
@ -89,23 +80,19 @@
|
|||
<string name="autoplay_by_calling_app_title">Lecture automatique</string>
|
||||
<string name="video_is_age_restricted">Afficher les vidéos soumises à une limite d\'âge. Autoriser ce type de contenu est possible depuis les paramètres.</string>
|
||||
<string name="user_report">Rapport utilisateur</string>
|
||||
|
||||
<string name="error_snackbar_action">SIGNALER</string>
|
||||
<string name="could_not_setup_download_menu">Impossible de configurer le menu de téléchargement</string>
|
||||
<string name="could_not_get_stream">Impossible d\'obtenir un flux</string>
|
||||
<string name="downloads">Téléchargements</string>
|
||||
<string name="downloads_title">Téléchargements</string>
|
||||
<string name="error_report_title">Rapport d\'erreur</string>
|
||||
|
||||
<string name="start">Lire</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="view">Lire</string>
|
||||
<string name="delete">Supprimer</string>
|
||||
<string name="checksum">Somme de contrôle</string>
|
||||
|
||||
<string name="add">Nouveau</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="msg_name">Nom du fichier</string>
|
||||
<string name="msg_threads">Threads</string>
|
||||
<string name="msg_error">Erreur</string>
|
||||
|
@ -117,71 +104,51 @@
|
|||
<string name="msg_wait">Veuillez patienter…</string>
|
||||
<string name="msg_copied">Copié dans le presse-papiers</string>
|
||||
<string name="no_available_dir">Sélectionner un dossier de téléchargement disponible</string>
|
||||
|
||||
<string name="could_not_load_image">Impossible de charger l\'image</string>
|
||||
<string name="app_ui_crash">L’application a crashé</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="black_theme_title">Noir</string>
|
||||
|
||||
<string name="all">Tout</string>
|
||||
<string name="channel">Chaîne</string>
|
||||
|
||||
|
||||
<string name="reCaptcha_title">Défi reCAPTCHA</string>
|
||||
<string name="recaptcha_request_toast">Défi reCAPTCHA demandé</string>
|
||||
|
||||
<string name="open_in_popup_mode">Ouvrir en mode fenêtré</string>
|
||||
<string name="popup_mode_share_menu_title">Mode fenêtré NewPipe</string>
|
||||
|
||||
<string name="popup_playing_toast">Lecture en mode fenêtré</string>
|
||||
<string name="yes">Oui</string>
|
||||
<string name="later">Plus tard</string>
|
||||
<string name="disabled">Désactivé</string>
|
||||
|
||||
<string name="info_labels">Quoi :\\nRequête :\\nLangue du contenu :\\nService :\\nHeure GMT :\\nPaquet :\\nVersion :\\nVersion du système :</string>
|
||||
<string name="use_old_player_title">Utiliser l\'ancien lecteur</string>
|
||||
<string name="use_old_player_summary">Ancienne version du lecteur Mediaframework</string>
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
|
||||
<string name="msg_popup_permission">Cette autorisation est nécessaire pour
|
||||
\nutiliser le mode fenêtré</string>
|
||||
|
||||
<string name="controls_background_title">Arrière-plan</string>
|
||||
<string name="controls_popup_title">Fenêtre</string>
|
||||
|
||||
<string name="default_popup_resolution_title">Résolution de la fenêtre par défaut</string>
|
||||
<string name="show_higher_resolutions_title">Afficher résolutions plus élevées</string>
|
||||
<string name="show_higher_resolutions_summary">Seulement certains appareils supportent la lecture 2K/4K</string>
|
||||
<string name="default_video_format_title">Format vidéo par défaut</string>
|
||||
<string name="popup_remember_size_pos_title">Mémoriser la taille et la position de la fenêtre</string>
|
||||
<string name="popup_remember_size_pos_summary">Mémoriser la dernière taille et position de la fenêtre</string>
|
||||
|
||||
<string name="settings_category_popup_title">Fenêtre</string>
|
||||
<string name="filter">Filtre</string>
|
||||
<string name="refresh">Actualiser</string>
|
||||
<string name="clear">Effacer</string>
|
||||
<string name="popup_resizing_indicator_title">Redimensionner</string>
|
||||
|
||||
<string name="short_billion">B</string>
|
||||
|
||||
<string name="use_external_video_player_summary">Supprime l\'audio à CERTAINES résolutions</string>
|
||||
<string name="player_gesture_controls_summary">Utiliser les gestes pour contrôler la luminosité et le volume du lecteur</string>
|
||||
<string name="show_search_suggestions_title">Suggestions de recherche</string>
|
||||
<string name="show_search_suggestions_summary">Afficher les suggestions lors d\'une recherche</string>
|
||||
|
||||
<string name="player_gesture_controls_title">Gestes pour contrôler la lecture</string>
|
||||
<string name="player_gesture_controls_title">Gestes pour contrôler la lecture</string>
|
||||
<string name="best_resolution">Meilleure résolution</string>
|
||||
|
||||
<string name="subscribe_button_title">S\'abonner</string>
|
||||
<string name="subscribed_button_title">Abonné</string>
|
||||
<string name="channel_unsubscribed">Désabonné de la chaîne</string>
|
||||
<string name="tab_main">Principal</string>
|
||||
<string name="tab_subscriptions">Abonnements</string>
|
||||
|
||||
<string name="fragment_whats_new">Nouveautés</string>
|
||||
|
||||
<string name="settings_category_downloads_title">Téléchargement</string>
|
||||
<string name="action_settings">Paramètres</string>
|
||||
<string name="action_about">À propos</string>
|
||||
|
@ -196,19 +163,16 @@
|
|||
<string name="app_license_title">Licence de NewPipe</string>
|
||||
<string name="read_full_license">Lire la licence</string>
|
||||
<string name="contribution_title">Contribuer</string>
|
||||
<string name="charset_letters_and_digits">Lettres et chiffres</string>
|
||||
<string name="charset_letters_and_digits">Lettres et chiffres</string>
|
||||
<string name="title_activity_about">À propos de NewPipe</string>
|
||||
<string name="copyright" formatted="true">© %1$s par %2$s sous %3$s</string>
|
||||
<string name="contribution_encouragement">Que ce soit pour des idées, traductions, changements de design, nettoyage ou gros changements de code, l\'aide est toujours la bienvenue. Plus on contribue, meilleur il devient !</string>
|
||||
<string name="subscription_change_failed">Impossible de modifier l\'abonnement</string>
|
||||
<string name="subscription_update_failed">Impossible d\'actualiser l\'abonnement</string>
|
||||
|
||||
<string name="resume_on_audio_focus_gain_summary">Continuer la lecture après les interruptions (ex : appels)</string>
|
||||
|
||||
<string name="settings_file_charset_title">Caractères autorisés dans les noms de fichiers</string>
|
||||
<string name="settings_file_replacement_character_summary">Les caractères invalides sont remplacés par cette valeur</string>
|
||||
<string name="settings_file_replacement_character_title">Caractère de remplacement</string>
|
||||
|
||||
<string name="enable_search_history_title">Historique de recherche</string>
|
||||
<string name="enable_search_history_summary">Conserver les recherches sur l\'appareil</string>
|
||||
<string name="enable_watch_history_title">Historique et cache</string>
|
||||
|
@ -219,10 +183,8 @@
|
|||
<string name="action_history">Historique</string>
|
||||
<string name="history_empty">L\'historique est vide</string>
|
||||
<string name="history_cleared">Historique supprimé</string>
|
||||
|
||||
<string name="notification_channel_name">Notification NewPipe</string>
|
||||
<string name="notification_channel_name">Notification NewPipe</string>
|
||||
<string name="undo">Annuler</string>
|
||||
|
||||
<string name="enable_watch_history_summary">Garder une trace des vidéos regardées</string>
|
||||
<string name="resume_on_audio_focus_gain_title">Reprendre sur le gain de focus</string>
|
||||
<string name="settings_category_player_title">Lecteur</string>
|
||||
|
@ -230,33 +192,27 @@
|
|||
<string name="settings_category_history_title">Historique & cache</string>
|
||||
<string name="playlist">Liste de lecture</string>
|
||||
<string name="notification_channel_description">Notifications pour les lecteurs \"arrière-plan\" et \"fenêtre\" de NewPipe</string>
|
||||
|
||||
<string name="search_no_results">Aucun résultat</string>
|
||||
<string name="empty_subscription_feed_subtitle">Aucun contenu</string>
|
||||
|
||||
<string name="no_subscribers">Aucun abonné</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s abonné</item>
|
||||
<item quantity="other">%s abonnés</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s abonné</item>
|
||||
<item quantity="other">%s abonnés</item>
|
||||
</plurals>
|
||||
<string name="no_views">Aucune vue</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s vue</item>
|
||||
<item quantity="other">%s vues</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s vue</item>
|
||||
<item quantity="other">%s vues</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Aucune vidéo</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">Vidéo</item>
|
||||
<item quantity="other">Vidéos</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Vidéo</item>
|
||||
<item quantity="other">Vidéos</item>
|
||||
</plurals>
|
||||
<string name="charset_most_special_characters">Caractères spéciaux</string>
|
||||
|
||||
<string name="item_deleted">Élément effacé</string>
|
||||
<string name="delete_item_search_history">Voulez-vous supprimer cet élément de l\'historique de recherche ?</string>
|
||||
<string name="main_page_content">Contenu de la page principale</string>
|
||||
<string name="delete_item_search_history">Voulez-vous supprimer cet élément de l\'historique de recherche ?</string>
|
||||
<string name="main_page_content">Contenu de la page principale</string>
|
||||
<string name="blank_page_summary">Page vide</string>
|
||||
<string name="subscription_page_summary">Abonnements</string>
|
||||
<string name="feed_page_summary">Page de Flux</string>
|
||||
|
@ -265,10 +221,9 @@
|
|||
<string name="trending">Populaires</string>
|
||||
<string name="top_50">Top 50</string>
|
||||
<string name="new_and_hot">Nouveau & populaire</string>
|
||||
<string name="background_player_append">En file d\'attente sur le lecteur en arrière-plan</string>
|
||||
<string name="background_player_append">En file d\'attente sur le lecteur en arrière-plan</string>
|
||||
<string name="popup_playing_append">En file d\'attente sur le lecteur en fenêtré</string>
|
||||
<string name="play_all">Tout lire</string>
|
||||
|
||||
<string name="player_stream_failure">Impossible de jouer ce flux</string>
|
||||
<string name="player_unrecoverable_failure">Une erreur irrécupérable du lecteur s\'est produite</string>
|
||||
<string name="no_channel_subscribed_yet">Pas encore d\'abonnements de chaînes</string>
|
||||
|
@ -280,12 +235,9 @@
|
|||
<string name="show_hold_to_append_title">Afficher l\'astuce « Maintenir pour ajouter »</string>
|
||||
<string name="show_hold_to_append_summary">Afficher l\'aide \"Appui long pour mettre en file d\'attente\" en appuyant sur les boutons \"Arrière-plan\" et \"Fenêtre\" sur la page de détails d\'une vidéo</string>
|
||||
<string name="unknown_content">[Inconnu]</string>
|
||||
|
||||
<string name="player_recoverable_failure">Récupération de l\'erreur du lecteur</string>
|
||||
|
||||
<string name="kiosk_page_summary">Page Kiosque</string>
|
||||
<string name="select_a_kiosk">Sélectionner un kiosque</string>
|
||||
|
||||
<string name="kiosk">Kiosque</string>
|
||||
<string name="hold_to_append">Appui long pour mettre en file d\'attente</string>
|
||||
<string name="enqueue_on_background">Mettre en file d\'attente en arrière-plan</string>
|
||||
|
@ -293,7 +245,7 @@
|
|||
<string name="start_here_on_main">Commencer la lecture ici</string>
|
||||
<string name="start_here_on_background">Démarrer ici en arrière-plan</string>
|
||||
<string name="start_here_on_popup">Démarrer ici en fenêtré</string>
|
||||
<string name="donation_title">Donner</string>
|
||||
<string name="donation_title">Donner</string>
|
||||
<string name="donation_encouragement">NewPipe est développé par des volontaires sur leur temps libre afin de vous proposer la meilleure expérience possible. Vous pouvez leur offrir un café pour les soutenir dans leurs efforts et rendre NewPipe encore meilleur.</string>
|
||||
<string name="website_title">Site</string>
|
||||
<string name="website_encouragement">Visitez le site internet de NewPipe pour plus d\'informations et de nouvelles.</string>
|
||||
|
@ -303,24 +255,19 @@
|
|||
<string name="switch_to_background">Arrière-plan</string>
|
||||
<string name="switch_to_popup">Fenêtré</string>
|
||||
<string name="switch_to_main">Normal</string>
|
||||
|
||||
<string name="service_title">Service</string>
|
||||
<string name="drawer_open">Ouvrir le menu</string>
|
||||
<string name="drawer_close">Fermer le menu</string>
|
||||
<string name="no_player_found_toast">Aucun lecteur de flux trouvé (vous pouvez installer VLC pour le lire).</string>
|
||||
<string name="always">Toujours</string>
|
||||
<string name="just_once">Une seule fois</string>
|
||||
|
||||
<string name="external_player_unsupported_link_type">Les lecteurs externes ne supportent pas ces types de liens</string>
|
||||
<string name="invalid_url_toast">Lien non valide</string>
|
||||
<string name="video_streams_empty">Aucun flux vidéo trouvé</string>
|
||||
<string name="audio_streams_empty">Aucun flux audio trouvé</string>
|
||||
|
||||
<string name="video_player">Lecteur vidéo</string>
|
||||
<string name="background_player">Lecteur en arrière-plan</string>
|
||||
<string name="popup_player">Lecteur en fenêtré</string>
|
||||
<string name="always_ask_player">Toujours demander</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Obtention des infos…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Chargement du contenu</string>
|
||||
<string name="import_data_title">Importer les données</string>
|
||||
|
@ -332,100 +279,75 @@
|
|||
<string name="no_valid_zip_file">Aucun fichier ZIP valide</string>
|
||||
<string name="could_not_import_all_files">Avertissement: Impossible d\'importer tous les fichiers.</string>
|
||||
<string name="override_current_data">Cela effacera vos paramètres actuels</string>
|
||||
|
||||
<string name="show_info">Afficher les infos</string>
|
||||
|
||||
<string name="tab_bookmarks">Marque-pages</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">Ajouter à</string>
|
||||
|
||||
<string name="detail_drag_description">Faites glisser pour réorganiser</string>
|
||||
|
||||
<string name="create">Créer</string>
|
||||
<string name="dismiss">Ignorer</string>
|
||||
<string name="rename">Renommer</string>
|
||||
|
||||
<string name="title_last_played">Dernière lecture</string>
|
||||
<string name="delete_all">Tout supprimer</string>
|
||||
<string name="delete_stream_history_prompt">Voulez-vous supprimer cet élément de votre historique \?</string>
|
||||
<string name="delete_all_history_prompt">Êtes-vous sûr de supprimer tout votre historique \?</string>
|
||||
<string name="title_most_played">Vidéos les plus regardées</string>
|
||||
|
||||
<string name="always_ask_open_action">Toujours demander</string>
|
||||
|
||||
<string name="create_playlist">Nouvelle liste de lecture</string>
|
||||
<string name="delete_playlist">Supprimer</string>
|
||||
<string name="rename_playlist">Renommer</string>
|
||||
<string name="playlist_name_input">Nom</string>
|
||||
<string name="append_playlist">Ajouter à la playlist</string>
|
||||
<string name="set_as_playlist_thumbnail">Enregistrer la playlist en local</string>
|
||||
|
||||
<string name="bookmark_playlist">Marquer cette playlist</string>
|
||||
<string name="unbookmark_playlist">Retirer la marque</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Supprimer cette liste de lecture \?</string>
|
||||
<string name="playlist_creation_success">Liste de lecture créée</string>
|
||||
<string name="playlist_add_stream_success">Ajouté à la liste de lecture</string>
|
||||
<string name="playlist_thumbnail_change_success">Miniature de la liste de lecture changée.</string>
|
||||
<string name="playlist_delete_failure">Impossible de supprimer la liste de lecture.</string>
|
||||
|
||||
<string name="caption_none">Aucuns sous-titres</string>
|
||||
|
||||
<string name="resize_fit">Ajuster</string>
|
||||
<string name="resize_zoom">Zoom</string>
|
||||
|
||||
<string name="caption_font_size_settings_title">Taille des sous-titres</string>
|
||||
<string name="smaller_caption_font_size">Petite</string>
|
||||
<string name="normal_caption_font_size">Normale</string>
|
||||
<string name="larger_caption_font_size">Grande</string>
|
||||
|
||||
<string name="use_inexact_seek_title">Recherche rapide approximative</string>
|
||||
<string name="use_inexact_seek_summary">Permettre au lecteur d\'accéder plus rapidement à une position au détriment de la précision</string>
|
||||
<string name="download_thumbnail_title">Charger les miniatures</string>
|
||||
<string name="download_thumbnail_summary">Désactivez pour empêcher le chargement des miniatures afin de réduire l’utilisation de bande passante et de mémoire. Modifier cette option vide le cache d’images en mémoire vive et sur le disque.</string>
|
||||
<string name="download_thumbnail_summary">Désactivez pour empêcher le chargement des miniatures afin de réduire l’utilisation de bande passante et de mémoire. Ce changement vide le cache d’images en mémoire vive et sur le disque.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Images en cache effacées</string>
|
||||
<string name="metadata_cache_wipe_title">Effacer les données en cache</string>
|
||||
<string name="metadata_cache_wipe_summary">Effacer toutes les pages web mises en cache</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">Données en cache effacées</string>
|
||||
<string name="file">Fichier</string>
|
||||
|
||||
<string name="invalid_directory">Aucun dossier de ce type</string>
|
||||
<string name="invalid_source">Aucun fichier/contenu de ce type</string>
|
||||
<string name="invalid_file">Le fichier n’existe pas ou n’est pas accessible en lecture/écriture</string>
|
||||
<string name="file_name_empty_error">Le nom du fichier ne peut être vide</string>
|
||||
<string name="error_occurred_detail">Une erreur s\'est produite: %1$s</string>
|
||||
|
||||
<string name="delete_one">Supprimer un seul média</string>
|
||||
<string name="drawer_header_action_paceholder_text">Quelque chose va bien bientôt arriver ;D</string>
|
||||
|
||||
|
||||
<string name="controls_download_desc">Télécharger le fichier de flux</string>
|
||||
<string name="auto_queue_title">Vidéo suivante en file d\'attente</string>
|
||||
<string name="auto_queue_summary">Ajout automatique d\'un morceau suggéré lors de la lecture du dernier morceau dans une file d\'attente non bouclée.</string>
|
||||
|
||||
<string name="settings_category_debug_title">Débogage</string>
|
||||
<string name="resize_fill">Remplir</string>
|
||||
<string name="caption_auto_generated">Générés automatiquement</string>
|
||||
<string name="enable_leak_canary_title">Activer LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">La surveillance de la mémoire peut mettre temporairement l\'application en pause pendant les nettoyages</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Signaler les erreurs de développement hors cycle</string>
|
||||
<string name="enable_disposed_exceptions_summary">Forcer le signalement des exceptions Rx qui surviennent hors activité</string>
|
||||
|
||||
<string name="import_export_title">Importer/exporter</string>
|
||||
<string name="import_title">Importer</string>
|
||||
<string name="import_from">Importer de</string>
|
||||
<string name="export_to">Exporter vers</string>
|
||||
|
||||
<string name="import_ongoing">Importation en cours…</string>
|
||||
<string name="export_ongoing">Exporation en cours…</string>
|
||||
|
||||
<string name="import_file_title">Importer fichier</string>
|
||||
<string name="previous_export">Export précédent</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Impossible d\'importer des abonnements</string>
|
||||
<string name="subscriptions_export_unsuccessful">Impossible d\'exporter les abonnements</string>
|
||||
|
||||
<string name="import_youtube_instructions">"Pour importer vos abonnements YouTube vous devez d\'abord télécharger un fichier spécial de YouTube, selon les modalités suivantes :
|
||||
\n
|
||||
\n1. Suivez ce lien : %1$s
|
||||
|
@ -438,27 +360,21 @@
|
|||
\n3. Connectez-vous à votre compte.
|
||||
\n4. Copier l’URL vers lequel vous venez d’être redirigé.</string>
|
||||
<string name="import_soundcloud_instructions_hint">votreID, soundcloud.com/votreid</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Cette opération peut consommer beaucoup de données mobiles.
|
||||
\n
|
||||
\nSouhaitez-vous continuer ?</string>
|
||||
|
||||
<string name="playback_speed_control">Vitesse de lecture</string>
|
||||
<string name="playback_tempo">Cadence</string>
|
||||
<string name="unhook_checkbox">Détacher (déformations possibles)</string>
|
||||
<string name="playback_default">Défaut</string>
|
||||
<string name="preferred_open_action_settings_title">Ouvrir de préférence avec</string>
|
||||
<string name="preferred_open_action_settings_title">Ouvrir de préférence avec</string>
|
||||
<string name="preferred_open_action_settings_summary">Action par défaut lors de l\'ouverture de contenu - %s</string>
|
||||
|
||||
<string name="no_streams_available_download">Aucun flux disponible au téléchargement</string>
|
||||
|
||||
<string name="caption_setting_title">Sous-titres</string>
|
||||
<string name="caption_setting_description">Modifier la taille du texte et les styles d\'arrière-plan du lecteur. Redémarrage requis pour prendre effet.</string>
|
||||
|
||||
<string name="playback_pitch">Ton</string>
|
||||
<string name="playback_nightcore">Nightcore</string>
|
||||
<string name="toast_no_player">Aucune application installée pour lire ce fichier</string>
|
||||
|
||||
<string name="clear_views_history_title">Effacer l\'historique</string>
|
||||
<string name="clear_views_history_summary">Supprimer l\'historique des flux regardés</string>
|
||||
<string name="delete_view_history_alert">Supprimer tout l\'historique regardé \?</string>
|
||||
|
@ -468,15 +384,13 @@
|
|||
<string name="delete_search_history_alert">Supprimer tout l\'historique de recherche \?</string>
|
||||
<string name="search_history_deleted">Historique des recherches effacé.</string>
|
||||
<string name="one_item_deleted">1 élément supprimé.</string>
|
||||
|
||||
<string name="app_license">"NewPipe est un logiciel sous licence libre : Vous pouvez l\'utiliser, l\'étudier, le partager et l\'améliorer comme bon vous semble. Vous pouvez le redistribuer et/ou le modifier sous les termes de la licence générale publique GNU, comme publiée par la Free Software Foundation, dans sa version 3, ou, à votre convenance, dans une version plus récente."</string>
|
||||
<string name="privacy_policy_title">Politique de confidentialité de NewPipe</string>
|
||||
<string name="read_privacy_policy">Lire la politique de confidentialité</string>
|
||||
<string name="import_settings">Voulez-vous également importer des paramètres \?</string>
|
||||
|
||||
<string name="accept">Accepter</string>
|
||||
<string name="decline">Refuser</string>
|
||||
<string name="privacy_policy_encouragement">Le projet NewPipe prend votre vie privée très à cœur. Ainsi, l’application n’envoie aucune donnée sans votre consentement.
|
||||
<string name="privacy_policy_encouragement">Le projet NewPipe prend votre vie privée très à cœur. Ainsi, l’application n’envoie aucune donnée sans votre consentement.
|
||||
\nLa politique de confidentialité de NewPipe explique en détail quelles données sont envoyées et stockées lorsque vous envoyez un rapport de plantage.</string>
|
||||
<string name="start_accept_privacy_policy">Afin de se conformer au Règlement Général sur la Protection des Données (RGPD ou GDPR), nous attirons votre attention sur la politique de vie privée de NewPipe. Merci de la lire attentivement.
|
||||
\nVous devez l\'accepter pour nous envoyer le rapport de bug.</string>
|
||||
|
@ -489,7 +403,6 @@
|
|||
<string name="skip_silence_checkbox">Accélérer pendant les silences</string>
|
||||
<string name="playback_step">Étape</string>
|
||||
<string name="playback_reset">Réinitialiser</string>
|
||||
|
||||
<string name="minimize_on_exit_title">Minimiser lors du changement d\'application</string>
|
||||
<string name="minimize_on_exit_summary">Action lors du changement d\'application depuis le lecteur vidéo —%s</string>
|
||||
<string name="minimize_on_exit_none_description">Aucune</string>
|
||||
|
@ -524,7 +437,40 @@
|
|||
<string name="app_update_notification_content_title">Une mise à jour de NewPipe disponible !</string>
|
||||
<string name="app_update_notification_content_text">Appuyez pour télécharger</string>
|
||||
<string name="missions_header_finished">Terminé</string>
|
||||
<string name="missions_header_pending">En file</string>
|
||||
<string name="missions_header_pending">Dans la file d\'attente</string>
|
||||
<string name="paused">En pause</string>
|
||||
<string name="download_failed">Téléchargement échoué</string>
|
||||
<string name="error_timeout">Délai de connection dépassé</string>
|
||||
<string name="conferences">Conférences</string>
|
||||
<string name="download_finished">Téléchargement terminé</string>
|
||||
<string name="download_finished_more">%s téléchargements terminés</string>
|
||||
<string name="queued">Ajouté à la file d\'attente</string>
|
||||
<string name="generate_unique_name">Générer un nom unique</string>
|
||||
<string name="overwrite">Écraser</string>
|
||||
<string name="overwrite_unrelated_warning">Un fichier avec ce nom existe déjà</string>
|
||||
<string name="overwrite_finished_warning">Un fichier téléchargé avec ce nom existe déjà</string>
|
||||
<string name="download_already_running">Il y a un téléchargement en cours avec ce nom</string>
|
||||
<string name="show_error">Afficher l\'erreur</string>
|
||||
<string name="label_code">Code</string>
|
||||
<string name="error_path_creation">Le fichier ne peut pas être créé</string>
|
||||
<string name="error_file_creation">Le dossier de destination ne peut pas être créé</string>
|
||||
<string name="error_permission_denied">Autorisation refusée par le système</string>
|
||||
<string name="error_ssl_exception">Échoué de la connexion sécurisée</string>
|
||||
<string name="error_unknown_host">Le serveur est introuvable</string>
|
||||
<string name="error_connect_host">Impossible de se connecter au serveur</string>
|
||||
<string name="error_http_no_content">Le serveur n’envoie pas de données</string>
|
||||
<string name="error_http_not_found">Introuvable</string>
|
||||
<string name="clear_finished_download">Effacer les téléchargements terminés</string>
|
||||
<string name="pause_downloads_on_mobile">Mettre en pause lors du passage en données mobiles</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Les téléchargements qui ne peuvent pas être mis en pause seront redémarrés</string>
|
||||
<string name="list_view_mode">Mode liste</string>
|
||||
<string name="post_processing">post-traitement</string>
|
||||
<string name="enqueue">File d’attente</string>
|
||||
<string name="permission_denied">Action refusée par le système</string>
|
||||
<string name="error_postprocessing_failed">Échec du post-traitement</string>
|
||||
<string name="max_retry_msg">Nombre maximum de tentatives</string>
|
||||
<string name="max_retry_desc">Nombre maximum de tentatives avant d\'annuler le téléchargement</string>
|
||||
<string name="saved_tabs_invalid_json">Utilisation des onglets par défaut, erreur lors de la lecture des onglets enregistrés</string>
|
||||
<string name="error_http_unsupported_range">Le serveur n\'accepte pas les téléchargements multi-threads, réessayez avec @string/msg_threads = 1</string>
|
||||
<string name="msg_pending_downloads">Continuer vos %s transferts en attente depuis Téléchargement</string>
|
||||
</resources>
|
|
@ -59,8 +59,6 @@
|
|||
<string name="play_audio">Audio</string>
|
||||
<string name="default_audio_format_title">Formato de audio predeterminado</string>
|
||||
<string name="default_video_format_title">Formato de vídeo predeterminado</string>
|
||||
<string name="webm_description">WebM — formato libre</string>
|
||||
<string name="m4a_description">M4A — mellor calidade</string>
|
||||
<string name="theme_title">Tema</string>
|
||||
<string name="light_theme_title">Claro</string>
|
||||
<string name="dark_theme_title">Escuro</string>
|
||||
|
@ -218,8 +216,6 @@
|
|||
<string name="audio">Audio</string>
|
||||
<string name="retry">Tentar de novo</string>
|
||||
<string name="storage_permission_denied">A permisión de acceso ao almacenamento foi denegada</string>
|
||||
<string name="use_old_player_title">Usar o reprodutor antigo</string>
|
||||
<string name="use_old_player_summary">Versión interna anticuada do reprodutor Mediaframework</string>
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
|
|
|
@ -22,15 +22,12 @@
|
|||
<string name="popup_mode_share_menu_title">מצב חלון צף של NewPipe</string>
|
||||
<string name="controls_background_title">רקע</string>
|
||||
<string name="controls_popup_title">חלון צף</string>
|
||||
|
||||
<string name="download_path_title">נתיב להורדת סרטונים</string>
|
||||
<string name="download_path_summary">נתיב מיקום לאחסון סרטונים</string>
|
||||
<string name="download_path_dialog_title">נא להקליד נתיב לשמירת סרטונים</string>
|
||||
|
||||
<string name="download_path_audio_title">תיקיית הורדות שמע</string>
|
||||
<string name="download_path_audio_summary">הורדות שמע נשמרות כאן</string>
|
||||
<string name="download_path_audio_dialog_title">נא להקליד נתיב לשמירת קובצי שמע</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">ניגון אוטומטי</string>
|
||||
<string name="autoplay_by_calling_app_summary">מנגן סרטון כאשר NewPipe נפתח דרך יישומון אחר</string>
|
||||
<string name="default_resolution_title">רזולוציית בררת המחדל</string>
|
||||
|
@ -54,7 +51,6 @@
|
|||
<string name="player_gesture_controls_summary">שימוש במחוות כדי לשלוט בבהירות ובעצמת השמע של הנגן</string>
|
||||
<string name="show_search_suggestions_title">הצעות חיפוש</string>
|
||||
<string name="show_search_suggestions_summary">הצגת הצעות בעת החיפוש</string>
|
||||
|
||||
<string name="download_dialog_title">הורדה</string>
|
||||
<string name="next_video_title">הבא</string>
|
||||
<string name="show_next_and_similar_title">להציג סרטונים דומים ובאים בתור</string>
|
||||
|
@ -69,7 +65,7 @@
|
|||
<string name="play_btn_text">נגינה</string>
|
||||
<string name="content">תוכן</string>
|
||||
<string name="show_age_restricted_content_title">תוכן עם הגבלת גיל</string>
|
||||
<string name="video_is_age_restricted">הצגת סרטונים עם הגבלת גיל. ניתן לאפשר תכנים שכאלה דרך ההגדרות.</string>
|
||||
<string name="video_is_age_restricted">הצגת סרטונים עם הגבלת גיל. ניתן לאפשר תכנים שכאלו דרך ההגדרות.</string>
|
||||
<string name="duration_live">חי</string>
|
||||
<string name="downloads">הורדות</string>
|
||||
<string name="downloads_title">הורדות</string>
|
||||
|
@ -83,7 +79,6 @@
|
|||
<string name="refresh">רענון</string>
|
||||
<string name="clear">פינוי</string>
|
||||
<string name="popup_resizing_indicator_title">שינוי גודל</string>
|
||||
|
||||
<string name="general_error">שגיאה</string>
|
||||
<string name="network_error">שגיאת רשת</string>
|
||||
<string name="could_not_load_thumbnails">אין אפשרות לטעון את כל התמונות הממוזערות</string>
|
||||
|
@ -104,17 +99,14 @@
|
|||
<string name="what_device_headline">מידע:</string>
|
||||
<string name="what_happened_headline">מה קרה:</string>
|
||||
<string name="info_labels">מה:\\nבקשה:\\nשפת התוכן:\\nשירות:\\nשעון גריניץ׳:\\nחבילה:\\nגרסה:\\nגרסת מערכת ההפעלה:</string>
|
||||
<string name="subscribe_button_title">עריכת מינוי</string>
|
||||
<string name="subscribe_button_title">עריכת מינוי</string>
|
||||
<string name="subscribed_button_title">נרשמת</string>
|
||||
<string name="channel_unsubscribed">ביטול מינוי לערוץ</string>
|
||||
<string name="subscription_change_failed">לא הצלחתי לשנות מינוי</string>
|
||||
<string name="subscription_update_failed">לא ניתן לעדכן את המינוי</string>
|
||||
|
||||
<string name="tab_main">ראשי</string>
|
||||
<string name="tab_subscriptions">מינויים</string>
|
||||
|
||||
<string name="fragment_whats_new">מה חדש</string>
|
||||
|
||||
<string name="enable_search_history_title">היסטוריית חיפוש</string>
|
||||
<string name="enable_search_history_summary">שמירת שאילתות החיפוש מקומית</string>
|
||||
<string name="enable_watch_history_title">היסטוריה ומטמון</string>
|
||||
|
@ -132,20 +124,14 @@
|
|||
<string name="best_resolution">רזולוציה מיטבית</string>
|
||||
<string name="undo">ביטול</string>
|
||||
<string name="play_all">לנגן הכול</string>
|
||||
|
||||
<string name="notification_channel_name">התראה מ־NewPipe</string>
|
||||
<string name="notification_channel_description">התראות עבור נגן הרקע והנגן הצף של NewPipe</string>
|
||||
|
||||
<string name="unknown_content">[לא ידוע]</string>
|
||||
|
||||
<string name="player_stream_failure">נגינת התזרים לא הצליחה</string>
|
||||
<string name="player_unrecoverable_failure">אירעה תקלה בנגן ממנה לא ניתן להשתקם</string>
|
||||
<string name="player_recoverable_failure">מתבצעת החלמה משגיאת נגן</string>
|
||||
|
||||
<string name="your_comment">ההערה שלך (באנגלית):</string>
|
||||
<string name="error_details_headline">פרטים:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">תמונה ממוזערת לתצוגה המקדימה של הסרטון</string>
|
||||
<string name="detail_thumbnail_view_description">תמונות ממוזערות לתצוגה המקדימה של הסרטון</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">תמונה ייצוגית של המפרסם</string>
|
||||
|
@ -157,54 +143,43 @@
|
|||
<string name="user_report">דוח משתמש</string>
|
||||
<string name="search_no_results">אין תוצאות</string>
|
||||
<string name="empty_subscription_feed_subtitle">אין כאן כלום מלבד צרצרים</string>
|
||||
|
||||
<string name="err_dir_create">לא ניתן ליצור את תיקיית ההורדות ‚%1$s’</string>
|
||||
<string name="info_dir_created">תיקיית ההורדות ‚%1$s’ נוצרה</string>
|
||||
|
||||
<string name="video">סרטון</string>
|
||||
<string name="audio">שמע</string>
|
||||
<string name="retry">ניסיון חוזר</string>
|
||||
<string name="storage_permission_denied">הגישה לאחסון נדחתה</string>
|
||||
<string name="use_old_player_title">השתמש בנגן הישן</string>
|
||||
<string name="use_old_player_summary">השתמש בנגן המובנה Mediaframework</string>
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">B</string>
|
||||
|
||||
<string name="no_subscribers">אין מנויים</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">מנוי אחד</item>
|
||||
<item quantity="two">שני מנויים</item>
|
||||
<item quantity="many">%s מנויים</item>
|
||||
<item quantity="other">%s מנויים</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">מנוי אחד</item>
|
||||
<item quantity="two">שני מנויים</item>
|
||||
<item quantity="many">%s מנויים</item>
|
||||
<item quantity="other">%s מנויים</item>
|
||||
</plurals>
|
||||
<string name="no_views">אין צפיות</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">צפייה אחת</item>
|
||||
<item quantity="two">שתי צפיות</item>
|
||||
<item quantity="many">%s צפיות</item>
|
||||
<item quantity="other">%s צפיות</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">צפייה אחת</item>
|
||||
<item quantity="two">שתי צפיות</item>
|
||||
<item quantity="many">%s צפיות</item>
|
||||
<item quantity="other">%s צפיות</item>
|
||||
</plurals>
|
||||
<string name="no_videos">אין סרטונים</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">סרטון</item>
|
||||
<item quantity="two">שני סרטונים</item>
|
||||
<item quantity="many">%s סרטונים</item>
|
||||
<item quantity="other">%s סרטונים</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">סרטון</item>
|
||||
<item quantity="two">שני סרטונים</item>
|
||||
<item quantity="many">%s סרטונים</item>
|
||||
<item quantity="other">%s סרטונים</item>
|
||||
</plurals>
|
||||
<string name="start">התחלה</string>
|
||||
<string name="pause">השהיה</string>
|
||||
<string name="view">נגינה</string>
|
||||
<string name="delete">מחיקה</string>
|
||||
<string name="checksum">גיבוב לאימות</string>
|
||||
|
||||
<string name="add">משימה חדשה</string>
|
||||
<string name="finish">אישור</string>
|
||||
|
||||
<string name="msg_name">שם קובץ</string>
|
||||
<string name="msg_threads">תת־דיונים</string>
|
||||
<string name="msg_error">שגיאה</string>
|
||||
|
@ -218,19 +193,15 @@
|
|||
<string name="no_available_dir">נא לבחור תיקיית הורדה זמינה</string>
|
||||
<string name="msg_popup_permission">הרשאה זו נדרשת לטובת
|
||||
\nפתיחה בחלון צף</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">אתגר reCAPTCHA</string>
|
||||
<string name="recaptcha_request_toast">התקבלה בקשה לאתגר reCAPTCHA</string>
|
||||
|
||||
<string name="settings_category_downloads_title">הורדה</string>
|
||||
<string name="settings_file_charset_title">רשימת תווים אפשרית בשמות קבצים</string>
|
||||
<string name="settings_file_replacement_character_summary">תווים לא נתמכים מוחלפים בערך הזה</string>
|
||||
<string name="settings_file_replacement_character_title">תו חלופי</string>
|
||||
|
||||
<string name="charset_letters_and_digits">אותיות וספרות</string>
|
||||
<string name="charset_most_special_characters">רוב התווים המיוחדים</string>
|
||||
|
||||
<string name="title_activity_about">על אודות NewPipe</string>
|
||||
<string name="action_settings">הגדרות</string>
|
||||
<string name="action_about">על אודות</string>
|
||||
|
@ -252,8 +223,6 @@
|
|||
<string name="website_encouragement">מומלץ לבקר באתר של NewPipe לפרטים נוספים ולחדשות.</string>
|
||||
<string name="app_license_title">הרישיון של NewPipe</string>
|
||||
<string name="read_full_license">הצגת הרישיון</string>
|
||||
|
||||
|
||||
<string name="title_activity_history">היסטוריה</string>
|
||||
<string name="title_history_search">נשלח כחיפוש</string>
|
||||
<string name="title_history_view">נצפו</string>
|
||||
|
@ -263,7 +232,6 @@
|
|||
<string name="history_cleared">ההיסטוריה התרוקנה</string>
|
||||
<string name="item_deleted">פריט נמחק</string>
|
||||
<string name="delete_item_search_history">למחוק את הפריט הזה מהיסטוריית החיפושים\?</string>
|
||||
|
||||
<string name="main_page_content">תוכן הדף הראשי</string>
|
||||
<string name="blank_page_summary">דף ריק</string>
|
||||
<string name="kiosk_page_summary">דף גישה מזדמנת</string>
|
||||
|
@ -273,7 +241,6 @@
|
|||
<string name="select_a_channel">נא לבחור ערוץ</string>
|
||||
<string name="no_channel_subscribed_yet">אין עדיין מינויים לערוצים</string>
|
||||
<string name="select_a_kiosk">נא לבחור סוג גישה מזדמנת</string>
|
||||
|
||||
<string name="kiosk">גישה מזדמנת</string>
|
||||
<string name="trending">החמים</string>
|
||||
<string name="top_50">50 המובילים</string>
|
||||
|
@ -289,29 +256,24 @@
|
|||
<string name="start_here_on_main">להתחיל לנגן מכאן</string>
|
||||
<string name="start_here_on_background">"להתחיל מכאן כאשר נגן הרקע מופעל"</string>
|
||||
<string name="start_here_on_popup">להתחיל כאן בנגן הצף</string>
|
||||
<string name="controls_download_desc">הורדת קובץ הזרמה</string>
|
||||
<string name="controls_download_desc">הורדת קובץ הזרמה</string>
|
||||
<string name="show_info">הצגת מידע</string>
|
||||
|
||||
<string name="tab_bookmarks">רשימות נגינה מסומנות</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">הוספה אל</string>
|
||||
|
||||
<string name="default_content_country_title">מדינת תוכן כבררת מחדל</string>
|
||||
<string name="service_title">שירות</string>
|
||||
<string name="settings_category_debug_title">ניפוי שגיאות</string>
|
||||
<string name="always">תמיד</string>
|
||||
<string name="just_once">חד פעמי</string>
|
||||
|
||||
<string name="import_data_title">ייבוא מסד נתונים</string>
|
||||
<string name="export_data_title">ייצוא מסד נתונים</string>
|
||||
<string name="external_player_unsupported_link_type">נגנים חיצוניים לא תומכים בסוגי קישורים כאלה</string>
|
||||
<string name="invalid_url_toast">כתובת שגויה</string>
|
||||
<string name="file">קובץ</string>
|
||||
|
||||
<string name="switch_to_background">העברה לרקע</string>
|
||||
<string name="switch_to_popup">העברה לחלון צף</string>
|
||||
<string name="no_player_found_toast">לא נמצא נגן צפייה ישירה (ניתן להתקין את VLC כדי לתקן זאת).</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">מטמון התמונות התרוקן</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">תמונות מטמון נמחקו</string>
|
||||
<string name="metadata_cache_wipe_title">ניקוי מטמון נתוני העל</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">מטמון נתוני העל התרוקן</string>
|
||||
<string name="export_data_summary">ייצוא היסטוריה, מינויים ורשימות נגינה</string>
|
||||
|
@ -322,61 +284,48 @@
|
|||
<string name="invalid_file">הקובץ אינו קיים או שחסרה הרשאה לקרוא אותו או לכתוב אליו</string>
|
||||
<string name="file_name_empty_error">שם הקובץ אינו יכול להיות ריק</string>
|
||||
<string name="detail_drag_description">ניתן לסדר מחדש בגרירה</string>
|
||||
|
||||
<string name="create">יצירה</string>
|
||||
<string name="delete_one">למחוק אחד</string>
|
||||
<string name="delete_all">למחוק הכול</string>
|
||||
<string name="dismiss">התעלמות</string>
|
||||
<string name="rename">שינוי שם</string>
|
||||
|
||||
<string name="one_item_deleted">פריט אחד נמחק.</string>
|
||||
|
||||
<string name="toast_no_player">לא מותקן יישומון שמתאים לנגינת הקובץ הזה</string>
|
||||
|
||||
<string name="delete_stream_history_prompt">למחוק את הפריט הזה מהיסטוריית הצפייה שלך\?</string>
|
||||
<string name="delete_all_history_prompt">למחוק את כל הפריטים מההיסטוריה\?</string>
|
||||
<string name="export_complete_toast">הייצוא הסתיים</string>
|
||||
<string name="import_complete_toast">הייבוא הסתיים</string>
|
||||
<string name="no_valid_zip_file">אין קובץ ZIP תקין</string>
|
||||
<string name="video_player">נגן וידאו</string>
|
||||
<string name="video_player">נגן סרטונים</string>
|
||||
<string name="background_player">נגן רקע</string>
|
||||
<string name="popup_player">נגן צף</string>
|
||||
<string name="always_ask_open_action">לשאול תמיד</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">המידע מתקבל…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">התוכן המבוקש בטעינה</string>
|
||||
|
||||
<string name="create_playlist">רשימת נגינה חדשה</string>
|
||||
<string name="delete_playlist">מחיקה</string>
|
||||
<string name="rename_playlist">שינוי שם</string>
|
||||
<string name="playlist_name_input">שם</string>
|
||||
<string name="append_playlist">הוספה לרשימת נגינה</string>
|
||||
<string name="bookmark_playlist">הוספה רשימת השמעה לסימניות</string>
|
||||
<string name="bookmark_playlist">הוספת רשימת נגינה לסימניות</string>
|
||||
<string name="unbookmark_playlist">הסרת סימנייה</string>
|
||||
|
||||
<string name="delete_playlist_prompt">למחוק רשימת נגינה זו\?</string>
|
||||
<string name="playlist_creation_success">רשימת הנגינה נוצרה</string>
|
||||
<string name="playlist_add_stream_success">נוסף לרשימת הנגינה</string>
|
||||
<string name="playlist_thumbnail_change_success">תמונת רשימת הנגינה הוחלפה.</string>
|
||||
<string name="resize_fill">מילוי</string>
|
||||
<string name="resize_zoom">תקריב</string>
|
||||
|
||||
<string name="caption_auto_generated">נוצרו אוטומטית</string>
|
||||
|
||||
<string name="import_export_title">ייבוא/ייצוא</string>
|
||||
<string name="import_title">ייבוא</string>
|
||||
<string name="import_from">ייבוא מ־</string>
|
||||
<string name="export_to">ייצוא אל</string>
|
||||
|
||||
<string name="import_ongoing">מתבצע ייבוא…</string>
|
||||
<string name="export_ongoing">מתבצע ייצוא…</string>
|
||||
|
||||
<string name="import_file_title">ייבוא קובץ</string>
|
||||
<string name="previous_export">ייצוא קודם</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">לא ניתן לייבא את המינויים</string>
|
||||
<string name="subscriptions_export_unsuccessful">לא ניתן לייצא את המינויים</string>
|
||||
|
||||
<string name="import_youtube_instructions">כדי לייבא את רשימת המינויים שלך מ־YouTube עליך להוריד את קובץ הייצוא:
|
||||
\n
|
||||
\n1. לעבור לכתובת הזו: %1$s
|
||||
|
@ -384,16 +333,15 @@
|
|||
\n3. ההורדה אמורה להתחיל (זה קובץ הייצוא)</string>
|
||||
<string name="playback_tempo">קצב</string>
|
||||
<string name="playback_default">ברירת מחדל</string>
|
||||
<string name="use_inexact_seek_title">שימוש בחיפוש מהיר גס</string>
|
||||
<string name="use_inexact_seek_title">שימוש בחיפוש מהיר ולא מדויק</string>
|
||||
<string name="use_inexact_seek_summary">חיפוש גס מאפשר לנגן לחפש נקודת זמן מהר יותר, ברמת דיוק נמוכה יותר</string>
|
||||
<string name="download_thumbnail_title">טעינת תמונות ממוזערות</string>
|
||||
<string name="download_thumbnail_summary">כיבוי האפשרות מונע את טעינת התמונות הממוזערות, חוסך בתקשורת נתונים ובניצולת הזיכרון. שינויים באפשרות זו מוחקים את המטמון בזיכרון ובכונן.</string>
|
||||
<string name="metadata_cache_wipe_summary">הסרת כל נתוני העמודים שבמטמון</string>
|
||||
<string name="auto_queue_title">הוספת התזרים הבא לרשימת הנגינה אוטומטית</string>
|
||||
<string name="auto_queue_summary">להוסיף אוטומטית תזרים דומה בעת נגינת התזרים האחרון בתור שאינו מחזורי.</string>
|
||||
<string name="auto_queue_summary">להוסיף אוטומטית תזרים דומה בעת נגינת התזרים האחרון בתור שאינו מחזורי</string>
|
||||
<string name="toggle_orientation">החלפת כיווניות</string>
|
||||
<string name="switch_to_main">העברה לראשי</string>
|
||||
|
||||
<string name="import_data_summary">משכתב את ההיסטוריה והמינויים הנוכחיים שלך</string>
|
||||
<string name="clear_views_history_summary">מחיקת היסטוריית התזרימים שהתנגנו</string>
|
||||
<string name="channels">ערוצים</string>
|
||||
|
@ -403,13 +351,12 @@
|
|||
<string name="delete_view_history_alert">למחוק את כל היסטוריית הצפייה\?</string>
|
||||
<string name="clear_search_history_summary">מחיקת היסטוריית מילות החיפוש</string>
|
||||
<string name="delete_search_history_alert">למחוק את כל היסטוריית החיפוש\?</string>
|
||||
<string name="video_streams_empty">לא נמצא תזרימי וידאו</string>
|
||||
<string name="audio_streams_empty">לא נמצא תזרימי שמע</string>
|
||||
<string name="video_streams_empty">לא נמצאו תזרימי וידאו</string>
|
||||
<string name="audio_streams_empty">לא נמצאו תזרימי שמע</string>
|
||||
<string name="invalid_directory">אין תיקייה כזו</string>
|
||||
<string name="invalid_source">אין מקור תיקייה/תוכן</string>
|
||||
<string name="error_occurred_detail">אירעה שגיאה: %1$s</string>
|
||||
<string name="no_streams_available_download">אין תזרימים זמינים להורדה</string>
|
||||
|
||||
<string name="privacy_policy_title">מדיניות הפרטיות של NewPipe</string>
|
||||
<string name="privacy_policy_encouragement">מיזם NewPipe שומר על הפרטיות שלך בצורה מאוד קפדנית. לפיכך, היישומון אינו אוסף נתונים ללא הסכמתך.
|
||||
\nמדיניות הפרטיות של NewPipe מסבירה בפרטי פרטים אילו נתונים נשלחים ומאוחסנים בעת שליחת דיווח על תקלה.</string>
|
||||
|
@ -417,29 +364,20 @@
|
|||
<string name="app_license">NewPipe הוא יישומון חופשי בהתאם לרישיון קופילפט: מותר לך להשתמש, לחקור, לשתף ולשפר בכל דרך שנראית לך. במיוחד מותר לך להפיץ מחדש ו/או לשנות תחת תנאי הרישיון הציבורי הכללי של GNU כפי שמופץ על ידי קרן התכנה החופשית, בין אם גרסה 3 של הרישיון או (לשיקולך) כל גרסה עדכנית יותר שלו.</string>
|
||||
<string name="title_last_played">התנגנו אחרונים</string>
|
||||
<string name="title_most_played">הכי נצפים</string>
|
||||
|
||||
<string name="could_not_import_all_files">אזהרה: ייבוא חלק מהקבצים נכשל.</string>
|
||||
<string name="override_current_data">פעולה זו תדרוס את ההגדרות הקיימות.</string>
|
||||
<string name="import_settings">לייבא גם הגדרות\?</string>
|
||||
|
||||
<string name="drawer_open">פתיחת מגירה</string>
|
||||
<string name="drawer_close">סגירת מגירה</string>
|
||||
<string name="drawer_header_action_paceholder_text">משהו יופיע כאן בקרוב ;D</string>
|
||||
|
||||
|
||||
<string name="preferred_open_action_settings_title">פעולת ‚פתיחה’ מועדפת</string>
|
||||
<string name="preferred_open_action_settings_summary">פעולת בררת מחדל בעת פתיחת תוכן - %s</string>
|
||||
|
||||
<string name="set_as_playlist_thumbnail">הגדרה כתמונת רשימת הנגינה</string>
|
||||
|
||||
<string name="playlist_delete_failure">לא ניתן למחוק רשימת נגינה.</string>
|
||||
|
||||
<string name="caption_none">אין כתוביות</string>
|
||||
|
||||
<string name="resize_fit">התאמה</string>
|
||||
<string name="caption_setting_title">כתוביות</string>
|
||||
<string name="caption_setting_description">שינוי גודל כותרת הנגן וסגנונות הרקע. נדרשת הפעלה מחדש כדי ששינויים אלה יכנסו לתוקף.</string>
|
||||
|
||||
<string name="enable_leak_canary_title">הפעלת LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">מעקב אחר זליגת זיכרון עשויה לגרום ליישומון להיות בלתי זמין בזמן העתקת תוכן הזיכרון לקובץ</string>
|
||||
<string name="import_soundcloud_instructions_hint">המזהה שלך, soundcloud.com/המזהה שלך</string>
|
||||
|
@ -479,7 +417,7 @@
|
|||
<string name="selection">בחירה</string>
|
||||
<string name="events">אירועים</string>
|
||||
<string name="conferences">כנסים</string>
|
||||
<string name="enable_disposed_exceptions_title">דיווח על שגיאות של חריגה ממחזור חיים</string>
|
||||
<string name="enable_disposed_exceptions_title">דיווח על שגיאות שמחוץ למחזור החיים</string>
|
||||
<string name="enable_disposed_exceptions_summary">אילוץ דיווח על חריגות מחוץ למקטעים או למחזור חיי הפעילות לאחר ההשלכה בתשדורת יוצאת</string>
|
||||
<string name="import_soundcloud_instructions">ניתן לייבא פרופיל SoundCloud על ידי הקלדת הכתובת או המזהה שלך:
|
||||
\n
|
||||
|
@ -502,7 +440,6 @@
|
|||
<string name="app_update_notification_content_title">יצא עדכון ל־NewPipe!</string>
|
||||
<string name="app_update_notification_content_text">יש לגעת כדי להוריד</string>
|
||||
<string name="missions_header_finished">הסתיים</string>
|
||||
<string name="missions_header_pending">בתור</string>
|
||||
<string name="paused">מושהה</string>
|
||||
<string name="queued">בתור</string>
|
||||
<string name="post_processing">עיבוד מאוחר</string>
|
||||
|
@ -513,12 +450,12 @@
|
|||
<string name="download_finished_more">%s הורדות הסתיימו</string>
|
||||
<string name="generate_unique_name">יצירת שם ייחודי</string>
|
||||
<string name="overwrite">שכתוב</string>
|
||||
<string name="overwrite_warning">כבר קיים קובץ בשם הזה</string>
|
||||
<string name="overwrite_finished_warning">כבר קיים קובץ בשם הזה</string>
|
||||
<string name="download_already_running">אחת ההורדות הפעילות כבר נושאת את השם הזה</string>
|
||||
<string name="show_error">הצגת שגיאה</string>
|
||||
<string name="label_code">קוד</string>
|
||||
<string name="error_path_creation">לא ניתן ליצור את הקובץ</string>
|
||||
<string name="error_file_creation">לא ניתן ליצור את תיקיית היעד</string>
|
||||
<string name="error_file_creation">לא ניתן ליצור את הקובץ</string>
|
||||
<string name="error_path_creation">לא ניתן ליצור את תיקיית היעד</string>
|
||||
<string name="error_permission_denied">ההרשאה נדחתה על ידי המערכת</string>
|
||||
<string name="error_ssl_exception">החיבור המאובטח נכשל</string>
|
||||
<string name="error_unknown_host">לא ניתן למצוא את השרת</string>
|
||||
|
@ -535,4 +472,5 @@
|
|||
<string name="max_retry_desc">מספר הניסיונות החוזרים המרבי בטרם ביטול ההורדה</string>
|
||||
<string name="pause_downloads_on_mobile">להשהות בעת מעבר לתקשורת נתונים סלולרית</string>
|
||||
<string name="pause_downloads_on_mobile_desc">הורדות שלא ניתן להשהות יופעלו מחדש</string>
|
||||
<string name="missions_header_pending">בהמתנה</string>
|
||||
</resources>
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="view_count_text">%1$s दृश्य</string>
|
||||
<string name="view_count_text">%1$s दृश्य</string>
|
||||
<string name="upload_date_text">%1$s को प्रकाशित</string>
|
||||
<string name="no_player_found">कोई स्ट्रीम प्लेयर नहीं मिला। क्या आप VLC इंस्टॉल करना चाहते हैं?</string>
|
||||
<string name="install">इंस्टॉल करें</string>
|
||||
<string name="open_in_browser">ब्राउज़र में खोलें</string>
|
||||
<string name="open_in_popup_mode">पॉपअप मोड में खोलें</string>
|
||||
<string name="share">शेयर करें</string>
|
||||
<string name="share">साझा करें</string>
|
||||
<string name="download">डाउनलोड</string>
|
||||
<string name="search">खोजें</string>
|
||||
<string name="settings">सेटिंग्स</string>
|
||||
|
@ -17,15 +17,13 @@
|
|||
<string name="subscribed_button_title">सदस्यता ली</string>
|
||||
<string name="channel_unsubscribed">चैनल सदस्यता रद्द करी गयी</string>
|
||||
<string name="tab_subscriptions">सदस्यता</string>
|
||||
|
||||
<string name="controls_background_title">पीछे</string>
|
||||
<string name="controls_popup_title">पॉपअप</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">ऑटोप्ले करें</string>
|
||||
<string name="play_audio">ऑडियो</string>
|
||||
<string name="light_theme_title">हलका</string>
|
||||
<string name="black_theme_title">काली</string>
|
||||
<string name="enable_watch_history_title">पूर्व और कैश</string>
|
||||
<string name="enable_watch_history_title">इतिहास व कॅशे</string>
|
||||
<string name="download_dialog_title">डाउनलोड</string>
|
||||
<string name="next_video_title">अगला</string>
|
||||
<string name="settings_category_video_audio_title">वीडियो और ऑडियो</string>
|
||||
|
@ -44,7 +42,6 @@
|
|||
<string name="app_license_title">न्यूपाइप का लाइसेंस</string>
|
||||
<string name="read_full_license">लाइसेंस पढ़ें</string>
|
||||
<string name="contribution_title">योगदान करें</string>
|
||||
|
||||
<string name="title_activity_history">इतिहास</string>
|
||||
<string name="title_history_search">खोजा जा चूका है</string>
|
||||
<string name="title_history_view">विडियो जो देख लिए गए है</string>
|
||||
|
@ -60,22 +57,18 @@
|
|||
<string name="did_you_mean">क्या आप का मतलब %1$s है?</string>
|
||||
<string name="share_dialog_title">शेयर करें</string>
|
||||
<string name="use_external_video_player_title">अन्य वीडियो प्लेयर उपयोग करें</string>
|
||||
<string name="use_external_video_player_summary">कुछ रेसोल्युशनस में नहीं आएगी</string>
|
||||
<string name="use_external_video_player_summary">कुछ प्रस्तावों पर ऑडियो निकालता है</string>
|
||||
<string name="use_external_audio_player_title">अन्य ऑडियो प्लेयर उपयोग करें</string>
|
||||
<string name="tab_main">मुख्य</string>
|
||||
<string name="subscription_change_failed">सदस्यता को बदलने में असमर्थ है</string>
|
||||
<string name="subscription_update_failed">सदस्यता को अपडेट करने में असमर्थ है</string>
|
||||
|
||||
<string name="subscription_change_failed">सदस्यता नहीं बदला जा सका</string>
|
||||
<string name="subscription_update_failed">सदस्यता का अद्यतन नहीं हो सका</string>
|
||||
<string name="fragment_whats_new">देखे की क्या नया है</string>
|
||||
|
||||
<string name="download_path_title">विडियो को डाउनलोड करने के लिए फाइल की जगह</string>
|
||||
<string name="download_path_summary">डाउनलोड किए गए विडियो फाइल को रखने की जगह</string>
|
||||
<string name="download_path_dialog_title">वीडियो के लिए डाउनलोड पथ दर्ज करें</string>
|
||||
|
||||
<string name="download_path_audio_title">ऑडियो डाउनलोड फ़ोल्डर</string>
|
||||
<string name="download_path_audio_summary">डाउनलोड किये गए ऑडियो यहाँ है</string>
|
||||
<string name="download_path_audio_dialog_title">ऑडियो फाइल डाउनलोड करने के लिए जगह दर्ज करें</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_summary">अन्य अप्प के द्वारा NewPipe के आह्वान पर वीडियो तुरंत चले</string>
|
||||
<string name="default_resolution_title">वीडियो का डिफ़ॉल्ट रिज़ॉल्यूशन</string>
|
||||
<string name="default_popup_resolution_title">विडियो पॉपअप का डिफ़ॉल्ट रिज़ॉल्यूशन</string>
|
||||
|
@ -84,11 +77,9 @@
|
|||
<string name="play_with_kodi_title">Kodi से चलाये</string>
|
||||
<string name="kore_not_found">Kore एप्प नहीं मिला, इसे इनस्टॉल करें?</string>
|
||||
<string name="show_play_with_kodi_title">\"Kodi से चलाये\" वाला विकल्प दिखाए</string>
|
||||
<string name="show_play_with_kodi_summary">उस विकल्प को दिखाए जिसमे Kodi Media Center के जरिये विडियो प्ले किया जाता है</string>
|
||||
<string name="show_play_with_kodi_summary">कोडी मीडिया सेंटर के माध्यम से वीडियो चलाने के लिए एक विकल्प प्रदर्शित करें</string>
|
||||
<string name="default_audio_format_title">डिफ़ॉल्ट ऑडियो का फॉर्मेट</string>
|
||||
<string name="default_video_format_title">डिफ़ॉल्ट विडियो का फॉर्मेट</string>
|
||||
<string name="webm_description">WebM - libre फॉर्मेट</string>
|
||||
<string name="m4a_description">M4A - बेहतर क्वालिटी</string>
|
||||
<string name="theme_title">एप्प का नया रूप</string>
|
||||
<string name="dark_theme_title">काला</string>
|
||||
<string name="popup_remember_size_pos_title">विडियो पॉपअप की आकर और उसकी स्थति को याद रखे</string>
|
||||
|
@ -99,15 +90,14 @@
|
|||
<string name="show_search_suggestions_summary">जब कुछ ढूंड रहे हो तो सुझाव दिखाये</string>
|
||||
<string name="enable_search_history_title">खोज के इतिहास को देखे</string>
|
||||
<string name="enable_search_history_summary">खोज के query को फ़ोन की मेमोरी में ही रखे</string>
|
||||
<string name="enable_watch_history_summary">देखे हुए वीडियोस का रिकॉर्ड रखें</string>
|
||||
<string name="resume_on_audio_focus_gain_title">जब फोकस मिले तो विडियो resume हो</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">रूकावट आने पर भी विडियो को जारी रखे (जैसे - फ़ोन कॉल आये)</string>
|
||||
<string name="enable_watch_history_summary">देखे हुए विडियो की सूची रखे</string>
|
||||
<string name="resume_on_audio_focus_gain_title">फोकस मिलने पर विडियो पुनः आगे चले</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">रूकावट आने पर भी विडियो को जारी रखें (जैसे - फ़ोन कॉल आये)</string>
|
||||
<string name="show_next_and_similar_title">\'अगला\' और \'पहले समान\' वीडियो दिखाए</string>
|
||||
<string name="show_hold_to_append_title">\"जोड़ने के लिए पकड़ें रहे\" दिखाए</string>
|
||||
<string name="show_hold_to_append_summary">जब बैकग्राउंड और पॉपअप बटन विडियो के विवरण पन्ने में दबाई जाए तो tip को दिखाए</string>
|
||||
<string name="url_not_supported_toast">ये वाला URL इसमें नहीं चलेगा</string>
|
||||
<string name="content_language_title">डिफ़ॉल्ट विषय की भाषा</string>
|
||||
|
||||
<string name="settings_category_player_title">प्लेयर</string>
|
||||
<string name="settings_category_player_behavior_title">चाल चलन</string>
|
||||
<string name="settings_category_popup_title">पॉपअप</string>
|
||||
|
@ -119,7 +109,7 @@
|
|||
<string name="play_btn_text">चलाये</string>
|
||||
<string name="content">विषयवस्तु</string>
|
||||
<string name="show_age_restricted_content_title">उम्र प्रतिबंधित विषय वस्तु</string>
|
||||
<string name="video_is_age_restricted">उम्र प्रतिबंदित विडियो है .इस प्रकार की विषयवस्तु को अनुमति देने के लिए Setting से संभव है |</string>
|
||||
<string name="video_is_age_restricted">उम्र प्रतिबंदित विडियो है .इस प्रकार की विषयवस्तु को अनुमति देने के लिए सेटिंग से संभव है |</string>
|
||||
<string name="duration_live">सीधा प्रसारण</string>
|
||||
<string name="downloads">डाउनलोड</string>
|
||||
<string name="downloads_title">डाउनलोड</string>
|
||||
|
@ -137,12 +127,9 @@
|
|||
<string name="best_resolution">बेहतर विडियो की क्वालिटी</string>
|
||||
<string name="undo">वापस जाए</string>
|
||||
<string name="play_all">सारे प्ले करे</string>
|
||||
|
||||
<string name="notification_channel_name">NewPipe की अधिसूचना</string>
|
||||
<string name="notification_channel_description">NewPipe के बैकग्राउंड में चल रहे विडियो और पॉपअप विडियो के लिए अधिसूचना</string>
|
||||
|
||||
<string name="unknown_content">[नहीं जानते]</string>
|
||||
|
||||
<string name="general_error">त्रुटी</string>
|
||||
<string name="network_error">नेटवर्क में त्रुटी</string>
|
||||
<string name="could_not_load_thumbnails">सारे thumbnail(फोटो जो फ़ोन की मेमोरी में है ) भरे नहीं जा सकते</string>
|
||||
|
@ -159,7 +146,6 @@
|
|||
<string name="player_stream_failure">इस विडियो को चलाने में असफल हुए</string>
|
||||
<string name="player_unrecoverable_failure">कभी ठीक न होने वाले विडियो प्लेयर की त्रुटी आ रही है</string>
|
||||
<string name="player_recoverable_failure">विडियो प्लेयर त्रुटी से ठीक हो रहा है</string>
|
||||
|
||||
<string name="sorry_string">खेद है की, ऐसा होना नहीं चाहिए था.</string>
|
||||
<string name="error_report_button_text">त्रुटी की रिपोर्ट को ईमेल से भेजे</string>
|
||||
<string name="error_snackbar_message">माफ़ करे , कुछ त्रुटियाँ हो रही है</string>
|
||||
|
@ -169,8 +155,6 @@
|
|||
<string name="info_labels">क्या:\\nमांग:\\nविषयवस्तु की भाषा:\\nसेवा:\\nजीएमटी समय:\\nपैकेज:\\nसंस्करण:\\nOS संस्करण:</string>
|
||||
<string name="your_comment">आपकी टिप्पणी:</string>
|
||||
<string name="error_details_headline">विवरण:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">विडियो के thumbnail के पूर्व दर्शन</string>
|
||||
<string name="detail_thumbnail_view_description">विडियो के thumbnail के पूर्व दर्शन</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">अपलोडर के thumbnail वाले फोटो</string>
|
||||
|
@ -182,50 +166,39 @@
|
|||
<string name="user_report">उपयोगकर्ता की रिपोर्ट</string>
|
||||
<string name="search_no_results">कोई परिणाम नहीं मिला</string>
|
||||
<string name="empty_subscription_feed_subtitle">यंहा कुछ नहीं है</string>
|
||||
|
||||
<string name="err_dir_create">"डाउनलोड वाली डायरेक्टरी को बना नहीं सकते \'%1$s\'"</string>
|
||||
<string name="info_dir_created">डाउनलोड की डायरेक्टरी बना दी गई है \'%1$s\'</string>
|
||||
|
||||
<string name="info_dir_created">डाउनलोड की निर्देशिका बना दी गई है \'%1$s\'</string>
|
||||
<string name="video">विडियो</string>
|
||||
<string name="audio">ऑडियो</string>
|
||||
<string name="retry">फिर से कोशिश करे</string>
|
||||
<string name="storage_permission_denied">स्टोरेज में प्रवेश के लिए अनुमति नहीं मिली</string>
|
||||
<string name="use_old_player_title">पुराना विडियो प्लेयर प्रयोग करे</string>
|
||||
<string name="use_old_player_summary">पुराना Mediaframework Player जो फ़ोन में बना हुआ है</string>
|
||||
|
||||
<string name="short_thousand">हज़ार</string>
|
||||
<string name="short_million">करोड़</string>
|
||||
<string name="short_billion">अरब</string>
|
||||
|
||||
<string name="no_subscribers">कोई भी सदस्य नहीं है</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s सदस्य</item>
|
||||
<item quantity="other">%s सदस्यो</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s सदस्य</item>
|
||||
<item quantity="other">%s सदस्यो</item>
|
||||
</plurals>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s दर्शक</item>
|
||||
<item quantity="other">%s दर्शके</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s दर्शक</item>
|
||||
<item quantity="other">%s दर्शके</item>
|
||||
</plurals>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s विडियो</item>
|
||||
<item quantity="other">%s वीडियो</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s विडियो</item>
|
||||
<item quantity="other">%s वीडियो</item>
|
||||
</plurals>
|
||||
<string name="start">शुरू</string>
|
||||
<string name="pause">रोके</string>
|
||||
<string name="view">चलाये</string>
|
||||
<string name="delete">मिटाए</string>
|
||||
<string name="checksum">checksum</string>
|
||||
|
||||
<string name="add">नया मिशन</string>
|
||||
<string name="finish">ठीक है</string>
|
||||
|
||||
<string name="msg_name">फाइल का नाम</string>
|
||||
<string name="msg_threads">मेसेज के thread</string>
|
||||
<string name="msg_error">त्रुटी</string>
|
||||
<string name="msg_server_unsupported">server ठीक से चल नहीं रहा</string>
|
||||
<string name="msg_server_unsupported">असमर्थित सर्वर</string>
|
||||
<string name="msg_exists">फाइल पहले से ही बनी हुई है</string>
|
||||
<string name="msg_url_malform">URL सही नहीं है या फिर हो सकता है इन्टरनेट उपलब्ध नहीं है</string>
|
||||
<string name="msg_running">न्यूपाइप डाउनलोड हो रहा है</string>
|
||||
|
@ -234,26 +207,21 @@
|
|||
<string name="msg_copied">क्लिपबोर्ड पर कॉपी हो गया है</string>
|
||||
<string name="no_available_dir">कृपया उपलब्ध डाउनलोड फोल्डर को चुने</string>
|
||||
<string name="msg_popup_permission">पॉपअप के तरीके में खोलने के लिए अनुमति की जरुरत है</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA चुनोती</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA चुनोती के लिए निवेदन</string>
|
||||
|
||||
<string name="reCaptcha_title">reCAPTCHA चुनौती</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA चुनौती का अनुरोध किया</string>
|
||||
<string name="settings_category_downloads_title">डाउनलोड</string>
|
||||
<string name="settings_file_charset_title">फाइल के नाम के लिए आवश्यक characters(जैसे - १२३, abc) की अनुमति है</string>
|
||||
<string name="settings_file_replacement_character_summary">अमान्य characters इस value से बदल जायेंगे</string>
|
||||
<string name="settings_file_replacement_character_title">रिप्लेसमेंट करैक्टर</string>
|
||||
|
||||
<string name="charset_letters_and_digits">वर्ण और अंक</string>
|
||||
<string name="charset_most_special_characters">विशेष वर्ण</string>
|
||||
|
||||
<string name="copyright" formatted="true">%2$s के द्वारा © %1$s जो %3$s के अधीन आते है</string>
|
||||
<string name="error_unable_to_load_license">लाइसेंस load नहीं हो रहा</string>
|
||||
<string name="tab_contributors">सहयोगकर्ता</string>
|
||||
<string name="app_description">एंड्राइड के लिए हल्का और मुफ्त स्ट्रीमिंग एप्लिकेशन|</string>
|
||||
<string name="contribution_encouragement">अगर आपके पास कोई सुझाव हो जैसे -अनुवाद , डिजाईन में बदलाव ,code को साफ़ रखना , या फिर code में जायदा बदलाव लाना हो तो - साहयता के लिए आपका स्वागत है . जितना ज्यादा होगा उतना बेहतर होगा !</string>
|
||||
<string name="delete_item_search_history">क्या आप इसको खोज इतिहास के मिटाना चाहते है ?</string>
|
||||
|
||||
<string name="main_page_content">मुख्य पेज की विषयवस्तु</string>
|
||||
<string name="blank_page_summary">खाली पन्ना</string>
|
||||
<string name="kiosk_page_summary">kiosk पन्ना</string>
|
||||
|
@ -263,11 +231,10 @@
|
|||
<string name="select_a_channel">चैनल को चुने</string>
|
||||
<string name="no_channel_subscribed_yet">अभी तक किसी भी चैनल के सदस्य नहीं है</string>
|
||||
<string name="select_a_kiosk">kiosk को चुने</string>
|
||||
|
||||
<string name="kiosk">kiosk</string>
|
||||
<string name="top_50">टॉप 50</string>
|
||||
<string name="new_and_hot">नया और गरम</string>
|
||||
<string name="title_activity_background_player">बैकग्राउंड प्लेयर</string>
|
||||
<string name="title_activity_background_player">पृष्ठभूमि प्लेयर</string>
|
||||
<string name="title_activity_popup_player">पॉपअप प्लेयर</string>
|
||||
<string name="play_queue_remove">निकाले</string>
|
||||
<string name="play_queue_stream_detail">विवरण</string>
|
||||
|
@ -277,41 +244,33 @@
|
|||
<string name="start_here_on_main">यंहा से चलाना शुरू करे</string>
|
||||
<string name="start_here_on_background">बैकग्राउंड में चलाना शुरू करे</string>
|
||||
<string name="start_here_on_popup">पॉपअप में चलाना शुरू करे</string>
|
||||
<string name="no_player_found_toast">स्ट्रीम करने के लिए प्लेयर उपलब्ध नहीं है (आप इसे चलाने के लिए VLC प्लेयर इंस्टॉल कर सकते हैं)।</string>
|
||||
<string name="no_player_found_toast">स्ट्रीम करने के लिए प्लेयर उपलब्ध नहीं है (आप इसे चलाने के लिए VLC प्लेयर इंस्टॉल कर सकते हैं)।</string>
|
||||
<string name="controls_download_desc">स्ट्रीम डाउनलोड करें</string>
|
||||
<string name="show_info">जानकारी दिखाएं</string>
|
||||
|
||||
<string name="tab_bookmarks">बुकमार्क किये गए प्लेलिस्टस</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">में जोड़े</string>
|
||||
|
||||
<string name="default_content_country_title">डिफ़ॉल्ट देश का विषय</string>
|
||||
<string name="service_title">सर्विस</string>
|
||||
<string name="always">हमेशा के लिए</string>
|
||||
<string name="just_once">सिर्फ एक बार के लिए</string>
|
||||
|
||||
<string name="toggle_orientation">टॉगल ओरिएंटेशन</string>
|
||||
<string name="switch_to_background">बैकग्राउंड में स्विच करें</string>
|
||||
<string name="switch_to_popup">पॉपअप मोड में जाएं</string>
|
||||
<string name="switch_to_main">मुख्य पर स्विच करें</string>
|
||||
|
||||
<string name="import_data_title">डेटाबेस आयात करें</string>
|
||||
<string name="export_data_title">डेटाबेस निर्यात करें</string>
|
||||
<string name="import_data_summary">आपके वर्तमान इतिहास और सब्सक्रिप्शन को ओवरराइड करेगा</string>
|
||||
<string name="import_data_summary">आपके वर्तमान इतिहास और सब्सक्रिप्शन को अधिभावी करेगा</string>
|
||||
<string name="export_data_summary">इतिहास, सब्सक्रिप्शन और प्लेलिस्ट निर्यात करें</string>
|
||||
<string name="external_player_unsupported_link_type">एक्सटर्नल प्लेयर इन प्रकार के लिंक सपोर्ट नहीं करता</string>
|
||||
<string name="invalid_url_toast">अमान्य URL</string>
|
||||
<string name="video_streams_empty">कोई वीडियो स्ट्रीम नहीं मिला</string>
|
||||
<string name="audio_streams_empty">कोई वीडियो स्ट्रीम नहीं मिला</string>
|
||||
|
||||
<string name="audio_streams_empty">कोई ऑडियो स्ट्रीम नहीं मिली</string>
|
||||
<string name="detail_drag_description">फिर से क्रम देने के लिए खींचें</string>
|
||||
|
||||
<string name="create">बनाइये</string>
|
||||
<string name="delete_one">एक को हटाएं</string>
|
||||
<string name="delete_all">सभी को हटाएँ</string>
|
||||
<string name="dismiss">ख़ारिज करें</string>
|
||||
<string name="rename">नाम बदलें</string>
|
||||
|
||||
<string name="donation_title">दान करें</string>
|
||||
<string name="donation_encouragement">NewPipe स्वयंसेवकों द्वारा विकसित किया जाता है जो आपको अच्छा अनुभव देने के लिए अपना खाली समय व्यतीत करते हैं। स्वयंसेवको को मदद भेजे, ताकि वह NewPipe को और अच्छा बना सके।</string>
|
||||
<string name="give_back">वापस दे</string>
|
||||
|
@ -321,66 +280,50 @@
|
|||
<string name="delete_all_history_prompt">क्या आप वाकई इतिहास से सभी आइटंस हटाना चाहते हैं?</string>
|
||||
<string name="title_last_played">पिछला चलाया गया</string>
|
||||
<string name="title_most_played">अधिकतम चलाए गए</string>
|
||||
|
||||
<string name="export_complete_toast">निर्यात पूर्ण हुआ</string>
|
||||
<string name="import_complete_toast">आयात पूर्ण हुआ</string>
|
||||
<string name="export_complete_toast">निर्यात किए गए</string>
|
||||
<string name="import_complete_toast">आयातित</string>
|
||||
<string name="no_valid_zip_file">कोई मांय ज़िप फ़ाइल नहीं</string>
|
||||
<string name="could_not_import_all_files">चेतावनी: सभी फ़ाइलों को आयात नहीं किया जा सका।</string>
|
||||
<string name="override_current_data">यह आपके वर्तमान सेटअप को ओवरराइड करेगा ।</string>
|
||||
|
||||
<string name="drawer_open">ड्रावर खोलें</string>
|
||||
<string name="drawer_close">ड्रावर बंद करें</string>
|
||||
<string name="drawer_header_action_paceholder_text">जल्द ही यहां पर कुछ दिखाई देगा ;D</string>
|
||||
|
||||
|
||||
<string name="video_player">वीडियो प्लेयर</string>
|
||||
<string name="background_player">बैकग्राउंड प्लेयर</string>
|
||||
<string name="popup_player">पॉपअप प्लेयर</string>
|
||||
<string name="always_ask_open_action">हमेशा पूछें</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">जानकारी प्राप्त की जा रही है…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">अनुरोधित सामग्री लोड कर रहे है</string>
|
||||
|
||||
<string name="create_playlist">नई प्लेलिस्ट बनाएं</string>
|
||||
<string name="delete_playlist">प्लेलिस्ट हटाएं</string>
|
||||
<string name="rename_playlist">प्लेलिस्ट का नाम बदलें</string>
|
||||
<string name="playlist_name_input">नाम</string>
|
||||
<string name="append_playlist">प्लेलिस्ट में जोड़ें</string>
|
||||
<string name="set_as_playlist_thumbnail">प्लेलिस्ट थंबनेल के रूप में सेट करें</string>
|
||||
|
||||
<string name="bookmark_playlist">प्लेलिस्ट बुकमार्क करें</string>
|
||||
<string name="unbookmark_playlist">बुकमार्क हटायें</string>
|
||||
|
||||
<string name="delete_playlist_prompt">क्या आप इस प्लेलिस्ट को हटाना चाहते हैं?</string>
|
||||
<string name="playlist_creation_success">सूची बना दी गई</string>
|
||||
<string name="playlist_add_stream_success">प्लेलिस्ट में जोड़ा गया</string>
|
||||
<string name="playlist_thumbnail_change_success">प्लेलिस्ट का थंबनेल बदल दिया गया है</string>
|
||||
<string name="playlist_delete_failure">सूची हटाने में असफल</string>
|
||||
|
||||
<string name="caption_none">कोई कैप्शन नहीं है</string>
|
||||
|
||||
<string name="resize_fit">फिट</string>
|
||||
<string name="resize_fill">भरें</string>
|
||||
<string name="resize_zoom">ज़ूम करें</string>
|
||||
|
||||
<string name="caption_font_size_settings_title">कैप्शन फ़ॉंट आकार</string>
|
||||
<string name="smaller_caption_font_size">छोटे फ़ॉंट</string>
|
||||
<string name="normal_caption_font_size">सामांय फ़ॉंट</string>
|
||||
<string name="larger_caption_font_size">बड़ा फ़ॉंट</string>
|
||||
|
||||
<string name="toggle_leak_canary">मॉनिटर लीक</string>
|
||||
<string name="enable_leak_canary_notice">मेमोरी लीक मॉनिटरिंग सक्षम है, हीप डंपिंग के समय ऐप अप्रतिसादी हो सकती है</string>
|
||||
<string name="disable_leak_canary_notice">मेमोरी लीक मॉनिटरिंग अक्षम है</string>
|
||||
<string name="settings_category_debug_title">डीबग करें</string>
|
||||
<string name="settings_category_debug_title">डीबग करें</string>
|
||||
<string name="caption_auto_generated">ऑटो-जनरेटेड</string>
|
||||
<string name="enable_leak_canary_title">LeakCanary सक्षम करें</string>
|
||||
<string name="enable_leak_canary_summary">हीप डंप करने के दौरान मेमोरी लीक मॉनिटरिंग ऐप को अनुत्तरदायी बना सकता है</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Out-of-Lifecycle त्रुटियों की रिपोर्ट करें</string>
|
||||
<string name="download_thumbnail_title">छायाप्रारुप लोड करें</string>
|
||||
<string name="use_inexact_seek_title">तेजी से अचूक तलाश का प्रयोग करें</string>
|
||||
<string name="use_inexact_seek_summary">अचूक खोज प्लेयर को कम परिशुद्धता के साथ तेजी से पदों की तलाश करने की अनुमति देता है</string>
|
||||
<string name="download_thumbnail_summary">बंद होने पे छोटी छवियां नहीं दिखेंगी। इससे डेटा और मेमोरी की बचत होगी। इसे बदलने से मेमोरी और डिस्क की छवि का भंडार भी साफ़ हो जाएगा।</string>
|
||||
<string name="download_thumbnail_summary">लोडिंग थंबनेल, डेटा और मेमोरी उपयोग को रोकने के लिए बंद करें। इन-मेमोरी और ऑन-डिस्क छवि कैश दोनों को बदलता है</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">छवि कैश मिटा दिया</string>
|
||||
<string name="metadata_cache_wipe_title">कैश मेटाडेटा वाइप करें</string>
|
||||
<string name="metadata_cache_wipe_summary">सभी कैश किए गए वेबपृष्ठ डेटा हटाएं</string>
|
||||
|
@ -388,67 +331,54 @@
|
|||
<string name="auto_queue_title">अगली स्ट्रीम को स्वचालित रूप से जोड़ें</string>
|
||||
<string name="auto_queue_summary">गैर-दोहराने वाली कतार में अंतिम स्ट्रीम चलाते समय संबंधित स्ट्रीम को स्वतः संलग्न करें</string>
|
||||
<string name="file">फाइल</string>
|
||||
|
||||
<string name="channels">चेनल्स</string>
|
||||
<string name="playlists">सूची</string>
|
||||
<string name="tracks">ट्रेक</string>
|
||||
<string name="users">उपभोगता</string>
|
||||
<string name="clear_views_history_title">देखे हुए वीडियो की सूची साफ करें</string>
|
||||
<string name="clear_views_history_summary">चलाये गए स्ट्रीम का इतिहास साफ करता है</string>
|
||||
<string name="delete_view_history_alert">देखे गए सभी का इतिहास साफ करें।</string>
|
||||
<string name="delete_view_history_alert">देखे गए सभी का इतिहास साफ करें\?</string>
|
||||
<string name="view_history_deleted">देखे हुए का इतिहास साफ कर दिया गया।</string>
|
||||
<string name="clear_search_history_title">ढूंढने के इतिहास को साफ करें</string>
|
||||
<string name="clear_search_history_summary">ढूंढे गए शब्दो का इतिहास साफ करता है</string>
|
||||
<string name="delete_search_history_alert">पूरे खोज इतिहास को मिटा दे \?</string>
|
||||
<string name="search_history_deleted">ढूंढने के इतिहास को साफ कर दिया।</string>
|
||||
<string name="invalid_directory">एसी कोई भी फ़ोल्डर मौजूद नहीं है</string>
|
||||
<string name="invalid_source">अमान्य फाइल/कॉन्टेंट उदभावस्थान</string>
|
||||
<string name="invalid_source">अमान्य फाइल/विषय - वस्तु का स्रोत</string>
|
||||
<string name="invalid_file">फ़ाइल मौजूद नहीं है या उसे पढ़ने या लिखने की पर्याप्त अनुमति नही़ं है</string>
|
||||
<string name="file_name_empty_error">फ़ाइल का नाम खाली नहीं हो सकता</string>
|
||||
<string name="error_occurred_detail">एक भूल हुई: %1$s</string>
|
||||
<string name="no_streams_available_download">डाउनलोड करने के लिए कोई स्ट्रीम उपलब्ध नही है</string>
|
||||
|
||||
<string name="one_item_deleted">एक चीज़ साफ कर दी गई।</string>
|
||||
|
||||
<string name="toast_no_player">इस फ़ाइल को चलाने के लिए कोई ऐप स्थापित नही है</string>
|
||||
|
||||
<string name="privacy_policy_title">न्यूपाइप की गोपनीयता नीति</string>
|
||||
<string name="privacy_policy_encouragement">न्यूपाइप परियोजना आपकी गोपनीयता को बहोत गंभीर रूप से लेता है। इसलिए, ऐप आपकी अनुमति के बिना कोई डेटा जमा नही करता।
|
||||
\nन्यूपाइप की गोपनीयता नीति विस्तार से समज़ाती है कि कोनसा डेटा भेजा या संग्रह किया जाता है जब आप क्रेश विवरण भेजते है।</string>
|
||||
<string name="read_privacy_policy">गोपनीयता नीति पढ़े</string>
|
||||
<string name="import_settings">क्या आप सेटिंग्स भी आयात करना चाहते है?</string>
|
||||
|
||||
<string name="preferred_open_action_settings_title">पसंदीदा \'खोलने पर\' करवाई</string>
|
||||
<string name="preferred_open_action_settings_summary">सामग्री खोलते समय डिफ़ॉल्ट कारवाही — %s</string>
|
||||
|
||||
<string name="caption_setting_title">केप्सन</string>
|
||||
<string name="caption_setting_description">प्लेयर केप्शन के शब्दों का परिमाण और पृष्ठभूमि शैलियो को बदले। लागू करने के लिए ऐप को पुनः प्रारम्भ करना जरूरी है।</string>
|
||||
|
||||
<string name="import_export_title">आयात/निर्यात</string>
|
||||
<string name="import_title">आयात</string>
|
||||
<string name="import_from">से आयात करे</string>
|
||||
<string name="export_to">पर निर्यात करे</string>
|
||||
|
||||
<string name="import_ongoing">आयात किया जा रहा है…</string>
|
||||
<string name="export_ongoing">निर्यात किया जा रहा है…</string>
|
||||
|
||||
<string name="import_file_title">फाइल आयात करे</string>
|
||||
<string name="previous_export">पहले वाला निर्यात</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">सब्सक्रिप्शन आयात नही कर सके</string>
|
||||
<string name="subscriptions_export_unsuccessful">सब्सक्रिप्शन निर्यात नही कर सके</string>
|
||||
|
||||
<string name="import_youtube_instructions">निर्यात की गई फाइल को डाउनलोड करके यूट्यूब सब्सक्रिप्शन को आयात करे:
|
||||
\n
|
||||
\n1. इस URL पर जाए: %1$s
|
||||
\n2. जब कहा जाए, लॉगिन करे
|
||||
\n3. एक डाउनलोड शुरू होना चाहिए (यही निर्यात की गई फाइल है)</string>
|
||||
<string name="import_soundcloud_instructions_hint">आपका आई डी, soundcloud.com/yourid</string>
|
||||
|
||||
<string name="import_network_expensive_warning">ध्यान रखे, यह तरीका नेटवर्क साधनो के लिए मंहगा हो सकता है।
|
||||
\n
|
||||
\nक्या आप आगे बढ़ना चाहते है?</string>
|
||||
|
||||
<string name="playback_speed_control">चलाने की गति के नियंत्रण</string>
|
||||
<string name="playback_tempo">गति</string>
|
||||
<string name="playback_pitch">ऊंचाई</string>
|
||||
|
@ -456,10 +386,8 @@
|
|||
<string name="skip_silence_checkbox">खामोशी के समय तेज़ी से आगे बढ़े</string>
|
||||
<string name="playback_step">कदम</string>
|
||||
<string name="playback_reset">रिसेट</string>
|
||||
|
||||
<string name="accept">स्वीकारे</string>
|
||||
<string name="decline">अस्वीकार करे</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">असीमित</string>
|
||||
<string name="limit_mobile_data_usage_title">मोबाइल डेटा उपयोग करते समय रेसॉल्युसेन मर्यादित करे</string>
|
||||
<string name="minimize_on_exit_title">ऐप बदलते समय मिनिमाइज करे</string>
|
||||
|
@ -468,4 +396,9 @@
|
|||
<string name="minimize_on_exit_background_description">पृष्ठभूमि प्लेयर जैसे मिनिमाइज करे</string>
|
||||
<string name="minimize_on_exit_popup_description">पॉप अप प्लेयर जैसे मिनिमाइज करे</string>
|
||||
<string name="app_license">न्यूपाइप एक काॅपीलेफ़्ट फ़्री साॅफ़्टवेर है: इसे आप अपनी इच्छा के अनुसार इस्तेमाल, जाँच, बाँट तथा और बेहतर बना सकते है। खास तौर पर आप इसे फ़्री साॅफ़्टवेर फ़ाउंडेशन के द्वारा जारी जीएनयू जनरल पब्लिक लाइसेंस के तीसरे या उसके बाद आने वाले कोई भी वर्णन के शर्तों के मुताबिक फिर से बाँट या बदल सकते हैं।</string>
|
||||
<string name="unsubscribe">सदस्यता वापस ले ली</string>
|
||||
<string name="tab_new">नया टॅब</string>
|
||||
<string name="tab_choose">टॅब चुने</string>
|
||||
<string name="volume_gesture_control_title">वॉल्यूम नियंत्रण</string>
|
||||
<string name="enqueue">कतार</string>
|
||||
</resources>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources><string name="main_bg_subtitle">Dodirnite pretragu za početak</string>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="main_bg_subtitle">Dodirnite pretragu za početak</string>
|
||||
<string name="view_count_text">%1$s pregleda</string>
|
||||
<string name="upload_date_text">Objavljeno %1$s</string>
|
||||
<string name="no_player_found">Reproduktor za stream nije pronađen. Želite li instalirati VLC?</string>
|
||||
|
@ -16,7 +17,7 @@
|
|||
<string name="choose_browser">Izaberi pretraživač</string>
|
||||
<string name="screen_rotation">rotacija</string>
|
||||
<string name="use_external_video_player_title">Koristi vanjski reproduktor videozapisa</string>
|
||||
<string name="use_external_video_player_summary">Neke razlučivosti NEĆE imati zvuk kad je ova opcija omogućena</string>
|
||||
<string name="use_external_video_player_summary">Uklanja zvuk na NEKIM rezolucijama</string>
|
||||
<string name="use_external_audio_player_title">Koristi vanjski reproduktor za zvuk</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe skočni prozor</string>
|
||||
<string name="subscribe_button_title">Pretplati se</string>
|
||||
|
@ -24,24 +25,18 @@
|
|||
<string name="channel_unsubscribed">Pretplata na kanalu otkazana</string>
|
||||
<string name="subscription_change_failed">Nije moguće promijeniti pretplatu</string>
|
||||
<string name="subscription_update_failed">Nije moguće osvježiti pretplatu</string>
|
||||
|
||||
<string name="tab_main">Početna</string>
|
||||
<string name="tab_subscriptions">Pretplate</string>
|
||||
|
||||
<string name="fragment_whats_new">Što je novo</string>
|
||||
|
||||
<string name="controls_background_title">Pozadina</string>
|
||||
<string name="controls_popup_title">Skočni prozor</string>
|
||||
|
||||
<string name="download_path_title">Put za preuzimanje videozapisa</string>
|
||||
<string name="download_path_summary">Put za spremanje videozapisa u</string>
|
||||
<string name="download_path_dialog_title">Unesi put za preuzimanje videozapisa</string>
|
||||
|
||||
<string name="download_path_audio_title">Put za preuzimanje zvuka</string>
|
||||
<string name="download_path_audio_summary">Put za spremanje preuzetog zvuka u</string>
|
||||
<string name="download_path_audio_title">Mapa za preuzimanje zvuka</string>
|
||||
<string name="download_path_audio_summary">Preuzeti zvuk je spremljen ovdje</string>
|
||||
<string name="download_path_audio_dialog_title">Unesi put za preuzimanje zvučne datoteke</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">Auto. reprod. kada je NewPipe pozvan iz druge apl.</string>
|
||||
<string name="autoplay_by_calling_app_title">Automatska reprodukcija</string>
|
||||
<string name="autoplay_by_calling_app_summary">Reproducira videozapis kad je NewPipe pozvan iz druge aplikacije</string>
|
||||
<string name="default_resolution_title">Zadana razlučivost</string>
|
||||
<string name="default_popup_resolution_title">Zadana razlučivost skočnog prozora</string>
|
||||
|
@ -66,16 +61,13 @@
|
|||
<string name="show_search_suggestions_summary">Prikaži prijedloge pri traženju</string>
|
||||
<string name="enable_search_history_title">Povijest pretraživanja</string>
|
||||
<string name="enable_search_history_summary">Svaku pretragu spremi lokalno</string>
|
||||
<string name="enable_watch_history_title">Povijest</string>
|
||||
<string name="enable_watch_history_title">Povijest & Predmemorija</string>
|
||||
<string name="enable_watch_history_summary">Pratite pogledane videozapise</string>
|
||||
<string name="resume_on_audio_focus_gain_title">Nastavi nakon dobivanja fokusa</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Nastavi reproducirati nakon prekidanja (npr. telefonski pozivi)</string>
|
||||
|
||||
|
||||
<string name="download_dialog_title">Preuzmi</string>
|
||||
|
||||
<string name="next_video_title">Sljedeći videozapis</string>
|
||||
<string name="show_next_and_similar_title">Prikaži \'sljedeće\' i \'slične\' videozapise</string>
|
||||
<string name="next_video_title">Sljedeće</string>
|
||||
<string name="show_next_and_similar_title">Prikaži \'Sljedeće\' i \'Slične\' videozapise</string>
|
||||
<string name="url_not_supported_toast">URL nije podržan</string>
|
||||
<string name="content_language_title">Zadani jezik sadržaja</string>
|
||||
<string name="settings_category_video_audio_title">Video i zvuk</string>
|
||||
|
@ -88,7 +80,7 @@
|
|||
<string name="content">Sadržaj</string>
|
||||
<string name="show_age_restricted_content_title">Prikaži eksplicitni sadržaj</string>
|
||||
<string name="video_is_age_restricted">Videozapis je dobno ograničen. Dopuštanje takvog sadržaja moguće je u postavkama.</string>
|
||||
<string name="duration_live">uživo</string>
|
||||
<string name="duration_live">UŽIVO</string>
|
||||
<string name="downloads">Preuzimanja</string>
|
||||
<string name="downloads_title">Preuzimanja</string>
|
||||
<string name="error_report_title">Prijavi grešku</string>
|
||||
|
@ -102,7 +94,6 @@
|
|||
<string name="clear">Očisti</string>
|
||||
<string name="popup_resizing_indicator_title">Mijenjanje veličine</string>
|
||||
<string name="best_resolution">Najbolja razlučivost</string>
|
||||
|
||||
<string name="general_error">Greška</string>
|
||||
<string name="network_error">Greška u mreži</string>
|
||||
<string name="could_not_load_thumbnails">Nije moguće učitati sve ikone</string>
|
||||
|
@ -112,7 +103,7 @@
|
|||
<string name="content_not_available">Sadržaj nije dostupan</string>
|
||||
<string name="blocked_by_gema">Blokirano od GEMA-e</string>
|
||||
<string name="could_not_setup_download_menu">Nije moguće postaviti izbornik za preuzimanje</string>
|
||||
<string name="live_streams_not_supported">Ovo je PRIJENOS UŽIVO, koji još nije podržan.</string>
|
||||
<string name="live_streams_not_supported">Prijenos uživo još nije podržan</string>
|
||||
<string name="could_not_get_stream">Nije moguće dobaviti stream</string>
|
||||
<string name="could_not_load_image">Nije moguće učitati sliku</string>
|
||||
<string name="app_ui_crash">Aplikacija/UI se srušio</string>
|
||||
|
@ -125,8 +116,6 @@
|
|||
<string name="info_labels">Što:\\nRequest:\\nContent Jezik:\\nService:\\nGMT Vrijeme:\\nPackage:\\nVersion:\\nOS version:</string>
|
||||
<string name="your_comment">Vaš komentar (na engleskom):</string>
|
||||
<string name="error_details_headline">Detalji:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">Sličica pregleda videozapisa</string>
|
||||
<string name="detail_thumbnail_view_description">Sličica pregleda videozapisa</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Profilna slika prenositelja</string>
|
||||
|
@ -136,31 +125,22 @@
|
|||
<string name="use_tor_summary">(Eksperimentalno) Prisili promet preuzimanja kroz Tor radi povećane privatnosti (streamanje videozapisa još nije podržano).</string>
|
||||
<string name="report_error">Prijavi grešku</string>
|
||||
<string name="user_report">Korisničke prijave</string>
|
||||
|
||||
<string name="err_dir_create">Nije moguće napraviti direktorij za preuzimanje \'%1$s\'</string>
|
||||
<string name="info_dir_created">Napravljen direktorij za preuzimanje \'%1$s\'</string>
|
||||
|
||||
<string name="video">Videozapis</string>
|
||||
<string name="audio">Zvuk</string>
|
||||
<string name="retry">Ponovno pokušaj</string>
|
||||
<string name="storage_permission_denied">Dozvola za pisanje po pohrani je odbijena</string>
|
||||
<string name="use_old_player_title">Koristi stari reproduktor</string>
|
||||
<string name="use_old_player_summary">Stari ugrađeni Mediaframework reproduktor</string>
|
||||
|
||||
|
||||
<string name="short_thousand">tis</string>
|
||||
<string name="short_million">mil</string>
|
||||
<string name="short_billion">mlrd</string>
|
||||
|
||||
<string name="start">Počni</string>
|
||||
<string name="pause">Pauziraj</string>
|
||||
<string name="view">Reproduciraj</string>
|
||||
<string name="delete">Izbriši</string>
|
||||
<string name="checksum">Kontrolna suma</string>
|
||||
|
||||
<string name="add">Novi zadatak</string>
|
||||
<string name="finish">U redu</string>
|
||||
|
||||
<string name="msg_name">Naziv datoteke</string>
|
||||
<string name="msg_threads">Niti</string>
|
||||
<string name="msg_error">Greška</string>
|
||||
|
@ -174,19 +154,15 @@
|
|||
<string name="no_available_dir">Molimo odaberite dostupnu mapu za preuzimanje</string>
|
||||
<string name="msg_popup_permission">Ova dozvola je potrebna za
|
||||
\notvaranje skočnog prozora</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA zadatak</string>
|
||||
<string name="recaptcha_request_toast">Traži se reCAPTCHA zadatak</string>
|
||||
|
||||
<string name="settings_category_downloads_title">Preuzimanja</string>
|
||||
<string name="settings_file_charset_title">Dozvoljeni znakovi u nazivima datoteka</string>
|
||||
<string name="settings_file_replacement_character_summary">Nedozvoljeni znakovi su zamjenjeni ovima</string>
|
||||
<string name="settings_file_replacement_character_title">Znak za zamjenu</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Slova i brojevi</string>
|
||||
<string name="charset_most_special_characters">Posebni znakovi</string>
|
||||
|
||||
<string name="title_activity_about">O NewPipeu</string>
|
||||
<string name="action_settings">Postavke</string>
|
||||
<string name="action_about">O aplikaciji</string>
|
||||
|
@ -203,61 +179,50 @@
|
|||
<string name="contribution_encouragement">Ako imate ideja za prijevod, promjene u dizajnu, čišćenje koda ili neke veće promjene u kodu, pomoć je uvijek dobro došla. Što više radimo, to bolji postajemo!</string>
|
||||
<string name="read_full_license">Pročitaj licencu</string>
|
||||
<string name="contribution_title">Doprinos</string>
|
||||
|
||||
<string name="title_activity_history">Povijest</string>
|
||||
<string name="title_history_search">Pretraživano</string>
|
||||
<string name="title_history_view">Gledano</string>
|
||||
<string name="history_disabled">Povijest ugašena</string>
|
||||
<string name="history_disabled">Povijest je ugašena</string>
|
||||
<string name="action_history">Povijest</string>
|
||||
<string name="history_empty">Povijest je prazna</string>
|
||||
<string name="history_cleared">Povijest očišćena</string>
|
||||
|
||||
<string name="notification_channel_name">NewPipe obavijest</string>
|
||||
<string name="notification_channel_name">NewPipe obavijest</string>
|
||||
<string name="notification_channel_description">Obavijesti za NewPipe pozadinske i skočne reproduktore</string>
|
||||
|
||||
<string name="settings_category_player_title">Reproduktor</string>
|
||||
<string name="settings_category_player_behavior_title">Ponašanje</string>
|
||||
<string name="settings_category_history_title">Povijest</string>
|
||||
<string name="settings_category_history_title">Povijest & predmemorija</string>
|
||||
<string name="playlist">Popis naslova</string>
|
||||
<string name="undo">Poništi</string>
|
||||
|
||||
<string name="search_no_results">Nema rezultata</string>
|
||||
<string name="empty_subscription_feed_subtitle">Ovdje nema ništa osim cvrčaka</string>
|
||||
|
||||
<string name="no_subscribers">Nema pretplatnika</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s pretplatnik</item>
|
||||
<item quantity="few">%s pretplatnika</item>
|
||||
<item quantity="other">%s pretplatnika</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s pretplatnik</item>
|
||||
<item quantity="few">%s pretplatnika</item>
|
||||
<item quantity="other">%s pretplatnika</item>
|
||||
</plurals>
|
||||
<string name="no_views">Nema pregleda</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s pregled</item>
|
||||
<item quantity="few">%s pregleda</item>
|
||||
<item quantity="other">%s pregledi</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s pregled</item>
|
||||
<item quantity="few">%s pregleda</item>
|
||||
<item quantity="other">%s pregledi</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Nema videozapisa</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">%s video</item>
|
||||
<item quantity="few">%s videozapisa</item>
|
||||
<item quantity="other">%s videozapisi</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s video</item>
|
||||
<item quantity="few">%s videozapisa</item>
|
||||
<item quantity="other">%s videozapisi</item>
|
||||
</plurals>
|
||||
<string name="item_deleted">Stavka je izbrisana</string>
|
||||
<string name="background_player_append">U redu čekanja za reprod. u pozadini</string>
|
||||
<string name="background_player_append">U redu čekanja za reprod. u pozadini</string>
|
||||
<string name="play_all">Reproduciraj sve</string>
|
||||
|
||||
<string name="player_stream_failure">Nije moguće reproducirati ovaj stream</string>
|
||||
<string name="player_unrecoverable_failure">Dogodila se neoporavljiva pogreška reproduktora</string>
|
||||
<string name="player_recoverable_failure">Oporavljanje od pogreške reproduktora</string>
|
||||
|
||||
<string name="show_hold_to_append_title">Prikaži savjet za držanje</string>
|
||||
<string name="show_hold_to_append_summary">Prikažite savjet kada je pritisnut gumb za pozadinsku ili skočnu reprodukciju na stranici detalja videozapisa</string>
|
||||
<string name="popup_playing_append">U redu čekanja za skočnu reprodukciju</string>
|
||||
<string name="delete_item_search_history">Želite li izbrisati ovu stavku iz povijesti pretraživanja?</string>
|
||||
|
||||
<string name="main_page_content">Sadržaj</string>
|
||||
<string name="blank_page_summary">Prazna stranica</string>
|
||||
<string name="kiosk_page_summary">Kiosk stranica</string>
|
||||
|
@ -267,78 +232,61 @@
|
|||
<string name="select_a_channel">Odaberite kanal</string>
|
||||
<string name="no_channel_subscribed_yet">Niste pretplaćeni na nijedan kanal</string>
|
||||
<string name="select_a_kiosk">Odaberite kiosk</string>
|
||||
|
||||
<string name="kiosk">Nazivi kioska</string>
|
||||
<string name="trending">U trendu</string>
|
||||
<string name="top_50">Vrh 50</string>
|
||||
<string name="new_and_hot">Novo i popularno</string>
|
||||
<string name="title_activity_background_player">Lista čekanja</string>
|
||||
<string name="title_activity_popup_player">Skočni reproduktcija</string>
|
||||
<string name="title_activity_background_player">Pozadinski player</string>
|
||||
<string name="title_activity_popup_player">Skočni reproduktor</string>
|
||||
<string name="play_queue_remove">Ukloni</string>
|
||||
<string name="play_queue_stream_detail">Detalji</string>
|
||||
<string name="play_queue_audio_settings">Postavke zvuka</string>
|
||||
<string name="hold_to_append">Zadržite za dodavanje u red čekanja</string>
|
||||
<string name="unknown_content">[Nepoznato]</string>
|
||||
|
||||
<string name="unknown_content">[Nepoznato]</string>
|
||||
<string name="donation_title">Doniraj</string>
|
||||
<string name="website_title">Web stranica</string>
|
||||
<string name="start_here_on_main">Ovdje započni reprodukciju</string>
|
||||
<string name="start_here_on_background">Ovdje započni repr. u pozadini</string>
|
||||
<string name="enqueue_on_background">Dodaj na red čekanja u pozadini</string>
|
||||
<string name="enqueue_on_popup">Dodaj na red u skočnom prozoru</string>
|
||||
<string name="enqueue_on_popup">Dodaj na red u novom skočnom prozoru</string>
|
||||
<string name="start_here_on_popup">Započni ovdje u Skočnom prozoru</string>
|
||||
|
||||
<string name="drawer_open">Otvori ladicu</string>
|
||||
<string name="drawer_close">Zatvori ladicu</string>
|
||||
<string name="drawer_header_action_paceholder_text">Nešto će zasigurno doći ovdje :D</string>
|
||||
|
||||
|
||||
<string name="drawer_header_action_paceholder_text">Nešto će se uskoro pojaviti :D</string>
|
||||
<string name="video_player">Video reprodukcija</string>
|
||||
<string name="background_player">Pozadinska reprodukcija</string>
|
||||
<string name="popup_player">Skočna reprodukcija</string>
|
||||
<string name="always_ask_open_action">Uvjek pitaj</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Dohvaćam informacije…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Odabrani sadržaj se učitava</string>
|
||||
|
||||
<string name="create_playlist">Napravi novu reprodukcijsku listu</string>
|
||||
<string name="delete_playlist">Izbriši reprodukcijsku listu</string>
|
||||
<string name="rename_playlist">Preimenuj reprodukcijsku listu</string>
|
||||
<string name="create_playlist">Nova reprodukcijska lista</string>
|
||||
<string name="delete_playlist">Izbriši</string>
|
||||
<string name="rename_playlist">Preimenuj</string>
|
||||
<string name="playlist_name_input">Ime liste</string>
|
||||
<string name="append_playlist">Dodaj na reprodukcijsku listu</string>
|
||||
<string name="set_as_playlist_thumbnail">Postavi kao sliku na listu</string>
|
||||
|
||||
<string name="bookmark_playlist">Markirajte reprodukcijsku listu</string>
|
||||
<string name="unbookmark_playlist">"Odmarkirajte "</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Želite li izbrisati listu?</string>
|
||||
<string name="playlist_creation_success">Reprodukcijska lista je kreirana</string>
|
||||
<string name="playlist_add_stream_success">Dodano na listuu</string>
|
||||
<string name="playlist_thumbnail_change_success">Slika liste se promjenila</string>
|
||||
<string name="playlist_delete_failure">Greška prilikom brisanja liste</string>
|
||||
|
||||
<string name="playlist_add_stream_success">Dodano na listu</string>
|
||||
<string name="playlist_thumbnail_change_success">Slika liste se promjenila.</string>
|
||||
<string name="playlist_delete_failure">Greška prilikom brisanja liste.</string>
|
||||
<string name="caption_none">Bez naslova</string>
|
||||
|
||||
<string name="resize_fit">Podesno</string>
|
||||
<string name="resize_fill">Ispuniti</string>
|
||||
<string name="resize_zoom">Povećaj</string>
|
||||
|
||||
<string name="caption_auto_generated">Auto generirano</string>
|
||||
<string name="caption_font_size_settings_title">Veličina fonta naslova</string>
|
||||
<string name="smaller_caption_font_size">Manji font</string>
|
||||
<string name="normal_caption_font_size">Normalni font</string>
|
||||
<string name="larger_caption_font_size">Veći font</string>
|
||||
|
||||
<string name="enable_leak_canary_title">Omogući \"LeakCanary\"</string>
|
||||
<string name="enable_leak_canary_summary">Monitoring curenja memorije može uzrokovati greške u radu aplikacije prilikom odlaganje gomile</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Izvijestite o pogreškama izvan životnog ciklusa</string>
|
||||
<string name="show_info">Prikaži informacije</string>
|
||||
|
||||
<string name="tab_bookmarks">Oznake</string>
|
||||
|
||||
<string name="tab_bookmarks">Označene Liste za reprodukciju</string>
|
||||
<string name="controls_add_to_playlist_title">Dodaj u</string>
|
||||
|
||||
<string name="download_thumbnail_title">Učitaj slike</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Slikovna predmemorija obrisana</string>
|
||||
<string name="metadata_cache_wipe_title">Obriši predmemorijsku metupodataka</string>
|
||||
|
@ -350,38 +298,32 @@
|
|||
<string name="always">Uvijek</string>
|
||||
<string name="just_once">Samo jednom</string>
|
||||
<string name="file">Datoteka</string>
|
||||
|
||||
<string name="switch_to_background">Prijeđi na pozadinu</string>
|
||||
<string name="switch_to_popup">Prijeđi na skočni prozor</string>
|
||||
<string name="switch_to_main">Prijeđi na glavni</string>
|
||||
|
||||
<string name="import_data_title">Uvoz baze podataka</string>
|
||||
<string name="export_data_title">Izvoz baze podataka</string>
|
||||
<string name="import_data_summary">Poništava vašu trenutnu povijest i pretplate</string>
|
||||
<string name="export_data_summary">Izvoz povijesti, pretplata i playlisti</string>
|
||||
<string name="clear_views_history_title">Očisti povijest gledanja</string>
|
||||
<string name="clear_views_history_summary">Briše povijest reproduciranih streamova</string>
|
||||
<string name="delete_view_history_alert">Obriši cijelu povijest gledanja.</string>
|
||||
<string name="delete_view_history_alert">Obriši cijelu povijest gledanja\?</string>
|
||||
<string name="view_history_deleted">Povijest gledanja izbrisana.</string>
|
||||
<string name="clear_search_history_title">Obriši povijest pretraživanja</string>
|
||||
<string name="delete_search_history_alert">Obriši cijelu povijest pretraživanja.</string>
|
||||
<string name="delete_search_history_alert">Obriši cijelu povijest pretraživanja\?</string>
|
||||
<string name="search_history_deleted">Povijest pretraživanja obrisana.</string>
|
||||
<string name="invalid_url_toast">Neispravan URL</string>
|
||||
<string name="invalid_directory">Nevažeći direktorij</string>
|
||||
<string name="invalid_directory">Nema takve mape</string>
|
||||
<string name="file_name_empty_error">Naziv datoteke ne može biti prazan</string>
|
||||
<string name="error_occurred_detail">Dogodila se greška: %1$s</string>
|
||||
<string name="detail_drag_description">Povucite za promjenu redoslijeda</string>
|
||||
|
||||
<string name="create">Stvori</string>
|
||||
<string name="delete_one">Izbriši jedan</string>
|
||||
<string name="delete_all">Izbriši sve</string>
|
||||
<string name="dismiss">Odbaci</string>
|
||||
<string name="rename">Preimenuj</string>
|
||||
|
||||
<string name="one_item_deleted">1 stavka izbrisana.</string>
|
||||
|
||||
<string name="toast_no_player">Nijedna aplikacija nije instalirana za reprodukciju te datoteke</string>
|
||||
|
||||
<string name="give_back">Vrati</string>
|
||||
<string name="website_encouragement">Posjetite web stranicu NewPipe za više informacija i vijesti.</string>
|
||||
<string name="privacy_policy_title">NewPipeova pravila o privatnosti</string>
|
||||
|
@ -390,52 +332,141 @@
|
|||
<string name="delete_all_history_prompt">Jeste li sigurni da želite izbrisati sve stavke iz povijesti?</string>
|
||||
<string name="title_last_played">Zadnje svirano</string>
|
||||
<string name="title_most_played">Najviše svirano</string>
|
||||
|
||||
<string name="export_complete_toast">Izvoz završen</string>
|
||||
<string name="import_complete_toast">Uvoz završen</string>
|
||||
<string name="no_valid_zip_file">Nema važeće ZIP datoteke</string>
|
||||
<string name="could_not_import_all_files">Upozorenje: Nije moguće uvesti sve datoteke.</string>
|
||||
<string name="override_current_data">Ovo će poništiti vaše trenutne postavke.</string>
|
||||
<string name="import_settings">Želite li također uvesti postavke?</string>
|
||||
|
||||
<string name="import_export_title">Uvoz/Izvoz</string>
|
||||
<string name="import_title">Uvoz</string>
|
||||
<string name="import_from">Uvoz iz</string>
|
||||
<string name="export_to">Izvoz u</string>
|
||||
|
||||
<string name="import_ongoing">Uvoz…</string>
|
||||
<string name="export_ongoing">Izvoz…</string>
|
||||
|
||||
<string name="import_file_title">Uvoz datoteke</string>
|
||||
<string name="previous_export">Prethodni izvozi</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Nije moguće uvesti pretplatnike</string>
|
||||
<string name="subscriptions_export_unsuccessful">Nije moguće izvesti pretplatnike</string>
|
||||
|
||||
<string name="import_youtube_instructions">Uvezite YouTube pretplatnike preuzimanjem izvozne datoteke:
|
||||
\n
|
||||
\n1. Idite na ovaj URL: %1%s
|
||||
\n2. Ulogirajte se
|
||||
<string name="import_youtube_instructions">Uvezite YouTube pretplatnike preuzimanjem izvozne datoteke:
|
||||
\n
|
||||
\n1. Idite na ovaj URL: %1$s
|
||||
\n2. Ulogirajte se
|
||||
\n3. Preuzimanje bi trebalo početi (to je izvozna datoteka)</string>
|
||||
<string name="import_soundcloud_instructions_hint">vašID, soundcloud.com/vašID</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Uzmite u obzir da ova operacija može uzrokovat veliku potrošnju prometa.
|
||||
\n
|
||||
\nŽelite li nastaviti?</string>
|
||||
|
||||
<string name="playback_speed_control">Kontrole brzine reprodukcije</string>
|
||||
<string name="skip_silence_checkbox">Premotaj naprijed tijekom šutnje</string>
|
||||
<string name="playback_step">Korak</string>
|
||||
<string name="playback_reset">Resetiraj</string>
|
||||
|
||||
<string name="accept">Prihvati</string>
|
||||
<string name="decline">Odbij</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Bez ograničenja</string>
|
||||
<string name="limit_mobile_data_usage_title">Ograniči rezoluciju tijekom korištenja mobilnih podataka</string>
|
||||
<string name="minimize_on_exit_none_description">Nijedan</string>
|
||||
<string name="no_player_found_toast">Reproduktor za stream nije pronađen (možete instalirati VLC za reprodukciju)</string>
|
||||
<string name="controls_download_desc">Preuzmite datoteku za stream.</string>
|
||||
<string name="no_player_found_toast">Reproduktor za stream nije pronađen (možete instalirati VLC za reprodukciju).</string>
|
||||
<string name="controls_download_desc">Preuzmite datoteku za stream</string>
|
||||
<string name="use_inexact_seek_title">Koristi brzo netočno premotavanje</string>
|
||||
<string name="use_inexact_seek_summary">Netočno premotavanje omogućava reproduktoru da premota na mjesto brže uz manju preciznost</string>
|
||||
</resources>
|
||||
<string name="unsubscribe">Otkaži pretplatu</string>
|
||||
<string name="tab_new">Nova kartica</string>
|
||||
<string name="tab_choose">Odaberi karticu</string>
|
||||
<string name="settings_category_updates_title">Ažuriranja</string>
|
||||
<string name="events">Događaji</string>
|
||||
<string name="file_deleted">Datoteka obrisana</string>
|
||||
<string name="app_update_notification_channel_description">Obavijest za novu verziju NewPipe-a</string>
|
||||
<string name="clear_search_history_summary">Briše povijest ključnih riječi pretraživanja</string>
|
||||
<string name="download_to_sdcard_error_title">Vanjska pohrana nije dostupna</string>
|
||||
<string name="updates_setting_title">Ažuriranja</string>
|
||||
<string name="updates_setting_description">Prikažite obavijest kada je dostupna nova verzija aplikacije</string>
|
||||
<string name="list">Lista</string>
|
||||
<string name="grid">Rešetka</string>
|
||||
<string name="switch_view">Promijeni prikaz</string>
|
||||
<string name="app_update_notification_content_title">NewPipe dostupno ažuriranje!</string>
|
||||
<string name="app_update_notification_content_text">Dodirnite za preuzimanje</string>
|
||||
<string name="download_failed">Preuzimanje nije uspjelo</string>
|
||||
<string name="download_finished">Preuzimanje gotovo</string>
|
||||
<string name="show_error">Prikaži pogrešku</string>
|
||||
<string name="download_thumbnail_summary">Isključite kako biste spriječili učitavanje sličica, spremanje podataka i korištenja memorije. Promjene čiste predmemoriju i predmemoriju slika.</string>
|
||||
<string name="metadata_cache_wipe_summary">Uklonite sve podatke iz privremenih web-stranica</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">Metapodaci su izbrisani</string>
|
||||
<string name="auto_queue_title">Automatski dodaj u red sljedeće strujanje</string>
|
||||
<string name="auto_queue_summary">Automatsko dodavanje povezanog videozapisa tijekom reprodukcije posljednjeg videozapisa u neponavljajućem redu.</string>
|
||||
<string name="volume_gesture_control_title">Kontrola glasnoće pomoću gesti</string>
|
||||
<string name="volume_gesture_control_summary">Koristi gesture za kontrolu glasnoće</string>
|
||||
<string name="brightness_gesture_control_title">Kontrola svjetline pomoću gesti</string>
|
||||
<string name="brightness_gesture_control_summary">Koristi gesture za kontrolu svjetline</string>
|
||||
<string name="default_content_country_title">Zadana zemlja sadržaja</string>
|
||||
<string name="settings_category_debug_title">Otkrivanje grešaka</string>
|
||||
<string name="app_update_notification_channel_name">Obavijest o ažuriranju aplikacije</string>
|
||||
<string name="toggle_orientation">Uključite ili isključite orijentaciju</string>
|
||||
<string name="download_to_sdcard_error_message">Preuzimanje na vanjsku SD karticu još nije moguće. Poništite lokaciju mape za preuzimanje\?</string>
|
||||
<string name="external_player_unsupported_link_type">Vanjski playeri ne podržavaju ove vrste veza</string>
|
||||
<string name="video_streams_empty">Nije pronađen nijedan videozapis</string>
|
||||
<string name="audio_streams_empty">Nije pronađen nijedan zvuk</string>
|
||||
<string name="invalid_source">Nema takve datoteke/izvora sadržaja</string>
|
||||
<string name="invalid_file">Datoteka ne postoji ili joj nedostaje dopuštenje za čitanje ili pisanje</string>
|
||||
<string name="no_streams_available_download">Nema dostupnih videozapisa za preuzimanje</string>
|
||||
<string name="saved_tabs_invalid_json">Pomoću zadanih kartica pojavljuje se pogreška prilikom čitanja spremljenih kartica</string>
|
||||
<string name="restore_defaults">Vratiti zadane</string>
|
||||
<string name="restore_defaults_confirmation">Želite li vratiti zadane postavke\?</string>
|
||||
<string name="subscribers_count_not_available">Broj pretplatnika nije dostupan</string>
|
||||
<string name="donation_encouragement">NewPipe razvijaju volonteri koji provode vrijeme donoseći vam najbolje iskustvo. Vratite im kako biste programerima učinili da NewPipe bude još bolji dok uživate u šalici kave.</string>
|
||||
<string name="main_page_content_summary">Koje su kartice prikazane na glavnoj stranici</string>
|
||||
<string name="selection">Izbor</string>
|
||||
<string name="conferences">Konferencije</string>
|
||||
<string name="preferred_open_action_settings_title">Preferirana \'otvori\' akcija</string>
|
||||
<string name="preferred_open_action_settings_summary">Zadana radnja pri otvaranju sadržaja — %s</string>
|
||||
<string name="caption_setting_title">Podnaslovi</string>
|
||||
<string name="caption_setting_description">Izmijenite skalu teksta naslova player-a i pozadinske stilove. Potrebno je ponovno pokretanje aplikacije kako bi stupilo na snagu.</string>
|
||||
<string name="enable_disposed_exceptions_summary">Prisilno izvješćivanje o greškama Rx-a koje se ne mogu isporučiti izvan \'fragmenta\' ili životnog ciklusa aktivnosti nakon odlaganja</string>
|
||||
<string name="import_soundcloud_instructions">Uvezite SoundCloud profil tako da upišete URL ili svoj ID:
|
||||
\n
|
||||
\n1. Omogućite \"način rada na radnoj površini\" u web-pregledniku (stranica nije dostupna na mobilnim uređajima)
|
||||
\n2. Idite na ovaj URL: %1$s
|
||||
\n3. Ulogirajte se
|
||||
\n4. Kopirajte URL profila na koji ste preusmjereni.</string>
|
||||
<string name="playback_tempo">Tempo</string>
|
||||
<string name="playback_pitch">Visina tona</string>
|
||||
<string name="unhook_checkbox">Prekini vezu (može uzrokovati izobličenje)</string>
|
||||
<string name="minimize_on_exit_title">Minimiziraj prilikom mjenjanje aplikacija</string>
|
||||
<string name="minimize_on_exit_summary">Radnja prilikom prebacivanja na drugu aplikaciju iz glavnog videoplayer-a — %s</string>
|
||||
<string name="minimize_on_exit_background_description">Minimiziraj na pozadinski player</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimiziraj na skočni player</string>
|
||||
<string name="list_view_mode">Način prikaza popisa</string>
|
||||
<string name="auto">Automatski</string>
|
||||
<string name="missions_header_finished">Gotovo</string>
|
||||
<string name="missions_header_pending">U redu za čekanje</string>
|
||||
<string name="paused">pauzirano</string>
|
||||
<string name="queued">Na redu za čekanje</string>
|
||||
<string name="post_processing">naknadna obrada</string>
|
||||
<string name="enqueue">Red</string>
|
||||
<string name="permission_denied">Sustav je odbio radnju</string>
|
||||
<string name="download_finished_more">%s preuzimanja dovršeno</string>
|
||||
<string name="generate_unique_name">Generirajte jedinstveni naziv</string>
|
||||
<string name="overwrite">Piši preko</string>
|
||||
<string name="overwrite_unrelated_warning">Datoteka s tim nazivom već postoji</string>
|
||||
<string name="overwrite_finished_warning">Preuzeta datoteka s tim nazivom već postoji</string>
|
||||
<string name="download_already_running">U tijeku je preuzimanje s ovim nazivom</string>
|
||||
<string name="label_code">Kod</string>
|
||||
<string name="error_path_creation">Datoteku nije moguće izraditi</string>
|
||||
<string name="error_file_creation">Odredišnu mapu nije moguće izraditi</string>
|
||||
<string name="error_permission_denied">Sustav je odbio dozvolu</string>
|
||||
<string name="error_ssl_exception">Sigurna veza nije uspjela</string>
|
||||
<string name="error_unknown_host">Nije moguće pronaći server</string>
|
||||
<string name="error_connect_host">Nije moguće povezati se s serverom</string>
|
||||
<string name="error_http_no_content">Server ne šalje podatke</string>
|
||||
<string name="error_http_unsupported_range">Poslužitelj ne prihvaća preuzimanja s više niti, pokušaj ponovo s @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Traženi raspon nije zadovoljavajući</string>
|
||||
<string name="error_http_not_found">Nije pronađeno</string>
|
||||
<string name="error_postprocessing_failed">Naknadna obrada nije uspjela</string>
|
||||
<string name="clear_finished_download">Obriši završena preuzimanja</string>
|
||||
<string name="msg_pending_downloads">Nastavite s prijenosima na čekanju za %s s preuzimanja</string>
|
||||
<string name="stop">Stop</string>
|
||||
<string name="max_retry_msg">Maksimalnih ponovnih pokušaja</string>
|
||||
<string name="max_retry_desc">Maksimalni broj pokušaja prije poništavanja preuzimanja</string>
|
||||
<string name="pause_downloads_on_mobile">Pauziraj prilikom prebacivanja na mobilne podatke</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Preuzimanja koja se ne mogu zaustaviti ponovno će se pokrenuti</string>
|
||||
</resources>
|
|
@ -24,8 +24,6 @@
|
|||
<string name="show_play_with_kodi_summary">Opció mutatása a videók Kodi médiaközponttal való lejátszására</string>
|
||||
<string name="play_audio">Hang</string>
|
||||
<string name="default_audio_format_title">Alapértelmezett hang formátum</string>
|
||||
<string name="webm_description">WebM — szabad formátum</string>
|
||||
<string name="m4a_description">M4A — jobb minőség</string>
|
||||
<string name="download_dialog_title">Letöltés</string>
|
||||
<string name="next_video_title">Következő</string>
|
||||
<string name="url_not_supported_toast">Nem támogatott webcím</string>
|
||||
|
@ -193,7 +191,6 @@
|
|||
|
||||
<string name="info_labels">Mi:\\nKérés:\\nTartalom nyelve:\\nSzolgáltatás:\\nGMT Idő:\\nCsomag:\\nVerzió:\\nOperációs Rendszer verzió:</string>
|
||||
<string name="search_no_results">Nincs találat</string>
|
||||
<string name="use_old_player_title">Régi lejátszó használata</string>
|
||||
<string name="controls_download_desc">Adatfolyam fájl letöltése</string>
|
||||
<string name="controls_add_to_playlist_title">Hozzáadás</string>
|
||||
|
||||
|
@ -236,8 +233,6 @@
|
|||
<string name="empty_subscription_feed_subtitle">Itt nincs semmi</string>
|
||||
<string name="detail_drag_description">Húzza az átrendezéshez</string>
|
||||
|
||||
<string name="use_old_player_summary">Régi beépített Mediaframework lejátszó</string>
|
||||
|
||||
<string name="short_thousand">e</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">Mrd</string>
|
||||
|
|
|
@ -14,15 +14,12 @@
|
|||
<string name="choose_browser">Pilih peramban</string>
|
||||
<string name="use_external_video_player_title">Gunakan pemutar video eksternal</string>
|
||||
<string name="use_external_audio_player_title">Gunakan pemutar audio eksternal</string>
|
||||
|
||||
<string name="download_path_title">Lokasi unduhan video</string>
|
||||
<string name="download_path_summary">Lokasi untuk menyimpan video yang diunduh</string>
|
||||
<string name="download_path_dialog_title">Masukkan lokasi unduhan video</string>
|
||||
|
||||
<string name="download_path_audio_title">Lokasi unduhan audio</string>
|
||||
<string name="download_path_audio_summary">Audio yang diunduh disimpan di sini</string>
|
||||
<string name="download_path_audio_dialog_title">Masukkan lokasi unduhan berkas audio</string>
|
||||
|
||||
<string name="autoplay_by_calling_app_title">Putar otomatis</string>
|
||||
<string name="autoplay_by_calling_app_summary">Putar video ketika NewPipe dijalankan dari aplikasi lain</string>
|
||||
<string name="default_resolution_title">Resolusi</string>
|
||||
|
@ -32,11 +29,8 @@
|
|||
<string name="show_play_with_kodi_summary">Tampilkan opsi untuk memutar video via Kodi</string>
|
||||
<string name="play_audio">Audio</string>
|
||||
<string name="default_audio_format_title">Format audio</string>
|
||||
<string name="webm_description">WebM — format bebas</string>
|
||||
<string name="m4a_description">M4A — kualitas lebih baik</string>
|
||||
<string name="dark_theme_title">Gelap</string>
|
||||
<string name="light_theme_title">Terang</string>
|
||||
|
||||
<string name="download_dialog_title">Unduh</string>
|
||||
<string name="next_video_title">Berikutnya</string>
|
||||
<string name="show_next_and_similar_title">Tampilkan video \'Berikutnya\' dan \'Serupa\'</string>
|
||||
|
@ -58,7 +52,6 @@
|
|||
<string name="downloads">Unduhan</string>
|
||||
<string name="downloads_title">Unduhan</string>
|
||||
<string name="error_report_title">Laporan galat</string>
|
||||
|
||||
<string name="general_error">Galat</string>
|
||||
<string name="parsing_error">Tidak bisa mengurai situs web</string>
|
||||
<string name="light_parsing_error">Tidak dapat menguraikan situs web sepenuhnya</string>
|
||||
|
@ -75,8 +68,6 @@
|
|||
<string name="what_happened_headline">Yang terjadi:</string>
|
||||
<string name="your_comment">Komentar anda (dalam bahasa Inggris):</string>
|
||||
<string name="error_details_headline">Detail:</string>
|
||||
|
||||
|
||||
<string name="list_thumbnail_view_description">Thumbnail pratinjau video</string>
|
||||
<string name="detail_thumbnail_view_description">Thumbnail pratinjau video</string>
|
||||
<string name="detail_likes_img_view_description">Suka</string>
|
||||
|
@ -87,21 +78,17 @@
|
|||
<string name="report_error">Laporkan Galat</string>
|
||||
<string name="err_dir_create">Tidak bisa membuat direktori unduhan \'%1$s\'</string>
|
||||
<string name="info_dir_created">Direktori unduhan dibuat \'%1$s\'</string>
|
||||
|
||||
<string name="video">Video</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="retry">Ulangi</string>
|
||||
<string name="storage_permission_denied">Izin akses penyimpanan ditolak</string>
|
||||
|
||||
<string name="delete">Hapus</string>
|
||||
<string name="view">Putar</string>
|
||||
<string name="start">Mulai</string>
|
||||
<string name="pause">Jeda</string>
|
||||
<string name="checksum">Ceksum</string>
|
||||
|
||||
<string name="add">Misi baru</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="msg_name">Nama berkas</string>
|
||||
<string name="msg_error">Galat</string>
|
||||
<string name="msg_server_unsupported">Server tidak didukung</string>
|
||||
|
@ -112,79 +99,55 @@
|
|||
<string name="msg_wait">Mohon tunggu…</string>
|
||||
<string name="msg_copied">Disalin ke papan klip</string>
|
||||
<string name="no_available_dir">Silakan pilih direktori unduhan yang tersedia</string>
|
||||
|
||||
<string name="no_player_found">Pemutar stream tidak ditemukan. Apakah anda ingin memasang VLC\?</string>
|
||||
<string name="youtube_signature_decryption_error">Tidak bisa dekripsi tanda tangan URL video</string>
|
||||
<string name="app_ui_crash">App/UI rusak</string>
|
||||
<string name="could_not_get_stream">Tidak bisa mendapatkan stream apapun</string>
|
||||
<string name="info_labels">Apa:\\nPermintaan:\\nBahasa Konten:\\nLayanan:\\nWaktu GMT:\\nPaket:\\nVersi:\\nVersi OS:</string>
|
||||
<string name="user_report">Laporan pengguna</string>
|
||||
|
||||
<string name="msg_threads">Thread</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">Tantangan reCAPTCHA</string>
|
||||
|
||||
<string name="recaptcha_request_toast">Meminta kode reCAPTCHA</string>
|
||||
|
||||
<string name="black_theme_title">Hitam</string>
|
||||
|
||||
<string name="all">Semua</string>
|
||||
<string name="channel">Channel</string>
|
||||
|
||||
<string name="short_thousand">R</string>
|
||||
<string name="short_million">J</string>
|
||||
<string name="short_billion">T</string>
|
||||
|
||||
|
||||
<string name="yes">Ya</string>
|
||||
<string name="later">Nanti</string>
|
||||
|
||||
|
||||
<string name="open_in_popup_mode">Buka di mode popup</string>
|
||||
<string name="msg_popup_permission">Izin ini dibutuhkan untuk
|
||||
\nmembuka di mode popup</string>
|
||||
|
||||
<string name="popup_mode_share_menu_title">Mode popup NewPipe</string>
|
||||
|
||||
<string name="popup_playing_toast">Memutar dalam mode popup</string>
|
||||
<string name="use_old_player_title">Gunakan pemutar lama</string>
|
||||
<string name="use_old_player_summary">Pemutar Mediaframework bawaan versi lama</string>
|
||||
<string name="disabled">Dinonaktifkan</string>
|
||||
|
||||
<string name="default_video_format_title">Format video</string>
|
||||
|
||||
<string name="default_popup_resolution_title">Resolusi popup</string>
|
||||
<string name="show_higher_resolutions_title">Tampilkan resolusi yang lebih tinggi</string>
|
||||
<string name="show_higher_resolutions_summary">Hanya perangkat tertentu yang mendukung pemutaran video 2K/4K</string>
|
||||
<string name="controls_background_title">Latar Belakang</string>
|
||||
<string name="controls_popup_title">Popup</string>
|
||||
|
||||
<string name="refresh">Segarkan</string>
|
||||
<string name="clear">Bersihkan</string>
|
||||
|
||||
<string name="filter">Filter</string>
|
||||
<string name="use_external_video_player_summary">Menghapus audio pada BEBERAPA resolusi</string>
|
||||
<string name="popup_remember_size_pos_title">Ingat ukuran dan posisi popup</string>
|
||||
<string name="popup_remember_size_pos_summary">Ingat ukuran dan posisi terakhir popup</string>
|
||||
|
||||
<string name="settings_category_popup_title">Popup</string>
|
||||
<string name="popup_resizing_indicator_title">Ubah ukuran</string>
|
||||
|
||||
<string name="player_gesture_controls_title">Kontrol gestur pemutar</string>
|
||||
<string name="player_gesture_controls_summary">Gunakan gestur untuk mengontrol kecerahan dan volume pemutar</string>
|
||||
<string name="show_search_suggestions_title">Saran pencarian</string>
|
||||
<string name="show_search_suggestions_summary">Tampilkan saran ketika mencari</string>
|
||||
|
||||
<string name="best_resolution">Resolusi terbaik</string>
|
||||
|
||||
<string name="best_resolution">Resolusi terbaik</string>
|
||||
<string name="settings_category_downloads_title">Unduh</string>
|
||||
<string name="settings_file_charset_title">Karakter yang diizinkan sebagai nama berkas</string>
|
||||
<string name="settings_file_replacement_character_summary">Karakter yang tidak valid akan diganti dengan karakter ini</string>
|
||||
<string name="settings_file_replacement_character_title">Karakter pengganti</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Huruf dan angka</string>
|
||||
<string name="charset_most_special_characters">Karakter spesial umum</string>
|
||||
|
||||
<string name="title_activity_about">Tentang NewPipe</string>
|
||||
<string name="action_settings">Pengaturan</string>
|
||||
<string name="action_about">Tentang</string>
|
||||
|
@ -195,19 +158,17 @@
|
|||
<string name="tab_about">Tentang</string>
|
||||
<string name="tab_contributors">Kontributor</string>
|
||||
<string name="tab_licenses">Lisensi</string>
|
||||
<string name="app_description">Aplikasi streaming libre dan ringan untuk Android.</string>
|
||||
<string name="app_description">Aplikasi streaming bebas dan ringan untuk Android.</string>
|
||||
<string name="view_on_github">Lihat di GitHub</string>
|
||||
<string name="app_license_title">Lisensi NewPipe</string>
|
||||
<string name="contribution_encouragement">Terlepas apakah anda memiliki ide untuk; terjemahan, perubahan desain, pembersihan kode, atau perubahan kode yang signifikan, segala bantuan akan selalu diterima. Semakin banyak akan semakin baik jadinya!</string>
|
||||
<string name="read_full_license">Baca lisensi</string>
|
||||
<string name="contribution_title">Kontribusi</string>
|
||||
<string name="subscribe_button_title">Subscribe</string>
|
||||
<string name="subscribe_button_title">Subscribe</string>
|
||||
<string name="subscribed_button_title">Disubscribe</string>
|
||||
<string name="fragment_whats_new">Apa Yang Baru</string>
|
||||
|
||||
<string name="resume_on_audio_focus_gain_title">Lanjutkan saat fokus</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Lanjutkan pemutaran setelah interupsi (mis. panggilan telepon)</string>
|
||||
|
||||
<string name="tab_main">Utama</string>
|
||||
<string name="enable_search_history_title">Riwayat pencarian</string>
|
||||
<string name="enable_search_history_summary">Simpan pencarian secara lokal</string>
|
||||
|
@ -241,16 +202,12 @@
|
|||
<string name="always">Selalu</string>
|
||||
<string name="just_once">Hanya Sekali</string>
|
||||
<string name="file">Berkas</string>
|
||||
|
||||
<string name="notification_channel_description">Notifikasi untuk pemutar latar belakang dan popup NewPipe</string>
|
||||
|
||||
<string name="unknown_content">[Tidak diketahui]</string>
|
||||
|
||||
<string name="toggle_orientation">Ubah Orientasi</string>
|
||||
<string name="switch_to_background">Alihkan ke Latar Belakang</string>
|
||||
<string name="switch_to_popup">Alihkan ke Popup</string>
|
||||
<string name="switch_to_main">Alihkan ke Utama</string>
|
||||
|
||||
<string name="import_data_title">Impor basis data</string>
|
||||
<string name="export_data_title">Ekspor basis data</string>
|
||||
<string name="import_data_summary">Timpa riwayat dan subscription anda saat ini</string>
|
||||
|
@ -267,32 +224,26 @@
|
|||
<string name="invalid_file">Berkas tidak tersedia atau tidak memiliki izin baca atau tulis</string>
|
||||
<string name="file_name_empty_error">Nama berkas tidak boleh kosong</string>
|
||||
<string name="error_occurred_detail">Telah terjadi galat: %1$s</string>
|
||||
|
||||
<string name="search_no_results">Tidak ada hasil</string>
|
||||
<string name="empty_subscription_feed_subtitle">Tidak ada apapun disini selain jangkrik</string>
|
||||
<string name="detail_drag_description">Geser untuk ubah urutan</string>
|
||||
|
||||
<string name="no_subscribers">Tidak ada subscriber</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="other">%s subscriber</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">%s subscriber</item>
|
||||
</plurals>
|
||||
<string name="no_views">Belum ditonton</string>
|
||||
<plurals name="views">
|
||||
<item quantity="other">%s ditonton</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">%s ditonton</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Tidak ada video</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="other">Video</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">Video</item>
|
||||
</plurals>
|
||||
<string name="create">Buat</string>
|
||||
<string name="delete_one">Hapus Satu</string>
|
||||
<string name="delete_all">Hapus Semua</string>
|
||||
<string name="dismiss">Abaikan</string>
|
||||
<string name="rename">Ubah nama</string>
|
||||
|
||||
<string name="donation_title">Donasi</string>
|
||||
<string name="donation_encouragement">NewPipe dikembangkan oleh relawan yang menyisihkan waktu untuk memberi anda pengalaman terbaik. Segala dukungan kepada pengembang akan membuat NewPipe menjadi lebih baik sambil menikmati secangkir kopi.</string>
|
||||
<string name="give_back">Beri dukungan</string>
|
||||
|
@ -306,7 +257,6 @@
|
|||
<string name="delete_all_history_prompt">Apakah Anda yakin ingin menghapus semua item dari riwayat\?</string>
|
||||
<string name="title_last_played">Terakhir Diputar</string>
|
||||
<string name="title_most_played">Sering Diputar</string>
|
||||
|
||||
<string name="main_page_content">Konten laman utama</string>
|
||||
<string name="blank_page_summary">Laman Kosong</string>
|
||||
<string name="kiosk_page_summary">Laman Kiosk</string>
|
||||
|
@ -321,7 +271,6 @@
|
|||
<string name="no_valid_zip_file">Berkas ZIP tidak valid</string>
|
||||
<string name="could_not_import_all_files">Perhatian: Tidak bisa mengimpor semua berkas.</string>
|
||||
<string name="override_current_data">Ini akan menimpa pengaturan anda saat ini.</string>
|
||||
|
||||
<string name="kiosk">Kiosk</string>
|
||||
<string name="trending">Trending</string>
|
||||
<string name="top_50">Top 50</string>
|
||||
|
@ -337,58 +286,45 @@
|
|||
<string name="start_here_on_main">Mulai putar di sini</string>
|
||||
<string name="start_here_on_background">Mulai dari sini ketika di latar belakang</string>
|
||||
<string name="start_here_on_popup">Mulai dari sini pada popup baru</string>
|
||||
|
||||
<string name="drawer_open">Buka Laci</string>
|
||||
<string name="drawer_close">Tutup Laci</string>
|
||||
<string name="drawer_header_action_paceholder_text">Sesuatu akan segera muncul di sini ;D</string>
|
||||
|
||||
|
||||
<string name="video_player">Pemutar video</string>
|
||||
<string name="background_player">Pemutar latar belakang</string>
|
||||
<string name="popup_player">Pemutar popup</string>
|
||||
<string name="always_ask_open_action">Selalu bertanya</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Mendapatkan info…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Memuat konten yang diminta</string>
|
||||
|
||||
<string name="create_playlist">Playlist Baru</string>
|
||||
<string name="delete_playlist">Hapus</string>
|
||||
<string name="rename_playlist">Ubah Nama</string>
|
||||
<string name="playlist_name_input">Nama</string>
|
||||
<string name="append_playlist">Tambahkan Ke Playlist</string>
|
||||
<string name="set_as_playlist_thumbnail">Atur sebagai Thumbnail Playlist</string>
|
||||
|
||||
<string name="bookmark_playlist">Markah Playlist</string>
|
||||
<string name="unbookmark_playlist">Hapus Markah</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Hapus playlist ini\?</string>
|
||||
<string name="playlist_creation_success">Playlist dibuat</string>
|
||||
<string name="playlist_add_stream_success">Diplaylist</string>
|
||||
<string name="playlist_thumbnail_change_success">Thumbnail playlist diubah.</string>
|
||||
<string name="playlist_delete_failure">Tidak bisa menghapus playlist.</string>
|
||||
|
||||
<string name="caption_none">Tidak ada Takarir</string>
|
||||
|
||||
<string name="resize_fit">Pas</string>
|
||||
<string name="resize_fill">Isi</string>
|
||||
<string name="resize_zoom">Perbesar</string>
|
||||
|
||||
<string name="caption_auto_generated">Otomatis dibuat</string>
|
||||
<string name="caption_font_size_settings_title">Ukuran fon deskripsi</string>
|
||||
<string name="smaller_caption_font_size">Fon lebih kecil</string>
|
||||
<string name="normal_caption_font_size">Fon normal</string>
|
||||
<string name="larger_caption_font_size">Fon lebih besar</string>
|
||||
|
||||
<string name="enable_leak_canary_title">Aktifkan LeakCanary</string>
|
||||
<string name="playback_nightcore">Nightcore</string>
|
||||
<string name="playback_default">Bawaan</string>
|
||||
<string name="no_player_found_toast">Pemutar stream tidak ditemukan (anda bisa memasang VLC untuk memutarnya).</string>
|
||||
<string name="no_player_found_toast">Pemutar stream tidak ditemukan (anda bisa memasang VLC untuk memutarnya).</string>
|
||||
<string name="controls_download_desc">Unduh berkas stream</string>
|
||||
<string name="subscription_change_failed">Tidak bisa mengubah subscription</string>
|
||||
<string name="show_info">Tampilkan info</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">Tambahkan Ke</string>
|
||||
|
||||
<string name="clear_views_history_title">Hapus riwayat tontonan</string>
|
||||
<string name="clear_views_history_summary">Hapus riwayat stream yang telah diputar</string>
|
||||
<string name="delete_view_history_alert">Hapus seluruh riwayat tontonan\?</string>
|
||||
|
@ -398,14 +334,10 @@
|
|||
<string name="delete_search_history_alert">Hapus seluruh riwayat pencarian\?</string>
|
||||
<string name="search_history_deleted">Riwayat pencarian dihapus.</string>
|
||||
<string name="no_streams_available_download">Tidak ada stream yang tersedia untuk diunduh</string>
|
||||
|
||||
<string name="one_item_deleted">1 item dihapus.</string>
|
||||
|
||||
<string name="toast_no_player">Tidak ada aplikasi terpasang untuk memutar berkas ini</string>
|
||||
|
||||
<string name="title_history_view">Ditonton</string>
|
||||
<string name="tab_bookmarks">Playlist Disimpan</string>
|
||||
|
||||
<string name="auto_queue_title">Antre otomatis stream berikutnya</string>
|
||||
<string name="channel_unsubscribed">Channel berhenti disubscribe</string>
|
||||
<string name="subscription_update_failed">Tidak bisa memperbarui subscription</string>
|
||||
|
@ -414,32 +346,23 @@
|
|||
<string name="use_inexact_seek_summary">Memungkinkan pengguna memilih posisi waktu video dengan cepat tetapi dengan tingkat presisi yang rendah</string>
|
||||
<string name="app_license">NewPipe adalah perangkat lunak libre copyleft: Anda bisa menggunakannya, mempelajarinya, berbagi, dan meningkatkannya. Secara khusus anda bisa mendistribusikan ulang dan/atau memodifikasinya dibawah syarat Lisensi Publik Umum GNU yang diterbitkan oleh Free Software Foundation, baik versi 3 dari Lisensi, atau (sesuai pilihan anda) versi yang lebih baru.</string>
|
||||
<string name="import_settings">Apakah anda juga ingin mengimpor pengaturan\?</string>
|
||||
|
||||
<string name="preferred_open_action_settings_title">Tindakan \'buka\' yang diinginkan</string>
|
||||
<string name="preferred_open_action_settings_summary">Tindakan baku ketika membuka konten — %s</string>
|
||||
|
||||
<string name="caption_setting_title">Takarir</string>
|
||||
<string name="caption_setting_description">Ubah skala teks takarir pemutar dan gaya latar belakang. Perlu memulai ulang apl.</string>
|
||||
|
||||
<string name="enable_leak_canary_summary">Pemantauan kebocoran memori dapat menyebabkan apl menjadi tidak responsif saat heap dumping</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Laporkan galat out-of-lifecycle</string>
|
||||
<string name="enable_disposed_exceptions_summary">Paksa pelaporan eksepsi Rx yang tak terkirim di luar fragmen atau siklus hidup aktivitas setelah dibuang</string>
|
||||
|
||||
<string name="import_export_title">Impor/ekspor</string>
|
||||
<string name="import_title">Impor</string>
|
||||
<string name="import_from">Impor dari</string>
|
||||
<string name="export_to">Ekspor ke</string>
|
||||
|
||||
<string name="import_ongoing">Mengimpor…</string>
|
||||
<string name="export_ongoing">Mengekspor…</string>
|
||||
|
||||
<string name="import_file_title">Impor berkas</string>
|
||||
<string name="previous_export">Ekspor sebelumnya</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Tidak bisa mengimpor subscription</string>
|
||||
<string name="subscriptions_export_unsuccessful">Tidak bisa mengekspor subscription</string>
|
||||
|
||||
<string name="import_youtube_instructions">Impor subscription YouTube dengan mengunduh berkas yang diekspor:
|
||||
\n
|
||||
\n1. Kunjungi URL ini: %1$s
|
||||
|
@ -452,11 +375,9 @@
|
|||
\n3. Masuk ketika ditanya
|
||||
\n4. Salin URL profil anda ketika dialihkan.</string>
|
||||
<string name="import_soundcloud_instructions_hint">idAnda, soundcloud.com/idAnda</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Perlu diingat operasi ini membutuhkan bandwidth yang besar.
|
||||
\n
|
||||
\nApakah anda ingin melanjutkan\?</string>
|
||||
|
||||
<string name="playback_speed_control">Kontrol Kecepatan Pemutaran</string>
|
||||
<string name="playback_tempo">Tempo</string>
|
||||
<string name="playback_pitch">Nada</string>
|
||||
|
@ -472,12 +393,10 @@
|
|||
<string name="skip_silence_checkbox">Percepat saat diam</string>
|
||||
<string name="playback_step">Langkah</string>
|
||||
<string name="playback_reset">Atur ulang</string>
|
||||
|
||||
<string name="start_accept_privacy_policy">Agar sesuai dengan Regulasi Perlindungan Data Umum Eropa (GDPR), dengan ini kami tarik perhatian anda ke kebijakan privasi NewPipe. Silakan baca dengan seksama.
|
||||
\nAnda harus menerimanya untuk mengirimkan laporan bug kepada kami.</string>
|
||||
<string name="accept">Setuju</string>
|
||||
<string name="decline">Tolak</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Tanpa batas</string>
|
||||
<string name="limit_mobile_data_usage_title">Batasi resolusi saat menggunakan data seluler</string>
|
||||
<string name="minimize_on_exit_title">Minimalkan saat beralih apl</string>
|
||||
|
@ -517,7 +436,7 @@
|
|||
<string name="app_update_notification_content_title">Pembaruan NewPipe Tersedia!</string>
|
||||
<string name="app_update_notification_content_text">Ketuk untuk mengunduh</string>
|
||||
<string name="missions_header_finished">Selesai</string>
|
||||
<string name="missions_header_pending">Di antrian</string>
|
||||
<string name="missions_header_pending">Tertunda</string>
|
||||
<string name="paused">dijeda</string>
|
||||
<string name="queued">antri</string>
|
||||
<string name="post_processing">pengolahan-pasca</string>
|
||||
|
@ -528,12 +447,12 @@
|
|||
<string name="download_finished_more">%s unduhan selesai</string>
|
||||
<string name="generate_unique_name">Hasilkan nama unik</string>
|
||||
<string name="overwrite">Timpa</string>
|
||||
<string name="overwrite_warning">File yang diunduh dengan nama ini sudah ada</string>
|
||||
<string name="overwrite_finished_warning">File yang diunduh dengan nama ini sudah ada</string>
|
||||
<string name="download_already_running">Ada unduhan yang sedang berlangsung dengan nama ini</string>
|
||||
<string name="show_error">Tunjukkan kesalahan</string>
|
||||
<string name="label_code">Kode</string>
|
||||
<string name="error_path_creation">File tidak dapat dibuat</string>
|
||||
<string name="error_file_creation">Folder tujuan tidak dapat dibuat</string>
|
||||
<string name="error_file_creation">File tidak dapat dibuat</string>
|
||||
<string name="error_path_creation">Folder tujuan tidak dapat dibuat</string>
|
||||
<string name="error_permission_denied">Izin ditolak oleh sistem</string>
|
||||
<string name="error_ssl_exception">Koneksi aman gagal</string>
|
||||
<string name="error_unknown_host">Tidak dapat menemukan server</string>
|
||||
|
@ -549,5 +468,5 @@
|
|||
<string name="max_retry_msg">Percobaan maksimum</string>
|
||||
<string name="max_retry_desc">Jumlah upaya maksimum sebelum membatalkan unduhan</string>
|
||||
<string name="pause_downloads_on_mobile">Berhenti ketika beralih ke data seluler</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Unduhan yang tidak dapat dijeda akan dimulai kembali</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Unduhan yang tidak dapat dijeda akan diulang dari awal</string>
|
||||
</resources>
|
|
@ -2,17 +2,17 @@
|
|||
<resources>
|
||||
<string name="view_count_text">%1$s visualizzazioni</string>
|
||||
<string name="upload_date_text">Pubblicato il %1$s</string>
|
||||
<string name="no_player_found">Nessun lettore multimediale trovato. Vuoi installare VLC?</string>
|
||||
<string name="no_player_found">Nessun lettore multimediale trovato. Vuoi installare VLC\?</string>
|
||||
<string name="install">Installa</string>
|
||||
<string name="cancel">Annulla</string>
|
||||
<string name="open_in_browser">Apri nel browser</string>
|
||||
<string name="open_in_browser">Apri nel Browser</string>
|
||||
<string name="share">Condividi</string>
|
||||
<string name="download">Scarica</string>
|
||||
<string name="search">Cerca</string>
|
||||
<string name="settings">Impostazioni</string>
|
||||
<string name="did_you_mean">Intendevi: %1$s\?</string>
|
||||
<string name="share_dialog_title">Condividi con</string>
|
||||
<string name="choose_browser">Scegli il browser</string>
|
||||
<string name="choose_browser">Scegli Browser</string>
|
||||
<string name="screen_rotation">rotazione</string>
|
||||
<string name="download_path_title">Percorso dei video scaricati</string>
|
||||
<string name="download_path_summary">Cartella in cui salvare i video scaricati</string>
|
||||
|
@ -30,7 +30,6 @@
|
|||
<string name="url_not_supported_toast">URL non supportato</string>
|
||||
<string name="content_language_title">Lingua predefinita per i contenuti</string>
|
||||
<string name="settings_category_video_audio_title">Video e Audio</string>
|
||||
|
||||
<string name="list_thumbnail_view_description">Miniatura anteprima video</string>
|
||||
<string name="detail_thumbnail_view_description">Miniatura anteprima video</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">Miniatura dell\'immagine di profilo dell\'utente</string>
|
||||
|
@ -38,22 +37,18 @@
|
|||
<string name="detail_likes_img_view_description">Mi piace</string>
|
||||
<string name="err_dir_create">Impossibile creare la cartella di download \'%1$s\'</string>
|
||||
<string name="info_dir_created">Creata la cartella per i download \'%1$s\'</string>
|
||||
<string name="use_external_video_player_title">Usa un lettore video esterno</string>
|
||||
<string name="use_external_audio_player_title">Usa un lettore audio esterno</string>
|
||||
|
||||
<string name="use_external_video_player_title">Usa Lettore Video Esterno</string>
|
||||
<string name="use_external_audio_player_title">Usa Lettore Audio Esterno</string>
|
||||
<string name="download_path_audio_title">Cartella degli audio scaricati</string>
|
||||
<string name="download_path_audio_summary">Cartella in cui salvare gli audio scaricati</string>
|
||||
<string name="download_path_audio_dialog_title">Inserisci la cartella per gli audio scaricati</string>
|
||||
|
||||
<string name="theme_title">Tema</string>
|
||||
<string name="dark_theme_title">Scuro</string>
|
||||
<string name="light_theme_title">Chiaro</string>
|
||||
|
||||
<string name="settings_category_appearance_title">Aspetto</string>
|
||||
<string name="settings_category_other_title">Altro</string>
|
||||
<string name="background_player_playing_toast">Riproduzione in sottofondo</string>
|
||||
<string name="play_btn_text">Riproduci</string>
|
||||
|
||||
<string name="general_error">Errore</string>
|
||||
<string name="network_error">Errore di connessione</string>
|
||||
<string name="could_not_load_thumbnails">Impossibile caricare tutte le miniature</string>
|
||||
|
@ -62,23 +57,16 @@
|
|||
<string name="blocked_by_gema">Bloccato da GEMA</string>
|
||||
<string name="use_tor_title">Usa Tor</string>
|
||||
<string name="use_tor_summary">(Sperimentale) Forza il download tramite Tor per una maggiore riservatezza (lo streaming dei video non è ancora supportato).</string>
|
||||
|
||||
<string name="parsing_error">Impossibile analizzare il sito web</string>
|
||||
<string name="could_not_setup_download_menu">Impossibile impostare il menu di download</string>
|
||||
|
||||
|
||||
<string name="live_streams_not_supported">I contenuti in diretta non sono al momento supportati</string>
|
||||
|
||||
|
||||
<string name="content">Contenuti</string>
|
||||
<string name="show_age_restricted_content_title">Contenuti vietati ai minori</string>
|
||||
<string name="video_is_age_restricted">Mostra video riversati a un pubblico maggiorenne. Si possono abilitare dalle Impostazioni.</string>
|
||||
|
||||
<string name="video_is_age_restricted">Mostra video riservati a un pubblico maggiorenne. Si possono abilitare dalle Impostazioni.</string>
|
||||
<string name="main_bg_subtitle">Tocca Cerca per iniziare</string>
|
||||
<string name="autoplay_by_calling_app_title">Riproduzione automatica</string>
|
||||
<string name="autoplay_by_calling_app_summary">Riproduci i video quando NewPipe viene aperto da un\'altra app</string>
|
||||
<string name="duration_live">IN DIRETTA</string>
|
||||
|
||||
<string name="light_parsing_error">Impossibile analizzare completamente il sito web</string>
|
||||
<string name="could_not_get_stream">Impossibile ottenere alcun flusso</string>
|
||||
<string name="sorry_string">Spiacenti, non sarebbe dovuto succedere.</string>
|
||||
|
@ -89,11 +77,8 @@
|
|||
<string name="what_happened_headline">Cosa è successo:</string>
|
||||
<string name="your_comment">Il tuo commento (in inglese):</string>
|
||||
<string name="error_details_headline">Dettagli:</string>
|
||||
|
||||
|
||||
<string name="report_error">Segnala un errore</string>
|
||||
<string name="user_report">Segnalazione dell\'utente</string>
|
||||
|
||||
<string name="video">Video</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="retry">Riprova</string>
|
||||
|
@ -101,16 +86,13 @@
|
|||
<string name="downloads">Download</string>
|
||||
<string name="downloads_title">Download</string>
|
||||
<string name="error_report_title">Segnalazione errori</string>
|
||||
|
||||
<string name="start">Inizia</string>
|
||||
<string name="pause">Pausa</string>
|
||||
<string name="view">Riproduci</string>
|
||||
<string name="delete">Elimina</string>
|
||||
<string name="checksum">Checksum</string>
|
||||
|
||||
<string name="add">Nuovo obiettivo</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="msg_name">Nome del file</string>
|
||||
<string name="msg_threads">Thread</string>
|
||||
<string name="msg_error">Errore</string>
|
||||
|
@ -122,41 +104,27 @@
|
|||
<string name="msg_wait">Attendi…</string>
|
||||
<string name="msg_copied">Copiato negli appunti</string>
|
||||
<string name="no_available_dir">Seleziona una cartella per il salvataggio dei download</string>
|
||||
|
||||
<string name="could_not_load_image">Impossibile caricare l\'immagine</string>
|
||||
<string name="app_ui_crash">L\'app/UI si è interrotta</string>
|
||||
<string name="info_labels">Cosa:\\nRichiesta:\\nLingua contenuto:\\nServizio:\\nOrario GMT:\\nPacchetto:\\nVersione:\\nVersione SO:</string>
|
||||
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">Risoluzione reCAPTCHA</string>
|
||||
|
||||
<string name="black_theme_title">Nero</string>
|
||||
|
||||
<string name="all">Tutto</string>
|
||||
<string name="channel">Canale</string>
|
||||
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">B</string>
|
||||
|
||||
<string name="recaptcha_request_toast">È richiesta la risoluzione del reCAPTCHA</string>
|
||||
|
||||
<string name="yes">Sì</string>
|
||||
<string name="later">Più tardi</string>
|
||||
|
||||
|
||||
<string name="open_in_popup_mode">Apri in modalità popup</string>
|
||||
<string name="popup_mode_share_menu_title">Modalità popup di NewPipe</string>
|
||||
|
||||
<string name="open_in_popup_mode">Apri in Modalità Popup</string>
|
||||
<string name="popup_mode_share_menu_title">Modalità Popup di NewPipe</string>
|
||||
<string name="popup_playing_toast">Riproduzione in modalità popup</string>
|
||||
<string name="disabled">Disattivato</string>
|
||||
|
||||
<string name="use_old_player_title">Usa il vecchio lettore multimediale</string>
|
||||
<string name="use_external_video_player_summary">Non riproduce l\'audio con ALCUNE risoluzioni</string>
|
||||
<string name="use_external_video_player_summary">Non riproduce l\'audio con ALCUNE risoluzioni</string>
|
||||
<string name="controls_background_title">In sottofondo</string>
|
||||
<string name="controls_popup_title">Popup</string>
|
||||
|
||||
<string name="default_popup_resolution_title">Risoluzione predefinita per la modalità popup</string>
|
||||
<string name="show_higher_resolutions_title">Mostra risoluzioni più alte</string>
|
||||
<string name="show_higher_resolutions_summary">Solo alcuni dispositivi supportano la riproduzione video in 2K e 4K</string>
|
||||
|
@ -167,19 +135,14 @@
|
|||
<string name="player_gesture_controls_summary">Usa i gesti per controllare la luminosità e il volume del lettore multimediale</string>
|
||||
<string name="show_search_suggestions_title">Suggerimenti di ricerca</string>
|
||||
<string name="show_search_suggestions_summary">Mostra i suggerimenti durante la ricerca</string>
|
||||
|
||||
<string name="settings_category_popup_title">Popup</string>
|
||||
<string name="filter">Filtra i risultati</string>
|
||||
<string name="refresh">Ricarica</string>
|
||||
<string name="clear">Cancella</string>
|
||||
<string name="popup_resizing_indicator_title">Ridimensionamento</string>
|
||||
<string name="best_resolution">Risoluzione migliore</string>
|
||||
|
||||
<string name="use_old_player_summary">Precedente lettore multimediale Mediaframework integrato</string>
|
||||
|
||||
<string name="msg_popup_permission">Questo permesso è necessario
|
||||
<string name="msg_popup_permission">Questo permesso è necessario
|
||||
\nper riprodurre in modalità popup</string>
|
||||
|
||||
<string name="action_settings">Impostazioni</string>
|
||||
<string name="action_about">Informazioni</string>
|
||||
<string name="title_licenses">Licenze di terze parti</string>
|
||||
|
@ -189,39 +152,32 @@
|
|||
<string name="tab_about">Informazioni</string>
|
||||
<string name="tab_contributors">Contributori</string>
|
||||
<string name="tab_licenses">Licenze</string>
|
||||
<string name="app_description">Interfaccia libera e leggera per lo streaming di YouTube su Android.</string>
|
||||
<string name="app_description">Streaming libero e leggero su Android.</string>
|
||||
<string name="view_on_github">Mostra su GitHub</string>
|
||||
<string name="app_license_title">Licenza di NewPipe</string>
|
||||
<string name="contribution_encouragement">Un aiuto è sempre il benvenuto: nuove idee e funzionalità, traduzioni, modifiche al design o cambiamenti radicali del codice rendono l\'applicazione sempre migliore!</string>
|
||||
<string name="read_full_license">Leggi la licenza</string>
|
||||
<string name="contribution_title">Contribuisci</string>
|
||||
<string name="title_activity_about">Informazioni su NewPipe</string>
|
||||
<string name="title_activity_about">Informazioni su NewPipe</string>
|
||||
<string name="subscribe_button_title">Iscriviti</string>
|
||||
<string name="subscribed_button_title">Iscritto</string>
|
||||
<string name="channel_unsubscribed">Disiscritto dal canale</string>
|
||||
<string name="channel_unsubscribed">Disiscritto dal Canale</string>
|
||||
<string name="subscription_change_failed">Impossibile cambiare l\'iscrizione</string>
|
||||
<string name="subscription_update_failed">Impossibile aggiornare l\'iscrizione</string>
|
||||
|
||||
<string name="tab_subscriptions">Iscrizioni</string>
|
||||
|
||||
<string name="fragment_whats_new">Novità</string>
|
||||
|
||||
<string name="enable_search_history_title">Cronologia ricerche</string>
|
||||
<string name="enable_search_history_summary">Salva le ricerche</string>
|
||||
<string name="enable_watch_history_title">Cronologia & Cache</string>
|
||||
<string name="enable_watch_history_summary">Salva la cronologia dei video visualizzati</string>
|
||||
<string name="resume_on_audio_focus_gain_title">Riprendi tornando in primo piano</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Continua a riprodurre dopo le interruzioni (es. chiamate)</string>
|
||||
|
||||
|
||||
<string name="settings_category_downloads_title">Scarica</string>
|
||||
<string name="settings_file_charset_title">Caratteri ammessi nei nomi dei file</string>
|
||||
<string name="settings_file_replacement_character_summary">I caratteri non validi vengono sostituiti con</string>
|
||||
<string name="settings_file_replacement_character_title">Carattere sostitutivo</string>
|
||||
|
||||
<string name="charset_letters_and_digits">Lettere e cifre</string>
|
||||
<string name="charset_most_special_characters">Caratteri speciali</string>
|
||||
|
||||
<string name="title_activity_history">Cronologia</string>
|
||||
<string name="title_history_search">Ricerche effettuate</string>
|
||||
<string name="title_history_view">Visualizzati</string>
|
||||
|
@ -229,41 +185,34 @@
|
|||
<string name="action_history">Cronologia</string>
|
||||
<string name="history_empty">La cronologia è vuota</string>
|
||||
<string name="history_cleared">Cronologia cancellata</string>
|
||||
|
||||
<string name="tab_main">Principale</string>
|
||||
<string name="tab_main">Principale</string>
|
||||
<string name="settings_category_player_title">Lettore multimediale</string>
|
||||
<string name="settings_category_player_behavior_title">Comportamento</string>
|
||||
<string name="settings_category_history_title">Cronologia e cache</string>
|
||||
<string name="playlist">Playlist</string>
|
||||
<string name="undo">Annulla</string>
|
||||
|
||||
<string name="notification_channel_name">Notifiche NewPipe</string>
|
||||
<string name="notification_channel_description">Notifiche per NewPipe in background e per il lettore a comparsa</string>
|
||||
|
||||
<string name="search_no_results">Nessun risultato</string>
|
||||
<string name="no_subscribers">Nessun iscritto</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s iscritto</item>
|
||||
<item quantity="other">%s iscritti</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s iscritto</item>
|
||||
<item quantity="other">%s iscritti</item>
|
||||
</plurals>
|
||||
<string name="no_views">Nessuna visualizzazione</string>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s visualizzazione</item>
|
||||
<item quantity="other">%s visualizzazioni</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">%s visualizzazione</item>
|
||||
<item quantity="other">%s visualizzazioni</item>
|
||||
</plurals>
|
||||
<string name="no_videos">Nessun video</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="one">Video</item>
|
||||
<item quantity="other">Video</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="one">Video</item>
|
||||
<item quantity="other">Video</item>
|
||||
</plurals>
|
||||
<string name="item_deleted">Elemento eliminato</string>
|
||||
<string name="empty_subscription_feed_subtitle">Nulla da mostrare</string>
|
||||
|
||||
<string name="empty_subscription_feed_subtitle">Nulla da mostrare</string>
|
||||
<string name="delete_item_search_history">Vuoi eliminare questo elemento dalla cronologia?</string>
|
||||
<string name="main_page_content">Contenuto della pagina principale</string>
|
||||
<string name="main_page_content">Contenuto della pagina principale</string>
|
||||
<string name="blank_page_summary">Pagina vuota</string>
|
||||
<string name="kiosk_page_summary">Locandina</string>
|
||||
<string name="subscription_page_summary">Pagina iscrizione</string>
|
||||
|
@ -272,35 +221,31 @@
|
|||
<string name="select_a_channel">Seleziona un canale</string>
|
||||
<string name="no_channel_subscribed_yet">Nessuna iscrizione ad un canale</string>
|
||||
<string name="select_a_kiosk">Seleziona una locandina</string>
|
||||
|
||||
<string name="kiosk">Locandina</string>
|
||||
<string name="trending">Tendenze</string>
|
||||
<string name="top_50">Top 50</string>
|
||||
<string name="new_and_hot">New & hot</string>
|
||||
<string name="show_hold_to_append_title">Mostra il suggerimento \"Tenere premuto per aggiungere video alla coda\"</string>
|
||||
<string name="show_hold_to_append_title">Mostra il suggerimento \"Tenere premuto per aggiungere video alla coda\"</string>
|
||||
<string name="show_hold_to_append_summary">Mostra suggerimento quando il pulsante per la riproduzione popup o in sottofondo viene premuto nella pagina dei dettagli del video</string>
|
||||
<string name="background_player_append">In coda al lettore multimediale in sottofondo</string>
|
||||
<string name="popup_playing_append">In coda al lettore multimediale a comparsa</string>
|
||||
<string name="play_all">Riproduci tutto</string>
|
||||
|
||||
<string name="player_stream_failure">Impossibile riprodurre questo flusso</string>
|
||||
<string name="player_unrecoverable_failure">Si è verificato un errore irreversibile</string>
|
||||
<string name="player_recoverable_failure">Ripristino dell\'errore del lettore multimediale</string>
|
||||
|
||||
<string name="title_activity_background_player">Riproduzione in sottofondo</string>
|
||||
<string name="title_activity_popup_player">Riproduzione in modalità a comparsa</string>
|
||||
<string name="play_queue_remove">Rimuovi</string>
|
||||
<string name="play_queue_stream_detail">Dettagli</string>
|
||||
<string name="play_queue_audio_settings">Impostazioni audio</string>
|
||||
<string name="hold_to_append">Tenere premuto per aggiungere alla coda</string>
|
||||
<string name="unknown_content">[Sconosciuto]</string>
|
||||
|
||||
<string name="unknown_content">[Sconosciuto]</string>
|
||||
<string name="enqueue_on_background">In coda in sottofondo</string>
|
||||
<string name="enqueue_on_popup">In coda nel riproduttore a comparsa</string>
|
||||
<string name="start_here_on_main">Inizia la riproduzione qui</string>
|
||||
<string name="start_here_on_background">Inizia qui in sottofondo</string>
|
||||
<string name="start_here_on_popup">Inizia qui nel riproduttore a comparsa</string>
|
||||
<string name="donation_title">Dona</string>
|
||||
<string name="donation_title">Dona</string>
|
||||
<string name="website_title">Sito web</string>
|
||||
<string name="website_encouragement">Visita il sito web di NewPipe per maggiori informazioni e novità.</string>
|
||||
<string name="donation_encouragement">NewPipe è sviluppato da volontari che trascorrono il loro tempo libero per offrire la migliore esperienza. Restituisci il favore per aiutare gli sviluppatori a rendere NewPipe ancora più piacevole mentre si gustano una tazza di caffè.</string>
|
||||
|
@ -310,27 +255,22 @@
|
|||
<string name="switch_to_background">Passa alla riproduzione in background</string>
|
||||
<string name="switch_to_popup">Passa alla visualizzazione popup</string>
|
||||
<string name="switch_to_main">Passa alla produzione predefinita</string>
|
||||
|
||||
<string name="service_title">Servizio</string>
|
||||
<string name="drawer_open">Apri il menu</string>
|
||||
<string name="drawer_close">Chiudi il menu</string>
|
||||
<string name="no_player_found_toast">Nessun lettore multimediale trovato. Puoi installare VLC per riprodurlo.</string>
|
||||
<string name="no_player_found_toast">Nessun lettore multimediale trovato (puoi installare VLC per riprodurlo).</string>
|
||||
<string name="always">Sempre</string>
|
||||
<string name="just_once">Solo una volta</string>
|
||||
|
||||
<string name="external_player_unsupported_link_type">I lettori multimediali esterni non supportano questa tipologia di collegamenti</string>
|
||||
<string name="invalid_url_toast">URL non valido</string>
|
||||
<string name="video_streams_empty">Nessun flusso video trovato</string>
|
||||
<string name="audio_streams_empty">Nessun flusso audio trovato</string>
|
||||
|
||||
<string name="video_player">Lettore video</string>
|
||||
<string name="background_player">Riproduzione in sottofondo</string>
|
||||
<string name="popup_player">Riproduzione in modalità popup</string>
|
||||
<string name="always_ask_player">Chiedi sempre</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Raccogliendo informazioni…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Caricamento del contenuto richiesto</string>
|
||||
<string name="import_data_title">Importa database</string>
|
||||
<string name="import_data_title">Importa database</string>
|
||||
<string name="export_data_title">Esporta database</string>
|
||||
<string name="import_data_summary">Sovrascrive la cronologia corrente e le iscrizioni</string>
|
||||
<string name="export_data_summary">Esporta la cronologia, le iscrizioni e le playlist</string>
|
||||
|
@ -339,94 +279,70 @@
|
|||
<string name="no_valid_zip_file">Nessun file ZIP valido</string>
|
||||
<string name="could_not_import_all_files">Attenzione: Impossibile importare tutti i file.</string>
|
||||
<string name="override_current_data">Questa operazione sostituirà le tue impostazioni attuali.</string>
|
||||
|
||||
<string name="controls_download_desc">Scarica il video</string>
|
||||
<string name="show_info">Mostra informazioni</string>
|
||||
|
||||
<string name="tab_bookmarks">Playlist preferite</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">Aggiungi a</string>
|
||||
|
||||
<string name="detail_drag_description">Trascina per riordinare</string>
|
||||
|
||||
<string name="create">Crea</string>
|
||||
<string name="delete_one">Elimina uno</string>
|
||||
<string name="delete_all">Elimina tutti</string>
|
||||
<string name="dismiss">Ignora</string>
|
||||
<string name="rename">Rinomina</string>
|
||||
|
||||
<string name="delete_stream_history_prompt">Vuoi eliminare questo elemento dalla cronologia delle visualizzazioni?</string>
|
||||
<string name="delete_all_history_prompt">Sei sicuro di voler eliminare tutti gli elementi dalla cronologia?</string>
|
||||
<string name="title_last_played">Ultima riproduzione</string>
|
||||
<string name="title_most_played">I più riprodotti</string>
|
||||
|
||||
<string name="always_ask_open_action">Chiedi sempre</string>
|
||||
|
||||
<string name="create_playlist">Nuova scaletta</string>
|
||||
<string name="delete_playlist">Elimina scaletta</string>
|
||||
<string name="rename_playlist">Rinomina scaletta</string>
|
||||
<string name="playlist_name_input">Nome</string>
|
||||
<string name="append_playlist">Aggiunti alla playlist</string>
|
||||
<string name="set_as_playlist_thumbnail">Imposta come miniatura della playlist</string>
|
||||
|
||||
<string name="bookmark_playlist">Segnalibri playlist</string>
|
||||
<string name="unbookmark_playlist">Rimuovi segnalibro</string>
|
||||
|
||||
<string name="delete_playlist_prompt">Eliminare questa scaletta\?</string>
|
||||
<string name="playlist_creation_success">Playlist creata</string>
|
||||
<string name="playlist_add_stream_success">Aggiunti alla scaletta</string>
|
||||
<string name="playlist_thumbnail_change_success">Miniatura della scaletta cambiata.</string>
|
||||
<string name="playlist_delete_failure">Impossibile eliminare la scaletta.</string>
|
||||
|
||||
<string name="caption_none">No sottotitoli</string>
|
||||
|
||||
<string name="resize_fit">Rientrato</string>
|
||||
<string name="resize_fill">Pieno</string>
|
||||
<string name="resize_zoom">Ingrandito</string>
|
||||
|
||||
<string name="caption_font_size_settings_title">Dimensione dei caratteri dei sottotitoli</string>
|
||||
<string name="smaller_caption_font_size">Carattere più piccolo</string>
|
||||
<string name="normal_caption_font_size">Carattere normale</string>
|
||||
<string name="larger_caption_font_size">Carattere più grande</string>
|
||||
|
||||
<string name="drawer_header_action_paceholder_text">A breve qualcosa apparirà qui ;D</string>
|
||||
|
||||
<string name="settings_category_debug_title">Debug</string>
|
||||
<string name="drawer_header_action_paceholder_text">A breve qualcosa apparirà qui ;D</string>
|
||||
<string name="settings_category_debug_title">Debug</string>
|
||||
<string name="caption_auto_generated">Generato automaticamente</string>
|
||||
<string name="enable_leak_canary_title">Abilita LeakCanary</string>
|
||||
<string name="enable_leak_canary_summary">Il monitoraggio delle perdite di memoria potrebbe causare la mancata risposta dell\'applicazione durante il dumping dell\'heap</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">Segnala Errori \"Out-of-lifecycle\"</string>
|
||||
<string name="enable_disposed_exceptions_summary">Forza la segnalazione di eccezioni Rx non consegnabili al di fuori del ciclo di vita dell\'attività dopo la chiusura</string>
|
||||
|
||||
<string name="use_inexact_seek_title">Usa la ricerca rapida ma imprecisa</string>
|
||||
<string name="use_inexact_seek_title">Usa la ricerca rapida ma imprecisa</string>
|
||||
<string name="use_inexact_seek_summary">La ricerca imprecisa permette al lettore multimediale di spostarsi nelle posizioni più velocemente con una precisione ridotta</string>
|
||||
<string name="auto_queue_title">Metti in coda automaticamente il prossimo flusso</string>
|
||||
<string name="auto_queue_summary">Aggiungi automaticamente un flusso correlato quando è in corso la riproduzione dell\'ultimo flusso in una coda non ripetitiva.</string>
|
||||
<string name="live_sync">SINCRONIZZAZIONE</string>
|
||||
|
||||
<string name="file">File</string>
|
||||
|
||||
<string name="invalid_directory">Nessuna cartella</string>
|
||||
<string name="invalid_source">Nessun file o cartella che contiene sorgenti</string>
|
||||
<string name="invalid_file">Il file non esiste o non si hanno i permessi sufficienti di scrittura o lettura</string>
|
||||
<string name="file_name_empty_error">Il nome del file non può essere vuoto</string>
|
||||
<string name="error_occurred_detail">Si è verificato un errore: %1$s</string>
|
||||
|
||||
<string name="import_export_title">Importa/esporta</string>
|
||||
<string name="import_title">Importa</string>
|
||||
<string name="import_from">Importa da</string>
|
||||
<string name="export_to">Esporta in</string>
|
||||
|
||||
<string name="import_ongoing">Importando…</string>
|
||||
<string name="export_ongoing">Esportando…</string>
|
||||
|
||||
<string name="import_file_title">Importa file</string>
|
||||
<string name="previous_export">Esportazione precedente</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">Impossibile importare le iscrizioni</string>
|
||||
<string name="subscriptions_export_unsuccessful">Impossibile esportare le iscrizioni</string>
|
||||
|
||||
<string name="import_youtube_instructions">Importa le iscrizioni di YouTube scaricando il file d\'esportazione:
|
||||
\n
|
||||
\n1. Vai a questo URL: %1$s
|
||||
|
@ -439,12 +355,11 @@
|
|||
\n3. Accedi quando richiesto
|
||||
\n4. Copia l\'URL del profilo a cui vieni indirizzato.</string>
|
||||
<string name="import_soundcloud_instructions_hint">iltuoID, soundcloud.com/iltuoid</string>
|
||||
|
||||
<string name="import_network_expensive_warning">Tieni presente che questa operazione può consumare una grande quantità di traffico dati.
|
||||
\n
|
||||
\nVuoi continuare?</string>
|
||||
<string name="download_thumbnail_title">Carica miniature</string>
|
||||
<string name="download_thumbnail_summary">Disabilita il caricamento delle miniature, risparmiando dati e memoria. La modifica dell\'opzione comporta la cancellazione della cache in memoria e sul disco.</string>
|
||||
<string name="download_thumbnail_title">Carica miniature</string>
|
||||
<string name="download_thumbnail_summary">Disabilita per prevenire il caricamento delle miniature, risparmiando dati e memoria. La modifica di questa opzione cancellerà la cache delle immagini in memoria e sul disco.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Pulizia della cache delle immagini completata</string>
|
||||
<string name="metadata_cache_wipe_title">Pulisci la cache dei metadati</string>
|
||||
<string name="metadata_cache_wipe_summary">Rimuovi tutti i dati delle pagine web memorizzati nella cache</string>
|
||||
|
@ -455,16 +370,12 @@
|
|||
<string name="unhook_checkbox">Scollega (può causare distorsione)</string>
|
||||
<string name="playback_nightcore">Nightcore</string>
|
||||
<string name="playback_default">Valore predefinito</string>
|
||||
<string name="no_streams_available_download">Nessun flusso disponibile per il download</string>
|
||||
|
||||
<string name="no_streams_available_download">Nessun flusso disponibile per il download</string>
|
||||
<string name="preferred_open_action_settings_title">\'Apri\' preferibilmente con</string>
|
||||
<string name="preferred_open_action_settings_summary">Azione predefinita all\'apertura del contenuto — %s</string>
|
||||
|
||||
<string name="caption_setting_title">Sottotitoli</string>
|
||||
<string name="caption_setting_description">Modifica la dimensione e gli stili di sfondo dei sottotitoli. Per applicare le modifiche è richesto un riavvio.</string>
|
||||
|
||||
<string name="toast_no_player">Nessuna app installata per riprodurre questo file</string>
|
||||
|
||||
<string name="clear_views_history_title">Pulisci cronologia visualizzazioni</string>
|
||||
<string name="clear_views_history_summary">Elimina la cronologia dei flussi riprodotti</string>
|
||||
<string name="delete_view_history_alert">Elimina l\'intera cronologia delle visualizzazioni\?</string>
|
||||
|
@ -474,10 +385,8 @@
|
|||
<string name="delete_search_history_alert">Elimina l\'intera cronologia delle ricerche\?</string>
|
||||
<string name="search_history_deleted">Cronologia delle ricerche eliminata.</string>
|
||||
<string name="one_item_deleted">1 elemento eliminato.</string>
|
||||
|
||||
<string name="app_license">NewPipe è un software libero con licenza copyleft: si può utilizzarlo, studiarlo, condividerlo e migliorarlo a proprio piacimento. In particolare, è possibile ridistribuirlo e/o modificarlo secondo i termini della GNU General Public License pubblicata dalla Free Software Foundation, sia nella versione 3 della Licenza, sia (a propria discrezione) in qualsiasi versione successiva.</string>
|
||||
<string name="import_settings">Vuoi anche importare le impostazioni?</string>
|
||||
|
||||
<string name="privacy_policy_title">Informativa sulla privacy</string>
|
||||
<string name="privacy_policy_encouragement">Il progetto NewPipe tiene molto alla tua privacy. Perciò, l\'app non raccoglie alcun dato senza il tuo consenso.
|
||||
\nL\'informativa sulla privacy di NewPipe spiega in dettaglio quali dati vengono inviati e memorizzati quando si invia un rapporto sugli arresti anomali.</string>
|
||||
|
@ -486,20 +395,17 @@
|
|||
\nDevi accettarla per inviarci il bug report.</string>
|
||||
<string name="accept">Accetto</string>
|
||||
<string name="decline">Rifiuto</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">Senza limiti</string>
|
||||
<string name="limit_mobile_data_usage_title">Limita la risoluzione quando si utilizzano dati mobili</string>
|
||||
<string name="skip_silence_checkbox">Avanzamento veloce durante il silenzio</string>
|
||||
<string name="playback_step">Step</string>
|
||||
<string name="playback_reset">Reset</string>
|
||||
|
||||
<string name="minimize_on_exit_title">Minimizza al cambio dell\'applicazione</string>
|
||||
<string name="minimize_on_exit_summary">Azione quando si passa ad un\'altra app dal lettore video principale — %s</string>
|
||||
<string name="minimize_on_exit_none_description">Nessuna</string>
|
||||
<string name="minimize_on_exit_background_description">Minimizza al lettore in sottofondo</string>
|
||||
<string name="minimize_on_exit_popup_description">Minimizza al lettore popup</string>
|
||||
|
||||
<string name="channels">Canali</string>
|
||||
<string name="channels">Canali</string>
|
||||
<string name="playlists">Playlist</string>
|
||||
<string name="tracks">Tracce</string>
|
||||
<string name="users">Utenti</string>
|
||||
|
@ -532,7 +438,7 @@
|
|||
<string name="app_update_notification_content_title">Aggiornamento di NewPipe disponibile!</string>
|
||||
<string name="app_update_notification_content_text">Premi per scaricare</string>
|
||||
<string name="missions_header_finished">Finito</string>
|
||||
<string name="missions_header_pending">In coda</string>
|
||||
<string name="missions_header_pending">In attesa di</string>
|
||||
<string name="paused">in pausa</string>
|
||||
<string name="queued">in coda</string>
|
||||
<string name="post_processing">post-processo</string>
|
||||
|
@ -543,12 +449,12 @@
|
|||
<string name="download_finished_more">%s download finiti</string>
|
||||
<string name="generate_unique_name">Genera un nome unico</string>
|
||||
<string name="overwrite">Sovrascrivi</string>
|
||||
<string name="overwrite_warning">Esiste già un file scaricato con lo stesso nome</string>
|
||||
<string name="overwrite_finished_warning">Esiste già un file scaricato con lo stesso nome</string>
|
||||
<string name="download_already_running">C\'è un download in progresso con questo nome</string>
|
||||
<string name="show_error">Mostra errore</string>
|
||||
<string name="label_code">Codice</string>
|
||||
<string name="error_path_creation">Impossibile creare il file</string>
|
||||
<string name="error_file_creation">Impossibile creare la cartella di destinazione</string>
|
||||
<string name="error_file_creation">Impossibile creare il file</string>
|
||||
<string name="error_path_creation">Impossibile creare la cartella di destinazione</string>
|
||||
<string name="error_permission_denied">Permesso negato dal sistema</string>
|
||||
<string name="error_ssl_exception">Connessione sicura fallita</string>
|
||||
<string name="error_unknown_host">Impossibile trovare il server</string>
|
||||
|
@ -564,7 +470,8 @@
|
|||
<string name="max_retry_msg">Tentativi massimi</string>
|
||||
<string name="max_retry_desc">Tentativi massimi prima di cancellare il download</string>
|
||||
<string name="pause_downloads_on_mobile">Metti in pausa quando si usano i dati mobili</string>
|
||||
<string name="pause_downloads_on_mobile_desc">I download che non possono essere messi in pausa verranno ravviati</string>
|
||||
<string name="pause_downloads_on_mobile_desc">I download che non possono essere messi in pausa verranno riavviati</string>
|
||||
<string name="events">Eventi</string>
|
||||
<string name="conferences">Conferenze</string>
|
||||
<string name="error_timeout">Connesione finita</string>
|
||||
</resources>
|
|
@ -3,7 +3,7 @@
|
|||
<string name="upload_date_text">%1$s に公開</string>
|
||||
<string name="no_player_found">動画プレイヤーが見つかりません。VLC を入手しますか?</string>
|
||||
<string name="install">入手</string>
|
||||
<string name="cancel">取り消し</string>
|
||||
<string name="cancel">キャンセル</string>
|
||||
<string name="open_in_browser">ブラウザで開く</string>
|
||||
<string name="share">共有</string>
|
||||
<string name="download">保存</string>
|
||||
|
@ -21,14 +21,14 @@
|
|||
<string name="kore_not_found">Koreが見つかりません。Kore を入手しますか?</string>
|
||||
<string name="show_play_with_kodi_title">\"Kodi で再生\" オプションを表示</string>
|
||||
<string name="show_play_with_kodi_summary">Kodi メディアセンター経由で動画を再生するための設定を表示します</string>
|
||||
<string name="play_audio">音楽</string>
|
||||
<string name="default_audio_format_title">デフォルトの音楽形式</string>
|
||||
<string name="play_audio">音声</string>
|
||||
<string name="default_audio_format_title">デフォルトの音声形式</string>
|
||||
<string name="download_dialog_title">保存</string>
|
||||
<string name="next_video_title">次</string>
|
||||
<string name="show_next_and_similar_title">「次の動画」と「関連動画」を表示</string>
|
||||
<string name="url_not_supported_toast">URLは使用できません</string>
|
||||
<string name="content_language_title">優先言語</string>
|
||||
<string name="settings_category_video_audio_title">動画と音楽</string>
|
||||
<string name="settings_category_video_audio_title">動画と音声</string>
|
||||
<string name="view_count_text">%1$s ビュー</string>
|
||||
<string name="list_thumbnail_view_description">動画 プレビュー サムネイル</string>
|
||||
<string name="detail_thumbnail_view_description">動画 プレビュー サムネイル</string>
|
||||
|
@ -38,23 +38,18 @@
|
|||
<string name="use_external_video_player_title">外部プレイヤーを使用する</string>
|
||||
<string name="use_external_audio_player_title">外部プレイヤーを使用する</string>
|
||||
<string name="background_player_playing_toast">バックグラウンドで再生中</string>
|
||||
|
||||
<string name="play_btn_text">再生</string>
|
||||
|
||||
<string name="use_tor_title">Torを使用する</string>
|
||||
<string name="use_tor_summary">(実験的) 強制的に Tor を経由した経路で保存して、匿名性を高めます(動画の同時再生は未だ対応していません)。</string>
|
||||
<string name="use_tor_summary">(実験的) 強制的に Tor を経由した経路で保存して、匿名性を高めます(ストリーミング再生には、まだ対応していません)。</string>
|
||||
<string name="theme_title">テーマ</string>
|
||||
<string name="dark_theme_title">ダーク</string>
|
||||
<string name="light_theme_title">ライト</string>
|
||||
|
||||
<string name="dark_theme_title">グレー</string>
|
||||
<string name="light_theme_title">ホワイト</string>
|
||||
<string name="settings_category_appearance_title">外観</string>
|
||||
<string name="settings_category_other_title">その他</string>
|
||||
<string name="network_error">ネットワークエラー</string>
|
||||
|
||||
<string name="download_path_audio_title">音楽を保存する場所</string>
|
||||
<string name="download_path_audio_title">音声を保存する場所</string>
|
||||
<string name="download_path_audio_summary">ダウンロードした音楽をここに保存します</string>
|
||||
<string name="download_path_audio_dialog_title">音楽ファイルをダウンロードする場所を入力して下さい。</string>
|
||||
|
||||
<string name="err_dir_create">保存場所 \'%1$s\' を作成できません</string>
|
||||
<string name="info_dir_created">保存場所 \'%1$s\' を作成しました</string>
|
||||
<string name="general_error">エラー</string>
|
||||
|
@ -63,126 +58,91 @@
|
|||
<string name="parsing_error">Webサイトを解析できませんでした</string>
|
||||
<string name="content_not_available">コンテンツが利用できません</string>
|
||||
<string name="blocked_by_gema">GEMA にブロックされました</string>
|
||||
|
||||
<string name="could_not_setup_download_menu">保存メニューを設定できませんでした</string>
|
||||
|
||||
|
||||
<string name="live_streams_not_supported">生放送にはまだ対応していません</string>
|
||||
|
||||
|
||||
<string name="content">コンテンツ</string>
|
||||
<string name="show_age_restricted_content_title">年齢制限のあるコンテンツ</string>
|
||||
<string name="video_is_age_restricted">この動画には年齢制限があります。視聴するには設定から制限を解除して下さい。</string>
|
||||
|
||||
<string name="show_age_restricted_content_title">年齢制限のあるコンテンツを表示する</string>
|
||||
<string name="video_is_age_restricted">年齢制限された動画を表示しています。設定から許可することができます。</string>
|
||||
<string name="light_parsing_error">ウェブサイトを完全には解析できませんでした</string>
|
||||
<string name="could_not_get_stream">動画を取得できませんでした</string>
|
||||
<string name="sorry_string">申し訳ありません。発生すべきでものではありませんでした。</string>
|
||||
<string name="error_report_button_text">メールで不具合を報告</string>
|
||||
<string name="error_snackbar_message">申し訳ありません、不具合が発生しました</string>
|
||||
<string name="error_snackbar_message">申し訳ありません、不具合が発生しました。</string>
|
||||
<string name="error_snackbar_action">報告</string>
|
||||
<string name="what_device_headline">情報:</string>
|
||||
<string name="what_happened_headline">何が起こりましたか:</string>
|
||||
<string name="your_comment">あなたの意見(英語で):</string>
|
||||
<string name="what_happened_headline">発生した内容:</string>
|
||||
<string name="your_comment">あなたのコメント(英語で):</string>
|
||||
<string name="error_details_headline">詳細:</string>
|
||||
|
||||
|
||||
<string name="video">動画</string>
|
||||
<string name="audio">音楽</string>
|
||||
<string name="audio">音声</string>
|
||||
<string name="retry">再試行</string>
|
||||
<string name="storage_permission_denied">ストレージへのアクセスが拒否されました</string>
|
||||
<string name="autoplay_by_calling_app_title">自動再生</string>
|
||||
<string name="autoplay_by_calling_app_summary">NewPipe が他のアプリから呼び出された時、動画を再生します。</string>
|
||||
<string name="report_error">不具合を報告</string>
|
||||
<string name="user_report">利用者報告</string>
|
||||
|
||||
<string name="user_report">利用者レポートを送る</string>
|
||||
<string name="duration_live">生放送</string>
|
||||
|
||||
<string name="main_bg_subtitle">開始するには検索をタップ</string>
|
||||
<string name="start">開始</string>
|
||||
<string name="pause">一時停止</string>
|
||||
<string name="view">再生</string>
|
||||
<string name="delete">削除</string>
|
||||
<string name="delete">削除する</string>
|
||||
<string name="checksum">チェックサム</string>
|
||||
|
||||
<string name="add">新しいミッション</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="msg_name">ファイル名</string>
|
||||
<string name="msg_threads">同時接続数</string>
|
||||
<string name="msg_error">エラー</string>
|
||||
<string name="msg_server_unsupported">サーバーが対応していません</string>
|
||||
<string name="msg_server_unsupported">このサーバーには対応していません</string>
|
||||
<string name="msg_exists">ファイルが既に存在します</string>
|
||||
<string name="msg_url_malform">URL の形式が正しくないか、通信が利用できません</string>
|
||||
<string name="msg_running">NewPipeの保存中</string>
|
||||
<string name="msg_running">NewPipeで保存中</string>
|
||||
<string name="msg_running_detail">タップして詳細を表示</string>
|
||||
<string name="msg_wait">お待ちください…</string>
|
||||
<string name="msg_copied">クリップボードにコピーしました</string>
|
||||
<string name="no_available_dir">ダウンロードフォルダを選択して下さい</string>
|
||||
|
||||
<string name="downloads">ダウンロード</string>
|
||||
<string name="downloads_title">ダウンロード</string>
|
||||
<string name="error_report_title">不具合報告</string>
|
||||
|
||||
<string name="could_not_load_image">画像を読み込みできません</string>
|
||||
|
||||
<string name="app_ui_crash">アプリ/UI がクラッシュしました</string>
|
||||
<string name="info_labels">何:\\\\n提案:\\\\nコンテンツ言語:\\\\nサービス:\\\\nGMT 時間:\\\\nパッケージ:\\\\nバージョン:\\\\nOSバージョン:</string>
|
||||
<string name="reCaptchaActivity">reCAPTCHA</string>
|
||||
<string name="reCaptcha_title">reCAPTCHA の要求</string>
|
||||
|
||||
<string name="recaptcha_request_toast">reCAPTCHA を要求しました</string>
|
||||
|
||||
<string name="black_theme_title">ブラック</string>
|
||||
|
||||
<string name="all">すべて</string>
|
||||
<string name="channel">チャンネル</string>
|
||||
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">B</string>
|
||||
|
||||
<string name="yes">はい</string>
|
||||
<string name="later">後で</string>
|
||||
|
||||
|
||||
<string name="open_in_popup_mode">ポップアップモードで開く</string>
|
||||
<string name="msg_popup_permission">ポップアップモードで開くには
|
||||
このアクセス許可が必要です</string>
|
||||
|
||||
\n権限の許可が必要です</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe ポップアップモード</string>
|
||||
|
||||
<string name="popup_playing_toast">ポップアップモードで再生中</string>
|
||||
<string name="use_old_player_title">古いプレーヤーを使用する</string>
|
||||
<string name="use_old_player_summary">古い内蔵のMediaframeworkプレーヤー</string>
|
||||
<string name="disabled">無効</string>
|
||||
|
||||
<string name="default_video_format_title">デフォルトの動画形式</string>
|
||||
|
||||
<string name="default_popup_resolution_title">デフォルトのポップアップ解像度</string>
|
||||
<string name="show_higher_resolutions_title">高い解像度で表示</string>
|
||||
<string name="show_higher_resolutions_summary">2K/4K ビデオの再生は一部のデバイスのみサポートしています</string>
|
||||
<string name="controls_background_title">背景</string>
|
||||
<string name="controls_background_title">バックグラウンド</string>
|
||||
<string name="controls_popup_title">ポップアップ</string>
|
||||
|
||||
<string name="filter">フィルター</string>
|
||||
<string name="refresh">更新</string>
|
||||
<string name="clear">クリア</string>
|
||||
|
||||
<string name="popup_remember_size_pos_title">ポップアップのサイズと位置を記憶する</string>
|
||||
<string name="popup_remember_size_pos_summary">前回のポップアップしたサイズと位置を記憶する</string>
|
||||
|
||||
<string name="popup_remember_size_pos_title">ポップアップのサイズと位置を記憶</string>
|
||||
<string name="popup_remember_size_pos_summary">ポップアップしたサイズと位置を記憶します</string>
|
||||
<string name="settings_category_popup_title">ポップアップ</string>
|
||||
<string name="popup_resizing_indicator_title">サイズを変更</string>
|
||||
|
||||
<string name="use_external_video_player_summary">一部の解像度では音声がありません</string>
|
||||
<string name="player_gesture_controls_title">プレーヤーのジェスチャー コントロール</string>
|
||||
<string name="player_gesture_controls_title">プレーヤーのジェスチャー制御</string>
|
||||
<string name="player_gesture_controls_summary">ジェスチャーを使用してプレーヤーの明るさと音量をコントロールする</string>
|
||||
<string name="show_search_suggestions_title">検索候補</string>
|
||||
<string name="show_search_suggestions_title">検索候補の表示</string>
|
||||
<string name="show_search_suggestions_summary">検索時に候補を表示します</string>
|
||||
|
||||
<string name="best_resolution">最高の解像度</string>
|
||||
|
||||
<string name="best_resolution">最高の解像度</string>
|
||||
<string name="title_activity_about">NewPipe について</string>
|
||||
<string name="action_settings">設定</string>
|
||||
<string name="action_about">このアプリについて</string>
|
||||
|
@ -199,34 +159,29 @@
|
|||
<string name="contribution_encouragement">翻訳、デザインの変更、コードの整理、動作の重いコードの変更など、アイデアをお持ちではありませんか?ヘルプはいつでも歓迎します。より良いものを一緒に作り上げましょう!</string>
|
||||
<string name="read_full_license">ライセンスを読む</string>
|
||||
<string name="contribution_title">貢献する</string>
|
||||
<string name="subscribe_button_title">チャンネル登録</string>
|
||||
<string name="subscribe_button_title">チャンネル登録</string>
|
||||
<string name="subscribed_button_title">チャンネル登録しました</string>
|
||||
<string name="channel_unsubscribed">チャンネル登録を解除しました</string>
|
||||
<string name="subscription_change_failed">チャンネル登録を変更できません</string>
|
||||
<string name="subscription_update_failed">チャンネル登録を更新できません</string>
|
||||
|
||||
<string name="tab_main">メイン</string>
|
||||
<string name="tab_subscriptions">登録リスト</string>
|
||||
|
||||
<string name="fragment_whats_new">新着</string>
|
||||
|
||||
<string name="enable_search_history_title">検索履歴</string>
|
||||
<string name="enable_search_history_summary">検索履歴をローカルに保存します</string>
|
||||
<string name="enable_search_history_summary">検索した履歴を記憶します</string>
|
||||
<string name="enable_watch_history_title">再生履歴とキャッシュ</string>
|
||||
<string name="enable_watch_history_summary">再生した動画を記録します</string>
|
||||
<string name="resume_on_audio_focus_gain_title">フォーカスで再開</string>
|
||||
<string name="enable_watch_history_summary">再生した履歴を記憶します</string>
|
||||
<string name="resume_on_audio_focus_gain_title">オーディオフォーカス復帰で再開する</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">電話などによる中断の後、再生を再開します</string>
|
||||
<string name="settings_category_player_title">プレーヤー</string>
|
||||
<string name="show_hold_to_append_summary">動画の詳細ページで背景、またはポップアップボタンが押されたときにヒントを表示する</string>
|
||||
<string name="show_hold_to_append_summary">動画の詳細ページで、背景またはポップアップボタンが押されたときにヒントを表示する</string>
|
||||
<string name="settings_category_player_behavior_title">動作</string>
|
||||
<string name="settings_category_history_title">履歴とキャッシュ</string>
|
||||
<string name="playlist">再生リスト</string>
|
||||
<string name="playlist">プレイリスト</string>
|
||||
<string name="undo">元に戻す</string>
|
||||
<string name="play_all">すべて再生</string>
|
||||
|
||||
<string name="notification_channel_name">通知</string>
|
||||
<string name="unknown_content">[不明]</string>
|
||||
|
||||
<string name="player_stream_failure">動画の再生ができませんでした</string>
|
||||
<string name="player_unrecoverable_failure">回復不能な再生エラーが発生しました</string>
|
||||
<string name="search_no_results">何も見つかりませんでした</string>
|
||||
|
@ -234,12 +189,10 @@
|
|||
<string name="no_videos">動画がありません</string>
|
||||
<string name="settings_category_downloads_title">保存</string>
|
||||
<string name="settings_file_charset_title">ファイル名に使用可能な文字</string>
|
||||
<string name="settings_file_replacement_character_summary">無効な文字は次の値で置き換えられます</string>
|
||||
<string name="settings_file_replacement_character_title">置換文字</string>
|
||||
|
||||
<string name="settings_file_replacement_character_summary">無効な文字はここで指定した文字に置き換えられます</string>
|
||||
<string name="settings_file_replacement_character_title">ファイル名の自動修正</string>
|
||||
<string name="charset_letters_and_digits">文字と数字</string>
|
||||
<string name="charset_most_special_characters">ほとんどの特殊文字</string>
|
||||
|
||||
<string name="charset_most_special_characters">文字と数字と、多くの特殊文字</string>
|
||||
<string name="donation_title">寄付</string>
|
||||
<string name="donation_encouragement">NewPipe は、あなたに最高の体験を味わってもらうために、ボランティアが自分たちの時間を使って開発しています。開発者たちがコーヒーを飲みながら NewPipe を継続的に改良できるよう、あなたのご支援をお願いします。</string>
|
||||
<string name="website_title">Webサイト</string>
|
||||
|
@ -247,24 +200,22 @@
|
|||
<string name="title_activity_history">履歴</string>
|
||||
<string name="title_history_search">検索履歴</string>
|
||||
<string name="title_history_view">再生履歴</string>
|
||||
<string name="history_disabled">履歴は無効です</string>
|
||||
<string name="history_disabled">履歴は無効になっています</string>
|
||||
<string name="action_history">履歴</string>
|
||||
<string name="history_empty">履歴に何もありません</string>
|
||||
<string name="history_cleared">履歴を消去しました</string>
|
||||
<string name="history_cleared">履歴を削除しました</string>
|
||||
<string name="item_deleted">アイテムを削除しました</string>
|
||||
<string name="delete_item_search_history">このアイテムを検索履歴から削除しますか?</string>
|
||||
|
||||
<string name="main_page_content">メインページのコンテンツ</string>
|
||||
<string name="blank_page_summary">空白ページ</string>
|
||||
<string name="kiosk_page_summary">キオスクページ</string>
|
||||
<string name="kiosk_page_summary">Kioskページ</string>
|
||||
<string name="subscription_page_summary">チャンネル登録ページ</string>
|
||||
<string name="feed_page_summary">フィードページ</string>
|
||||
<string name="channel_page_summary">チャンネルページ</string>
|
||||
<string name="select_a_channel">選択したチャンネル</string>
|
||||
<string name="select_a_channel">チャンネルを選択</string>
|
||||
<string name="no_channel_subscribed_yet">購読しているチャンネルはありません</string>
|
||||
<string name="select_a_kiosk">選択したキオスク</string>
|
||||
|
||||
<string name="kiosk">キオスク</string>
|
||||
<string name="select_a_kiosk">Kioskを選択</string>
|
||||
<string name="kiosk">Kiosk</string>
|
||||
<string name="trending">人気</string>
|
||||
<string name="top_50">トップ50</string>
|
||||
<string name="title_activity_popup_player">ポップアップ再生</string>
|
||||
|
@ -272,113 +223,92 @@
|
|||
<string name="play_queue_stream_detail">詳細</string>
|
||||
<string name="play_queue_audio_settings">音声の設定</string>
|
||||
<string name="toggle_orientation">画面を回転</string>
|
||||
<string name="switch_to_background">バックグラウンド再生に変更</string>
|
||||
<string name="switch_to_popup">ポップアップ再生に変更</string>
|
||||
<string name="switch_to_main">メイン再生に変更</string>
|
||||
|
||||
<string name="switch_to_background">バックグラウンド再生を開始</string>
|
||||
<string name="switch_to_popup">ポップアップ再生を開始</string>
|
||||
<string name="switch_to_main">メイン再生に切り替え</string>
|
||||
<string name="no_player_found_toast">動画プレイヤーが見つかりません (VLCをインストールして再生できます)。</string>
|
||||
<string name="default_content_country_title">デフォルトのコンテンツの国</string>
|
||||
<string name="default_content_country_title">デフォルトの地域設定</string>
|
||||
<string name="service_title">サービス</string>
|
||||
<string name="always">常に</string>
|
||||
<string name="just_once">一度だけ</string>
|
||||
|
||||
<string name="import_data_title">データベースのインポート</string>
|
||||
<string name="export_data_title">データベースのエクスポート</string>
|
||||
<string name="import_data_title">データベースをインポート</string>
|
||||
<string name="export_data_title">データベースをエクスポート</string>
|
||||
<string name="import_data_summary">既存の履歴と購読リストは上書きされます</string>
|
||||
<string name="export_data_summary">履歴や購読リスト、プレイリストをエクスポートします</string>
|
||||
<string name="player_recoverable_failure">再生エラーからの回復中</string>
|
||||
<string name="external_player_unsupported_link_type">外部プレーヤーは、これらのタイプのリンクをサポートしていません</string>
|
||||
<string name="invalid_url_toast">無効なURL</string>
|
||||
<string name="export_complete_toast">エクスポートが完了</string>
|
||||
<string name="import_complete_toast">インポートが完了</string>
|
||||
<string name="export_complete_toast">エクスポートしました</string>
|
||||
<string name="import_complete_toast">インポートしました</string>
|
||||
<string name="no_valid_zip_file">有効な ZIP ファイルではありません</string>
|
||||
<string name="could_not_import_all_files">警告: すべてのファイルをインポートできませんでした。</string>
|
||||
<string name="override_current_data">これにより、現在の設定が上書きされます。</string>
|
||||
|
||||
<string name="title_activity_background_player">バックグラウンド再生</string>
|
||||
<string name="start_here_on_main">ここから再生を開始</string>
|
||||
<string name="start_here_on_background">ここからバックグランド再生を開始</string>
|
||||
<string name="drawer_open">ドロワーを開く</string>
|
||||
<string name="drawer_close">ドロワーを閉じる</string>
|
||||
|
||||
<string name="video_player">動画プレーヤー</string>
|
||||
<string name="background_player">バックグラウンドプレーヤー</string>
|
||||
<string name="popup_player">ポップアッププレーヤー</string>
|
||||
<string name="always_ask_player">常に尋ねる</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">情報を取得しています…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">コンテンツを読み込んでいます</string>
|
||||
<string name="controls_download_desc">動画ファイルをダウンロード</string>
|
||||
<string name="controls_download_desc">動画ファイルをダウンロード</string>
|
||||
<string name="show_info">情報を表示</string>
|
||||
|
||||
<string name="tab_bookmarks">ブックマーク</string>
|
||||
|
||||
<string name="download_thumbnail_title">サムネイルを読み込む</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">画像キャッシュを消去しました</string>
|
||||
<string name="metadata_cache_wipe_title">メタデータのキャッシュを消去</string>
|
||||
<string name="metadata_cache_wipe_summary">ウェブページのキャッシュデータをすべて削除します</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">メタデータのキャッシュを消去しました</string>
|
||||
<string name="auto_queue_title">次の動画を自動でキューに追加</string>
|
||||
<string name="metadata_cache_wipe_title">キャッシュを消去</string>
|
||||
<string name="metadata_cache_wipe_summary">アプリ内のキャッシュをデータすべて削除します</string>
|
||||
<string name="metadata_cache_wipe_complete_notice">キャッシュが消去されました</string>
|
||||
<string name="auto_queue_title">関連動画を自動でキューに追加する</string>
|
||||
<string name="settings_category_debug_title">デバッグ</string>
|
||||
<string name="file">ファイル</string>
|
||||
|
||||
<string name="video_streams_empty">動画が見つかりません</string>
|
||||
<string name="audio_streams_empty">音声が見つかりません</string>
|
||||
<string name="invalid_directory">そのフォルダーはありません</string>
|
||||
<string name="invalid_file">ファイルが存在しないか、ファイルへの読み書きができません</string>
|
||||
<string name="invalid_directory">フォルダーが見つかりません</string>
|
||||
<string name="invalid_file">ファイルが存在しないか、読み書きする権限がありません</string>
|
||||
<string name="file_name_empty_error">ファイル名は空白にできません</string>
|
||||
<string name="error_occurred_detail">エラーが発生しました: %1$s</string>
|
||||
<string name="no_streams_available_download">ダウンロードできる動画はありません</string>
|
||||
|
||||
<string name="detail_drag_description">ドラッグして並べ替え</string>
|
||||
|
||||
<string name="create">作成</string>
|
||||
<string name="delete_one">削除</string>
|
||||
<string name="delete_all">すべて削除</string>
|
||||
<string name="dismiss">破棄</string>
|
||||
<string name="rename">名前を変更</string>
|
||||
|
||||
<string name="delete_stream_history_prompt">このアイテムを再生履歴から削除しますか?</string>
|
||||
<string name="delete_all_history_prompt">すべてのアイテムを再生履歴から削除しますか?</string>
|
||||
<string name="always_ask_open_action">常に確認</string>
|
||||
|
||||
<string name="create_playlist">新規プレイリスト</string>
|
||||
<string name="delete_playlist">削除</string>
|
||||
<string name="delete_playlist">削除する</string>
|
||||
<string name="rename_playlist">変更</string>
|
||||
<string name="playlist_name_input">プレイリスト名</string>
|
||||
<string name="append_playlist">プレイリストに追加</string>
|
||||
<string name="set_as_playlist_thumbnail">プレイリストのサムネイルとして設定</string>
|
||||
|
||||
<string name="bookmark_playlist">プレイリストをブックマーク</string>
|
||||
<string name="unbookmark_playlist">ブックマークを削除</string>
|
||||
|
||||
<string name="delete_playlist_prompt">このプレイリストを削除しますか?</string>
|
||||
<string name="playlist_creation_success">プレイリストが作成されました</string>
|
||||
<string name="playlist_add_stream_success">プレイリストに追加しました</string>
|
||||
<string name="playlist_thumbnail_change_success">プレイリストのサムネイルを変更しました。</string>
|
||||
<string name="playlist_delete_failure">プレイリストが削除できませんでした。</string>
|
||||
|
||||
<string name="caption_none">字幕なし</string>
|
||||
|
||||
<string name="playlist_delete_failure">プレイリストを削除できませんでした。</string>
|
||||
<string name="caption_none">字幕表示なし</string>
|
||||
<string name="caption_font_size_settings_title">字幕の文字サイズ</string>
|
||||
<string name="import_export_title">インポート/エクスポート</string>
|
||||
<string name="import_title">インポート</string>
|
||||
<string name="import_from">インポート元</string>
|
||||
<string name="export_to">エクスポート先</string>
|
||||
|
||||
<string name="import_ongoing">インポートしています…</string>
|
||||
<string name="export_ongoing">エクスポートしています…</string>
|
||||
|
||||
<string name="import_file_title">ファイルからインポート</string>
|
||||
<string name="previous_export">前回のエクスポート</string>
|
||||
|
||||
<string name="previous_export">前回のエクスポート先</string>
|
||||
<string name="subscriptions_import_unsuccessful">購読リストがインポートできませんでした</string>
|
||||
<string name="subscriptions_export_unsuccessful">購読リストがエクスポートできませんでした</string>
|
||||
|
||||
<string name="playback_tempo">テンポ</string>
|
||||
<string name="playback_tempo">速度</string>
|
||||
<string name="playback_pitch">音程</string>
|
||||
<string name="playback_default">デフォルト</string>
|
||||
<string name="background_player_append">バックグラウンド再生の順番待ちに追加</string>
|
||||
<string name="background_player_append">バックグラウンド再生の順番待ちに追加</string>
|
||||
<string name="popup_playing_append">ポップアップ再生の順番待ちに追加</string>
|
||||
<string name="clear_views_history_title">再生履歴を消去</string>
|
||||
<string name="clear_views_history_summary">再生した動画の履歴を削除します</string>
|
||||
|
@ -387,9 +317,7 @@
|
|||
<string name="clear_search_history_summary">検索キーワードの履歴を削除します</string>
|
||||
<string name="search_history_deleted">検索履歴を削除しました。</string>
|
||||
<string name="toast_no_player">このファイルを再生するためのアプリがインストールされていません</string>
|
||||
|
||||
<string name="import_settings">設定をインポートしますか?</string>
|
||||
|
||||
<string name="import_settings">設定もインポートしますか?</string>
|
||||
<string name="caption_setting_title">字幕</string>
|
||||
<string name="channels">チャンネル</string>
|
||||
<string name="playlists">プレイリスト</string>
|
||||
|
@ -397,81 +325,65 @@
|
|||
<string name="privacy_policy_title">NewPipe プライバシーポリシー</string>
|
||||
<string name="read_privacy_policy">プライバシーポリシーを確認</string>
|
||||
<string name="use_inexact_seek_title">おおまかなシーク</string>
|
||||
<string name="use_inexact_seek_summary">おおまかなシークを使用すると、正確さ下がりますが、高速なシークが可能になります</string>
|
||||
<string name="use_inexact_seek_summary">おおまかなシークを使用すると、正確さが下がりますが高速なシークが可能になります</string>
|
||||
<string name="download_thumbnail_summary">すべてのサムネイルの読み込みと保存を無効化します、このオプションを切り替えるとメモリおよびディスク上の画像キャッシュがクリアされます。</string>
|
||||
<string name="auto_queue_summary">繰り返しでないキューの最後の動画を再生時、関連動画を自動的にキューに追加する。</string>
|
||||
<string name="delete_view_history_alert">すべての再生履歴を削除します?</string>
|
||||
<string name="delete_search_history_alert">すべての検索履歴を削除します?</string>
|
||||
<string name="auto_queue_summary">繰り返しではないキューの再生後、関連動画を自動的にキューに追加します</string>
|
||||
<string name="delete_view_history_alert">すべての再生履歴を削除しますか?</string>
|
||||
<string name="delete_search_history_alert">すべての検索履歴を削除しますか?</string>
|
||||
<string name="invalid_source">このファイル/コンテンツはありません</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="other">登録者数 %s 人</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">登録者数 %s 人</item>
|
||||
</plurals>
|
||||
<string name="no_views">視聴なし</string>
|
||||
<plurals name="views">
|
||||
<item quantity="other">視聴回数 %s 回</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">視聴回数 %s 回</item>
|
||||
</plurals>
|
||||
<plurals name="videos">
|
||||
<item quantity="other">本の動画</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">本の動画</item>
|
||||
</plurals>
|
||||
<string name="one_item_deleted">1 つのアイテムが削除されました</string>
|
||||
|
||||
<string name="give_back">支援する</string>
|
||||
<string name="privacy_policy_encouragement">NewPipe プロジェクトはあなたのプライバシーを非常に大切にしています。あなたの同意がない限り、アプリはいかなるデータも収集しません。NewPipe のプライバシー・ポリシーでは、クラッシュリポート送信時にどのような種類のデータが送信・記録されるかを詳細に説明しています。</string>
|
||||
<string name="app_license">NewPipe は著作権が自由のソフトウェアです。あなたは自由にそれを使用し、研究し、そして改善することができます。あなたは、GNU フリーソフトウェア財団が公開する GNU General Public ライセンス バージョン3以降の下に、自由に再配布・修正を行うことができます。</string>
|
||||
<string name="title_last_played">最終再生日時</string>
|
||||
<string name="title_most_played">最も再生した動画</string>
|
||||
|
||||
<string name="resize_zoom">ズーム</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">追加...</string>
|
||||
|
||||
<string name="show_hold_to_append_title">「長押しして追加」のヒントを表示</string>
|
||||
<string name="controls_add_to_playlist_title">プレイリスト</string>
|
||||
<string name="show_hold_to_append_title">「長押しして追加」のヒントを表示する</string>
|
||||
<string name="tracks">トラック</string>
|
||||
<string name="notification_channel_description">NewPipe バックグラウンドおよびポップアップのプレーヤーの通知</string>
|
||||
|
||||
<string name="new_and_hot">新しい & ホット</string>
|
||||
<string name="new_and_hot">新着 & 人気</string>
|
||||
<string name="hold_to_append">長押ししてキューに入れる</string>
|
||||
<string name="enqueue_on_background">バックグラウンド時にキューに入れる</string>
|
||||
<string name="enqueue_on_popup">ポップアップ時にキューに入れる</string>
|
||||
<string name="start_here_on_popup">新ポップアップ時にここから開始</string>
|
||||
|
||||
<string name="enqueue_on_background">バックグラウンド再生のキューに入れる</string>
|
||||
<string name="enqueue_on_popup">ポップアップ再生のキューに入れる</string>
|
||||
<string name="start_here_on_popup">ポップアップ時にここから開始</string>
|
||||
<string name="drawer_header_action_paceholder_text">すぐにここに表示されます;D</string>
|
||||
|
||||
|
||||
<string name="preferred_open_action_settings_title">お好みの \'開く\' アクション</string>
|
||||
<string name="preferred_open_action_settings_summary">コンテンツを開くときのデフォルト動作 — %s</string>
|
||||
|
||||
<string name="resize_fit">フィット</string>
|
||||
<string name="resize_fill">埋める</string>
|
||||
<string name="resize_fill">全画面</string>
|
||||
<string name="caption_auto_generated">自動生成</string>
|
||||
|
||||
<string name="caption_setting_description">プレーヤーのキャプション文字スケールと背景スタイルを変更します。有効にするにはアプリの再起動が必要です。</string>
|
||||
|
||||
<string name="caption_setting_description">アプリの再起動後、設定した字幕設定が反映されます</string>
|
||||
<string name="empty_subscription_feed_subtitle">何もありません</string>
|
||||
<string name="import_youtube_instructions">保存したエクスポートファイルからYoutubeの購読をインポート:
|
||||
<string name="import_youtube_instructions">保存したエクスポートファイルからYouTubeの購読をインポート:
|
||||
\n
|
||||
\n1. このURLを開きます: %1$s
|
||||
\n2. ログインしていなければログインします
|
||||
\n3. ダウンロードが始まります (これがエクスポートファイルです)</string>
|
||||
<string name="playback_reset">リセット</string>
|
||||
|
||||
<string name="accept">同意する</string>
|
||||
<string name="decline">拒否</string>
|
||||
|
||||
<string name="decline">拒否する</string>
|
||||
<string name="limit_data_usage_none_description">制限なし</string>
|
||||
<string name="limit_mobile_data_usage_title">モバイルデータ使用時の解像度の制限</string>
|
||||
<string name="minimize_on_exit_title">アプリ切り替え時の最小化</string>
|
||||
<string name="minimize_on_exit_summary">プレーヤーから他アプリに切り替え時の動作 — %s</string>
|
||||
<string name="minimize_on_exit_summary">プレーヤーから他のアプリに切り替え時の動作 — %s</string>
|
||||
<string name="minimize_on_exit_none_description">何もしない</string>
|
||||
<string name="minimize_on_exit_background_description">バックグラウンドに変更</string>
|
||||
<string name="minimize_on_exit_popup_description">ポップアップに変更</string>
|
||||
<string name="enable_leak_canary_title">LeakCanary を有効にする</string>
|
||||
<string name="enable_leak_canary_summary">メモリリークの監視は、ヒープのダンピング時にアプリが無反応になる原因となります</string>
|
||||
<string name="enable_leak_canary_summary">メモリリークの監視は、ヒープダンピング時にアプリが無反応になる原因となります</string>
|
||||
<string name="enable_disposed_exceptions_title">ライフサイクルエラーの報告</string>
|
||||
<string name="enable_disposed_exceptions_summary">破棄後のフラグメントまたはアクティビティライフサイクル外の到達不能RX例外を強制的に報告します</string>
|
||||
<string name="enable_disposed_exceptions_summary">破棄されたフラグメントまたはアクティビティの、ライフサイクル範囲外での配信不能なRx例外を強制的に報告します</string>
|
||||
<string name="import_soundcloud_instructions">URL または ID を入力して SoundCloud プロファイルをインポートします:
|
||||
\n
|
||||
\n1. Web ブラウザーで \"デスクトップモード\" を有効にします (サイトは携帯デバイスで利用できません)
|
||||
|
@ -479,77 +391,79 @@
|
|||
\n3. 必要に応じてログインします
|
||||
\n4. リダイレクトされたプロファイル URL をコピーします。</string>
|
||||
<string name="import_soundcloud_instructions_hint">あなたのID, soundcloud.com/あなたのid</string>
|
||||
<string name="import_network_expensive_warning">この操作により通信料金が増えることがあることにご注意ください。
|
||||
<string name="import_network_expensive_warning">この操作により通信料金が増えることがあります。ご注意ください。
|
||||
\n
|
||||
\n続行しますか\?</string>
|
||||
<string name="playback_speed_control">再生速度制御</string>
|
||||
<string name="unhook_checkbox">リンク解除 (不備が生じる可能性があります)</string>
|
||||
<string name="playback_speed_control">再生速度を変更</string>
|
||||
<string name="unhook_checkbox">速度と音程を連動せずに変更 (歪むかもしれません)</string>
|
||||
<string name="skip_silence_checkbox">無音の間に早送り</string>
|
||||
<string name="playback_step">ステップ</string>
|
||||
<string name="playback_step">音程幅</string>
|
||||
<string name="unsubscribe">購読解除</string>
|
||||
<string name="tab_new">新しいタブ</string>
|
||||
<string name="tab_choose">タブを選択</string>
|
||||
<string name="settings_category_updates_title">更新</string>
|
||||
<string name="settings_category_updates_title">アプリの更新</string>
|
||||
<string name="events">催し物</string>
|
||||
<string name="app_update_notification_channel_description">新しい NewPipe バージョンの通知</string>
|
||||
<string name="download_to_sdcard_error_title">外部記憶装置きません</string>
|
||||
<string name="download_to_sdcard_error_title">外部記憶装置は利用できません</string>
|
||||
<string name="restore_defaults">既定値に戻す</string>
|
||||
<string name="restore_defaults_confirmation">既定の設定を復元しますか\?</string>
|
||||
<string name="subscribers_count_not_available">加入者数は利用できません</string>
|
||||
<string name="subscribers_count_not_available">登録者数は表示できません</string>
|
||||
<string name="selection">選択</string>
|
||||
<string name="conferences">会議</string>
|
||||
<string name="start_accept_privacy_policy">ヨーロッパの一般データ保護規制(GDPR)に準拠するために、NewPipeの個人情報保護方針にご注意ください。よく読んでください。
|
||||
\nあなたは私たちにバグレポートを送るためにそれを受け入れなければなりません。</string>
|
||||
<string name="updates_setting_title">更新</string>
|
||||
<string name="list_view_mode">リスト ビュー モード</string>
|
||||
\n私たちに不具合報告を送るためには、これを受け入れなければなりません。</string>
|
||||
<string name="updates_setting_title">アプリの更新</string>
|
||||
<string name="list_view_mode">リストビュー モード</string>
|
||||
<string name="list">リスト</string>
|
||||
<string name="grid">グリッド</string>
|
||||
<string name="auto">自動</string>
|
||||
<string name="switch_view">スイッチビュー</string>
|
||||
<string name="app_update_notification_content_title">利用可能なNewPipe更新!</string>
|
||||
<string name="app_update_notification_content_text">ダウンロードするをタップ</string>
|
||||
<string name="app_update_notification_content_title">NewPipeのアップデートがあります!</string>
|
||||
<string name="app_update_notification_content_text">タップでダウンロード</string>
|
||||
<string name="missions_header_finished">終了しました</string>
|
||||
<string name="missions_header_pending">順番待ち</string>
|
||||
<string name="missions_header_pending">保留中</string>
|
||||
<string name="paused">一時停止</string>
|
||||
<string name="queued">待ち行列</string>
|
||||
<string name="post_processing">後処理</string>
|
||||
<string name="enqueue">キュー</string>
|
||||
<string name="permission_denied">システムによって拒否されたアクション</string>
|
||||
<string name="queued">順番待ちに追加しました</string>
|
||||
<string name="post_processing">保存処理をしています</string>
|
||||
<string name="enqueue">順番に処理する</string>
|
||||
<string name="permission_denied">操作がシステムによって拒否されました</string>
|
||||
<string name="download_failed">ダウンロードに失敗しました</string>
|
||||
<string name="download_finished">ダウンロードが完了しました</string>
|
||||
<string name="download_finished_more">%s 件のダウンロード終了</string>
|
||||
<string name="generate_unique_name">一意の名前を生成します</string>
|
||||
<string name="overwrite">上書き</string>
|
||||
<string name="overwrite_warning">この名前のファイルが既に存在します</string>
|
||||
<string name="download_already_running">この名前を持つ進行中のダウンロードがあります</string>
|
||||
<string name="show_error">エラーを表示します</string>
|
||||
<string name="overwrite_unrelated_warning">この名前のファイルは既に存在します</string>
|
||||
<string name="overwrite_finished_warning">この名前のダウンロードファイルは既に存在します</string>
|
||||
<string name="download_already_running">同じ名前を持つダウンロードが既に進行中です</string>
|
||||
<string name="show_error">エラーを表示する</string>
|
||||
<string name="label_code">コード</string>
|
||||
<string name="error_path_creation">ファイルを作成できません</string>
|
||||
<string name="error_file_creation">宛先フォルダを作成できません</string>
|
||||
<string name="error_permission_denied">システムが拒否する許可</string>
|
||||
<string name="error_permission_denied">権限がシステムによって拒否されました</string>
|
||||
<string name="error_ssl_exception">安全な接続に失敗しました</string>
|
||||
<string name="error_unknown_host">サーバが見つからなかった</string>
|
||||
<string name="error_unknown_host">サーバが見つかりませんでした</string>
|
||||
<string name="error_connect_host">サーバに接続できません</string>
|
||||
<string name="error_http_no_content">サーバーはデータを送信しません</string>
|
||||
<string name="error_http_unsupported_range">サーバーは、マルチ スレッドのダウンロードを受け付けない、再試行してください @string/msg_threads = 1</string>
|
||||
<string name="error_http_no_content">サーバがデータを送信していません</string>
|
||||
<string name="error_http_unsupported_range">サーバが同時接続ダウンロードを受け付けません。再試行してください @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">必要な範囲が満たされていません</string>
|
||||
<string name="error_http_not_found">見つかりません</string>
|
||||
<string name="error_postprocessing_failed">後処理失敗</string>
|
||||
<string name="clear_finished_download">明確な完成したダウンロード</string>
|
||||
<string name="error_postprocessing_failed">保存処理に失敗しました</string>
|
||||
<string name="clear_finished_download">完了済みを一覧から削除します</string>
|
||||
<string name="stop">停止</string>
|
||||
<string name="max_retry_msg">最大再試行回数</string>
|
||||
<string name="max_retry_desc">ダウンロードをキャンセルする前に試行の最大数</string>
|
||||
<string name="volume_gesture_control_title">音量ジェスチャー制御</string>
|
||||
<string name="max_retry_desc">ダウンロードを中止するまでの最大再試行回数</string>
|
||||
<string name="volume_gesture_control_title">音量のジェスチャー制御</string>
|
||||
<string name="volume_gesture_control_summary">ジェスチャーを使用して、プレーヤーの音量を制御します</string>
|
||||
<string name="brightness_gesture_control_title">明るさジェスチャー制御</string>
|
||||
<string name="brightness_gesture_control_title">明るさのジェスチャー制御</string>
|
||||
<string name="brightness_gesture_control_summary">ジェスチャーを使用して、プレーヤーの明るさを制御します</string>
|
||||
<string name="file_deleted">ファイルを削除しました</string>
|
||||
<string name="app_update_notification_channel_name">アプリの更新通知</string>
|
||||
<string name="download_to_sdcard_error_message">まだ外部 SD カードにダウンロードできません。ダウンロードフォルダーの場所をリセットしますか\?</string>
|
||||
<string name="saved_tabs_invalid_json">デフォルトのタブを使用します。保存タブの読み取りエラーが発生しました</string>
|
||||
<string name="saved_tabs_invalid_json">デフォルトのタブを使用します。保存されたタブの読み込みエラーが発生しました</string>
|
||||
<string name="main_page_content_summary">メインページに表示されるタブ</string>
|
||||
<string name="updates_setting_description">新しいバージョンが利用可能なときにアプリの更新を確認する通知を表示します</string>
|
||||
<string name="msg_pending_downloads">ダウンロードから %s の保留中の転送を続行します</string>
|
||||
<string name="pause_downloads_on_mobile">モバイルデータ通信に切り替え時に休止</string>
|
||||
<string name="pause_downloads_on_mobile_desc">休止できないダウンロードが再開されます</string>
|
||||
<string name="error_timeout">接続タイムアウト</string>
|
||||
</resources>
|
|
@ -30,7 +30,6 @@
|
|||
<string name="url_not_supported_toast">지원하지 않는 URL 입니다</string>
|
||||
<string name="content_language_title">기본 컨텐츠 언어</string>
|
||||
<string name="settings_category_video_audio_title">비디오 & 오디오</string>
|
||||
|
||||
<string name="list_thumbnail_view_description">비디오 미리보기 썸네일</string>
|
||||
<string name="detail_thumbnail_view_description">비디오 미리보기 썸네일</string>
|
||||
<string name="detail_uploader_thumbnail_view_description">업로더 썸네일</string>
|
||||
|
@ -38,24 +37,19 @@
|
|||
<string name="detail_likes_img_view_description">좋아요</string>
|
||||
<string name="use_external_video_player_title">외부 비디오 플레이어 사용</string>
|
||||
<string name="use_external_audio_player_title">외부 오디오 플레이어 사용</string>
|
||||
|
||||
<string name="download_path_audio_title">오디오 다운로드 폴더</string>
|
||||
<string name="download_path_audio_summary">다운로드된 오디오는 여기에 저장됩니다</string>
|
||||
<string name="download_path_audio_dialog_title">오디오 파일 다운로드 경로를 입력하세요</string>
|
||||
|
||||
<string name="theme_title">테마</string>
|
||||
<string name="dark_theme_title">어두운 테마</string>
|
||||
<string name="light_theme_title">밝은 테마</string>
|
||||
|
||||
<string name="settings_category_appearance_title">외관</string>
|
||||
<string name="settings_category_other_title">기타</string>
|
||||
<string name="background_player_playing_toast">백그라운드에서 재생 중</string>
|
||||
<string name="play_btn_text">재생</string>
|
||||
<string name="network_error">네트워크 오류</string>
|
||||
|
||||
<string name="use_tor_title">Tor 사용</string>
|
||||
<string name="use_tor_summary">(실험적) 향상된 프라이버시를 위해 다운로드 트래픽을 강제로 Tor를 통해 전송 (스트리밍 비디오는 아직 지원되지 않습니다).</string>
|
||||
|
||||
<string name="err_dir_create">다운로드 디렉토리를 만들 수 없습니다 \'%1$s\'</string>
|
||||
<string name="info_dir_created">다운로드 디렉토리를 만들었습니다 \'%1$s\'</string>
|
||||
<string name="main_bg_subtitle">검색 버튼을 눌러서 시작하세요</string>
|
||||
|
@ -65,7 +59,6 @@
|
|||
<string name="show_age_restricted_content_title">연령 제한 컨텐츠</string>
|
||||
<string name="video_is_age_restricted">연령 제한 비디오입니다. 설정 메뉴에서 시청 허용 여부를 변경하실 수 있습니다.</string>
|
||||
<string name="duration_live">라이브</string>
|
||||
|
||||
<string name="general_error">오류</string>
|
||||
<string name="could_not_load_thumbnails">모든 썸네일을 불러올 수 없습니다</string>
|
||||
<string name="youtube_signature_decryption_error">비디오 URL 서명을 복호화할 수 없습니다</string>
|
||||
|
@ -84,11 +77,8 @@
|
|||
<string name="what_happened_headline">다음이 발생함:</string>
|
||||
<string name="your_comment">내용 (영어로 작성):</string>
|
||||
<string name="error_details_headline">자세한 사항:</string>
|
||||
|
||||
|
||||
<string name="report_error">오류 보고</string>
|
||||
<string name="user_report">사용자 보고서</string>
|
||||
|
||||
<string name="video">비디오</string>
|
||||
<string name="audio">오디오</string>
|
||||
<string name="retry">재시도</string>
|
||||
|
@ -99,8 +89,7 @@
|
|||
<string name="pause">일시정지</string>
|
||||
<string name="delete">삭제</string>
|
||||
<string name="checksum">체크섬</string>
|
||||
|
||||
<string name="open_in_popup_mode">팝업 모드에서 열기</string>
|
||||
<string name="open_in_popup_mode">팝업 모드에서 열기</string>
|
||||
<string name="use_external_video_player_summary">일부 해상도에서 소리가 나지 않습니다</string>
|
||||
<string name="popup_mode_share_menu_title">뉴파이프 팝업 모드</string>
|
||||
<string name="subscribe_button_title">구독</string>
|
||||
|
@ -108,15 +97,11 @@
|
|||
<string name="channel_unsubscribed">채널 구독 해제됨</string>
|
||||
<string name="subscription_change_failed">구독 여부를 변경할 수 없음</string>
|
||||
<string name="subscription_update_failed">구독을 업데이트할 수 없음</string>
|
||||
|
||||
<string name="tab_main">메인 화면</string>
|
||||
<string name="tab_subscriptions">구독</string>
|
||||
|
||||
<string name="fragment_whats_new">새로운 영상</string>
|
||||
|
||||
<string name="controls_background_title">배경</string>
|
||||
<string name="controls_popup_title">팝업</string>
|
||||
|
||||
<string name="default_popup_resolution_title">기본 팝업 해상도</string>
|
||||
<string name="show_higher_resolutions_title">높은 해상도 표시</string>
|
||||
<string name="show_higher_resolutions_summary">일부 기기에서만 2K/4K 해상도 재생이 지원됩니다</string>
|
||||
|
@ -157,48 +142,36 @@
|
|||
<string name="best_resolution">최대 해상도</string>
|
||||
<string name="undo">되돌리기</string>
|
||||
<string name="play_all">전부 재생</string>
|
||||
|
||||
<string name="notification_channel_name">뉴파이프 알림</string>
|
||||
<string name="notification_channel_description">뉴파이프 백그라운드 및 팝업 플레이어 알림</string>
|
||||
|
||||
<string name="unknown_content">[알 수 없음]</string>
|
||||
|
||||
<string name="could_not_load_image">이미지를 불러올 수 없습니다</string>
|
||||
<string name="app_ui_crash">앱/UI 충돌</string>
|
||||
<string name="player_stream_failure">이 스트림을 재생할 수 없습니다</string>
|
||||
<string name="player_unrecoverable_failure">복구할 수 없는 플레이어 오류가 발생했습니다</string>
|
||||
<string name="player_recoverable_failure">플레이어 오류로부터 복구 중</string>
|
||||
|
||||
<string name="info_labels">무엇을:\\n요청:\\n컨텐츠 언어:\\n서비스:\\nGMT 기준 시간:\\n패키지:\\n버전:\\n안드로이드 버전:</string>
|
||||
<string name="search_no_results">결과 없음</string>
|
||||
<string name="empty_subscription_feed_subtitle">구독할 항목을 추가하세요</string>
|
||||
|
||||
<string name="use_old_player_title">구형 플레이어 사용</string>
|
||||
<string name="use_old_player_summary">내장된 구형 Mediaframework 플레이어 사용</string>
|
||||
|
||||
<string name="short_thousand">천</string>
|
||||
<string name="short_million">백만</string>
|
||||
<string name="short_billion">10억</string>
|
||||
|
||||
<string name="no_subscribers">구독자 없음</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="other">%s 구독자</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">%s 구독자</item>
|
||||
</plurals>
|
||||
<string name="no_views">시청 횟수 없음</string>
|
||||
<plurals name="views">
|
||||
<item quantity="other">%s 시청 횟수</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">%s 시청 횟수</item>
|
||||
</plurals>
|
||||
<string name="no_videos">비디오 없음</string>
|
||||
<plurals name="videos">
|
||||
<item quantity="other">비디오</item>
|
||||
</plurals>
|
||||
|
||||
<item quantity="other">비디오</item>
|
||||
</plurals>
|
||||
<string name="view">재생</string>
|
||||
<string name="add">새로운 미션</string>
|
||||
<string name="finish">OK</string>
|
||||
|
||||
<string name="msg_name">파일명</string>
|
||||
<string name="msg_threads">쓰레드</string>
|
||||
<string name="msg_error">오류</string>
|
||||
|
@ -212,18 +185,14 @@
|
|||
<string name="no_available_dir">다운로드 할 폴더를 선택하세요</string>
|
||||
<string name="msg_popup_permission">이 권한은 팝업 모드에서
|
||||
\n열기 위해 필요합니다</string>
|
||||
|
||||
<string name="reCaptchaActivity">로봇인지 확인 (reCAPTCHA)</string>
|
||||
<string name="recaptcha_request_toast">reCAPTCHA challenge 요청됨</string>
|
||||
|
||||
<string name="settings_category_downloads_title">다운로드</string>
|
||||
<string name="settings_file_charset_title">파일명에 허용되는 문자</string>
|
||||
<string name="settings_file_replacement_character_summary">올바르지 않은 문자는 다음 문자로 대체됩니다</string>
|
||||
<string name="settings_file_replacement_character_title">대체 문자</string>
|
||||
|
||||
<string name="charset_letters_and_digits">문자 및 숫자</string>
|
||||
<string name="charset_most_special_characters">가장 특수한 문자</string>
|
||||
|
||||
<string name="title_activity_about">뉴파이프에 대해서</string>
|
||||
<string name="action_settings">설정</string>
|
||||
<string name="action_about">뉴파이프</string>
|
||||
|
@ -245,8 +214,6 @@
|
|||
<string name="website_encouragement">뉴파이프에 관한 최신 및 상세 정보를 얻으려면 웹사이트를 방문하세요.</string>
|
||||
<string name="app_license_title">뉴파이프가 채택한 라이센스</string>
|
||||
<string name="read_full_license">라이센스 읽기</string>
|
||||
|
||||
|
||||
<string name="title_activity_history">기록</string>
|
||||
<string name="title_history_search">검색함</string>
|
||||
<string name="title_history_view">시청함</string>
|
||||
|
@ -256,7 +223,6 @@
|
|||
<string name="history_cleared">기록이 삭제되었습니다</string>
|
||||
<string name="item_deleted">항목이 삭제되었습니다</string>
|
||||
<string name="delete_item_search_history">이 항목을 검색 기록에서 삭제할까요?</string>
|
||||
|
||||
<string name="main_page_content">메인 화면의 내용</string>
|
||||
<string name="blank_page_summary">빈 페이지</string>
|
||||
<string name="kiosk_page_summary">키오스크 페이지</string>
|
||||
|
@ -266,7 +232,6 @@
|
|||
<string name="select_a_channel">채널 선택</string>
|
||||
<string name="no_channel_subscribed_yet">구독중인 채널이 없습니다</string>
|
||||
<string name="select_a_kiosk">키오스크 선택</string>
|
||||
|
||||
<string name="kiosk">키오스크</string>
|
||||
<string name="trending">인기 급상승</string>
|
||||
<string name="top_50">탑 50</string>
|
||||
|
@ -276,20 +241,17 @@
|
|||
<string name="play_queue_remove">제거</string>
|
||||
<string name="play_queue_stream_detail">상세 정보</string>
|
||||
<string name="play_queue_audio_settings">오디오 설정</string>
|
||||
<string name="hold_to_append">눌러서 대기 목록에 추가</string>
|
||||
<string name="enqueue_on_background">백그라운드에 대기</string>
|
||||
<string name="enqueue_on_popup">팝업에 대기</string>
|
||||
<string name="hold_to_append">눌러서 대기열에 추가</string>
|
||||
<string name="enqueue_on_background">백그라운드로 갈 경우 대기</string>
|
||||
<string name="enqueue_on_popup">새 팝업으로 갈 경우 대기</string>
|
||||
<string name="start_here_on_main">여기서부터 재생</string>
|
||||
<string name="start_here_on_background">여기서부터 백그라운드에서 재생</string>
|
||||
<string name="start_here_on_popup">여기서부터 팝업에 재생</string>
|
||||
<string name="no_player_found_toast">스트리밍 플레이어를 찾을 수 없습니다. VLC를 설치하면 플레이하실 수 있습니다</string>
|
||||
<string name="start_here_on_background">백그라운드로 갈 경우 여기서부터 재생</string>
|
||||
<string name="start_here_on_popup">새 팝업으로 갈 경우 여기서부터 재생</string>
|
||||
<string name="no_player_found_toast">스트리밍 플레이어를 찾을 수 없습니다. VLC를 설치하면 플레이하실 수 있습니다.</string>
|
||||
<string name="controls_download_desc">스트리밍 파일 다운로드하기</string>
|
||||
<string name="show_info">정보 보기</string>
|
||||
|
||||
<string name="tab_bookmarks">플레이리스트 북마크</string>
|
||||
|
||||
<string name="controls_add_to_playlist_title">이곳에 추가</string>
|
||||
|
||||
<string name="use_inexact_seek_title">정확하지는 않지만 빠른 탐색</string>
|
||||
<string name="use_inexact_seek_summary">정확하지 않은 탐색은 빠르게 위치로 탐색할 수 있지만 정확도는 떨어집니다</string>
|
||||
<string name="auto_queue_title">다음 스트림을 자동으로 재생열에 추가하기</string>
|
||||
|
@ -300,12 +262,10 @@
|
|||
<string name="live">라이브 (LIVE)</string>
|
||||
<string name="always">항상</string>
|
||||
<string name="just_once">한번만</string>
|
||||
|
||||
<string name="toggle_orientation">디바이스 방향 토글</string>
|
||||
<string name="switch_to_background">백그라운드로 전환</string>
|
||||
<string name="switch_to_popup">팝업으로 전환</string>
|
||||
<string name="switch_to_main">기본으로 전환</string>
|
||||
|
||||
<string name="import_data_title">데이터베이스 가져오기</string>
|
||||
<string name="export_data_title">데이터베이스 내보내기</string>
|
||||
<string name="import_data_summary">현재 시청 기록 및 구독 목록을 덮어쓰기 합니다</string>
|
||||
|
@ -314,102 +274,79 @@
|
|||
<string name="invalid_url_toast">잘못된 URL</string>
|
||||
<string name="video_streams_empty">발견된 비디오 스트림 없음</string>
|
||||
<string name="audio_streams_empty">발견된 오디오 스트림 없음</string>
|
||||
|
||||
<string name="detail_drag_description">드래그하여 재배열</string>
|
||||
|
||||
<string name="create">만들기</string>
|
||||
<string name="delete_one">1개 삭제하기</string>
|
||||
<string name="delete_all">모두 삭제하기</string>
|
||||
<string name="dismiss">취소</string>
|
||||
<string name="rename">이름 바꾸기</string>
|
||||
|
||||
<string name="reCaptcha_title">로봇인지 확인합니다</string>
|
||||
<string name="delete_stream_history_prompt">이 항목을 시청 기록에서 삭제하시겠습니까?</string>
|
||||
<string name="delete_all_history_prompt">모든 항목을 시청 기록에서 삭제하시겠습니까?</string>
|
||||
<string name="title_last_played">마지막으로 재생</string>
|
||||
<string name="title_most_played">가장 많이 재생</string>
|
||||
|
||||
<string name="export_complete_toast">내보내기 완료</string>
|
||||
<string name="import_complete_toast">가져오기 완료</string>
|
||||
<string name="no_valid_zip_file">유효한 ZIP 파일 없음</string>
|
||||
<string name="could_not_import_all_files">경고: 모든 파일 가져오기를 실패했습니다.</string>
|
||||
<string name="override_current_data">이것은 현재 설정을 덮어쓸 것입니다.</string>
|
||||
|
||||
<string name="drawer_open">드로어 열기</string>
|
||||
<string name="drawer_close">드로어 닫기</string>
|
||||
<string name="drawer_header_action_paceholder_text">여기에 무언가가 추가될 거에요~ :D</string>
|
||||
|
||||
|
||||
<string name="video_player">비디오 플레이어</string>
|
||||
<string name="background_player">백그라운드 플레이어</string>
|
||||
<string name="popup_player">팝업 플레이어</string>
|
||||
<string name="always_ask_open_action">항상 묻기</string>
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">정보 가져오는 중…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">요청한 콘텐츠를 로딩 중입니다</string>
|
||||
|
||||
<string name="create_playlist">새로운 재생목록</string>
|
||||
<string name="delete_playlist">삭제</string>
|
||||
<string name="rename_playlist">이름 바꾸기</string>
|
||||
<string name="playlist_name_input">이름</string>
|
||||
<string name="append_playlist">재생목록에 추가</string>
|
||||
<string name="set_as_playlist_thumbnail">재생목록 썸네일로 설정</string>
|
||||
|
||||
<string name="bookmark_playlist">재생목록 북마크하기</string>
|
||||
<string name="unbookmark_playlist">북마크 제거하기</string>
|
||||
|
||||
<string name="delete_playlist_prompt">이 재생목록을 삭제하시겠습니까?</string>
|
||||
<string name="playlist_creation_success">재생목록 생성 완료</string>
|
||||
<string name="playlist_add_stream_success">재생목록에 추가됨</string>
|
||||
<string name="playlist_thumbnail_change_success">재생목록 썸내일이 바뀜.</string>
|
||||
<string name="playlist_delete_failure">재생목록을 삭제할 수 없습니다.</string>
|
||||
|
||||
<string name="caption_none">자막 없음</string>
|
||||
|
||||
<string name="resize_fit">꼭 맞게 하기</string>
|
||||
<string name="resize_fill">채우기</string>
|
||||
<string name="resize_zoom">확대</string>
|
||||
|
||||
<string name="caption_auto_generated">자동 생성됨</string>
|
||||
<string name="caption_font_size_settings_title">자막 폰트 크기</string>
|
||||
<string name="smaller_caption_font_size">작은 폰트</string>
|
||||
<string name="normal_caption_font_size">보통 폰트</string>
|
||||
<string name="larger_caption_font_size">큰 폰트</string>
|
||||
|
||||
<string name="live_sync">동기화</string>
|
||||
|
||||
<string name="enable_leak_canary_title">LeakCanary 할성화</string>
|
||||
<string name="enable_leak_canary_summary">힙 덤프 중 메모리 누수 점검으로 앱이 불안정해질 수 있습니다</string>
|
||||
|
||||
<string name="enable_disposed_exceptions_title">out-of-lifecycle 오류 보고</string>
|
||||
<string name="enable_disposed_exceptions_summary">프래그먼트 또는 버려진 액티비티 주기 밖에서 일어나는 전달할 수 없는 Rx 예외를 강제적으로 보고하기</string>
|
||||
|
||||
<string name="file">파일</string>
|
||||
|
||||
<string name="file">파일</string>
|
||||
<string name="invalid_directory">폴더가 존재하지 않습니다</string>
|
||||
<string name="invalid_source">잘못된 파일/콘덴츠 소스</string>
|
||||
<string name="invalid_source">잘못된 파일/콘텐츠 소스</string>
|
||||
<string name="invalid_file">파일이 존재하지 않거나 읽기/쓰기 권한이 없습니다</string>
|
||||
<string name="file_name_empty_error">파일명이 비어 있으면 안됩니다</string>
|
||||
<string name="error_occurred_detail">오류 발생: %1$s</string>
|
||||
|
||||
<string name="import_export_title">가져오기/내보내기</string>
|
||||
<string name="import_title">가져오기</string>
|
||||
<string name="import_from">이곳으로부터 가져오기</string>
|
||||
<string name="export_to">이곳으로 내보내기</string>
|
||||
|
||||
<string name="import_ongoing">가져오는 중.…</string>
|
||||
<string name="export_ongoing">내보내는 중…</string>
|
||||
|
||||
<string name="import_file_title">파일 가져오기</string>
|
||||
<string name="previous_export">이전 내보내기</string>
|
||||
|
||||
<string name="subscriptions_import_unsuccessful">구독 목록 가져오기 실패</string>
|
||||
<string name="subscriptions_export_unsuccessful">구독 목록 내보내기 실패</string>
|
||||
|
||||
<string name="import_youtube_instructions">YouTube 구독 목록을 가져오려면 내보내기 파일이 필요합니다. 다운로드 하려면
|
||||
\n1. 이곳으로 가세요: $1$s
|
||||
\n2. 로그인이 필요하면 하세요
|
||||
\n3. 다운로드가 곧 시작 됩니다 (이 파일이 내보내기 파일 입니다)</string>
|
||||
<string name="import_youtube_instructions">\'YouTube 구독 파일\'을 다운로드해서 구독 목록을 가져올 수 있습니다:
|
||||
\n
|
||||
\n1. 이곳으로 가세요: $1$s
|
||||
\n2. 요청에 따라 로그인을 진행합니다
|
||||
\n3. 다운로드가 곧 시작 됩니다 (이 파일이 구독 파일입니다)</string>
|
||||
<string name="import_soundcloud_instructions">SoundCloud 프로필을 가져오시려면 URL 및 ID를 입력해주세요.
|
||||
\n
|
||||
\n프로필 URL을 찾으시려면 다음 과정을 따라해 주세요.
|
||||
|
@ -418,11 +355,10 @@
|
|||
\n3. 로그인이 필요하면 하세요.
|
||||
\n4. 리디렉트된 곳의 URL을 복사하세요. (이 URL이 당신의 프로필 URL 입니다)</string>
|
||||
<string name="import_soundcloud_instructions_hint">프로필ID, soundcloud.com/프로필ID</string>
|
||||
|
||||
<string name="import_network_expensive_warning">경고: 데이터 소모량이 늘어날 수 있습니다.
|
||||
\n
|
||||
\n계속하시겠습니까?</string>
|
||||
<string name="download_thumbnail_title">썸내일 로드하기</string>
|
||||
<string name="download_thumbnail_title">썸내일 로드하기</string>
|
||||
<string name="download_thumbnail_summary">동영상 썸네일을 로드하지 않으며, 데이터와 메모리 사용을 최대한 줄입니다. 이 옵션을
|
||||
\n선택 시 모든 메모리 캐시와 저장소 캐시를 삭제합니다.</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">이미지 캐시 지워짐</string>
|
||||
|
@ -435,16 +371,12 @@
|
|||
<string name="unhook_checkbox">영상과 소리 분리 (소리가 깨질 수 있음)</string>
|
||||
<string name="playback_nightcore">나이트코어</string>
|
||||
<string name="playback_default">기본</string>
|
||||
<string name="no_streams_available_download">다운로드 가능한 스트림이 없습니다</string>
|
||||
|
||||
<string name="no_streams_available_download">다운로드 가능한 스트림이 없습니다</string>
|
||||
<string name="toast_no_player">이 파일을 재생할 수 있는 플레이어 앱이 없습니다</string>
|
||||
|
||||
<string name="preferred_open_action_settings_title">선호하는 열기 동작</string>
|
||||
<string name="preferred_open_action_settings_summary">컨텐츠를 열 때 사용할 기본 동작 — %s</string>
|
||||
|
||||
<string name="caption_setting_title">자막</string>
|
||||
<string name="caption_setting_description">플레이어 자막 텍스트 크기와 배경 스타일을 변경합니다. 효과를 적용하려면 앱을 재시작 해야합니다.</string>
|
||||
|
||||
<string name="channels">채널만</string>
|
||||
<string name="playlists">재생 목록만</string>
|
||||
<string name="clear_views_history_title">시청 기록 삭제하기</string>
|
||||
|
@ -459,15 +391,12 @@
|
|||
<string name="privacy_policy_encouragement">뉴파이프 프로젝트는 사용자의 개인 정보 보호를 최우선으로 생각하며, 동의 없이 어떠한 정보도 수집하지 않습니다.
|
||||
\n뉴파이프 개인정보 보호 정책에서는 오류 보고 시 어떠한 정보가 수집되고 저장되는지 자세히 명시되어 있습니다.</string>
|
||||
<string name="read_privacy_policy">개인정보 보호 정책 읽기</string>
|
||||
<string name="app_license">뉴파이프는 카피레프트 자유 소프트웨어입니다. 사용자는 이 앱을 사용, 공유, 또는 수정하는 것이 가능하고, 수정 후 재배포 시 자유 소프트웨어 재단의 GNU 라이센스 버전
|
||||
\n3 또는 그 이상의 버전을 포함해야 합니다.</string>
|
||||
<string name="app_license">뉴파이프는 카피레프트 자유 소프트웨어입니다. 사용자는 이 앱을 사용, 공유, 또는 수정할 수 있고, 수정 후 재배포 시 자유 소프트웨어 재단의 GNU 라이센스 버전 3 또는 그 이상의 버전을 포함해야 합니다.</string>
|
||||
<string name="import_settings">앱 설정을 가져오시겠습니까?</string>
|
||||
|
||||
<string name="skip_silence_checkbox">무음 구간 스킵</string>
|
||||
<string name="start_accept_privacy_policy">유럽 연합 일반 데이터 보호 규정 (GDPR) 에 따라, 사용자는 뉴파이프 개인정보 보호 정책을 읽고 꼼꼼히 확인해야 합니다. 버그 리포트를 보내시려면 개인정보 보호 정책에 동의해주세요.</string>
|
||||
<string name="accept">동의</string>
|
||||
<string name="decline">동의하지 않음</string>
|
||||
|
||||
<string name="limit_data_usage_none_description">데이터 제한 없음</string>
|
||||
<string name="limit_mobile_data_usage_title">모바일 데이터 사용 시 화질 제한</string>
|
||||
<string name="unsubscribe">구독 해제</string>
|
||||
|
@ -486,4 +415,63 @@
|
|||
<string name="app_update_notification_channel_description">새 뉴파이프 버전을 알림</string>
|
||||
<string name="download_to_sdcard_error_title">외부 저장소 없음</string>
|
||||
<string name="download_to_sdcard_error_message">다운로드할 SD 카드를 찾을 수 없습니다. 다운로드 폴더 경로를 초기화 하시겠습니까\?</string>
|
||||
<string name="one_item_deleted">1개의 항목이 삭제되었습니다.</string>
|
||||
<string name="minimize_on_exit_title">앱 전환시 최소화</string>
|
||||
<string name="minimize_on_exit_summary">비디오 플레이어에서 다른 앱으로 전환 시 다음과 같은 동작 실행 — %s</string>
|
||||
<string name="minimize_on_exit_none_description">없음</string>
|
||||
<string name="minimize_on_exit_background_description">백그라운드 플레이어로 최소화</string>
|
||||
<string name="minimize_on_exit_popup_description">팝업 플레이어로 최소화</string>
|
||||
<string name="playback_step">단계</string>
|
||||
<string name="playback_reset">초기화</string>
|
||||
<string name="saved_tabs_invalid_json">저장된 탭을 읽는 중 오류가 발생하여 기본 탭을 사용합니다</string>
|
||||
<string name="restore_defaults">기본값 복원</string>
|
||||
<string name="restore_defaults_confirmation">기본값을 복원할까요\?</string>
|
||||
<string name="subscribers_count_not_available">구독자 숫자가 없습니다</string>
|
||||
<string name="main_page_content_summary">메인 화면에 표시할 탭</string>
|
||||
<string name="selection">선택</string>
|
||||
<string name="updates_setting_title">업데이트</string>
|
||||
<string name="updates_setting_description">새 버전이 있을 경우 앱을 업데이트하도록 알림 표시</string>
|
||||
<string name="list_view_mode">\'목록으로 보기\' 모드</string>
|
||||
<string name="list">목록</string>
|
||||
<string name="grid">격자</string>
|
||||
<string name="auto">자동</string>
|
||||
<string name="switch_view">보기 방식 전환</string>
|
||||
<string name="app_update_notification_content_title">NewPipe 업데이트가 있습니다!</string>
|
||||
<string name="app_update_notification_content_text">여기를 눌러서 다운로드</string>
|
||||
<string name="missions_header_finished">완료됨</string>
|
||||
<string name="missions_header_pending">대기열에 있음</string>
|
||||
<string name="paused">일시중지됨</string>
|
||||
<string name="queued">대기열에 추가됨</string>
|
||||
<string name="post_processing">후처리 실행 중</string>
|
||||
<string name="enqueue">대기열</string>
|
||||
<string name="permission_denied">시스템에 의해 실행이 거부되었습니다</string>
|
||||
<string name="download_failed">다운로드 실패</string>
|
||||
<string name="download_finished">다운로드 완료</string>
|
||||
<string name="download_finished_more">%s 다운로드 완료됨</string>
|
||||
<string name="generate_unique_name">별개의 이름 생성</string>
|
||||
<string name="overwrite">덮어쓰기</string>
|
||||
<string name="overwrite_unrelated_warning">이 이름을 가진 파일이 이미 있습니다.</string>
|
||||
<string name="overwrite_finished_warning">이 이름을 가진 다운로드 된 파일이 이미 있습니다.</string>
|
||||
<string name="download_already_running">해당 이름을 가진 다운로드가 이미 진행중입니다</string>
|
||||
<string name="show_error">오류 표시</string>
|
||||
<string name="label_code">코드</string>
|
||||
<string name="error_path_creation">파일을 만들 수 없습니다</string>
|
||||
<string name="error_file_creation">지정한 폴더를 만들 수 없습니다</string>
|
||||
<string name="error_permission_denied">시스템에 의해 권한이 거부되었습니다</string>
|
||||
<string name="error_ssl_exception">보안 연결 실패</string>
|
||||
<string name="error_unknown_host">서버를 찾을 수 없습니다</string>
|
||||
<string name="error_connect_host">서버에 접속할 수 없습니다</string>
|
||||
<string name="error_http_no_content">서버가 데이터를 전송하지 않고 있습니다</string>
|
||||
<string name="error_http_unsupported_range">서버가 다중 스레드 다운로드를 받아들이지 않습니다, @string/msg_threads = 1 를 사용해 다시 시도해보세요</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">요청된 HTTP 범위가 충분하지 않습니다</string>
|
||||
<string name="error_http_not_found">HTTP 찾을 수 없습니다</string>
|
||||
<string name="error_postprocessing_failed">후처리 작업이 실패하였습니다</string>
|
||||
<string name="clear_finished_download">완료된 다운로드 비우기</string>
|
||||
<string name="msg_pending_downloads">대기중인 %s 다운로드를 지속하세요</string>
|
||||
<string name="stop">멈추기</string>
|
||||
<string name="max_retry_msg">최대 재시도 횟수</string>
|
||||
<string name="max_retry_desc">다운로드를 취소하기 전까지 다시 시도할 최대 횟수</string>
|
||||
<string name="pause_downloads_on_mobile">모바일 데이터로 전환시 일시정지</string>
|
||||
<string name="pause_downloads_on_mobile_desc">일시정지 할 수 없는 다운로드의 경우에는 다시 시작됩니다</string>
|
||||
<string name="conferences">컨퍼런스</string>
|
||||
</resources>
|
|
@ -120,8 +120,6 @@
|
|||
<string name="video">Vaizdas</string>
|
||||
<string name="audio">Muzika</string>
|
||||
<string name="retry">Bandyti iš naujo</string>
|
||||
<string name="use_old_player_title">Naudoti seną grotuvą</string>
|
||||
<string name="use_old_player_summary">Senas įtaisytas media grotuvas</string>
|
||||
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%s prenumeratorius</item>
|
||||
|
|
|
@ -202,8 +202,6 @@
|
|||
<string name="audio">Звук</string>
|
||||
<string name="retry">Пробај повторно</string>
|
||||
<string name="storage_permission_denied">Нема привилегии за пристап</string>
|
||||
<string name="use_old_player_title">Користи го стариот плеер</string>
|
||||
<string name="use_old_player_summary">Користи го стариот Mediaframework плеер</string>
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
|
|
|
@ -432,7 +432,6 @@
|
|||
<string name="app_update_notification_content_title">Kemas kini NewPipe Tersedia!</string>
|
||||
<string name="app_update_notification_content_text">Ketik untuk muat turun</string>
|
||||
<string name="missions_header_finished">Selesai</string>
|
||||
<string name="missions_header_pending">Dalam barisan</string>
|
||||
<string name="paused">dijeda</string>
|
||||
<string name="queued">telah beratur</string>
|
||||
<string name="post_processing">pemprosesan-pasca</string>
|
||||
|
@ -443,12 +442,12 @@
|
|||
<string name="download_finished_more">%s muat turun selesai</string>
|
||||
<string name="generate_unique_name">Menjana nama yang unik</string>
|
||||
<string name="overwrite">Timpa</string>
|
||||
<string name="overwrite_warning">Fail yang dimuat turun dengan nama ini sudah wujud</string>
|
||||
<string name="overwrite_finished_warning">Fail yang dimuat turun dengan nama ini sudah wujud</string>
|
||||
<string name="download_already_running">Terdapat muat turun yang sedang berjalan dengan nama ini</string>
|
||||
<string name="show_error">Tunjukkan kesilapan</string>
|
||||
<string name="label_code">Kod</string>
|
||||
<string name="error_path_creation">Fail tidak boleh dibuat</string>
|
||||
<string name="error_file_creation">Folder destinasi tidak boleh dibuat</string>
|
||||
<string name="error_file_creation">Fail tidak boleh dibuat</string>
|
||||
<string name="error_path_creation">Folder destinasi tidak boleh dibuat</string>
|
||||
<string name="error_permission_denied">Kebenaran ditolak oleh sistem</string>
|
||||
<string name="error_ssl_exception">Sambungan selamat gagal</string>
|
||||
<string name="error_unknown_host">Tidak dapat mencari server</string>
|
||||
|
@ -465,4 +464,5 @@
|
|||
<string name="max_retry_desc">Jumlah percubaan maksimum sebelum membatalkan muat turun</string>
|
||||
<string name="pause_downloads_on_mobile">Jeda semasa beralih ke data mudah alih</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Muat turun yang tidak dapat dihentikan akan dimulakan semula</string>
|
||||
<string name="missions_header_pending">Menunggu</string>
|
||||
</resources>
|
|
@ -141,8 +141,6 @@
|
|||
<string name="later">Senere</string>
|
||||
<string name="disabled">Avskrudd</string>
|
||||
|
||||
<string name="use_old_player_title">Bruk gammel avspiller</string>
|
||||
|
||||
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
|
@ -153,8 +151,7 @@
|
|||
|
||||
<string name="recaptcha_request_toast">reCAPTCHA-oppgave forespurt</string>
|
||||
|
||||
<string name="use_old_player_summary">Gammel innebygd Mediaframework-avspiller</string>
|
||||
<string name="use_external_video_player_summary">Fjerner lyd ved NOEN oppløsninger</string>
|
||||
<string name="use_external_video_player_summary">Fjerner lyd ved NOEN oppløsninger</string>
|
||||
<string name="subscribe_button_title">Abonner</string>
|
||||
<string name="subscribed_button_title">Abonnert</string>
|
||||
<string name="channel_unsubscribed">Kanalabonnent oppsagt</string>
|
||||
|
@ -315,8 +312,7 @@
|
|||
<string name="video_player">Videoavspiller</string>
|
||||
<string name="background_player">Bakgrunnsavspiller</string>
|
||||
<string name="popup_player">Oppsprettsavspiller</string>
|
||||
<string name="always_ask_player">Spør alltid</string>
|
||||
|
||||
|
||||
<string name="preferred_player_fetcher_notification_title">Henter informasjon…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Laster forespurt innhold</string>
|
||||
<string name="import_data_title">Importer database</string>
|
||||
|
@ -519,7 +515,6 @@
|
|||
<string name="app_update_notification_content_title">Ny NewPipe-versjon tilgjengelig.</string>
|
||||
<string name="app_update_notification_content_text">Trykk for å laste ned</string>
|
||||
<string name="missions_header_finished">Fullført</string>
|
||||
<string name="missions_header_pending">I kø</string>
|
||||
<string name="paused">pauset</string>
|
||||
<string name="queued">i kø</string>
|
||||
<string name="post_processing">etterbehandling</string>
|
||||
|
@ -530,12 +525,12 @@
|
|||
<string name="download_finished_more">%s nedlastinger fullført</string>
|
||||
<string name="generate_unique_name">Generer unikt navn</string>
|
||||
<string name="overwrite">Overskriv</string>
|
||||
<string name="overwrite_warning">Nedlastet fil ved dette navnet finnes allerede</string>
|
||||
<string name="overwrite_finished_warning">Nedlastet fil ved dette navnet finnes allerede</string>
|
||||
<string name="download_already_running">Nedlasting med dette navnet underveis allerede</string>
|
||||
<string name="show_error">Vis feil</string>
|
||||
<string name="label_code">Kode</string>
|
||||
<string name="error_path_creation">Filen kan ikke opprettes</string>
|
||||
<string name="error_file_creation">Målmappen kan ikke opprettes</string>
|
||||
<string name="error_file_creation">Filen kan ikke opprettes</string>
|
||||
<string name="error_path_creation">Målmappen kan ikke opprettes</string>
|
||||
<string name="error_permission_denied">Tilgang nektet av systemet</string>
|
||||
<string name="error_ssl_exception">Sikker tilkobling mislyktes</string>
|
||||
<string name="error_unknown_host">Fant ikke tjeneren</string>
|
||||
|
|
|
@ -189,8 +189,6 @@
|
|||
<string name="audio">Geluid</string>
|
||||
<string name="retry">Opnieuw proberen</string>
|
||||
<string name="storage_permission_denied">Toegang tot opslag geweigerd</string>
|
||||
<string name="use_old_player_title">Gebruik oude speler</string>
|
||||
<string name="use_old_player_summary">Verouderden ingebouwde Mediaframework-speler</string>
|
||||
<string name="short_thousand">K</string>
|
||||
<string name="short_million">M</string>
|
||||
<string name="short_billion">B</string>
|
||||
|
@ -292,7 +290,7 @@
|
|||
<string name="could_not_import_all_files">Opgelet: kon niet alle bestanden importeren.</string>
|
||||
<string name="override_current_data">Dit zal uw huidige configuratie overschrijven.</string>
|
||||
<string name="kiosk">Kiosk</string>
|
||||
<string name="trending">Trending</string>
|
||||
<string name="trending">Populair</string>
|
||||
<string name="top_50">Top 50</string>
|
||||
<string name="new_and_hot">Nieuw en populair</string>
|
||||
<string name="title_activity_background_player">Achtergrondspeler</string>
|
||||
|
@ -436,7 +434,6 @@
|
|||
<string name="app_update_notification_content_title">NewPipe-update beschikbaar!</string>
|
||||
<string name="app_update_notification_content_text">Tikt voor te downloaden</string>
|
||||
<string name="missions_header_finished">Voltooid</string>
|
||||
<string name="missions_header_pending">In wachtrij</string>
|
||||
<string name="paused">gepauzeerd</string>
|
||||
<string name="queued">toegevoegd aan wachtrij</string>
|
||||
<string name="post_processing">nabewerking</string>
|
||||
|
@ -447,12 +444,12 @@
|
|||
<string name="download_finished_more">%s downloads voltooid</string>
|
||||
<string name="generate_unique_name">Unieke naam genereren</string>
|
||||
<string name="overwrite">Overschrijven</string>
|
||||
<string name="overwrite_warning">Der bestaat al een gedownload bestand met deze naam</string>
|
||||
<string name="overwrite_finished_warning">Der bestaat al een gedownload bestand met deze naam</string>
|
||||
<string name="download_already_running">Der is al een download met deze naam bezig</string>
|
||||
<string name="show_error">Foutmelding weergeven</string>
|
||||
<string name="label_code">Code</string>
|
||||
<string name="error_path_creation">Het bestand kan niet aangemaakt worden</string>
|
||||
<string name="error_file_creation">De doelmap kan niet aangemaakt worden</string>
|
||||
<string name="error_file_creation">Het bestand kan niet aangemaakt worden</string>
|
||||
<string name="error_path_creation">De doelmap kan niet aangemaakt worden</string>
|
||||
<string name="error_permission_denied">Toelating geweigerd door het systeem</string>
|
||||
<string name="error_ssl_exception">Beveiligde verbinding is mislukt</string>
|
||||
<string name="error_unknown_host">Kon de server niet vinden</string>
|
||||
|
|
|
@ -123,8 +123,6 @@
|
|||
\nopenen in pop-upmodus</string>
|
||||
<string name="popup_mode_share_menu_title">NewPipe-pop-upmodus</string>
|
||||
<string name="popup_playing_toast">Speelt af in pop-upmodus</string>
|
||||
<string name="use_old_player_title">Oude speler gebruiken</string>
|
||||
<string name="use_old_player_summary">Verouderde ingebouwde Mediaframework-speler</string>
|
||||
<string name="default_video_format_title">Standaard videoformaat</string>
|
||||
<string name="disabled">Uitgeschakeld</string>
|
||||
<string name="default_popup_resolution_title">Standaardresolutie van pop-up</string>
|
||||
|
@ -155,7 +153,7 @@
|
|||
<string name="tab_about">Over</string>
|
||||
<string name="tab_contributors">Bijdragers</string>
|
||||
<string name="tab_licenses">Licenties</string>
|
||||
<string name="app_description">Vrij en lichtgewicht streamen op Android.</string>
|
||||
<string name="app_description">Vrij en licht streamen voor Android.</string>
|
||||
<string name="view_on_github">Bekijken op GitHub</string>
|
||||
<string name="app_license_title">Licentie van NewPipe</string>
|
||||
<string name="contribution_encouragement">Hulp is altijd welkom. Of je nu nieuwe ideeën hebt, vertalingen kan aanleveren, wijzigingen in het ontwerp kan verrichten, code kan opschonen of van grote wijzigingen voorzien. Hoe meer hulp, hoe beter het wordt!</string>
|
||||
|
@ -270,7 +268,6 @@
|
|||
<string name="video_player">Videospeler</string>
|
||||
<string name="background_player">Achtergrondspeler</string>
|
||||
<string name="popup_player">Pop-upspeler</string>
|
||||
<string name="always_ask_player">Altijd vragen</string>
|
||||
<string name="preferred_player_fetcher_notification_title">Bezig met ophalen van informatie…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">Bezig met laden van gevraagde inhoud</string>
|
||||
<string name="import_data_title">Databank importeren</string>
|
||||
|
@ -441,7 +438,7 @@
|
|||
<string name="app_update_notification_content_title">NewPipe-update beschikbaar!</string>
|
||||
<string name="app_update_notification_content_text">Tik om te downloaden</string>
|
||||
<string name="missions_header_finished">Voltooid</string>
|
||||
<string name="missions_header_pending">In de wachtrij</string>
|
||||
<string name="missions_header_pending">In afwachting van</string>
|
||||
<string name="paused">gepauzeerd</string>
|
||||
<string name="queued">aan de wachtrij toegevoegd</string>
|
||||
<string name="post_processing">nabewerking</string>
|
||||
|
@ -452,12 +449,12 @@
|
|||
<string name="download_finished_more">%s downloads voltooid</string>
|
||||
<string name="generate_unique_name">Genereer een unieke naam</string>
|
||||
<string name="overwrite">Overschrijven</string>
|
||||
<string name="overwrite_warning">Er bestaat al een gedownload bestand met deze naam</string>
|
||||
<string name="overwrite_finished_warning">Er bestaat al een gedownload bestand met deze naam</string>
|
||||
<string name="download_already_running">Er is een download aan de gang met deze naam</string>
|
||||
<string name="show_error">Toon foutmelding</string>
|
||||
<string name="label_code">Code</string>
|
||||
<string name="error_path_creation">Het bestand kan niet worden gemaakt</string>
|
||||
<string name="error_file_creation">De doelmap kan niet worden gemaakt</string>
|
||||
<string name="error_file_creation">Het bestand kan niet worden gemaakt</string>
|
||||
<string name="error_path_creation">De doelmap kan niet worden gemaakt</string>
|
||||
<string name="error_permission_denied">Toestemming door het systeem geweigerd</string>
|
||||
<string name="error_ssl_exception">Beveiligde connectie is mislukt</string>
|
||||
<string name="error_unknown_host">Kon de server niet vinden</string>
|
||||
|
@ -476,4 +473,5 @@
|
|||
<string name="pause_downloads_on_mobile_desc">Downloads die niet kunnen worden gepauzeerd zullen worden herstart</string>
|
||||
<string name="events">Gebeurtenissen</string>
|
||||
<string name="conferences">Conferenties</string>
|
||||
<string name="error_timeout">Time-out van verbinding</string>
|
||||
</resources>
|
|
@ -47,7 +47,7 @@
|
|||
<string name="play_btn_text">Odtwórz</string>
|
||||
<string name="content">Zawartość</string>
|
||||
<string name="show_age_restricted_content_title">Treści z ograniczeniem wiekowym</string>
|
||||
<string name="video_is_age_restricted">Pokaż wideo z ograniczeniem wiekowym. Zezwalanie na takie materiały jest możliwe w Ustawieniach.</string>
|
||||
<string name="video_is_age_restricted">Pokaż wideo z ograniczeniami wiekowymi. Dopuszczenie takiego materiału jest możliwe z poziomu Ustawienia.</string>
|
||||
<string name="duration_live">Na żywo</string>
|
||||
<string name="downloads">Pobrane</string>
|
||||
<string name="downloads_title">Pobrane</string>
|
||||
|
@ -208,7 +208,7 @@
|
|||
<plurals name="subscribers">
|
||||
<item quantity="one">%s subskrybent</item>
|
||||
<item quantity="few">%s subskrybentów</item>
|
||||
<item quantity="many">%s subskrybentów</item>
|
||||
<item quantity="many">%s subskrybenci</item>
|
||||
</plurals>
|
||||
<plurals name="views">
|
||||
<item quantity="one">%s odtworzenie</item>
|
||||
|
@ -356,7 +356,7 @@
|
|||
\n
|
||||
\nCzy chcesz kontynuować?</string>
|
||||
<string name="playback_speed_control">Kontrola prędkości odtwarzania</string>
|
||||
<string name="playback_tempo">Tempo</string>
|
||||
<string name="playback_tempo">Czas</string>
|
||||
<string name="playback_pitch">Wysokość dźwięku</string>
|
||||
<string name="import_soundcloud_instructions_hint">twojeID, soundcloud.com/yourid</string>
|
||||
<string name="unhook_checkbox">Odłącz (może powodować zniekształcenia)</string>
|
||||
|
@ -435,7 +435,6 @@
|
|||
<string name="app_update_notification_content_title">Dostępna jest aktualizacja NewPipe!</string>
|
||||
<string name="app_update_notification_content_text">Stuknij, aby pobrać</string>
|
||||
<string name="missions_header_finished">Gotowe</string>
|
||||
<string name="missions_header_pending">W kolejce</string>
|
||||
<string name="paused">wstrzymane</string>
|
||||
<string name="queued">w kolejce</string>
|
||||
<string name="post_processing">przetwarzanie końcowe</string>
|
||||
|
@ -446,28 +445,29 @@
|
|||
<string name="download_finished_more">%s pobieranie zostało zakończone</string>
|
||||
<string name="generate_unique_name">Wygeneruj unikalną nazwę</string>
|
||||
<string name="overwrite">Zastąp</string>
|
||||
<string name="overwrite_warning">Pobrany plik o tej nazwie już istnieje</string>
|
||||
<string name="overwrite_finished_warning">Pobrany plik o tej nazwie już istnieje</string>
|
||||
<string name="download_already_running">Trwa pobieranie z tą nazwą</string>
|
||||
<string name="show_error">Pokaż błąd</string>
|
||||
<string name="label_code">Kod</string>
|
||||
<string name="error_path_creation">Nie można utworzyć pliku</string>
|
||||
<string name="error_file_creation">Nie można utworzyć folderu docelowego</string>
|
||||
<string name="error_file_creation">Nie można utworzyć pliku</string>
|
||||
<string name="error_path_creation">Nie można utworzyć folderu docelowego</string>
|
||||
<string name="error_permission_denied">Odmowa dostępu do systemu</string>
|
||||
<string name="error_ssl_exception">Bezpieczne połączenie nie powiodło się</string>
|
||||
<string name="error_unknown_host">Nie można znaleźć serwera</string>
|
||||
<string name="error_connect_host">Nie można połączyć się z serwerem</string>
|
||||
<string name="error_http_no_content">Serwer nie wysyła danych</string>
|
||||
<string name="error_http_unsupported_range">Serwer nie akceptuje pobierania wielowątkowego, spróbuj ponownie za pomocą @string/msg_threads = 1</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Żądany zakres jest niewłaściwy</string>
|
||||
<string name="error_http_requested_range_not_satisfiable">Niewłaściwy zakres</string>
|
||||
<string name="error_http_not_found">Nie znaleziono</string>
|
||||
<string name="error_postprocessing_failed">Przetwarzanie końcowe nie powiodło się</string>
|
||||
<string name="clear_finished_download">Wyczyść ukończone pobieranie</string>
|
||||
<string name="msg_pending_downloads">Kontynuuj %s oczekujące transfery z plików do pobrania</string>
|
||||
<string name="stop">Zatrzymaj</string>
|
||||
<string name="max_retry_msg">Maksymalna liczba prób</string>
|
||||
<string name="max_retry_msg">Maksymalna liczba powtórzeń</string>
|
||||
<string name="max_retry_desc">Maksymalna liczba prób przed anulowaniem pobierania</string>
|
||||
<string name="pause_downloads_on_mobile">Przerwij przełączanie na dane mobilne</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Pobierane pliki, których nie można wstrzymać, zostaną ponownie uruchomione</string>
|
||||
<string name="pause_downloads_on_mobile_desc">Pobierane pliki, których nie można wstrzymać, zostaną zrestartowane</string>
|
||||
<string name="events">Zdarzenia</string>
|
||||
<string name="conferences">Konferencje</string>
|
||||
<string name="missions_header_pending">Oczekuje</string>
|
||||
</resources>
|