diff --git a/README.md b/README.md
index f78725338..987327ab8 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
Screenshots • Description • Features • Updates • Contribution • Donate • License
-Website • Blog • Press
+Website • Blog • FAQ • Press
WARNING: THIS IS A BETA VERSION, THEREFORE YOU MAY ENCOUNTER BUGS. IF YOU DO, OPEN AN ISSUE VIA OUR GITHUB REPOSITORY.
diff --git a/app/build.gradle b/app/build.gradle
index 219d2b202..0ca03f158 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,8 +11,8 @@ android {
applicationId "org.schabi.newpipe"
minSdkVersion 19
targetSdkVersion 28
- versionCode 800
- versionName "0.18.0"
+ versionCode 820
+ versionName "0.18.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -62,7 +62,7 @@ dependencies {
exclude module: 'support-annotations'
})
- implementation 'com.github.TeamNewPipe:NewPipeExtractor:bdbfa26'
+ implementation 'com.github.TeamNewPipe:NewPipeExtractor:ff61e284'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.23.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9052dabab..21a846494 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -153,6 +153,7 @@
+
diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index 90d299c7f..cce02f526 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -449,6 +449,16 @@ public class MainActivity extends AppCompatActivity {
sharedPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false).apply();
NavigationHelper.openMainActivity(this);
}
+
+ if (sharedPreferences.getBoolean(Constants.KEY_ENABLE_WATCH_HISTORY, true)) {
+ if (DEBUG) Log.d(TAG, "do not show History-menu as its disabled in settings");
+ drawerItems.getMenu().findItem(ITEM_ID_HISTORY).setVisible(true);
+ }
+
+ if (!sharedPreferences.getBoolean(Constants.KEY_ENABLE_WATCH_HISTORY, true)) {
+ if (DEBUG) Log.d(TAG, "show History-menu as its enabled in settings");
+ drawerItems.getMenu().findItem(ITEM_ID_HISTORY).setVisible(false);
+ }
}
@Override
@@ -551,8 +561,6 @@ public class MainActivity extends AppCompatActivity {
if (!(fragment instanceof SearchFragment)) {
findViewById(R.id.toolbar).findViewById(R.id.toolbar_search_container).setVisibility(View.GONE);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main_menu, menu);
}
ActionBar actionBar = getSupportActionBar();
@@ -574,14 +582,6 @@ public class MainActivity extends AppCompatActivity {
case android.R.id.home:
onHomeButtonPressed();
return true;
- case R.id.action_show_downloads:
- return NavigationHelper.openDownloads(this);
- case R.id.action_history:
- NavigationHelper.openStatisticFragment(getSupportFragmentManager());
- return true;
- case R.id.action_settings:
- NavigationHelper.openSettings(this);
- return true;
default:
return super.onOptionsItemSelected(item);
}
diff --git a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java
index 2326e795e..e028c0322 100644
--- a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java
@@ -99,11 +99,6 @@ public class AboutActivity extends AppCompatActivity {
case android.R.id.home:
finish();
return true;
- case R.id.action_settings:
- NavigationHelper.openSettings(this);
- return true;
- case R.id.action_show_downloads:
- return NavigationHelper.openDownloads(this);
}
return super.onOptionsItemSelected(item);
diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
index 449a790e8..26e5d94be 100644
--- a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
@@ -78,11 +78,7 @@ public class DownloadActivity extends AppCompatActivity {
onBackPressed();
return true;
}
- case R.id.action_settings: {
- Intent intent = new Intent(this, SettingsActivity.class);
- startActivity(intent);
- return true;
- }
+
default:
return super.onOptionsItemSelected(item);
}
diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
index 853bb6d68..44966744b 100644
--- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
+++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
@@ -832,7 +832,6 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
psArgs = new String[]{
selectedStream.getFormat().getSuffix(),
"false",// ignore empty frames
- "false",// detect youtube duplicate lines
};
}
break;
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 14e989625..f59cfaef0 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -79,6 +79,7 @@ import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.InfoCache;
+import org.schabi.newpipe.util.KoreUtil;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
@@ -624,7 +625,7 @@ public class VideoDetailFragment
url.replace("https", "http")));
} catch (Exception e) {
if (DEBUG) Log.i(TAG, "Failed to start kore", e);
- showInstallKoreDialog(activity);
+ KoreUtil.showInstallKoreDialog(activity);
}
return true;
default:
@@ -632,16 +633,6 @@ public class VideoDetailFragment
}
}
- private static void showInstallKoreDialog(final Context context) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setMessage(R.string.kore_not_found)
- .setPositiveButton(R.string.install, (DialogInterface dialog, int which) ->
- NavigationHelper.installKore(context))
- .setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
- });
- builder.create().show();
- }
-
private void setupActionBarOnError(final String url) {
if (DEBUG) Log.d(TAG, "setupActionBarHandlerOnError() called with: url = [" + url + "]");
Log.e("-----", "missing code");
diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java
index 761b50d85..1b5b5d07c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java
@@ -55,10 +55,7 @@ public final class BackgroundPlayerActivity extends ServicePlayerActivity {
return true;
}
- this.player.setRecovery();
- getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
- getApplicationContext().startService(getSwitchIntent(PopupVideoPlayer.class));
- return true;
+ return switchTo(PopupVideoPlayer.class);
}
return false;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
index 6452a9850..46ca3921d 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
@@ -150,6 +150,8 @@ public abstract class BasePlayer implements
@NonNull
public static final String RESUME_PLAYBACK = "resume_playback";
@NonNull
+ public static final String START_PAUSED = "start_paused";
+ @NonNull
public static final String SELECT_ON_APPEND = "select_on_append";
/*//////////////////////////////////////////////////////////////////////////
@@ -304,7 +306,7 @@ public abstract class BasePlayer implements
}
// Good to go...
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
- /*playOnInit=*/true);
+ /*playOnInit=*/!intent.getBooleanExtra(START_PAUSED, false));
}
protected void initPlayback(@NonNull final PlayQueue queue,
@@ -944,10 +946,10 @@ public abstract class BasePlayer implements
public void onPlayPause() {
if (DEBUG) Log.d(TAG, "onPlayPause() called");
- if (!isPlaying()) {
- onPlay();
- } else {
+ if (isPlaying()) {
onPause();
+ } else {
+ onPlay();
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
index 7a3e60c66..1153c41fd 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
@@ -28,6 +28,7 @@ import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -75,6 +76,7 @@ import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
import org.schabi.newpipe.util.AnimationUtils;
+import org.schabi.newpipe.util.KoreUtil;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
@@ -435,6 +437,7 @@ public final class MainVideoPlayer extends AppCompatActivity
private boolean queueVisible;
private ImageButton moreOptionsButton;
+ private ImageButton kodiButton;
private ImageButton shareButton;
private ImageButton toggleOrientationButton;
private ImageButton switchPopupButton;
@@ -471,6 +474,7 @@ public final class MainVideoPlayer extends AppCompatActivity
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
this.secondaryControls = rootView.findViewById(R.id.secondaryControls);
+ this.kodiButton = rootView.findViewById(R.id.kodi);
this.shareButton = rootView.findViewById(R.id.share);
this.toggleOrientationButton = rootView.findViewById(R.id.toggleOrientation);
this.switchBackgroundButton = rootView.findViewById(R.id.switchBackground);
@@ -482,6 +486,9 @@ public final class MainVideoPlayer extends AppCompatActivity
titleTextView.setSelected(true);
channelTextView.setSelected(true);
+ boolean showKodiButton = PreferenceManager.getDefaultSharedPreferences(this.context).getBoolean(
+ this.context.getString(R.string.show_play_with_kodi_key), false);
+ kodiButton.setVisibility(showKodiButton ? View.VISIBLE : View.GONE);
getRootView().setKeepScreenOn(true);
}
@@ -518,6 +525,7 @@ public final class MainVideoPlayer extends AppCompatActivity
closeButton.setOnClickListener(this);
moreOptionsButton.setOnClickListener(this);
+ kodiButton.setOnClickListener(this);
shareButton.setOnClickListener(this);
toggleOrientationButton.setOnClickListener(this);
switchBackgroundButton.setOnClickListener(this);
@@ -588,6 +596,17 @@ public final class MainVideoPlayer extends AppCompatActivity
finish();
}
+ public void onKodiShare() {
+ onPause();
+ try {
+ NavigationHelper.playWithKore(this.context, Uri.parse(
+ playerImpl.getVideoUrl().replace("https", "http")));
+ } catch (Exception e) {
+ if (DEBUG) Log.i(TAG, "Failed to start kore", e);
+ KoreUtil.showInstallKoreDialog(this.context);
+ }
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Player Overrides
//////////////////////////////////////////////////////////////////////////*/
@@ -614,7 +633,8 @@ public final class MainVideoPlayer extends AppCompatActivity
this.getPlaybackPitch(),
this.getPlaybackSkipSilence(),
this.getPlaybackQuality(),
- false
+ false,
+ !isPlaying()
);
context.startService(intent);
@@ -637,7 +657,8 @@ public final class MainVideoPlayer extends AppCompatActivity
this.getPlaybackPitch(),
this.getPlaybackSkipSilence(),
this.getPlaybackQuality(),
- false
+ false,
+ !isPlaying()
);
context.startService(intent);
@@ -686,6 +707,8 @@ public final class MainVideoPlayer extends AppCompatActivity
} else if (v.getId() == closeButton.getId()) {
onPlaybackShutdown();
return;
+ } else if (v.getId() == kodiButton.getId()) {
+ onKodiShare();
}
if (getCurrentState() != STATE_COMPLETED) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
index 969c47990..70fb77060 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
@@ -567,7 +567,8 @@ public final class PopupVideoPlayer extends Service {
this.getPlaybackPitch(),
this.getPlaybackSkipSilence(),
this.getPlaybackQuality(),
- false
+ false,
+ !isPlaying()
);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
@@ -1123,4 +1124,4 @@ public final class PopupVideoPlayer extends Service {
return distanceFromCloseButton(popupMotionEvent) <= getClosingRadius();
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java
index 44fcdb8dd..b2af6d9d8 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java
@@ -48,10 +48,7 @@ public final class PopupVideoPlayerActivity extends ServicePlayerActivity {
@Override
public boolean onPlayerOptionSelected(MenuItem item) {
if (item.getItemId() == R.id.action_switch_background) {
- this.player.setRecovery();
- getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
- getApplicationContext().startService(getSwitchIntent(BackgroundPlayer.class));
- return true;
+ return switchTo(BackgroundPlayer.class);
}
return false;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
index 2207808ac..08fcbc769 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
@@ -157,18 +157,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
case R.id.action_append_playlist:
appendAllToPlaylist();
return true;
- case R.id.action_settings:
- NavigationHelper.openSettings(this);
- redraw = true;
- return true;
case R.id.action_system_audio:
startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
return true;
case R.id.action_switch_main:
- this.player.setRecovery();
- getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
- getApplicationContext().startActivity(getSwitchIntent(MainVideoPlayer.class));
- return true;
+ return switchTo(MainVideoPlayer.class);
}
return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
}
@@ -189,8 +182,17 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
this.player.getPlaybackPitch(),
this.player.getPlaybackSkipSilence(),
null,
+ false,
false
- ).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(BasePlayer.START_PAUSED, !this.player.isPlaying());
+ }
+
+ protected boolean switchTo(final Class clazz) {
+ this.player.setRecovery();
+ getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
+ getApplicationContext().startActivity(getSwitchIntent(clazz));
+ return true;
}
////////////////////////////////////////////////////////////////////////////
diff --git a/app/src/main/java/org/schabi/newpipe/streams/SrtFromTtmlWriter.java b/app/src/main/java/org/schabi/newpipe/streams/SrtFromTtmlWriter.java
new file mode 100644
index 000000000..6f1cceeed
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/streams/SrtFromTtmlWriter.java
@@ -0,0 +1,95 @@
+package org.schabi.newpipe.streams;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+import org.jsoup.parser.Parser;
+import org.jsoup.select.Elements;
+import org.schabi.newpipe.streams.io.SharpStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @author kapodamy
+ */
+public class SrtFromTtmlWriter {
+ private static final String NEW_LINE = "\r\n";
+
+ private SharpStream out;
+ private boolean ignoreEmptyFrames;
+ private final Charset charset = StandardCharsets.UTF_8;
+
+ private int frameIndex = 0;
+
+ public SrtFromTtmlWriter(SharpStream out, boolean ignoreEmptyFrames) {
+ this.out = out;
+ this.ignoreEmptyFrames = ignoreEmptyFrames;
+ }
+
+ private static String getTimestamp(Element frame, String attr) {
+ return frame
+ .attr(attr)
+ .replace('.', ',');// SRT subtitles uses comma as decimal separator
+ }
+
+ private void writeFrame(String begin, String end, StringBuilder text) throws IOException {
+ writeString(String.valueOf(frameIndex++));
+ writeString(NEW_LINE);
+ writeString(begin);
+ writeString(" --> ");
+ writeString(end);
+ writeString(NEW_LINE);
+ writeString(text.toString());
+ writeString(NEW_LINE);
+ writeString(NEW_LINE);
+ }
+
+ private void writeString(String text) throws IOException {
+ out.write(text.getBytes(charset));
+ }
+
+ public void build(SharpStream ttml) throws IOException {
+ /*
+ * TTML parser with BASIC support
+ * multiple CUE is not supported
+ * styling is not supported
+ * tag timestamps (in auto-generated subtitles) are not supported, maybe in the future
+ * also TimestampTagOption enum is not applicable
+ * Language parsing is not supported
+ */
+
+ // parse XML
+ byte[] buffer = new byte[(int) ttml.available()];
+ ttml.read(buffer);
+ Document doc = Jsoup.parse(new ByteArrayInputStream(buffer), "UTF-8", "", Parser.xmlParser());
+
+ StringBuilder text = new StringBuilder(128);
+ Elements paragraph_list = doc.select("body > div > p");
+
+ // check if has frames
+ if (paragraph_list.size() < 1) return;
+
+ for (Element paragraph : paragraph_list) {
+ text.setLength(0);
+
+ for (Node children : paragraph.childNodes()) {
+ if (children instanceof TextNode)
+ text.append(((TextNode) children).text());
+ else if (children instanceof Element && ((Element) children).tagName().equalsIgnoreCase("br"))
+ text.append(NEW_LINE);
+ }
+
+ if (ignoreEmptyFrames && text.length() < 1) continue;
+
+ String begin = getTimestamp(paragraph, "begin");
+ String end = getTimestamp(paragraph, "end");
+
+ writeFrame(begin, end, text);
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/streams/SubtitleConverter.java b/app/src/main/java/org/schabi/newpipe/streams/SubtitleConverter.java
deleted file mode 100644
index c41db4373..000000000
--- a/app/src/main/java/org/schabi/newpipe/streams/SubtitleConverter.java
+++ /dev/null
@@ -1,369 +0,0 @@
-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;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.text.ParseException;
-import java.util.Locale;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPathExpressionException;
-
-/**
- * @author kapodamy
- */
-public class SubtitleConverter {
- private static final String NEW_LINE = "\r\n";
-
- 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()) {
- return;
- }
- out.write(String.valueOf(frameIndex++).getBytes(charset));
- out.write(NEW_LINE.getBytes(charset));
- out.write(getTime(frame.start, true).getBytes(charset));
- out.write(" --> ".getBytes(charset));
- out.write(getTime(frame.end, true).getBytes(charset));
- out.write(NEW_LINE.getBytes(charset));
- out.write(frame.text.getBytes(charset));
- out.write(NEW_LINE.getBytes(charset));
- 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,
- String root, String formatAttr, String formatVersion, String[] cuePath, String[] framePath,
- String timeAttr, String durationAttr, boolean hasTimestamp
- ) throws IOException, ParseException, SAXException, ParserConfigurationException, XPathExpressionException {
- /*
- * XML based subtitles parser with BASIC support
- * multiple CUE is not supported
- * styling is not supported
- * tag timestamps (in auto-generated subtitles) are not supported, maybe in the future
- * also TimestampTagOption enum is not applicable
- * Language parsing is not supported
- */
-
- byte[] buffer = new byte[(int) source.available()];
- source.read(buffer);
-
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document xml = builder.parse(new ByteArrayInputStream(buffer));
-
- String attr;
-
- // get the format version or namespace
- Element node = xml.getDocumentElement();
-
- if (node == null) {
- throw new ParseException("Can't get the format version. ¿wrong namespace?", -1);
- } else if (!node.getNodeName().equals(root)) {
- throw new ParseException("Invalid root", -1);
- }
-
- if (formatAttr.equals("xmlns")) {
- if (!node.getNamespaceURI().equals(formatVersion)) {
- throw new UnsupportedOperationException("Expected xml namespace: " + formatVersion);
- }
- } else {
- attr = node.getAttributeNS(formatVersion, formatAttr);
- if (attr == null) {
- throw new ParseException("Can't get the format attribute", -1);
- }
- if (!attr.equals(formatVersion)) {
- throw new ParseException("Invalid format version : " + attr, -1);
- }
- }
-
- NodeList node_list;
-
- int line_break = 0;// Maximum characters per line if present (valid for TranScript v3)
-
- if (!hasTimestamp) {
- node_list = selectNodes(xml, cuePath, formatVersion);
-
- if (node_list != null) {
- // if the subtitle has multiple CUEs, use the highest value
- for (int i = 0; i < node_list.getLength(); i++) {
- try {
- int tmp = Integer.parseInt(((Element) node_list.item(i)).getAttributeNS(formatVersion, "ah"));
- if (tmp > line_break) {
- line_break = tmp;
- }
- } catch (Exception err) {
- }
- }
- }
- }
-
- // parse every frame
- node_list = selectNodes(xml, framePath, formatVersion);
-
- if (node_list == null) {
- return;// no frames detected
- }
-
- int fs_ff = -1;// first timestamp of first frame
- boolean limit_lines = false;
-
- for (int i = 0; i < node_list.getLength(); i++) {
- Element elem = (Element) node_list.item(i);
- SubtitleFrame obj = new SubtitleFrame();
- obj.text = elem.getTextContent();
-
- attr = elem.getAttribute(timeAttr);// ¡this cant be null!
- obj.start = hasTimestamp ? parseTimestamp(attr) : Integer.parseInt(attr);
-
- attr = elem.getAttribute(durationAttr);
- if (obj.text == null || attr == null) {
- continue;// normally is a blank line (on auto-generated subtitles) ignore
- }
-
- if (hasTimestamp) {
- obj.end = parseTimestamp(attr);
-
- if (detectYoutubeDuplicateLines) {
- if (limit_lines) {
- int swap = obj.end;
- obj.end = fs_ff;
- fs_ff = swap;
- } else {
- if (fs_ff < 0) {
- fs_ff = obj.end;
- } else {
- if (fs_ff < obj.start) {
- limit_lines = true;// the subtitles has duplicated lines
- } else {
- detectYoutubeDuplicateLines = false;
- }
- }
- }
- }
- } else {
- obj.end = obj.start + Integer.parseInt(attr);
- }
-
- if (/*node.getAttribute("w").equals("1") &&*/line_break > 1 && obj.text.length() > line_break) {
-
- // implement auto line breaking (once)
- StringBuilder text = new StringBuilder(obj.text);
- obj.text = null;
-
- switch (text.charAt(line_break)) {
- case ' ':
- case '\t':
- putBreakAt(line_break, text);
- break;
- default:// find the word start position
- for (int j = line_break - 1; j > 0; j--) {
- switch (text.charAt(j)) {
- case ' ':
- case '\t':
- putBreakAt(j, text);
- j = -1;
- break;
- case '\r':
- case '\n':
- j = -1;// long word, just ignore
- break;
- }
- }
- break;
- }
-
- obj.text = text.toString();// set the processed text
- }
-
- callback.yield(obj);
- }
- }
-
- private static NodeList selectNodes(Document xml, String[] path, String namespaceUri) {
- Element ref = xml.getDocumentElement();
-
- for (int i = 0; i < path.length - 1; i++) {
- NodeList nodes = ref.getChildNodes();
- if (nodes.getLength() < 1) {
- return null;
- }
-
- Element elem;
- for (int j = 0; j < nodes.getLength(); j++) {
- if (nodes.item(j).getNodeType() == Node.ELEMENT_NODE) {
- elem = (Element) nodes.item(j);
- if (elem.getNodeName().equals(path[i]) && elem.getNamespaceURI().equals(namespaceUri)) {
- ref = elem;
- break;
- }
- }
- }
- }
-
- return ref.getElementsByTagNameNS(namespaceUri, path[path.length - 1]);
- }
-
- private static int parseTimestamp(String multiImpl) throws NumberFormatException, ParseException {
- if (multiImpl.length() < 1) {
- return 0;
- } else if (multiImpl.length() == 1) {
- return Integer.parseInt(multiImpl) * 1000;// ¡this must be a number in seconds!
- }
-
- // detect wallclock-time
- if (multiImpl.startsWith("wallclock(")) {
- throw new UnsupportedOperationException("Parsing wallclock timestamp is not implemented");
- }
-
- // detect offset-time
- if (multiImpl.indexOf(':') < 0) {
- int multiplier = 1000;
- char metric = multiImpl.charAt(multiImpl.length() - 1);
- switch (metric) {
- case 'h':
- multiplier *= 3600000;
- break;
- case 'm':
- multiplier *= 60000;
- break;
- case 's':
- if (multiImpl.charAt(multiImpl.length() - 2) == 'm') {
- multiplier = 1;// ms
- }
- break;
- default:
- if (!Character.isDigit(metric)) {
- throw new NumberFormatException("Invalid metric suffix found on : " + multiImpl);
- }
- metric = '\0';
- break;
- }
- try {
- String offset_time = multiImpl;
-
- if (multiplier == 1) {
- offset_time = offset_time.substring(0, offset_time.length() - 2);
- } else if (metric != '\0') {
- offset_time = offset_time.substring(0, offset_time.length() - 1);
- }
-
- double time_metric_based = Double.parseDouble(offset_time);
- if (Math.abs(time_metric_based) <= Double.MAX_VALUE) {
- return (int) (time_metric_based * multiplier);
- }
- } catch (Exception err) {
- throw new UnsupportedOperationException("Invalid or not implemented timestamp on: " + multiImpl);
- }
- }
-
- // detect clock-time
- int time = 0;
- String[] units = multiImpl.split(":");
-
- if (units.length < 3) {
- throw new ParseException("Invalid clock-time timestamp", -1);
- }
-
- time += Integer.parseInt(units[0]) * 3600000;// hours
- time += Integer.parseInt(units[1]) * 60000;//minutes
- time += Float.parseFloat(units[2]) * 1000f;// seconds and milliseconds (if present)
-
- // frames and sub-frames are ignored (not implemented)
- // time += units[3] * fps;
- return time;
- }
-
- private static void putBreakAt(int idx, StringBuilder str) {
- // this should be optimized at compile time
-
- if (NEW_LINE.length() > 1) {
- str.delete(idx, idx + 1);// remove after replace
- str.insert(idx, NEW_LINE);
- } else {
- str.setCharAt(idx, NEW_LINE.charAt(0));
- }
- }
-
- private static String getTime(int time, boolean comma) {
- // cast every value to integer to avoid auto-round in ToString("00").
- StringBuilder str = new StringBuilder(12);
- str.append(numberToString(time / 1000 / 3600, 2));// hours
- str.append(':');
- str.append(numberToString(time / 1000 / 60 % 60, 2));// minutes
- str.append(':');
- str.append(numberToString(time / 1000 % 60, 2));// seconds
- str.append(comma ? ',' : '.');
- str.append(numberToString(time % 1000, 3));// miliseconds
-
- return str.toString();
- }
-
- private static String numberToString(int nro, int pad) {
- return String.format(Locale.ENGLISH, "%0".concat(String.valueOf(pad)).concat("d"), nro);
- }
-
-
- /******************
- * helper classes *
- ******************/
-
- private interface FrameWriter {
-
- void yield(SubtitleFrame frame) throws IOException;
- }
-
- private static class SubtitleFrame {
- //Java no support unsigned int
-
- public int end;
- public int start;
- public String text = "";
-
- private boolean isEmptyText() {
- if (text == null) {
- return true;
- }
-
- for (int i = 0; i < text.length(); i++) {
- switch (text.charAt(i)) {
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- break;
- default:
- return false;
- }
- }
-
- return true;
- }
- }
-
-}
diff --git a/app/src/main/java/org/schabi/newpipe/util/Constants.java b/app/src/main/java/org/schabi/newpipe/util/Constants.java
index b01b6df6a..50350651d 100644
--- a/app/src/main/java/org/schabi/newpipe/util/Constants.java
+++ b/app/src/main/java/org/schabi/newpipe/util/Constants.java
@@ -11,5 +11,7 @@ public class Constants {
public static final String KEY_THEME_CHANGE = "key_theme_change";
public static final String KEY_MAIN_PAGE_CHANGE = "key_main_page_change";
+ public static final String KEY_ENABLE_WATCH_HISTORY = "enable_watch_history";
+
public static final int NO_SERVICE_ID = -1;
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/KoreUtil.java b/app/src/main/java/org/schabi/newpipe/util/KoreUtil.java
new file mode 100644
index 000000000..2ed3c698d
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/util/KoreUtil.java
@@ -0,0 +1,23 @@
+package org.schabi.newpipe.util;
+
+
+import android.content.Context;
+import android.content.DialogInterface;
+import androidx.appcompat.app.AlertDialog;
+
+import org.schabi.newpipe.R;
+
+
+public class KoreUtil {
+ private KoreUtil() { }
+
+ public static void showInstallKoreDialog(final Context context) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setMessage(R.string.kore_not_found)
+ .setPositiveButton(R.string.install,
+ (DialogInterface dialog, int which) -> NavigationHelper.installKore(context))
+ .setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
+ });
+ builder.create().show();
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index e2b03c8e8..a19aa92ae 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -109,12 +109,14 @@ public class NavigationHelper {
final float playbackPitch,
final boolean playbackSkipSilence,
@Nullable final String playbackQuality,
- final boolean resumePlayback) {
+ final boolean resumePlayback,
+ final boolean startPaused) {
return getPlayerIntent(context, targetClazz, playQueue, playbackQuality, resumePlayback)
.putExtra(BasePlayer.REPEAT_MODE, repeatMode)
.putExtra(BasePlayer.PLAYBACK_SPEED, playbackSpeed)
.putExtra(BasePlayer.PLAYBACK_PITCH, playbackPitch)
- .putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence);
+ .putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence)
+ .putExtra(BasePlayer.START_PAUSED, startPaused);
}
public static void playOnMainPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
index 773ff92d1..e93e83a87 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
@@ -80,7 +80,7 @@ public abstract class Postprocessing implements Serializable {
private transient DownloadMission mission;
- private File tempFile;
+ private transient File tempFile;
Postprocessing(boolean reserveSpace, boolean worksOnSameFile, String algorithmName) {
this.reserveSpace = reserveSpace;
@@ -95,8 +95,12 @@ public abstract class Postprocessing implements Serializable {
public void cleanupTemporalDir() {
if (tempFile != null && tempFile.exists()) {
- //noinspection ResultOfMethodCallIgnored
- tempFile.delete();
+ try {
+ //noinspection ResultOfMethodCallIgnored
+ tempFile.delete();
+ } catch (Exception e) {
+ // nothing to do
+ }
}
}
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/TtmlConverter.java b/app/src/main/java/us/shandian/giga/postprocessing/TtmlConverter.java
index 5a5b687f7..8ed0dfae5 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/TtmlConverter.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/TtmlConverter.java
@@ -2,15 +2,10 @@ package us.shandian.giga.postprocessing;
import android.util.Log;
-import org.schabi.newpipe.streams.SubtitleConverter;
+import org.schabi.newpipe.streams.SrtFromTtmlWriter;
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
@@ -27,33 +22,16 @@ class TtmlConverter extends Postprocessing {
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);
+ boolean ignoreEmptyFrames = getArgumentAt(1, "true").equals("true");
if (format == null || format.equals("ttml")) {
- SubtitleConverter ttmlDumper = new SubtitleConverter();
+ SrtFromTtmlWriter writer = new SrtFromTtmlWriter(out, ignoreEmptyFrames);
try {
- ttmlDumper.dumpTTML(
- sources[0],
- out,
- getArgumentAt(1, "true").equals("true"),
- getArgumentAt(2, "true").equals("true")
- );
+ writer.build(sources[0]);
} 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 err instanceof IOException ? 1 : 8;
}
return OK_RESULT;
diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManager.java b/app/src/main/java/us/shandian/giga/service/DownloadManager.java
index e8bc468e9..994c6ee63 100644
--- a/app/src/main/java/us/shandian/giga/service/DownloadManager.java
+++ b/app/src/main/java/us/shandian/giga/service/DownloadManager.java
@@ -139,6 +139,9 @@ public class DownloadManager {
Log.d(TAG, "Loading pending downloads from directory: " + mPendingMissionsDir.getAbsolutePath());
}
+ File tempDir = pickAvailableTemporalDir(ctx);
+ Log.i(TAG, "using '" + tempDir + "' as temporal directory");
+
for (File sub : subs) {
if (!sub.isFile()) continue;
if (sub.getName().equals(".tmp")) continue;
@@ -184,7 +187,7 @@ public class DownloadManager {
if (mis.psAlgorithm != null) {
mis.psAlgorithm.cleanupTemporalDir();
- mis.psAlgorithm.setTemporalDir(pickAvailableTemporalDir(ctx));
+ mis.psAlgorithm.setTemporalDir(tempDir);
}
mis.metadata = sub;
@@ -513,13 +516,21 @@ public class DownloadManager {
}
static File pickAvailableTemporalDir(@NonNull Context ctx) {
- if (isDirectoryAvailable(ctx.getExternalFilesDir(null)))
- return ctx.getExternalFilesDir(null);
- else if (isDirectoryAvailable(ctx.getFilesDir()))
- return ctx.getFilesDir();
+ File dir = ctx.getExternalFilesDir(null);
+ if (isDirectoryAvailable(dir)) return dir;
+
+ dir = ctx.getFilesDir();
+ if (isDirectoryAvailable(dir)) return dir;
// this never should happen
- return ctx.getDir("tmp", Context.MODE_PRIVATE);
+ dir = ctx.getDir("muxing_tmp", Context.MODE_PRIVATE);
+ if (isDirectoryAvailable(dir)) return dir;
+
+ // fallback to cache dir
+ dir = ctx.getCacheDir();
+ if (isDirectoryAvailable(dir)) return dir;
+
+ throw new RuntimeException("Not temporal directories are available");
}
@Nullable
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index b535db2b8..98017b132 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -305,7 +305,7 @@
tools:text="English" />
+
+
+
+
-
-
diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml
deleted file mode 100644
index 05920099a..000000000
--- a/app/src/main/res/menu/main_menu.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_about.xml b/app/src/main/res/menu/menu_about.xml
index 673cef94b..dbe91a04f 100644
--- a/app/src/main/res/menu/menu_about.xml
+++ b/app/src/main/res/menu/menu_about.xml
@@ -3,14 +3,4 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.schabi.newpipe.about.AboutActivity">
-
-
-
-
diff --git a/app/src/main/res/menu/menu_play_queue.xml b/app/src/main/res/menu/menu_play_queue.xml
index 6261b8c18..5413794be 100644
--- a/app/src/main/res/menu/menu_play_queue.xml
+++ b/app/src/main/res/menu/menu_play_queue.xml
@@ -10,11 +10,6 @@
android:visible="true"
app:showAsAction="ifRoom"/>
-
-
- 在浏览器中打开
在悬浮窗模式下打开
您是不是要找:%1$s?
- 找不到串流播放器 (您可以安裝并使用VLC播放)。
+ 找不到串流播放器 (您可以安装 VLC 进行播放)。
下载串流文件
安装
取消
@@ -16,7 +16,7 @@
设置
分享给...
选择浏览器
- 视频下载文件夹
+ 视频下载路径
已下载的视频存储在这里
请选择下载视频的保存位置
已下载的音频存储在这里
@@ -42,7 +42,7 @@
禁用
- 背景
+ 后台播放
过滤器
刷新
搜索建议
@@ -157,8 +157,8 @@
切换服务,当前选择:
找不到串流播放器。您想安装 VLC 吗?
旋转
- 使用第三方视频播放器
- 使用第三方视频播放器
+ 使用外部视频播放器
+ 使用外部音频播放器
音频下载文件夹
从其他应用调用 NewPipe 时播放视频
默认分辨率
@@ -209,7 +209,7 @@
\n需要此权限
reCAPTCHA验证
请求的新的CAPTCHA验证
- NewPipe悬浮窗模式
+ NewPipe 悬浮窗模式
在悬浮窗中播放
默认悬浮窗分辨率
使用更高的分辨率
@@ -219,7 +219,7 @@
记住最后一次使用悬浮窗的大小和位置
悬浮窗
调整大小
- 删除“某些”分辨率的音频
+ 部分分辨率的视频将没有声音
播放器手势控制
使用手势控制播放器的亮度和音量
显示搜索建议
@@ -234,9 +234,9 @@
取消订阅频道
无法修改订阅
无法更新订阅
- 主页面
+ 主页
订阅
- 新增功能
+ 最新
恢复前台焦点
中断后继续播放(例如突然来电后)
搜索历史记录
@@ -321,7 +321,7 @@
警告:无法导入所有文件。
这将覆盖当前设置。
显示信息
- 已收藏
+ 书签
确定要从观看历史记录中删除该项吗?
是否确实要从历史记录中删除所有项目?
最后播放
@@ -516,8 +516,8 @@
重新启动应用后,语言将更改。
PeerTube 服务器
- 设置自己喜欢的peertube服务器
- 查找最适合你的服务器https://joinpeertube.org/instances#instances-list
+ 设置自己喜欢的PeerTube服务器
+ 查找最适合你的服务器%s
添加服务器
输入服务器网址
无法验证服务器
@@ -533,4 +533,7 @@
快进 / 快退的单位时间
在锁屏界面显示视频缩略图
在后台播放时,锁屏界面将会显示视频的缩略图
+ 清除下载历史记录
+ 删除下载了的文件
+ 已删除 %1$s 下载
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 586da69ee..53b9a52eb 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -79,7 +79,7 @@
Dein Kommentar (auf englisch):
Konnte keinen Stream abrufen
Automatische Wiedergabe
- Wiedergabe eines Videos, wenn NewPipe von einer anderen App aufgerufen wurde
+ Video abspielen, wenn NewPipe von einer anderen App aufgerufen wird
Einen Fehler melden
Anwenderbericht
LIVE
@@ -489,7 +489,7 @@
NewPipe wurde während der Verarbeitung der Datei geschlossen
Kein Speicherplatz mehr auf dem Gerät
Vorgang abgebrochen, da die Datei gelöscht wurde
- Bist Du sicher\?
+ Möchtest du deinen Downloadverlauf oder alle heruntergeladenen Dateien löschen\?
Downloadwarteschlange begrenzen
Ein Download wird zur gleichen Zeit ausgeführt
Downloads starten
@@ -536,4 +536,7 @@
Dieser Download kann nicht wiederhergestellt werden
Video-Vorschaubild für Sperrbildschirm aktivieren
Bei Verwendung des Hintergrundplayers wird ein Video-Miniaturbild auf dem Sperrbildschirm angezeigt
+ Downloadverlauf löschen
+ Heruntergeladene Dateien löschen
+ %1$s Downloads gelöscht
\ No newline at end of file
diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml
index 6d19f8213..224e8837e 100644
--- a/app/src/main/res/values-eo/strings.xml
+++ b/app/src/main/res/values-eo/strings.xml
@@ -15,9 +15,9 @@
turno
Uzi eksteran filmetoludilon
Uzi eksteran sonludilon
- Defaŭlta distingivo
- Legi per Kodi
- Montri \"Legi per Kodi\"-opcion
+ Defaŭlta rezolucio
+ Ludi per Kodi
+ Montri \"Ludi per Kodi\"-opcion
Sono
Defaŭlta sondosierformo
Etoso
@@ -30,8 +30,8 @@
Filmeto kaj sono
Apero
Alia
- Ludado fone
- Legi
+ Ludanta fone
+ Ludi
Eraro
Reteraro
Enhavo malhavebla
@@ -45,7 +45,7 @@
La subskribo de la ligilo de la filmeto ne malĉifreblas
La retejo ne analizeblas
Bildeto de la antaŭrigardo de la filmeto
- Legi filmeton, daŭro:
+ Ludi filmeton, daŭro:
Bildeto de la alŝutinto
La elŝutujo \'%1$s\' ne kreeblas
Elŝutujo \'%1$s\' kreita
@@ -69,7 +69,7 @@
Premu serĉo por komenci
Neniu elsendlflua ludilo trovita (instalu VLC por ludi ĝin).
Malfermi en ŝprucfenestron modon
- Forigas aŭdion ĉe KELKAJ distingivoj
+ Forigas aŭdon ĉe KELKAJ rezolucioj
NewPipe ŝprucfenestron modon
Aboni
Abonita
@@ -86,10 +86,10 @@
Ŝprucfenestro
Aldonu al
Aŭtomata play
- Legas filmeton kiam NewPipe vokas de alia programo
- Defaŭlta distingivo de la ŝprucfenestro
- Montri pli altajn distingivojn
- Nur kelkaj aparatoj subtenas legante 2K / 4K filmetojn
+ Ludas filmeton kiam NewPipe vokas el alia programo
+ Defaŭlta rezolucio de la ŝprucfenestro
+ Montri pli altajn rezoluciojn
+ Nur kelkaj aparatoj subtenas ludi 2K / 4K filmetojn
Defaŭlta fomato de filmeto
Nigra
Memoru ŝprucfenestron kaj pozicion
@@ -122,7 +122,7 @@
Poste
Tiu permeso estas necesa por
\nmalfermi en ŝprucfenestro modo
- Leganta en ŝprucfenestro modo
+ Ludanta en ŝprucfenestro modo
Malaktiva
Filtri
Aktualigi
@@ -133,13 +133,13 @@
Uzu gestojn por kontroli la brilon kaj volumenon de la ludilo
Serĉi sugestojn
Montri sugestojn kiam serĉanto
- Plej bona distingivo
+ Plej bona rezolucio
Libera malpeza torentado ĉe Android.
Elŝuti
Leteroj kaj ciferoj
Plej specialaj karakteroj
Rekomencu en fokusa gajno
- Daŭrigi la legon post la interrompaĵoj (ekzemple telefonadoj)
+ Daŭrigi la ludon post la interrompaĵoj (ekzemple telefonadoj)
Serĉa historio
Konservi la historio de serĉo lokale
Rigardu historion
@@ -205,7 +205,7 @@
Ne povis forigi ludlisto.
Malcimigi
Auto-vico sekva fluo
- Aŭto-aldoni rilatan enhavon kiam leganta la lasta enhavo en malrepetita atendovico
+ Aŭto-aldoni rilatan enhavon kiam ludanta la lasta enhavo en malrepetita atendovico
Dosiero
Tia dosierujo ne ekzistas
Tia dosiero/enhavo ne ekzistas
@@ -236,7 +236,7 @@
Forviŝi la serĉajn ŝlosilvortojn
Ĉu vi volas forviŝi la totalon de la historio de serĉo \?
Historio de serĉo forviŝita.
- Limigi distingivo kiam uzanta moveblan datumon
+ Limigi rezolucio kiam uzanta moveblan datumon
Minimumigi al ŝprucfenestro ludilo
Kanaloj
Ludlistoj
@@ -265,7 +265,7 @@
Konferencoj
Montri komentojn
Malebligu por malvidigi komentojn
- Aŭtolego
+ Aŭtoludo
- Komentoj
@@ -342,7 +342,7 @@
Rigardu ĉe GitHub
Permesilo de NewPipe
Ĉu vi havas ideojn pri; traduko, desegnaĵoj ŝanĝoj, purigado de kodo, aŭ realaj masivaj ŝanĝoj—helpo estas ĉiam bonvena. Ju pli oni faras, des pli bonas!
- Legu permesilon
+ Legi permesilon
Kontribui
Permesitaj karakteroj en dosiernomoj
Nevalidaj karakteroj estas anstataŭigita kun ĉi tiu valoro
@@ -375,7 +375,7 @@
Neniuj kanalaj abonoj ankoraŭ
Elekti kioskon
Komenci ludi ĉi tie
- Komenci ludi en la fono
+ Komenci ludi fone
Donaci
NewPipe estas programada par volontuoj, elspezante tempo por alporti vin la plej bona sperto. Redonu por helpi programistojn plibonigi NewPipe dum ĝuante tason da kafo.
Redoni
@@ -413,7 +413,7 @@
La monitorado de la memorlikadoj povas frostigi la apon dum la hejta dumpingo
Signali ekster-vivciklajn erarojn
Perforti signalante neenretigaj Rx esceptoj eksere la fragmento aŭ aktiveco vivciklo post dispono
- La dosiero ne ekzistas aŭ la legopermeso mankas
+ La dosiero ne ekzistas aŭ la ludopermeso mankas
Importi/eksporti
Importi
Importi el
@@ -440,10 +440,10 @@
NewPipe estas programaro sub rajtoceda permesilo: Vi povas uzi, studi, komuniki kaj plibonigi ĝin kiel vi volas. Precize, vi povas redistribui kaj/aŭ modifi ĝin sub la kondiĉoj de la Ĝenerala Publika Permesilo de GNU, kiel publikigita per la Free Software Foundation, ĉu en la versio 3, ĉu (se vi volas) ajna posta versio.
Ĉu vi volas ankaŭ importi agordojn\?
Privateca politiko de NewPipe
- La NewPipe projekto respektas vian privatecon serioze. Konsekvence, la apo ne kolektas ajnan datumo sen via konsento.
+ La NewPipe projekto serioze respektas vian privatecon. Konsekvence, la apo ne kolektas ajnan datumo sen via konsento.
\nLa privateco politiko de Newpipe detale eksplikas kion datumon estas sendita kaj stokita kiam vi sendas falegosignalon.
Legi la privatecan politikon
- Por konformiĝi al la Ĝenerala Datum-Protekta Regularon (GDPR), ni allogas vian atento al la privateca politiko de NewPipe. Bonvolu legi ĝin atentive.
+ Por konformiĝi al la Ĝenerala Datum-Protekta Regularon (GDPR), ni allogas vian atenton al la privateca politiko de NewPipe. Bonvolu atentive legi ĝin.
\nVi devas akcepti ĝin por sendi nin la cimsignalo.
Akcepti
Rifuzi
@@ -455,7 +455,7 @@
Plirapidigi dum silentoj
Paŝo
Restarigi
- Uzante defaŭltajn ongletojn, eraro dum leganta savajn ongletojn
+ Uzante defaŭltajn ongletojn, eraro ludante savajn ongletojn
Restaŭri la defaŭltojn
Ĉu vi volas restaŭri la defaŭltojn \?
Kalkulo de abonantoj malhavebla
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index eacda9f4a..9f25208bb 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -520,16 +520,18 @@
El idioma cambiará luego de que la app sea reiniciada.
Duración de búsqueda al avanzar y/o retroceder
Instancias de PeerTube
- Elige tus instancias favoritas de PeerTube
- Encuentra las mejores instancias para ti en https://joinpeertube.org/instances#instances-list
+ Selecciona tus instancias favoritas de PeerTube
+ Encuentra las mejores instancias para ti en %s
Agregar instancia
- Dirección URL de la instancia
- Error al validar la instancia
- Sólo URLs con HTTPS
+ Ingresar URL de la instancia
+ No se pudo validar la instancia
+ Sólo URLs con HTTPS son soportados
La instancia ya existe
Local
Agregados recientemente
Más gustados
Generado automáticamente (no se encontró creador)
Elige una instancia
+ Habilitar miniatura de video de la pantalla de bloqueo
+ Al usar el reproductor de fondo, se mostrará una miniatura de video en la pantalla de bloqueo
\ No newline at end of file
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 463057480..444310aef 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -122,7 +122,7 @@
M
Cette autorisation est nécessaire pour
\nutiliser le mode flottant
- Arrière-plan
+ Lire l\'audio
Flottant
Définition de la fenêtre flottante par défaut
Afficher des définitions plus élevées
@@ -185,7 +185,7 @@
Notification NewPipe
Annuler
Garde un suivi des vidéos vues
- Reprendre à l’obtention de la cible de saisie
+ Reprendre lors du retour dans l\'application
Lecteur
Comportement
Historique et cache
@@ -310,7 +310,7 @@
Utiliser la recherche rapide approximative
Permet au lecteur d’accéder plus rapidement à une position au détriment de la précision
Charger les miniatures
- Désactiver pour empêcher le chargement des miniatures afin d\'économiser vos données. Modifier cette option vide le cache en mémoire vive et sur le disque.
+ Désactivez pour empêcher le chargement des miniatures afin de réduire l’utilisation de la bande passante et de la mémoire. La modification de cette option, vide le cache en mémoire vive et sur le disque.
Images en cache effacées
Effacer les métadonnées en cache
Efface toutes les données de pages Web en cache
@@ -534,5 +534,5 @@
Choisissez une instance
Généré automatiquement (pas de téléverseur trouvé)
Activer la vidéo miniaturisée sur l\'écran de verrouillage
- En utilisant le lecteur en arrière-plan, une vidéo miniaturisé sera affichée sur l\'écran de verrouillage
+ En utilisant le lecteur audio, la miniature de la vidéo sera affichée sur l\'écran de verrouillage
\ No newline at end of file
diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml
index d1a72739d..7a1338f60 100644
--- a/app/src/main/res/values-he/strings.xml
+++ b/app/src/main/res/values-he/strings.xml
@@ -496,7 +496,7 @@
לא נשאר מקום במכשיר
התהליך אבד כיוון שהקובץ נמחק
החיבור המתין זמן רב מדי
- בוודאות\?
+ למחוק את היסטוריית ההורדות שלך או למחוק את כל הקבצים שהורדת\?
הגבלת תור ההורדה
רק הורדה אחת תרוץ בו־זמנית
התחלת הורדות
@@ -547,4 +547,7 @@
נא לבחור מופע
הפעלת תמונה מוקטנת של הסרטון במסך הנעילה
בעת השימוש בנגן הרקע תופיע תמונה מוקטנת של הסרטון על מסך הנעילה
+ מחיקת היסטוריית ההורדות
+ למחוק את הקבצים שהורדתי
+ נמחקו %1$s הורדות
\ No newline at end of file
diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml
index 1038d15c4..d01647f5d 100644
--- a/app/src/main/res/values-nb-rNO/strings.xml
+++ b/app/src/main/res/values-nb-rNO/strings.xml
@@ -521,4 +521,9 @@
Nylig lagt til
Mest likt
Velg en instans
+ Tøm nedlastingshistorikk
+ Slett nedlastede filer
+ Slettet %1$s nedlastninger
+ Aktiver videominiatyrbilde med låseskjerm
+ Når du bruker bakgrunnsspilleren, vises en videominiaturbilde på låseskjermen
\ No newline at end of file
diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml
index 190c2c890..e69e43b44 100644
--- a/app/src/main/res/values-oc/strings.xml
+++ b/app/src/main/res/values-oc/strings.xml
@@ -2,8 +2,8 @@
%1$s vistas
Publicat lo %1$s
- Cap de lector de flus trobat. Volètz installar VLC\?
- Cap de lector de flus trobat (podètz installar VLC per lo legir).
+ Cap de legidor de flus trobat. Volètz installar VLC\?
+ Cap de legidor de flus trobat (podètz installar VLC per lo legir).
Installar
Anullar
Dobrir dins lo navegador
@@ -17,7 +17,7 @@
Partejar amb
Causir un navegador
rotacion
- Utilizar un lector de vidèo extèrne
+ Utilizar un legidor de vidèo extèrne
Mòde fenestron de NewPipe
S\'abonar
Abonat
@@ -27,4 +27,50 @@
Afichar las informacions
Principal
Abonaments
+ Clicatz sul boton de recèrca per començar
+ Lèva l\'àudio per CÈRTAS resolucions
+ Utilizar lo legidor àudio extèrne
+ Abonament a la cadena anullat
+ Listas de lectura enregistradas
+ Onglet novèl
+ Causir un onglet
+ Çò novèl
+ Rèireplan
+ Fenestron
+ Apondre a
+ Dorsièr de telecargament de vidèos
+ Los fichièrs vidèo telecargats son aquí
+ Causissètz lo dorsièr de telecargament de las vidèos
+ Dorsièr de telecargament dels àudios
+ Los fichièrs àudio telecargats son estremats aicí
+ Causissètz lo dorsièr de telecargament pels àudios
+ Cambiatz los dorsièrs de telecargament per venga efectiu
+ Lectura automatica
+ Legís una vidèo quand NewPIpe es apelat dempuèi una autra aplicacion
+ Resolucion per defaut
+ Resolucion per defaut dels fenestrons
+ Afichar de resolucions mai nautas
+ Totes los dispositius pòdon pas legir de vidèos 2K/4K
+ Jogar amb Kodi
+ Trobam pas l\'aplicacion Kore. La volètz installar\?
+ Afichar l\'opcion \"Legir amb Kodi\"
+ Activar la vidèo miniatura sus l\'ecran de blocatge
+ Afichar una opcion per legir una vidèo dempuèi Kodi
+ En utilizant lo legidor de rèireplan, una vidèo miniatura s\'aficharà sus l\'ecran de blocatge
+ Àudio
+ Format àudio per defaut
+ Format vidèo per defaut
+ Tèma
+ Clar
+ Escur
+ Negre
+ Se remembrar la talha e la posicion del fenestron
+ Se remembrar las darrièras talha e posicion del fenestron
+ Utilzar la recèrca rapida inexacta
+ La recèrca inexacta permet a l\'utilizaire de recercar mai rapidament una posicion amb mens de precision
+ Durada d\'avançada/reculada rapida
+ Cargar las miniaturas
+ Afichar los comentaris
+ Desactivar per afichar pas mai los comentaris
+ Apondre la vidèo seguenta dins la coa de lectura
\ No newline at end of file
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index e2a2ae80b..0da89ad48 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -491,7 +491,7 @@
NewPipe został zamknięty podczas pracy nad plikiem
Brak miejsca na urządzeniu
Postęp został utracony ze wzgledu na usunięcie pliku
- Czy jesteś pewien\?
+ Czy chcesz wyczyścić historię pobierania lub usunąć wszystkie pobrane pliki\?
Ogranicz kolejkę pobierania
Tylko jedno pobieranie będzie realizowane jednocześnie
Rozpocznij pobieranie
@@ -541,4 +541,7 @@
Wybierz instancję
Włącz miniaturę wideo na ekranie blokady
Podczas korzystania z odtwarzacza w tle na ekranie blokady zostanie wyświetlona miniatura filmu
+ Wyczyść historię pobierania
+ Usuń pobrane pliki
+ Usunięte% 1$s pobrania
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index f3fdbbc18..1da98cc74 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -492,7 +492,7 @@
NewPipe была закрыта во время работы над файлом
Закончилось свободное место на устройстве
Прогресс потерян, так как файл был удалён
- Вы уверены\?
+ Действительно удалить историю загрузок и загруженные файлы\?
Ограничить очередь загрузки
Только одна одновременная загрузка
Начать загрузку
@@ -522,10 +522,10 @@
- %s слушателей
Язык будет изменён после перезапуска
- Перемотка двойным нажатием
+ Шаг перемотки
Серверы PeerTube
- Выберите предпочтительные серверы PeerTube
- Выберите подходящие серверы на %s
+ Выберите предпочтительные серверы
+ Каталог серверов: %s
Новый сервер
URL сервера
Не удалось проверить сервер
@@ -540,4 +540,7 @@
Выберите сервер
Миниатюра на экране блокировки
Показать миниатюру видео на экране блокировки при воспроизведении в фоне
+ Очистить историю загрузок
+ Удаление загруженных файлов
+ Удалено загрузок: %1$s
\ No newline at end of file
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 1ea8ad817..c6603382d 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -5,7 +5,7 @@
Yayınlanma: %1$s
Akış oynatıcısı bulunamadı. VLC\'yi yüklemek ister misiniz\?
Yükle
- İptal et
+ Vazgeç
Tarayıcıda aç
Paylaş
İndir
@@ -484,7 +484,7 @@
Aygıt üzerinde yer yok
İlerleme kaybedildi, çünkü dosya silinmiş
Bağlantı zaman aşımı
- Emin misiniz\?
+ İndirme geçmişinizi temizlemek veya indirilen tüm dosyaları silmek istiyor musunuz\?
İndirme kuyruğunu sınırla
Aynı anda yalnızca bir indirme yürütülecek
İndirmeleri başlat
@@ -535,4 +535,7 @@
Bir örnek seçin
Kilit ekranı video küçük resmini etkinleştir
Arka plan oynatıcıyı kullanırken kilit ekranında bir video küçük resmi görüntülenecektir
+ İndirme geçmişini temizle
+ İndirilen dosyaları sil
+ %1$s indirme silindi
\ No newline at end of file
diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml
index 089b793c8..724c9c3ed 100644
--- a/app/src/main/res/values-ur/strings.xml
+++ b/app/src/main/res/values-ur/strings.xml
@@ -8,7 +8,7 @@
بانٹیں
ڈاؤن لوڈکریں
تلاش کریں
- کیا آپ کا مطلب تھا: %1$s \?
+ کیا آپ کا مطلب تھا: s$1%\?
انٹرنیٹ میں کھولیں
ترتیبات
کوئیstream پلیئر نہیں ملا.کیا آپ VLC انسٹال کرنا چاہتے ہیں؟
@@ -159,7 +159,7 @@
ایسی کوئی فائل / مواد کا ذریعہ نہیں
فائل موجود نہیں ہے اور نہ ہی اسے پڑھنے یا لکھنے کی اجازت ہے
فائل کا نام ضروری ہے
- ایک خامی پیش آگئی:٪ 1 $ s
+ ایک خامی پیش آگئی: s$1%
کوئی اسٹریمز ڈاؤن لوڈ کرنے کے لئے دستیاب نہیں
معذرت ، ایسا نہیں ہونا چاہئے تھا۔
ای میل کے ذریعے غلطی کی اطلاع دیں
@@ -182,8 +182,8 @@
کوئی نتیجہ نہیں
یہاں کچھ نہیں مگر اداسی کے
دوبارہ ترتیب دینے کیلئے کھینچں
- ڈاؤن لوڈ ڈائریکٹری \'٪ 1 $ s\' تشکیل نہیں دے سکتے
- ڈاؤن لوڈ ڈائریکٹری \'٪ 1 $ s\' بن گئی
+ ڈاؤن لوڈ ڈائریکٹری \'s$1%\' تشکیل نہیں دے سکتے
+ ڈاؤن لوڈ ڈائریکٹری \'s$1%\' بن گئی
ویڈیو
آڈیو
دوبارہ کوشش کریں
@@ -193,18 +193,18 @@
بی
کوئی صارفین نہیں
- - % s صارف
- - % s صارفین
+ - s% صارف
+ - s% صارفین
کوئی مناظر نہیں
- - % s منظر
- - % s مناظر
+ - s% منظر
+ - s% مناظر
ویڈیوز دستیاب نہیں
- ویڈیوز
-
+
شروع کریں
توقف
@@ -306,7 +306,7 @@
دراز بند کریں
یہاں جلد ہی کچھ نظر آئے گا D D
ترجیح \' کھلی \' عمل
- مواد کھولنے پر ڈیفالٹ کارروائی -٪ s
+ مواد کھولنے پر ڈیفالٹ کارروائی — s%
ویڈیو پلیئر
پس منظر پلیئر
پوپ اپ پلیئر
@@ -345,16 +345,16 @@
پچھلی برآمد
سبسکرپشنز کو درآمد نہیں کیا جاسکا
رکنیت برآمد نہیں کر سکا
- برآمد فائل کو ڈاؤن لوڈ کرکے YouTube کی رکنیت کو درآمد کریں:
-\n
-\n1. اس یو آر ایل پر جائیں:٪ 1 $ s
-\n2. جب پوچھا جائے تو لاگ ان کریں
+ برآمد فائل کو ڈاؤن لوڈ کرکے YouTube کی رکنیت کو درآمد کریں:
+\n
+\n1. اس یو آر ایل پر جائیں:s$1%
+\n2. جب پوچھا جائے تو لاگ ان کریں
\nA. ڈاؤن لوڈ شروع ہونا چاہئے (یہ برآمد فائل ہے)
- URL یا آپ کی ID ٹائپ کرکے ایک SoundCloud پروفائل درآمد کریں:
-\n
-\n1. ویب براؤزر میں \"ڈیسک ٹاپ موڈ\" کو فعال کریں (سائٹ موبائل آلات کے لئے دستیاب نہیں ہے)
-\n2. اس URL پر جائیں: %1 $ s
-\n3. پوچھا گیا میں لاگ ان کریں
+ URL یا آپ کی ID ٹائپ کرکے ایک SoundCloud پروفائل درآمد کریں:
+\n
+\n1. ویب براؤزر میں \"ڈیسک ٹاپ موڈ\" کو فعال کریں (سائٹ موبائل آلات کے لئے دستیاب نہیں ہے)
+\n2. اس URL پر جائیں: s$1%
+\n3. پوچھا گیا میں لاگ ان کریں
\n4. پروفائل یو آر ایل کاپی کریں جو آپ کو ہدایت کی گئی تھی.
yourID، soundcloud.com/yourid
یاد رکھیں کہ یہ آپریشن نیٹ ورک مہنگا ہوسکتا ہے۔
@@ -388,7 +388,7 @@
کوئی حد نہیں
موبائل ڈیٹا کا استعمال کرتے وقت ریذولوشن کو محدود کریں
ایپ سوئچ کو کم سے کم کریں
- اہم ویڈیو پلیئر سے دوسرے ایپ میں سوئچنگ کرتے وقت کارروائی-% s
+ اہم ویڈیو پلیئر سے دوسرے ایپ میں سوئچنگ کرتے وقت کارروائی — %s
کوئی نہیں
پس منظری پلیر میں کم کریں
پاپ اپ پلیر میں کم کریں
@@ -437,7 +437,7 @@
سسٹم نےکارروائی سے انکار کیا گیا
ڈاؤن لوڈ ناکام
ڈاؤن لوڈ تکمیل
- ٪ s ڈاؤن لوڈ مکمل ہوگئے
+ s% ڈاؤن لوڈ مکمل ہوگئے
منفرد نام بنائیں
برتحریر
اس نام کے ساتھ ایک ڈاؤن لوڈ جاری ہے
@@ -466,7 +466,7 @@
آٹوپلے
- تبصرے
-
+
کوئی تبصرہ نہیں
تبصرے لوڈ نہیں ہوسکے
diff --git a/fastlane/metadata/android/en-US/changelogs/810.txt b/fastlane/metadata/android/en-US/changelogs/810.txt
new file mode 100644
index 000000000..43fcc5287
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/810.txt
@@ -0,0 +1,19 @@
+New
+• Show video thumbnail on the lock screen when playing in the background
+
+Improved
+• Add local playlist to queue when long pressing on background / popup button
+• Make main page tabs scrollable and hide when there is only a single tab
+• Limit amount of notification thumbnail updates in background player
+• Add dummy thumbnail for empty local playlists
+• Use *.opus file extension instead of *.webm and show "opus" in format label instead of "WebM Opus" in the download dropdown
+• Add button to delete downloaded files or download history in "Downloads"
+• [YouTube] Add support to /c/shortened_url channel links
+
+Fixed
+• Fixed multiple issues when sharing a video to NewPipe and downloading its streams directly
+• Fixed player access out of its creation thread
+• Fixed search result paging
+• [YouTube] Fixed switching on null causing NPE
+• [YouTube] Fixed viewing comments when opening an invidio.us url
+• [SoundCloud] Updated client_id
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/820.txt b/fastlane/metadata/android/en-US/changelogs/820.txt
new file mode 100644
index 000000000..d56291711
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/820.txt
@@ -0,0 +1 @@
+Fixed decrypt function name regex making YouTube unusable.