1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2026-01-14 21:48:00 +00:00

Compare commits

...

122 Commits

Author SHA1 Message Date
Christian Schabesberger
f65f2da890 moved on to v0.11.6 2018-02-04 18:40:45 +01:00
Christian Schabesberger
30ab58c33d added some more lambdas 2018-02-04 17:50:22 +01:00
Christian Schabesberger
87ba5a7eb6 Merge branch 'eximport' into dev 2018-02-04 13:40:03 +01:00
Christian Schabesberger
6e8593af91 add import database function
bla

remove unused restart function

add allert dialog and add time to filename
2018-02-04 13:38:58 +01:00
Weblate
0ab1d3fc40 Merge remote-tracking branch 'origin/dev' into dev 2018-02-04 03:36:15 +01:00
ezjerry liao
f22d13e695 Translated using Weblate (Chinese (Traditional))
Currently translated at 83.5% (223 of 267 strings)
2018-02-04 03:36:07 +01:00
Mauricio Colli
cdde61a460 Change service icons for now
- Use place holders while the legal discussion is happening
2018-02-03 22:32:01 -02:00
Mauricio Colli
989ce126f1 Improve up button behavior
- Closes #614
2018-02-03 09:03:55 -02:00
ScratchBuild
28618e822e Translated using Weblate (Japanese)
Currently translated at 74.5% (199 of 267 strings)
2018-02-03 08:38:18 +01:00
Weblate
6772381afc Merge remote-tracking branch 'origin/dev' into dev 2018-01-31 13:34:27 +01:00
孟武尼德霍格龍
75b45beabc Translated using Weblate (Chinese (Traditional))
Currently translated at 77.2% (207 of 268 strings)
2018-01-31 13:34:24 +01:00
ButterflyOfFire
56d53e9b01 Translated using Weblate (Arabic)
Currently translated at 95.1% (255 of 268 strings)
2018-01-31 13:34:15 +01:00
Mauricio Colli
3a8b04e2d1 Fix and improve service switching (introduced colors)
- Every service now have its own colors
- Fix bug navigation button and backstack count
- Fix and themed properly the icons and colors of the main fragment tabs
- Re-organized the styles and colors (too much in one file)
2018-01-30 05:07:40 -02:00
Christian Schabesberger
1ce7d66fb1 Merge pull request #1043 from TobiGr/preferred-string
Make preferred string not translatable
2018-01-29 00:47:55 +01:00
TobiGr
7b5a9b69fe make preferred string not translatable 2018-01-28 21:27:20 +01:00
Allan Nordhøy
837b22ccac Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (268 of 268 strings)
2018-01-28 19:24:39 +01:00
Christian Schabesberger
7146719393 add export newipe db function 2018-01-28 19:02:34 +01:00
Weblate
71ee604c69 Merge remote-tracking branch 'origin/dev' into dev 2018-01-27 21:19:32 +01:00
Mateusz
9945a5b813 Translated using Weblate (Polish)
Currently translated at 98.1% (263 of 268 strings)
2018-01-27 21:19:31 +01:00
Kompiuterių meistras +37060040
7254387042 Translated using Weblate (Lithuanian)
Currently translated at 91.0% (244 of 268 strings)
2018-01-27 21:19:29 +01:00
Jonas
3a7f2a94a6 Translated using Weblate (French)
Currently translated at 100.0% (268 of 268 strings)
2018-01-27 21:19:26 +01:00
Mauricio Colli
6bea4aa96b Fix player switching
- Background to popup wasn't asking for permission
- The new task flag is needed to switch from the background/popup UI to the main player
2018-01-27 02:57:00 -02:00
Mauricio Colli
fa262bbceb Improve settings theme color
- Closes #863
2018-01-27 02:56:10 -02:00
Eduardo Caron
3139fe0170 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.8% (265 of 268 strings)
2018-01-25 22:39:19 +01:00
Freddy Morán Jr
ef6c5de65b Translated using Weblate (Spanish)
Currently translated at 100.0% (268 of 268 strings)
2018-01-25 19:40:22 +01:00
M1ck
07799563b5 Translated using Weblate (French)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 18:36:21 +01:00
Nathan Follens
b1de4b7bd6 Translated using Weblate (Dutch)
Currently translated at 100.0% (268 of 268 strings)
2018-01-25 18:16:29 +01:00
E T
2b8ae9a5ea Translated using Weblate (Turkish)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 14:42:33 +01:00
Georg Rieger
7c52d3ec5d Translated using Weblate (German)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 14:37:17 +01:00
Osoitz
aefaa7619e Translated using Weblate (Basque)
Currently translated at 99.6% (267 of 268 strings)
2018-01-25 14:34:34 +01:00
Emanuele Petriglia
ca202290bf Translated using Weblate (Italian)
Currently translated at 100.0% (268 of 268 strings)
2018-01-24 14:46:59 +01:00
Weblate
cbdbc4cba2 Merge remote-tracking branch 'origin/dev' into dev 2018-01-24 13:10:42 +01:00
M1ck
8abf904a78 Translated using Weblate (French)
Currently translated at 100.0% (252 of 252 strings)
2018-01-24 13:10:32 +01:00
Mauricio Colli
ecf7969c46 Improve settings up button behavior
- Fix #736
2018-01-23 11:45:41 -02:00
Mauricio Colli
a473e3d623 Add preferred player 2018-01-23 11:15:36 -02:00
Weblate
1f8e90858e Merge remote-tracking branch 'origin/dev' into dev 2018-01-23 12:17:34 +01:00
Osoitz
2c2edca8fa Translated using Weblate (Spanish)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:33 +01:00
Rubix
50e86ff1ca Translated using Weblate (Romanian)
Currently translated at 87.6% (221 of 252 strings)
2018-01-23 12:17:33 +01:00
Rintaro matsuo
02ecc5011a Translated using Weblate (Japanese)
Currently translated at 78.9% (199 of 252 strings)
2018-01-23 12:17:32 +01:00
nautilusx
6e666a018b Translated using Weblate (German)
Currently translated at 96.8% (244 of 252 strings)
2018-01-23 12:17:31 +01:00
M2ck
66fbb2ce1e Translated using Weblate (French)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:30 +01:00
r2308145
b00722ec0a Translated using Weblate (Czech)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:29 +01:00
ButterflyOfFire
77b1413319 Translated using Weblate (Arabic)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:29 +01:00
Osoitz
87b8d60c9d Translated using Weblate (Basque)
Currently translated at 100.0% (252 of 252 strings)
2018-01-23 12:17:26 +01:00
Christian Schabesberger
db5203e1ff Merge pull request #1023 from TobiGr/update-screenshots
Update screenshots
2018-01-23 00:27:28 +01:00
TobiGr
ea022670c4 Update screenshots 2018-01-22 21:04:27 +01:00
r2308145
54b009cc49 Translated using Weblate (Czech)
Currently translated at 100.0% (252 of 252 strings)
2018-01-22 19:09:37 +01:00
E T
80c3acace9 Translated using Weblate (Turkish)
Currently translated at 100.0% (252 of 252 strings)
2018-01-21 17:40:52 +01:00
Nathan Follens
cea9428b47 Translated using Weblate (Dutch)
Currently translated at 100.0% (252 of 252 strings)
2018-01-21 17:34:51 +01:00
Emanuele Petriglia
f8ffbfabbe Translated using Weblate (Italian)
Currently translated at 100.0% (252 of 252 strings)
2018-01-21 12:12:04 +01:00
Allan Nordhøy
836a1e652b Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 23:27:15 +01:00
Freddy Morán Jr
d8544e0b84 Translated using Weblate (Spanish)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 23:06:06 +01:00
M2ck
4817d7fddc Translated using Weblate (French)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 23:00:00 +01:00
ButterflyOfFire
e6a385a85e Translated using Weblate (Arabic)
Currently translated at 100.0% (252 of 252 strings)
2018-01-20 21:34:50 +01:00
Weblate
3634f68364 Merge remote-tracking branch 'origin/dev' into dev 2018-01-20 21:31:01 +01:00
Freddy Morán Jr
f17ffa94fe Translated using Weblate (Spanish)
Currently translated at 100.0% (249 of 249 strings)
2018-01-20 21:31:00 +01:00
Coffeemaker
d52bcd46a1 Translated using Weblate (German)
Currently translated at 97.5% (243 of 249 strings)
2018-01-20 21:30:56 +01:00
ButterflyOfFire
7e58b0b6fe Translated using Weblate (Arabic)
Currently translated at 100.0% (249 of 249 strings)
2018-01-20 21:30:49 +01:00
Christian Schabesberger
f451f1f65d resolve conflict 2018-01-20 18:06:34 +01:00
Christian Schabesberger
4d12e71fba move on to v0.11.5 2018-01-20 16:00:39 +01:00
Christian Schabesberger
66fde7a212 fix loop in channel 2018-01-20 15:59:34 +01:00
Christian Schabesberger
86eccf219d refactore some more lambda functions 2018-01-20 15:24:45 +01:00
Christian Schabesberger
677865f347 player popup menu icons for white theme 2018-01-20 14:46:10 +01:00
Christian Schabesberger
eb4b3810e9 refactor ExtractionHelper using lambda expression 2018-01-20 13:57:31 +01:00
Christian Schabesberger
5f26501ddf fix triangle play button when returning to app 2018-01-20 13:39:06 +01:00
Emanuele Petriglia
b33a72f864 Translated using Weblate (Italian)
Currently translated at 100.0% (249 of 249 strings)
2018-01-19 20:07:50 +01:00
Freddy Morán Jr
675f43b968 Translated using Weblate (Spanish)
Currently translated at 100.0% (249 of 249 strings)
2018-01-19 01:24:52 +01:00
M2ck
9f117a2e59 Translated using Weblate (French)
Currently translated at 100.0% (249 of 249 strings)
2018-01-19 00:33:40 +01:00
Yann Hodiesne
a0844229a3 Translated using Weblate (French)
Currently translated at 97.9% (244 of 249 strings)
2018-01-19 00:23:06 +01:00
M2ck
114fcc144c Translated using Weblate (French)
Currently translated at 97.9% (244 of 249 strings)
2018-01-19 00:19:11 +01:00
Weblate
43372ff648 Merge remote-tracking branch 'origin/dev' into dev 2018-01-19 00:17:53 +01:00
ScratchBuild
b8ebbc5404 Translated using Weblate (Japanese)
Currently translated at 79.5% (194 of 244 strings)
2018-01-19 00:17:51 +01:00
M2ck
28309f82f3 Translated using Weblate (French)
Currently translated at 100.0% (244 of 244 strings)
2018-01-19 00:17:45 +01:00
Christian Schabesberger
c70fa391b6 fix conflict with weblate 2018-01-18 20:43:30 +01:00
nautilusx
caab589dce Translated using Weblate (German)
Currently translated at 99.5% (243 of 244 strings)
2018-01-18 08:18:08 +01:00
maruyuki
20370054e7 Translated using Weblate (Japanese)
Currently translated at 56.9% (139 of 244 strings)
2018-01-18 08:18:04 +01:00
f1882cb1e1 Translated using Weblate (German)
Currently translated at 97.5% (238 of 244 strings)
2018-01-12 19:37:15 +01:00
Nick Undnick
2ed149852d Translated using Weblate (German)
Currently translated at 97.5% (238 of 244 strings)
2018-01-10 18:22:38 +01:00
Coffeemaker
ac7226a0df Translated using Weblate (German)
Currently translated at 97.5% (238 of 244 strings)
2018-01-10 18:22:00 +01:00
Coffeemaker
5705650ca8 Translated using Weblate (Telugu)
Currently translated at 53.6% (131 of 244 strings)
2018-01-09 17:53:16 +01:00
Coffeemaker
60855ca7c5 Translated using Weblate (Tamil)
Currently translated at 5.7% (14 of 244 strings)
2018-01-09 17:53:16 +01:00
Coffeemaker
b8d8d181f3 Translated using Weblate (Slovak)
Currently translated at 70.0% (171 of 244 strings)
2018-01-09 17:53:16 +01:00
Thomas Lavend'Homme
6309160fc6 Translated using Weblate (French)
Currently translated at 100.0% (244 of 244 strings)
2018-01-09 17:53:14 +01:00
ButterflyOfFire
fc0e6ed273 Translated using Weblate (Arabic)
Currently translated at 100.0% (244 of 244 strings)
2018-01-09 17:53:04 +01:00
Christian Schabesberger
ada0cee656 move on to v0.11.4 2018-01-09 14:11:37 +01:00
Christian Schabesberger
6dde524d2c Merge branch 'dev' of github.com:teamnewpipe/NewPipe into dev 2018-01-09 14:02:39 +01:00
Christian Schabesberger
6a631e1915 forece select activity when opening with browser 2018-01-09 14:02:32 +01:00
Christian Schabesberger
bb6fa343cf Merge pull request #976 from coffeemakr/feature-share-subject
Add subject to shared URL's (fixes #975)
2018-01-09 13:53:29 +01:00
Christian Schabesberger
7557acde6c Merge pull request #977 from TobiGr/TranslationChecker-Fix
Fix crash due to no "other" item in plurals
2018-01-09 13:51:14 +01:00
TobiGr
25ed8952f9 Fix crash due to no "other" item in plurals 2018-01-09 13:24:50 +01:00
Coffeemakr
b93d94b0bd Add subject to shared URL's (fixes #975) 2018-01-09 12:41:30 +01:00
Christian Schabesberger
33d75fd2fb switch languageCode to content country 2018-01-09 12:25:40 +01:00
Christian Schabesberger
28a9855fd2 add countrycodes 2018-01-09 11:33:17 +01:00
Christian Schabesberger
9aad07621c fix many/other problem 2018-01-09 10:28:28 +01:00
Christian Schabesberger
384cde6eaa fix weblate merge failure 2018-01-08 13:29:25 +01:00
Sebastian Rasmussen
5ae98661ad Translated using Weblate (Swedish)
Currently translated at 100.0% (244 of 244 strings)
2018-01-08 13:21:19 +01:00
Alberto Moshpirit
8f4d9ceca9 Translated using Weblate (Spanish)
Currently translated at 100.0% (244 of 244 strings)
2018-01-08 13:21:15 +01:00
Christian Schabesberger
83d9a1233e horrible hack for fixing channel load next page foo 2018-01-06 20:39:33 +01:00
thami simo
522a287d79 Translated using Weblate (Arabic)
Currently translated at 96.3% (235 of 244 strings)
2018-01-06 17:21:06 +01:00
Sebastian Rasmussen
e052d4660d Translated using Weblate (Swedish)
Currently translated at 100.0% (244 of 244 strings)
2018-01-06 17:21:03 +01:00
John Zhen Mo
39b0b2f032 -Added player conversion to background and popup players.
-[#919] Fixed custom notification does not trigger unlocking on lockscreen.
-[#947] Fixes player crashing on internet outage, issue partially addressed.
-Fixed main player losing state after destroy while in background.
-Fixed main player controls not hiding automatically after orientation change.
-Fixed dialog uploader not marqueeing when too long.
-Fixed popup permission throwing NPE on BaseList.
-Refactored popup permissions to start in NavigationHelper.
-Extracted hardcoded string for player menus.
-Bump Java version to 1.8.
-Some lambda conversions.
2018-01-03 22:53:38 -08:00
Christian Schabesberger
0223d6d200 moved on to v0.11.3 2018-01-04 05:34:19 +01:00
Christian Schabesberger
808ce72078 fix share menu for playlists 2018-01-04 05:28:01 +01:00
Christian Schabesberger
3a84c47176 hopefully fix plurals 2018-01-04 04:56:45 +01:00
Weblate
20c2426128 Merge remote-tracking branch 'origin/dev' into dev 2017-12-30 19:06:47 +01:00
Phạm Nguyễn Hoàng
bf11d4c9fa Translated using Weblate (Vietnamese)
Currently translated at 59.0% (144 of 244 strings)
2017-12-30 19:06:47 +01:00
Matej U
783c0f79d7 Translated using Weblate (Slovenian)
Currently translated at 91.8% (224 of 244 strings)
2017-12-30 19:06:46 +01:00
Ivan Krušlin
98b94bd9c4 Translated using Weblate (Croatian)
Currently translated at 97.1% (237 of 244 strings)
2017-12-30 19:06:44 +01:00
Rex_sa
ff0178f965 Translated using Weblate (Arabic)
Currently translated at 91.8% (224 of 244 strings)
2017-12-30 19:06:41 +01:00
Schabi
7f88c3d0a9 roleback wrong fix 2017-12-30 00:27:29 +01:00
Schabi
11e8e38f2c setup context for making notifications open via setContextIntent() 2017-12-29 17:29:15 +01:00
Schabi
50c5314eaf fix yt trending content language 2017-12-29 15:02:23 +01:00
Schabi
a7a76d4f58 add beta 2 logo 2017-12-26 14:48:06 +01:00
wb9688
f5f8371865 Remove setting 2017-11-20 19:31:33 +01:00
wb9688
1191455d37 Show selected service 2017-11-20 16:04:18 +01:00
wb9688
011e151c91 Merge branch 'dev' into multiple-services 2017-11-19 17:41:57 +01:00
wb9688
54aa40eac1 Add simple drawer for selecting service 2017-11-19 17:21:46 +01:00
wb9688
621a1909ec Merge remote-tracking branch 'origin/dev' into multiple-services 2017-11-11 13:18:26 +01:00
wb9688
25db3c2940 Update NewPipeExtractor 2017-09-16 10:25:54 +02:00
wb9688
442290d7f0 Hide spinner 2017-09-14 11:43:30 +02:00
wb9688
a6eb871f5e Change layout for audio-only streams 2017-09-14 10:49:39 +02:00
wb9688
b500c3f526 Add service setting 2017-09-14 09:31:01 +02:00
131 changed files with 4131 additions and 1228 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@
gradle.properties
*~
.weblate
*.class

170
CheckTranslations.java Normal file
View File

@@ -0,0 +1,170 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.*;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.nio.file.Files;
import java.nio.charset.Charset;
public final class CheckTranslations {
private static boolean debug = false;
private static boolean plurals = false;
private static boolean empty = false;
private static boolean remove = false;
private static int checks = 0;
private static int matches = 0;
private static int changes = 0;
private static Pattern p, pb, pe, e, o;
/**
* Search translated strings.xml files for empty item / plural tags
* and remove them.
* @param args directories which contain string.xml files (in any subdirectory)
* -e option to find all empty string tags
* -p option to find all empty plurals and item tags
* -r option to remove all occurrences from the files
* -d option to see more details
*/
public static void main(String[] args) {
if (args.length < 1 || (args[0].equals("-d") && args.length < 2)) {
System.out.println("Not enough arguments");
return;
}
for (int i = 0; i < args.length; i++) {
switch (args[i]) {
case "-d":
debug = true;
break;
case "-p":
plurals = true;
break;
case "-e":
empty = true;
break;
case "-r":
remove = true;
break;
}
}
if (!plurals && !empty) {
plurals = true;
empty = true;
}
p = Pattern.compile("(<item quantity=\")(zero|one|two|three|few|many|other)(\"></item>|\"/>)");
pb = Pattern.compile("(<plurals[\\sa-zA-Z=\"]*>)");
pe = Pattern.compile("(</plurals>)");
e = Pattern.compile("(<string[\\sa-z_\\\"=]*)((><\\/string>|\\/>){1})");
o = Pattern.compile("(<item quantity=\"other\">)[^</>]*(<\\/item>)");
for (int i = 0; i < args.length; i++) {
if (!args[i].equals("-d") && !args[i].equals("-p") && !args[i].equals("-e") && !args[i].equals("-r")) {
File f = new File(args[i]);
if (f.exists() && !f.isDirectory()) {
checkFile(f);
} else if (f.isDirectory()) {
checkFiles(f.listFiles());
} else {
System.out.println("'" + args[i] + "' does not exist!");
}
}
}
System.out.println(checks + " files were checked.");
System.out.println(matches + " corrupt lines detected.");
if (remove) {
System.out.println(matches + " corrupt lines removed and " + changes + " lines fixed.");
}
}
private static void checkFiles(File[] f) {
for (int i = 0; i < f.length; i++) {
if (f[i].exists() && !f[i].isDirectory()) {
if (f[i].toString().contains("strings.xml")) {
checkFile(f[i]);
}
} else if (f[i].isDirectory()) {
checkFiles(f[i].listFiles());
}
}
}
private static void checkFile(File f) {
// Do not check our original English strings to cause no unwanted changes
// Btw. there should not be empty plural/item tags
if (f.toString().contains("values/strings.xml")) {
return;
}
if (debug) System.out.println("Checking " + f.toString());
checks++;
List<String> lines = new ArrayList<String>();
boolean checkFailed = false;
boolean otherDetected = false;
boolean inPlurals = false;
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
String line;
int ln = 0;
while ((line = br.readLine()) != null) {
ln++;
if (plurals && p.matcher(line).find()) {
matches++;
if (debug) System.out.println(" Line " + ln + " was " + ((remove) ? "removed" : "detected") + ": '" + line + "'");
checkFailed = true;
} else if (empty && e.matcher(line).find()) {
matches++;
checkFailed = true;
if (debug) System.out.println(" Line " + ln + " was " + ((remove) ? "removed" : "detected") + ": '" + line + "'");
} else {
if (remove) lines.add(line);
}
}
br.close();
int pluralsLine = 0;
for (int i = 0; i < lines.size(); i++) {
if (o.matcher(lines.get(i)).find()) {
otherDetected = true;
}
if (plurals && pb.matcher(lines.get(i)).find()) {
inPlurals = true;
pluralsLine = i;
} else if (plurals && pe.matcher(lines.get(i)).find()) {
inPlurals = false;
if (!otherDetected) {
boolean b = false;
check: for(int j = pluralsLine; j < i; j++) {
if (lines.get(j).contains("many")) {
b = true;
pluralsLine = j;
break check;
}
}
if (remove && b) {
if (debug) System.out.println(" Line " + (pluralsLine + 1) + " was " + ((remove) ? "changed" : "detected") + ": '" + lines.get(pluralsLine) + "'");
lines.set(pluralsLine, lines.get(pluralsLine).replace("many", "other"));
changes++;
checkFailed = true;
} else if (debug) {
if (debug) System.out.println(" WARNING: Line " + (i + 1) + " - No <item quantity=\"other\"> found!");
}
}
otherDetected = false;
}
}
if (remove && checkFailed) {
Files.write(f.toPath(), lines, Charset.forName("UTF-8"));
}
} catch (IOException e) {
System.out.println(e);
}
}
}

View File

@@ -8,8 +8,8 @@ android {
applicationId "org.schabi.newpipe"
minSdkVersion 15
targetSdkVersion 27
versionCode 43
versionName "0.11.2"
versionCode 47
versionName "0.11.6"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -42,8 +42,8 @@ android {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
@@ -55,7 +55,7 @@ dependencies {
exclude module: 'support-annotations'
}
implementation 'com.github.TeamNewPipe:NewPipeExtractor:2d191c4ca'
implementation 'com.github.TeamNewPipe:NewPipeExtractor:7fd21ec08581d'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19'

View File

@@ -16,7 +16,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:logo="@mipmap/ic_launcher"
android:theme="@style/DarkTheme"
android:theme="@style/OpeningTheme"
tools:ignore="AllowBackup">
<activity
android:name=".MainActivity"
@@ -31,7 +31,7 @@
<activity
android:name=".player.old.PlayVideoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/VideoPlayerTheme"
android:theme="@style/OldVideoPlayerTheme"
tools:ignore="UnusedAttribute"/>
<service
@@ -56,8 +56,7 @@
android:name=".player.MainVideoPlayer"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/PlayerTheme"/>
android:launchMode="singleTask"/>
<activity
android:name=".settings.SettingsActivity"
@@ -124,7 +123,7 @@
<activity
android:name=".RouterActivity"
android:taskAffinity=""
android:theme="@android:style/Theme.NoDisplay">
android:theme="@style/RouterActivityThemeDark">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
@@ -175,17 +174,21 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
<service
android:name=".RouterPlayerActivity$FetcherService"
android:exported="false"/>
<activity
android:name=".RouterPopupActivity"
android:label="@string/popup_mode_share_menu_title"
android:name=".RouterPlayerActivity"
android:excludeFromRecents="true"
android:label="@string/preferred_player_share_menu_title"
android:taskAffinity=""
android:theme="@style/PopupPermissionsTheme">
android:theme="@style/RouterActivityThemeDark">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
@@ -204,6 +207,11 @@
<data android:pathPrefix="/embed/"/>
<data android:pathPrefix="/watch"/>
<data android:pathPrefix="/attribution_link"/>
<!-- channel prefix -->
<data android:pathPrefix="/channel/"/>
<data android:pathPrefix="/user/"/>
<!-- playlist prefix -->
<data android:pathPrefix="/playlist"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>

View File

@@ -1,9 +1,12 @@
package org.schabi.newpipe;
import android.app.AlarmManager;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
@@ -116,7 +119,6 @@ public class App extends Application {
});
}
private void initACRA() {
try {
final ACRAConfiguration acraConfig = new ConfigurationBuilder(this)
@@ -149,4 +151,5 @@ public class App extends Application {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannel(mChannel);
}
}

View File

@@ -77,17 +77,6 @@ public abstract class BaseFragment extends Fragment {
protected void initListeners() {
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
protected final int resolveResourceIdFromAttr(@AttrRes int attr) {
TypedArray a = activity.getTheme().obtainStyledAttributes(new int[]{attr});
int attributeResourceId = a.getResourceId(0, 0);
a.recycle();
return attributeResourceId;
}
/*//////////////////////////////////////////////////////////////////////////
// DisplayImageOptions default configurations
//////////////////////////////////////////////////////////////////////////*/

View File

@@ -28,8 +28,12 @@ import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
@@ -50,11 +54,13 @@ import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.search.SearchFragment;
import org.schabi.newpipe.history.HistoryListener;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.StateSaver;
import org.schabi.newpipe.util.ThemeHelper;
@@ -67,8 +73,10 @@ import io.reactivex.subjects.PublishSubject;
public class MainActivity extends AppCompatActivity implements HistoryListener {
private static final String TAG = "MainActivity";
public static final boolean DEBUG = false;
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
private SharedPreferences sharedPreferences;
private ActionBarDrawerToggle toggle = null;
/*//////////////////////////////////////////////////////////////////////////
// Activity's LifeCycle
@@ -77,7 +85,10 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
ThemeHelper.setTheme(this);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this));
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
@@ -85,13 +96,53 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
initFragments();
}
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
setSupportActionBar(findViewById(R.id.toolbar));
setupDrawer();
initHistory();
}
private void setupDrawer() {
final Toolbar toolbar = findViewById(R.id.toolbar);
final DrawerLayout drawer = findViewById(R.id.drawer_layout);
final NavigationView drawerItems = findViewById(R.id.navigation);
//drawerItems.setItemIconTintList(null); // Set null to use the original icon
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
if (!BuildConfig.BUILD_TYPE.equals("release")) {
toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close);
toggle.syncState();
drawer.addDrawerListener(toggle);
drawer.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
private int lastService;
@Override
public void onDrawerOpened(View drawerView) {
lastService = ServiceHelper.getSelectedServiceId(MainActivity.this);
}
@Override
public void onDrawerClosed(View drawerView) {
if (lastService != ServiceHelper.getSelectedServiceId(MainActivity.this)) {
new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
}
}
});
drawerItems.setNavigationItemSelectedListener(item -> {
if (item.getGroupId() == R.id.menu_services_group) {
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(false);
ServiceHelper.setSelectedServiceId(this, item.getTitle().toString());
drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true);
}
drawer.closeDrawers();
return true;
});
} else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
@@ -112,20 +163,14 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
sharedPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, false).apply();
// https://stackoverflow.com/questions/10844112/runtimeexception-performing-pause-of-activity-that-is-not-resumed
// Briefly, let the activity resume properly posting the recreate call to end of the message queue
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
MainActivity.this.recreate();
}
});
new Handler(Looper.getMainLooper()).post(MainActivity.this::recreate);
}
if(sharedPreferences.getBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false)) {
if (sharedPreferences.getBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false)) {
if (DEBUG) Log.d(TAG, "main page has changed, recreating main fragment...");
sharedPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, false).apply();
NavigationHelper.openMainActivity(this);
}
}
@Override
@@ -159,6 +204,38 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
} else super.onBackPressed();
}
/**
* Implement the following diagram behavior for the up button:
* <pre>
* +---------------+
* | Main Screen +----+
* +-------+-------+ |
* | |
* ▲ Up | Search Button
* | |
* +----+-----+ |
* +------------+ Search |◄-----+
* | +----+-----+
* | Open |
* | something ▲ Up
* | |
* | +------------+-------------+
* | | |
* | | Video <-> Channel |
* +---►| Channel <-> Playlist |
* | Video <-> .... |
* | |
* +--------------------------+
* </pre>
*/
private void onHomeButtonPressed() {
// If search fragment wasn't found in the backstack...
if (!NavigationHelper.tryGotoSearchFragment(getSupportFragmentManager())) {
// ...go to the main fragment
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
}
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@@ -184,6 +261,9 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(false);
}
updateDrawerNavigation();
return true;
}
@@ -194,7 +274,7 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
switch (id) {
case android.R.id.home:
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
onHomeButtonPressed();
return true;
case R.id.action_settings:
NavigationHelper.openSettings(this);
@@ -228,6 +308,27 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void updateDrawerNavigation() {
if (getSupportActionBar() == null) return;
final Toolbar toolbar = findViewById(R.id.toolbar);
final DrawerLayout drawer = findViewById(R.id.drawer_layout);
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
if (fragment instanceof MainFragment) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
if (toggle != null) {
toggle.syncState();
toolbar.setNavigationOnClickListener(v -> drawer.openDrawer(GravityCompat.START));
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNDEFINED);
}
} else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(v -> onHomeButtonPressed());
}
}
private void handleIntent(Intent intent) {
if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");

View File

@@ -3,14 +3,25 @@ package org.schabi.newpipe;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.widget.Toast;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.Collection;
import java.util.HashSet;
/**
import icepick.Icepick;
import icepick.State;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
/*
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
* RouterActivity.java is part of NewPipe.
*
@@ -34,23 +45,71 @@ import java.util.HashSet;
*/
public class RouterActivity extends AppCompatActivity {
@State
protected String currentUrl;
protected CompositeDisposable disposables = new CompositeDisposable();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Icepick.restoreInstanceState(this, savedInstanceState);
String videoUrl = getUrl(getIntent());
handleUrl(videoUrl);
if (TextUtils.isEmpty(currentUrl)) {
currentUrl = getUrl(getIntent());
if (TextUtils.isEmpty(currentUrl)) {
Toast.makeText(this, R.string.invalid_url_toast, Toast.LENGTH_LONG).show();
finish();
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Icepick.saveInstanceState(this, outState);
}
@Override
protected void onStart() {
super.onStart();
handleUrl(currentUrl);
}
protected void handleUrl(String url) {
boolean success = NavigationHelper.openByLink(this, url);
if (!success) {
disposables.add(Observable
.fromCallable(() -> NavigationHelper.getIntentByLink(this, url))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(intent -> {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}, this::handleError)
);
}
protected void handleError(Throwable error) {
error.printStackTrace();
if (error instanceof ExtractionException) {
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
} else {
ExtractorHelper.handleGeneralException(this, -1, null, error, UserAction.SOMETHING_ELSE, null);
}
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
disposables.clear();
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@@ -71,7 +130,8 @@ public class RouterActivity extends AppCompatActivity {
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
//this means that vidoe was called through share menu
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
videoUrl = getUris(extraText)[0];
final String[] uris = getUris(extraText);
videoUrl = uris.length > 0 ? uris[0] : null;
}
return videoUrl;

View File

@@ -0,0 +1,413 @@
package org.schabi.newpipe;
import android.app.IntentService;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.preference.PreferenceManager;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.StreamingService.LinkType;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.playlist.ChannelPlayQueue;
import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.playlist.PlaylistPlayQueue;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable;
import java.util.Arrays;
import icepick.State;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
/**
* Get the url from the intent and open it in the chosen preferred player
*/
public class RouterPlayerActivity extends RouterActivity {
@State
protected int currentServiceId = -1;
private StreamingService currentService;
@State
protected LinkType currentLinkType;
@State
protected int selectedRadioPosition = -1;
protected int selectedPreviously = -1;
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setTheme(ThemeHelper.isLightThemeSelected(this) ? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
}
@Override
protected void handleUrl(String url) {
disposables.add(Observable
.fromCallable(() -> {
if (currentServiceId == -1) {
currentService = NewPipe.getServiceByUrl(url);
currentServiceId = currentService.getServiceId();
currentLinkType = currentService.getLinkTypeByUrl(url);
currentUrl = NavigationHelper.getCleanUrl(currentService, url, currentLinkType);
} else {
currentService = NewPipe.getService(currentServiceId);
}
return currentLinkType != LinkType.NONE;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result) {
onSuccess();
} else {
onError();
}
}, this::handleError));
}
protected void onError() {
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
finish();
}
protected void onSuccess() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
if ((isExtAudioEnabled || isExtVideoEnabled) && currentLinkType != LinkType.STREAM) {
Toast.makeText(this, R.string.external_player_unsupported_link_type, Toast.LENGTH_LONG).show();
finish();
return;
}
// TODO: Add some sort of "capabilities" field to services (audio only, video and audio, etc.)
if (currentService == ServiceList.SoundCloud.getService()) {
handleChoice(getString(R.string.background_player_key));
return;
}
final String playerChoiceKey = preferences.getString(getString(R.string.preferred_player_key), getString(R.string.preferred_player_default));
final String alwaysAskKey = getString(R.string.always_ask_player_key);
if (playerChoiceKey.equals(alwaysAskKey)) {
showDialog();
} else {
handleChoice(playerChoiceKey);
}
}
private void showDialog() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(this,
ThemeHelper.isLightThemeSelected(this) ? R.style.LightTheme : R.style.DarkTheme);
LayoutInflater inflater = LayoutInflater.from(themeWrapper);
final LinearLayout rootLayout = (LinearLayout) inflater.inflate(R.layout.preferred_player_dialog_view, null, false);
final RadioGroup radioGroup = rootLayout.findViewById(android.R.id.list);
final AdapterChoiceItem[] choices = {
new AdapterChoiceItem(getString(R.string.video_player_key), getString(R.string.video_player),
resolveResourceIdFromAttr(themeWrapper, R.attr.play)),
new AdapterChoiceItem(getString(R.string.background_player_key), getString(R.string.background_player),
resolveResourceIdFromAttr(themeWrapper, R.attr.audio)),
new AdapterChoiceItem(getString(R.string.popup_player_key), getString(R.string.popup_player),
resolveResourceIdFromAttr(themeWrapper, R.attr.popup))
};
final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> {
final int indexOfChild = radioGroup.indexOfChild(radioGroup.findViewById(radioGroup.getCheckedRadioButtonId()));
final AdapterChoiceItem choice = choices[indexOfChild];
handleChoice(choice.key);
if (which == DialogInterface.BUTTON_POSITIVE) {
preferences.edit().putString(getString(R.string.preferred_player_key), choice.key).apply();
}
};
final AlertDialog alertDialog = new AlertDialog.Builder(themeWrapper)
.setTitle(R.string.preferred_player_share_menu_title)
.setView(radioGroup)
.setCancelable(true)
.setNegativeButton(R.string.just_once, dialogButtonsClickListener)
.setPositiveButton(R.string.always, dialogButtonsClickListener)
.setOnDismissListener((dialog) -> finish())
.create();
alertDialog.setOnShowListener(dialog -> {
setDialogButtonsState(alertDialog, radioGroup.getCheckedRadioButtonId() != -1);
});
radioGroup.setOnCheckedChangeListener((group, checkedId) -> setDialogButtonsState(alertDialog, true));
final View.OnClickListener radioButtonsClickListener = v -> {
final int indexOfChild = radioGroup.indexOfChild(v);
if (indexOfChild == -1) return;
selectedPreviously = selectedRadioPosition;
selectedRadioPosition = indexOfChild;
if (selectedPreviously == selectedRadioPosition) {
handleChoice(choices[selectedRadioPosition].key);
}
};
int id = 12345;
for (AdapterChoiceItem item : choices) {
final RadioButton radioButton = (RadioButton) inflater.inflate(R.layout.list_radio_icon_item, null);
radioButton.setText(item.description);
radioButton.setCompoundDrawablesWithIntrinsicBounds(item.icon, 0, 0, 0);
radioButton.setChecked(false);
radioButton.setId(id++);
radioButton.setLayoutParams(new RadioGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
radioButton.setOnClickListener(radioButtonsClickListener);
radioGroup.addView(radioButton);
}
if (selectedRadioPosition == -1) {
final String lastSelectedPlayer = preferences.getString(getString(R.string.preferred_player_last_selected_key), null);
if (!TextUtils.isEmpty(lastSelectedPlayer)) {
for (int i = 0; i < choices.length; i++) {
AdapterChoiceItem c = choices[i];
if (lastSelectedPlayer.equals(c.key)) {
selectedRadioPosition = i;
break;
}
}
}
}
selectedRadioPosition = Math.min(Math.max(-1, selectedRadioPosition), choices.length - 1);
if (selectedRadioPosition != -1) {
((RadioButton) radioGroup.getChildAt(selectedRadioPosition)).setChecked(true);
}
selectedPreviously = selectedRadioPosition;
alertDialog.show();
}
private void setDialogButtonsState(AlertDialog dialog, boolean state) {
final Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
if (negativeButton == null || positiveButton == null) return;
negativeButton.setEnabled(state);
positiveButton.setEnabled(state);
}
private void handleChoice(final String playerChoiceKey) {
if (Arrays.asList(getResources().getStringArray(R.array.preferred_player_values_list)).contains(playerChoiceKey)) {
PreferenceManager.getDefaultSharedPreferences(this).edit()
.putString(getString(R.string.preferred_player_last_selected_key), playerChoiceKey).apply();
}
if (playerChoiceKey.equals(getString(R.string.popup_player_key)) && !PermissionHelper.isPopupEnabled(this)) {
PermissionHelper.showPopupEnablementToast(this);
finish();
return;
}
final Intent intent = new Intent(this, FetcherService.class);
intent.putExtra(FetcherService.KEY_CHOICE, new Choice(currentService.getServiceId(), currentLinkType, currentUrl, playerChoiceKey));
startService(intent);
finish();
}
private static class AdapterChoiceItem {
final String description, key;
@DrawableRes
final int icon;
AdapterChoiceItem(String key, String description, int icon) {
this.description = description;
this.key = key;
this.icon = icon;
}
}
private static class Choice implements Serializable {
final int serviceId;
final String url, playerChoice;
final LinkType linkType;
Choice(int serviceId, LinkType linkType, String url, String playerChoice) {
this.serviceId = serviceId;
this.linkType = linkType;
this.url = url;
this.playerChoice = playerChoice;
}
@Override
public String toString() {
return serviceId + ":" + url + " > " + linkType + " ::: " + playerChoice;
}
}
/*//////////////////////////////////////////////////////////////////////////
// Service Fetcher
//////////////////////////////////////////////////////////////////////////*/
public static class FetcherService extends IntentService {
private static final int ID = 456;
public static final String KEY_CHOICE = "key_choice";
private Disposable fetcher;
public FetcherService() {
super(FetcherService.class.getSimpleName());
}
@Override
public void onCreate() {
super.onCreate();
startForeground(ID, createNotification().build());
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent == null) return;
final Serializable serializable = intent.getSerializableExtra(KEY_CHOICE);
if (!(serializable instanceof Choice)) return;
Choice playerChoice = (Choice) serializable;
handleChoice(playerChoice);
}
public void handleChoice(Choice choice) {
Single<? extends Info> single = null;
UserAction userAction = UserAction.SOMETHING_ELSE;
switch (choice.linkType) {
case STREAM:
single = ExtractorHelper.getStreamInfo(choice.serviceId, choice.url, false);
userAction = UserAction.REQUESTED_STREAM;
break;
case CHANNEL:
single = ExtractorHelper.getChannelInfo(choice.serviceId, choice.url, false);
userAction = UserAction.REQUESTED_CHANNEL;
break;
case PLAYLIST:
single = ExtractorHelper.getPlaylistInfo(choice.serviceId, choice.url, false);
userAction = UserAction.REQUESTED_PLAYLIST;
break;
}
if (single != null) {
final UserAction finalUserAction = userAction;
final Consumer<Info> resultHandler = getResultHandler(choice);
fetcher = single
.observeOn(AndroidSchedulers.mainThread())
.subscribe(info -> {
resultHandler.accept(info);
if (fetcher != null) fetcher.dispose();
}, throwable -> ExtractorHelper.handleGeneralException(this,
choice.serviceId, choice.url, throwable, finalUserAction, ", opened with " + choice.playerChoice));
}
}
public Consumer<Info> getResultHandler(Choice choice) {
return info -> {
final String videoPlayerKey = getString(R.string.video_player_key);
final String backgroundPlayerKey = getString(R.string.background_player_key);
final String popupPlayerKey = getString(R.string.popup_player_key);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean isExtVideoEnabled = preferences.getBoolean(getString(R.string.use_external_video_player_key), false);
boolean isExtAudioEnabled = preferences.getBoolean(getString(R.string.use_external_audio_player_key), false);
boolean useOldVideoPlayer = PlayerHelper.isUsingOldPlayer(this);
PlayQueue playQueue;
String playerChoice = choice.playerChoice;
if (info instanceof StreamInfo) {
if (playerChoice.equals(backgroundPlayerKey) && isExtAudioEnabled) {
NavigationHelper.playOnExternalAudioPlayer(this, (StreamInfo) info);
} else if (playerChoice.equals(videoPlayerKey) && isExtVideoEnabled) {
NavigationHelper.playOnExternalVideoPlayer(this, (StreamInfo) info);
} else if (playerChoice.equals(videoPlayerKey) && useOldVideoPlayer) {
NavigationHelper.playOnOldVideoPlayer(this, (StreamInfo) info);
} else {
playQueue = new SinglePlayQueue((StreamInfo) info);
if (playerChoice.equals(videoPlayerKey)) {
NavigationHelper.playOnMainPlayer(this, playQueue);
} else if (playerChoice.equals(backgroundPlayerKey)) {
NavigationHelper.enqueueOnBackgroundPlayer(this, playQueue, true);
} else if (playerChoice.equals(popupPlayerKey)) {
NavigationHelper.enqueueOnPopupPlayer(this, playQueue, true);
}
}
}
if (info instanceof ChannelInfo || info instanceof PlaylistInfo) {
playQueue = info instanceof ChannelInfo ? new ChannelPlayQueue((ChannelInfo) info) : new PlaylistPlayQueue((PlaylistInfo) info);
if (playerChoice.equals(videoPlayerKey)) {
NavigationHelper.playOnMainPlayer(this, playQueue);
} else if (playerChoice.equals(backgroundPlayerKey)) {
NavigationHelper.playOnBackgroundPlayer(this, playQueue);
} else if (playerChoice.equals(popupPlayerKey)) {
NavigationHelper.playOnPopupPlayer(this, playQueue);
}
}
};
}
@Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
if (fetcher != null) fetcher.dispose();
}
private NotificationCompat.Builder createNotification() {
return new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
.setOngoing(true)
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentTitle(getString(R.string.preferred_player_fetcher_notification_title))
.setContentText(getString(R.string.preferred_player_fetcher_notification_message));
}
}
}

View File

@@ -1,50 +0,0 @@
package org.schabi.newpipe;
import android.content.Intent;
import android.os.Build;
import android.widget.Toast;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.PermissionHelper;
/**
* Get the url from the intent and open a popup player
*/
public class RouterPopupActivity extends RouterActivity {
@Override
protected void handleUrl(String url) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& !PermissionHelper.checkSystemAlertWindowPermission(this)) {
Toast.makeText(this, R.string.msg_popup_permission, Toast.LENGTH_LONG).show();
finish();
return;
}
StreamingService service;
try {
service = NewPipe.getServiceByUrl(url);
} catch (ExtractionException e) {
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
return;
}
Intent callIntent = new Intent(this, PopupVideoPlayer.class);
switch (service.getLinkTypeByUrl(url)) {
case STREAM:
break;
default:
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
return;
}
callIntent.putExtra(Constants.KEY_URL, url);
callIntent.putExtra(Constants.KEY_SERVICE_ID, service.getServiceId());
startService(callIntent);
finish();
}
}

View File

@@ -1,6 +1,7 @@
package org.schabi.newpipe.fragments;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
@@ -240,4 +241,28 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView, ErrorActivity.ErrorInfo.make(userAction, serviceName, request, errorId));
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
public void setTitle(String title) {
if (DEBUG) Log.d(TAG, "setTitle() called with: title = [" + title + "]");
if (activity != null && activity.getSupportActionBar() != null) {
activity.getSupportActionBar().setTitle(title);
}
}
protected void openUrlInBrowser(String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(Intent.createChooser(intent, activity.getString(R.string.share_dialog_title)));
}
protected void shareUrl(String subject, String url) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title)));
}
}

View File

@@ -23,6 +23,7 @@ import android.view.ViewGroup;
import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
@@ -33,23 +34,20 @@ import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.ThemeHelper;
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
private ViewPager viewPager;
private boolean showBlankTab = false;
public int currentServiceId = -1;
private ViewPager viewPager;
/*//////////////////////////////////////////////////////////////////////////
// Constants
//////////////////////////////////////////////////////////////////////////*/
private static final int FALLBACK_SERVICE_ID = 0; // Youtube
private static final String FALLBACK_CHANNEL_URL =
"https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ";
private static final int FALLBACK_SERVICE_ID = ServiceList.YouTube.getId();
private static final String FALLBACK_CHANNEL_URL = "https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ";
private static final String FALLBACK_CHANNEL_NAME = "Music";
private static final String FALLBACK_KIOSK_ID = "Trending";
private static final int KIOSK_MENU_OFFSET = 2000;
@@ -66,8 +64,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
currentServiceId = Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.current_service_key), "0"));
currentServiceId = ServiceHelper.getSelectedServiceId(activity);
return inflater.inflate(R.layout.fragment_main, container, false);
}
@@ -85,22 +82,10 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
tabLayout.setupWithViewPager(viewPager);
int channelIcon;
int whatsHotIcon;
int channelIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_channel);
int whatsHotIcon = ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.ic_hot);
if (ThemeHelper.isLightThemeSelected(getActivity())) {
tabLayout.setBackgroundColor(getResources().getColor(R.color.light_youtube_primary_color));
channelIcon = R.drawable.ic_channel_black_24dp;
whatsHotIcon = R.drawable.ic_whatshot_black_24dp;
} else {
channelIcon = R.drawable.ic_channel_white_24dp;
whatsHotIcon = R.drawable.ic_whatshot_white_24dp;
}
if (PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key))) {
if (isSubscriptionsPageOnlySelected()) {
tabLayout.getTabAt(0).setIcon(channelIcon);
} else {
tabLayout.getTabAt(0).setIcon(whatsHotIcon);
@@ -138,7 +123,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
NavigationHelper.openSearchFragment(getFragmentManager(), 0, "");
NavigationHelper.openSearchFragment(getFragmentManager(), ServiceHelper.getSelectedServiceId(activity), "");
return true;
}
return super.onOptionsItemSelected(item);
@@ -163,11 +148,6 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
private class PagerAdapter extends FragmentPagerAdapter {
private int[] tabTitles = new int[]{
R.string.tab_main,
R.string.tab_subscriptions
};
PagerAdapter(FragmentManager fm) {
super(fm);
}
@@ -176,13 +156,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
public Fragment getItem(int position) {
switch (position) {
case 0:
if(PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key))) {
return new SubscriptionFragment();
} else {
return getMainPageFragment();
}
return isSubscriptionsPageOnlySelected() ? new SubscriptionFragment() : getMainPageFragment();
case 1:
return new SubscriptionFragment();
default:
@@ -198,13 +172,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
@Override
public int getCount() {
if(PreferenceManager.getDefaultSharedPreferences(getActivity())
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key))) {
return 1;
} else {
return 2;
}
return isSubscriptionsPageOnlySelected() ? 1 : 2;
}
}
@@ -212,28 +180,33 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
// Main page content
//////////////////////////////////////////////////////////////////////////*/
private boolean isSubscriptionsPageOnlySelected() {
return PreferenceManager.getDefaultSharedPreferences(activity)
.getString(getString(R.string.main_page_content_key), getString(R.string.blank_page_key))
.equals(getString(R.string.subscription_page_key));
}
private Fragment getMainPageFragment() {
try {
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(getActivity());
final String setMainPage = preferences.getString(getString(R.string.main_page_content_key),
getString(R.string.main_page_selectd_kiosk_id));
if(setMainPage.equals(getString(R.string.blank_page_key))) {
getString(R.string.main_page_selectd_kiosk_id));
if (setMainPage.equals(getString(R.string.blank_page_key))) {
return new BlankFragment();
} else if(setMainPage.equals(getString(R.string.kiosk_page_key))) {
} else if (setMainPage.equals(getString(R.string.kiosk_page_key))) {
int serviceId = preferences.getInt(getString(R.string.main_page_selected_service),
FALLBACK_SERVICE_ID);
String kioskId = preferences.getString(getString(R.string.main_page_selectd_kiosk_id),
FALLBACK_KIOSK_ID);
KioskFragment fragment = KioskFragment.getInstance(serviceId, kioskId
);
KioskFragment fragment = KioskFragment.getInstance(serviceId, kioskId);
fragment.useAsFrontPage(true);
return fragment;
} else if(setMainPage.equals(getString(R.string.feed_page_key))) {
} else if (setMainPage.equals(getString(R.string.feed_page_key))) {
FeedFragment fragment = new FeedFragment();
fragment.useAsFrontPage(true);
return fragment;
} else if(setMainPage.equals(getString(R.string.channel_page_key))) {
} else if (setMainPage.equals(getString(R.string.channel_page_key))) {
int serviceId = preferences.getInt(getString(R.string.main_page_selected_service),
FALLBACK_SERVICE_ID);
String url = preferences.getString(getString(R.string.main_page_selected_channel_url),
@@ -266,7 +239,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
StreamingService service = NewPipe.getService(currentServiceId);
KioskList kl = service.getKioskList();
int i = 0;
for(final String ks : kl.getAvailableKiosks()) {
for (final String ks : kl.getAvailableKiosks()) {
menu.add(0, KIOSK_MENU_OFFSET + i, Menu.NONE,
KioskTranslator.getTranslatedKioskName(ks, getContext()))
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {

View File

@@ -13,7 +13,6 @@ import android.support.annotation.DrawableRes;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.text.TextUtilsCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
@@ -25,7 +24,6 @@ import android.text.util.Linkify;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -37,7 +35,6 @@ import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
@@ -51,7 +48,6 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.download.DownloadDialog;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
@@ -80,6 +76,7 @@ import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable;
import java.util.ArrayList;
@@ -342,7 +339,11 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
}
break;
case R.id.detail_thumbnail_root_layout:
openVideoPlayer();
if (currentInfo.video_streams.isEmpty() && currentInfo.video_only_streams.isEmpty()) {
openBackgroundPlayer(false);
} else {
openVideoPlayer();
}
break;
case R.id.detail_title_root_layout:
toggleTitleAndDescription();
@@ -390,7 +391,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
if (relatedStreamsView.getChildCount() > initialCount) {
relatedStreamsView.removeViews(initialCount, relatedStreamsView.getChildCount() - (initialCount));
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(activity, resolveResourceIdFromAttr(R.attr.expand)));
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
return;
}
@@ -400,7 +401,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
//Log.d(TAG, "i = " + i);
relatedStreamsView.addView(infoItemBuilder.buildView(relatedStreamsView, item));
}
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(activity, resolveResourceIdFromAttr(R.attr.collapse)));
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse)));
}
/*//////////////////////////////////////////////////////////////////////////
@@ -505,7 +506,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
NavigationHelper.enqueueOnPopupPlayer(getActivity(), new SinglePlayQueue(item));
break;
default:
break;
@@ -575,7 +576,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
relatedStreamRootLayout.setVisibility(View.VISIBLE);
relatedStreamExpandButton.setVisibility(View.VISIBLE);
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(activity, resolveResourceIdFromAttr(R.attr.expand)));
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
} else {
if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE);
relatedStreamExpandButton.setVisibility(View.GONE);
@@ -623,24 +624,12 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
if (DEBUG) Log.d(TAG, "setupActionBarHandler() called with: info = [" + info + "]");
sortedStreamVideosList = new ArrayList<>(ListHelper.getSortedStreamVideosList(activity, info.getVideoStreams(), info.getVideoOnlyStreams(), false));
actionBarHandler.setupStreamList(sortedStreamVideosList, spinnerToolbar);
actionBarHandler.setOnShareListener(new ActionBarHandler.OnActionListener() {
@Override
public void onActionSelected(int selectedStreamId) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, info.getUrl());
intent.setType("text/plain");
startActivity(Intent.createChooser(intent, activity.getString(R.string.share_dialog_title)));
}
});
actionBarHandler.setOnShareListener(selectedStreamId -> shareUrl(info.name, info.url));
actionBarHandler.setOnOpenInBrowserListener(new ActionBarHandler.OnActionListener() {
@Override
public void onActionSelected(int selectedStreamId) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(info.getUrl()));
startActivity(Intent.createChooser(intent, activity.getString(R.string.choose_browser)));
openUrlInBrowser(info.getUrl());
}
});
@@ -815,16 +804,13 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
if (!useExternalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 16) {
openNormalBackgroundPlayer(append);
} else {
openExternalBackgroundPlayer(audioStream);
NavigationHelper.playOnExternalPlayer(activity, currentInfo.getName(), currentInfo.getUploaderName(), audioStream);
}
}
private void openPopupPlayer(final boolean append) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
if (!PermissionHelper.isPopupEnabled(activity)) {
PermissionHelper.showPopupEnablementToast(activity);
return;
}
@@ -852,13 +838,12 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
}
if (PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(this.getString(R.string.use_external_video_player_key), false)) {
openExternalVideoPlayer(selectedVideoStream);
NavigationHelper.playOnExternalPlayer(activity, currentInfo.getName(), currentInfo.getUploaderName(), selectedVideoStream);
} else {
openNormalPlayer(selectedVideoStream);
}
}
private void openNormalBackgroundPlayer(final boolean append) {
final PlayQueue itemQueue = new SinglePlayQueue(currentInfo);
if (append) {
@@ -868,40 +853,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
}
}
private void openExternalBackgroundPlayer(AudioStream audioStream) {
Intent intent;
intent = new Intent();
try {
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(audioStream.getUrl()), audioStream.getFormat().getMimeType());
intent.putExtra(Intent.EXTRA_TITLE, currentInfo.getName());
intent.putExtra("title", currentInfo.getName());
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(R.string.no_player_found)
.setPositiveButton(R.string.install, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(activity.getString(R.string.fdroid_vlc_url)));
activity.startActivity(intent);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "You unlocked a secret unicorn.");
}
});
builder.create().show();
Log.e(TAG, "Either no Streaming player for audio was installed, or something important crashed:");
e.printStackTrace();
}
}
private void openNormalPlayer(VideoStream selectedVideoStream) {
Intent mIntent;
boolean useOldPlayer = PlayerHelper.isUsingOldPlayer(activity) || (Build.VERSION.SDK_INT < 16);
@@ -920,33 +871,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
startActivity(mIntent);
}
private void openExternalVideoPlayer(VideoStream selectedVideoStream) {
// External Player
Intent intent = new Intent();
try {
intent.setAction(Intent.ACTION_VIEW)
.setDataAndType(Uri.parse(selectedVideoStream.getUrl()), selectedVideoStream.getFormat().getMimeType())
.putExtra(Intent.EXTRA_TITLE, currentInfo.getName())
.putExtra("title", currentInfo.getName());
this.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(R.string.no_player_found)
.setPositiveButton(R.string.install, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent()
.setAction(Intent.ACTION_VIEW)
.setData(Uri.parse(getString(R.string.fdroid_vlc_url)));
startActivity(intent);
}
})
.setNegativeButton(R.string.cancel, null);
builder.create().show();
}
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@@ -1173,6 +1097,13 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
showSnackBarError(info.getErrors(), UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(info.getServiceId()), info.getUrl(), 0);
}
if (info.video_streams.isEmpty() && info.video_only_streams.isEmpty()) {
detailControlsBackground.setVisibility(View.GONE);
detailControlsPopup.setVisibility(View.GONE);
spinnerToolbar.setVisibility(View.GONE);
thumbnailPlayButton.setImageResource(R.drawable.ic_headset_white_24dp);
}
if (autoPlayEnabled) {
openVideoPlayer();
// Only auto play in the first open

View File

@@ -1,16 +1,21 @@
package org.schabi.newpipe.fragments.list;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem;
@@ -24,6 +29,7 @@ import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.StateSaver;
import java.util.List;
@@ -192,6 +198,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{
@@ -207,7 +214,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break;
default:
break;

View File

@@ -84,17 +84,6 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
currentNextItemsUrl = (String) savedObjects.poll();
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
public void setTitle(String title) {
Log.d(TAG, "setTitle() called with: title = [" + title + "]");
if (activity.getSupportActionBar() != null) {
activity.getSupportActionBar().setTitle(title);
}
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@@ -124,20 +113,12 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
currentWorker = loadResult(forceLoad)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<I>() {
@Override
public void accept(@NonNull I result) throws Exception {
isLoading.set(false);
currentInfo = result;
currentNextItemsUrl = result.next_streams_url;
handleResult(result);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
onError(throwable);
}
});
.subscribe((@NonNull I result) -> {
isLoading.set(false);
currentInfo = result;
currentNextItemsUrl = result.next_streams_url;
handleResult(result);
}, (@NonNull Throwable throwable) -> onError(throwable));
}
/**
@@ -153,18 +134,12 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
currentWorker = loadMoreItemsLogic()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ListExtractor.NextItemsResult>() {
@Override
public void accept(@io.reactivex.annotations.NonNull ListExtractor.NextItemsResult nextItemsResult) throws Exception {
isLoading.set(false);
handleNextItems(nextItemsResult);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
isLoading.set(false);
onError(throwable);
}
.subscribe((@io.reactivex.annotations.NonNull ListExtractor.NextItemsResult nextItemsResult) -> {
isLoading.set(false);
handleNextItems(nextItemsResult);
}, (@io.reactivex.annotations.NonNull Throwable throwable) -> {
isLoading.set(false);
onError(throwable);
});
}

View File

@@ -1,10 +1,10 @@
package org.schabi.newpipe.fragments.list.channel;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -12,7 +12,6 @@ import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -23,7 +22,6 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.jakewharton.rxbinding2.view.RxView;
@@ -45,7 +43,6 @@ import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -104,11 +101,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
if(activity != null
&& useAsFrontPage
&& isVisibleToUser) {
try {
activity.getSupportActionBar().setTitle(currentInfo.getName());
} catch (Exception e) {
onError(e);
}
setTitle(currentInfo != null ? currentInfo.getName() : name);
}
}
@@ -153,6 +146,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
@Override
protected void showStreamDialog(final StreamInfoItem item) {
final Activity activity = getActivity();
final Context context = getContext();
if (context == null || context.getResources() == null || getActivity() == null) return;
@@ -173,7 +167,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break;
case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
@@ -182,7 +176,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break;
case 4:
NavigationHelper.playOnPopupPlayer(context, getPlayQueue(index));
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
break;
default:
break;
@@ -222,18 +216,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
}
}
private void openChannelUriInBrowser() {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
}
private void shareChannelUri() {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title)));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@@ -241,10 +223,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
openRssFeed();
break;
case R.id.menu_item_openInBrowser:
openChannelUriInBrowser();
openUrlInBrowser(url);
break;
case R.id.menu_item_share: {
shareChannelUri();
shareUrl(name, url);
break;
}
default:
@@ -466,13 +448,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
headerPopupButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
return;
}
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue());
}
});

View File

@@ -5,6 +5,7 @@ import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -56,15 +57,12 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
@State
protected String kioskId = "";
protected String kioskTranslatedName;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private View headerRootLayout;
private TextView headerTitleView;
public static KioskFragment getInstance(int serviceId)
throws ExtractionException {
return getInstance(serviceId, NewPipe.getService(serviceId)
@@ -90,16 +88,11 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onActivityCreated(Bundle savedState) {
super.onActivityCreated(savedState);
try {
activity.getSupportActionBar()
.setTitle(KioskTranslator.getTranslatedKioskName(kioskId, getActivity()));
} catch (Exception e) {
onUnrecoverableError(e, UserAction.UI_ERROR,
"none",
"none", R.string.app_ui_crash);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
kioskTranslatedName = KioskTranslator.getTranslatedKioskName(kioskId, activity);
name = kioskTranslatedName;
}
@Override
@@ -107,8 +100,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
super.setUserVisibleHint(isVisibleToUser);
if(useAsFrontPage && isVisibleToUser && activity != null) {
try {
activity.getSupportActionBar()
.setTitle(KioskTranslator.getTranslatedKioskName(kioskId, getActivity()));
setTitle(kioskTranslatedName);
} catch (Exception e) {
onUnrecoverableError(e, UserAction.UI_ERROR,
"none",
@@ -118,11 +110,8 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_kiosk, container, false);
activity.getSupportActionBar()
.setTitle(KioskTranslator.getTranslatedKioskName(kioskId, getActivity()));
return view;
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_kiosk, container, false);
}
/*//////////////////////////////////////////////////////////////////////////
@@ -146,14 +135,18 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
public Single<KioskInfo> loadResult(boolean forceReload) {
String contentCountry = PreferenceManager
.getDefaultSharedPreferences(activity)
.getString(getString(R.string.search_language_key),
getString(R.string.default_language_value));
.getString(getString(R.string.content_country_key),
getString(R.string.default_country_value));
return ExtractorHelper.getKioskInfo(serviceId, url, contentCountry, forceReload);
}
@Override
public Single<ListExtractor.NextItemsResult> loadMoreItemsLogic() {
return ExtractorHelper.getMoreKioskItems(serviceId, url, currentNextItemsUrl);
String contentCountry = PreferenceManager
.getDefaultSharedPreferences(activity)
.getString(getString(R.string.content_country_key),
getString(R.string.default_country_value));
return ExtractorHelper.getMoreKioskItems(serviceId, url, currentNextItemsUrl, contentCountry);
}
/*//////////////////////////////////////////////////////////////////////////
@@ -170,9 +163,8 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
public void handleResult(@NonNull final KioskInfo result) {
super.handleResult(result);
String title = KioskTranslator.getTranslatedKioskName(result.id, getActivity());
ActionBar supportActionBar = activity.getSupportActionBar();
supportActionBar.setTitle(title);
name = kioskTranslatedName;
setTitle(kioskTranslatedName);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(),

View File

@@ -1,22 +1,21 @@
package org.schabi.newpipe.fragments.list.playlist;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.ListExtractor;
@@ -32,7 +31,6 @@ import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import io.reactivex.Single;
@@ -98,16 +96,10 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
infoListAdapter.useMiniItemVariants(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_playlist, menu);
}
@Override
protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext();
final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{
@@ -127,7 +119,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break;
case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item));
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break;
case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
@@ -136,7 +128,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break;
case 4:
NavigationHelper.playOnPopupPlayer(context, getPlayQueue(index));
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
break;
default:
break;
@@ -146,6 +138,14 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
new InfoItemDialog(getActivity(), item, commands, actions).show();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_playlist, menu);
}
/*//////////////////////////////////////////////////////////////////////////
// Load and handle
//////////////////////////////////////////////////////////////////////////*/
@@ -160,6 +160,23 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
return ExtractorHelper.getPlaylistInfo(serviceId, url, forceLoad);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_openInBrowser:
openUrlInBrowser(url);
break;
case R.id.menu_item_share: {
shareUrl(name, url);
break;
}
default:
return super.onOptionsItemSelected(item);
}
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@@ -211,13 +228,6 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
headerPopupButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
return;
}
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue());
}
});

View File

@@ -111,7 +111,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
private int currentPage = 0;
private int currentNextPage = 0;
private String searchLanguage;
private String contentCountry;
private boolean isSuggestionsEnabled = true;
private boolean isSearchHistoryEnabled = true;
@@ -176,7 +176,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
isSuggestionsEnabled = preferences.getBoolean(getString(R.string.show_search_suggestions_key), true);
searchLanguage = preferences.getString(getString(R.string.search_language_key), getString(R.string.default_language_value));
contentCountry = preferences.getString(getString(R.string.content_country_key), getString(R.string.default_country_value));
}
@Override
@@ -619,7 +619,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
return local.materialize();
}
final Observable<List<SuggestionItem>> network = ExtractorHelper.suggestionsFor(serviceId, query, searchLanguage).toObservable()
final Observable<List<SuggestionItem>> network = ExtractorHelper.suggestionsFor(serviceId, query, contentCountry).toObservable()
.map(new Function<List<String>, List<SuggestionItem>>() {
@Override
public List<SuggestionItem> apply(@io.reactivex.annotations.NonNull List<String> strings) throws Exception {
@@ -731,7 +731,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
super.startLoading(forceLoad);
if (disposables != null) disposables.clear();
if (searchDisposable != null) searchDisposable.dispose();
searchDisposable = ExtractorHelper.searchFor(serviceId, searchQuery, currentPage, searchLanguage, filter)
searchDisposable = ExtractorHelper.searchFor(serviceId, searchQuery, currentPage, contentCountry, filter)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<SearchResult>() {
@@ -755,7 +755,7 @@ public class SearchFragment extends BaseListFragment<SearchResult, ListExtractor
showListFooter(true);
if (searchDisposable != null) searchDisposable.dispose();
currentNextPage = currentPage + 1;
searchDisposable = ExtractorHelper.getMoreSearchItems(serviceId, searchQuery, currentNextPage, searchLanguage, filter)
searchDisposable = ExtractorHelper.getMoreSearchItems(serviceId, searchQuery, currentNextPage, contentCountry, filter)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ListExtractor.NextItemsResult>() {

View File

@@ -65,7 +65,6 @@ public final class BackgroundPlayer extends Service {
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.BackgroundPlayer.CLOSE";
public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.BackgroundPlayer.PLAY_PAUSE";
public static final String ACTION_OPEN_CONTROLS = "org.schabi.newpipe.player.BackgroundPlayer.OPEN_CONTROLS";
public static final String ACTION_REPEAT = "org.schabi.newpipe.player.BackgroundPlayer.REPEAT";
public static final String ACTION_PLAY_NEXT = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_NEXT";
public static final String ACTION_PLAY_PREVIOUS = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_PREVIOUS";
@@ -195,11 +194,14 @@ public final class BackgroundPlayer extends Service {
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationStop,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_CONTROLS), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
// Starts background player activity -- attempts to unlock lockscreen
final Intent intent = NavigationHelper.getBackgroundPlayerActivityIntent(this);
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getActivity(this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT));
if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_previous);
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_next);
@@ -393,7 +395,7 @@ public final class BackgroundPlayer extends Service {
if (index < 0 || index >= info.audio_streams.size()) return null;
final AudioStream audio = info.audio_streams.get(index);
return buildMediaSource(audio.getUrl(), MediaFormat.getSuffixById(audio.format));
return buildMediaSource(audio.getUrl(), MediaFormat.getSuffixById(audio.getFormatId()));
}
@Override
@@ -453,7 +455,6 @@ public final class BackgroundPlayer extends Service {
super.setupBroadcastReceiver(intentFilter);
intentFilter.addAction(ACTION_CLOSE);
intentFilter.addAction(ACTION_PLAY_PAUSE);
intentFilter.addAction(ACTION_OPEN_CONTROLS);
intentFilter.addAction(ACTION_REPEAT);
intentFilter.addAction(ACTION_PLAY_PREVIOUS);
intentFilter.addAction(ACTION_PLAY_NEXT);
@@ -478,9 +479,6 @@ public final class BackgroundPlayer extends Service {
case ACTION_PLAY_PAUSE:
onVideoPlayPause();
break;
case ACTION_OPEN_CONTROLS:
NavigationHelper.openBackgroundPlayerControl(getApplicationContext());
break;
case ACTION_REPEAT:
onRepeatClicked();
break;

View File

@@ -1,8 +1,12 @@
package org.schabi.newpipe.player;
import android.content.Intent;
import android.view.MenuItem;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.PermissionHelper;
import static org.schabi.newpipe.player.BackgroundPlayer.ACTION_CLOSE;
public final class BackgroundPlayerActivity extends ServicePlayerActivity {
@@ -36,4 +40,31 @@ public final class BackgroundPlayerActivity extends ServicePlayerActivity {
((BackgroundPlayer.BasePlayerImpl) player).removeActivityListener(this);
}
}
@Override
public int getPlayerOptionMenuResource() {
return R.menu.menu_play_queue_bg;
}
@Override
public boolean onPlayerOptionSelected(MenuItem item) {
if (item.getItemId() == R.id.action_switch_popup) {
if (!PermissionHelper.isPopupEnabled(this)) {
PermissionHelper.showPopupEnablementToast(this);
return true;
}
this.player.setRecovery();
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
getApplicationContext().startService(getSwitchIntent(PopupVideoPlayer.class));
return true;
}
return false;
}
@Override
public Intent getPlayerShutdownIntent() {
return new Intent(ACTION_CLOSE);
}
}

View File

@@ -111,6 +111,7 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
public static final String PLAYBACK_QUALITY = "playback_quality";
public static final String PLAY_QUEUE = "play_queue";
public static final String APPEND_ONLY = "append_only";
public static final String SELECT_ON_APPEND = "select_on_append";
/*//////////////////////////////////////////////////////////////////////////
// Playback
@@ -218,7 +219,13 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
// Resolve append intents
if (intent.getBooleanExtra(APPEND_ONLY, false) && playQueue != null) {
int sizeBeforeAppend = playQueue.size();
playQueue.append(queue.getStreams());
if (intent.getBooleanExtra(SELECT_ON_APPEND, false) && queue.getStreams().size() > 0) {
playQueue.setIndex(sizeBeforeAppend);
}
return;
}

View File

@@ -37,7 +37,6 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
@@ -62,10 +61,9 @@ import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.PopupMenuIconHacker;
import org.schabi.newpipe.util.ThemeHelper;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
@@ -78,6 +76,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public final class MainVideoPlayer extends Activity {
private static final String TAG = ".MainVideoPlayer";
private static final boolean DEBUG = BasePlayer.DEBUG;
private static final String PLAYER_STATE_INTENT = "player_state_intent";
private GestureDetector gestureDetector;
@@ -99,19 +98,41 @@ public final class MainVideoPlayer extends Activity {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) getWindow().setStatusBarColor(Color.BLACK);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
if (getIntent() == null) {
final Intent intent;
if (savedInstanceState != null && savedInstanceState.getParcelable(PLAYER_STATE_INTENT) != null) {
intent = savedInstanceState.getParcelable(PLAYER_STATE_INTENT);
} else {
intent = getIntent();
}
if (intent == null) {
Toast.makeText(this, R.string.general_error, Toast.LENGTH_SHORT).show();
finish();
return;
}
showSystemUi();
setContentView(R.layout.activity_main_player);
playerImpl = new VideoPlayerImpl(this);
playerImpl.setup(findViewById(android.R.id.content));
playerImpl.handleIntent(getIntent());
playerImpl.handleIntent(intent);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (this.playerImpl == null) return;
final Intent intent = NavigationHelper.getPlayerIntent(
getApplicationContext(),
this.getClass(),
this.playerImpl.getPlayQueue(),
this.playerImpl.getRepeatMode(),
this.playerImpl.getPlaybackSpeed(),
this.playerImpl.getPlaybackPitch(),
this.playerImpl.getPlaybackQuality()
);
outState.putParcelable(PLAYER_STATE_INTENT, intent);
}
@Override
@@ -303,7 +324,7 @@ public final class MainVideoPlayer extends Activity {
this.playNextButton = rootView.findViewById(R.id.playNextButton);
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
this.moreOptionsPopupMenu = new PopupMenu(context, moreOptionsButton);
this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions, moreOptionsPopupMenu.getMenu());
buildMoreOptionsMenu();
titleTextView.setSelected(true);
channelTextView.setSelected(true);
@@ -356,7 +377,7 @@ public final class MainVideoPlayer extends Activity {
titleTextView.setText(getVideoTitle());
channelTextView.setText(getUploaderName());
playPauseButton.setImageResource(R.drawable.ic_pause_white);
//playPauseButton.setImageResource(R.drawable.ic_pause_white);
}
@Override
@@ -376,9 +397,8 @@ public final class MainVideoPlayer extends Activity {
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
if (simpleExoPlayer == null) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& !PermissionHelper.checkSystemAlertWindowPermission(MainVideoPlayer.this)) {
Toast.makeText(MainVideoPlayer.this, R.string.msg_popup_permission, Toast.LENGTH_LONG).show();
if (!PermissionHelper.isPopupEnabled(context)) {
PermissionHelper.showPopupEnablementToast(context);
return;
}
@@ -448,12 +468,9 @@ public final class MainVideoPlayer extends Activity {
if (getCurrentState() != STATE_COMPLETED) {
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
animateView(getControlsRoot(), true, 300, 0, new Runnable() {
@Override
public void run() {
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
}
animateView(getControlsRoot(), true, 300, 0, () -> {
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
}
});
}
@@ -479,25 +496,7 @@ public final class MainVideoPlayer extends Activity {
private void onMoreOptionsClicked() {
if (DEBUG) Log.d(TAG, "onMoreOptionsClicked() called");
buildMoreOptionsMenu();
try {
Field[] fields = moreOptionsPopupMenu.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(moreOptionsPopupMenu);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
moreOptionsPopupMenu.show();
isSomePopupMenuVisible = true;
showControls(300);
@@ -506,6 +505,7 @@ public final class MainVideoPlayer extends Activity {
private void onScreenRotationClicked() {
if (DEBUG) Log.d(TAG, "onScreenRotationClicked() called");
toggleOrientation();
showControlsThenHide();
}
@Override
@@ -561,12 +561,9 @@ public final class MainVideoPlayer extends Activity {
@Override
public void onPlaying() {
super.onPlaying();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, new Runnable() {
@Override
public void run() {
playPauseButton.setImageResource(R.drawable.ic_pause_white);
animatePlayButtons(true, 200);
}
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
playPauseButton.setImageResource(R.drawable.ic_pause_white);
animatePlayButtons(true, 200);
});
showSystemUi();
getRootView().setKeepScreenOn(true);
@@ -575,12 +572,9 @@ public final class MainVideoPlayer extends Activity {
@Override
public void onPaused() {
super.onPaused();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, new Runnable() {
@Override
public void run() {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
animatePlayButtons(true, 200);
}
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
animatePlayButtons(true, 200);
});
showSystemUi();
@@ -598,12 +592,9 @@ public final class MainVideoPlayer extends Activity {
@Override
public void onCompleted() {
showSystemUi();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, new Runnable() {
@Override
public void run() {
playPauseButton.setImageResource(R.drawable.ic_replay_white);
animatePlayButtons(true, 300);
}
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> {
playPauseButton.setImageResource(R.drawable.ic_replay_white);
animatePlayButtons(true, 300);
});
getRootView().setKeepScreenOn(false);
@@ -632,17 +623,10 @@ public final class MainVideoPlayer extends Activity {
public void hideControls(final long duration, long delay) {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
getControlsVisibilityHandler().postDelayed(new Runnable() {
@Override
public void run() {
animateView(getControlsRoot(), false, duration, 0, new Runnable() {
@Override
public void run() {
hideSystemUi();
}
});
}
}, delay);
getControlsVisibilityHandler().postDelayed(() ->
animateView(getControlsRoot(), false, duration, 0, MainVideoPlayer.this::hideSystemUi),
delay
);
}
private void updatePlaybackButtons() {
@@ -654,24 +638,39 @@ public final class MainVideoPlayer extends Activity {
}
private void buildMoreOptionsMenu() {
if (moreOptionsPopupMenu == null) return;
moreOptionsPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.toggleOrientation:
onScreenRotationClicked();
break;
case R.id.switchPopup:
onFullScreenButtonClicked();
break;
case R.id.switchBackground:
onPlayBackgroundButtonClicked();
break;
}
return false;
this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions,
moreOptionsPopupMenu.getMenu());
moreOptionsPopupMenu.setOnMenuItemClickListener(menuItem -> {
switch (menuItem.getItemId()) {
case R.id.toggleOrientation:
onScreenRotationClicked();
break;
case R.id.switchPopup:
onFullScreenButtonClicked();
break;
case R.id.switchBackground:
onPlayBackgroundButtonClicked();
break;
}
return false;
});
try {
PopupMenuIconHacker.setShowPopupIcon(moreOptionsPopupMenu);
} catch (Exception e) {
e.printStackTrace();
}
// fix icon theme
if(ThemeHelper.isLightThemeSelected(MainVideoPlayer.this)) {
moreOptionsPopupMenu.getMenu()
.findItem(R.id.toggleOrientation)
.setIcon(R.drawable.ic_screen_rotation_black_24dp);
moreOptionsPopupMenu.getMenu()
.findItem(R.id.switchPopup)
.setIcon(R.drawable.ic_fullscreen_exit_black_24dp);
}
}
private void buildQueue() {
@@ -692,12 +691,7 @@ public final class MainVideoPlayer extends Activity {
playQueueAdapter.setSelectedListener(getOnSelectedListener());
itemsListCloseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onQueueClosed();
}
});
itemsListCloseButton.setOnClickListener(view -> onQueueClosed());
}
private OnScrollBelowItemsListener getQueueScrollListener() {

View File

@@ -31,7 +31,6 @@ import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
@@ -49,44 +48,25 @@ import android.widget.PopupMenu;
import android.widget.RemoteViews;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.playlist.PlayQueueItem;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.IOException;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.player.helper.PlayerHelper.isUsingOldPlayer;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
@@ -102,7 +82,6 @@ public final class PopupVideoPlayer extends Service {
private static final int NOTIFICATION_ID = 40028922;
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE";
public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.PopupVideoPlayer.PLAY_PAUSE";
public static final String ACTION_OPEN_CONTROLS = "org.schabi.newpipe.player.PopupVideoPlayer.OPEN_CONTROLS";
public static final String ACTION_REPEAT = "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT";
private static final String POPUP_SAVED_WIDTH = "popup_saved_width";
@@ -127,8 +106,8 @@ public final class PopupVideoPlayer extends Service {
private RemoteViews notRemoteView;
private VideoPlayerImpl playerImpl;
private Disposable currentWorker;
private LockManager lockManager;
/*//////////////////////////////////////////////////////////////////////////
// Service-Activity Binder
//////////////////////////////////////////////////////////////////////////*/
@@ -159,31 +138,8 @@ public final class PopupVideoPlayer extends Service {
if (playerImpl.getPlayer() == null) initPopup();
if (!playerImpl.isPlaying()) playerImpl.getPlayer().setPlayWhenReady(true);
if (intent != null && intent.getStringExtra(Constants.KEY_URL) != null) {
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
final String url = intent.getStringExtra(Constants.KEY_URL);
playerImpl.handleIntent(intent);
playerImpl.setStartedFromNewPipe(false);
final FetcherHandler fetcherRunnable = new FetcherHandler(this, serviceId, url);
currentWorker = ExtractorHelper.getStreamInfo(serviceId,url,false)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<StreamInfo>() {
@Override
public void accept(@NonNull StreamInfo info) throws Exception {
fetcherRunnable.onReceive(info);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
fetcherRunnable.onError(throwable);
}
});
} else {
playerImpl.setStartedFromNewPipe(true);
playerImpl.handleIntent(intent);
}
return START_NOT_STICKY;
}
@@ -267,11 +223,14 @@ public final class PopupVideoPlayer extends Service {
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
notRemoteView.setOnClickPendingIntent(R.id.notificationStop,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_CONTROLS), PendingIntent.FLAG_UPDATE_CURRENT));
notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
// Starts popup player activity -- attempts to unlock lockscreen
final Intent intent = NavigationHelper.getPopupPlayerActivityIntent(this);
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getActivity(this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT));
setRepeatModeRemote(notRemoteView, playerImpl.getRepeatMode());
return new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
@@ -311,7 +270,6 @@ public final class PopupVideoPlayer extends Service {
}
if (lockManager != null) lockManager.releaseWifiAndCpu();
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
if (currentWorker != null) currentWorker.dispose();
mBinder = null;
playerImpl = null;
@@ -421,12 +379,7 @@ public final class PopupVideoPlayer extends Service {
super.initViews(rootView);
resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
fullScreenButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onFullScreenButtonClicked();
}
});
fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked());
}
@Override
@@ -466,7 +419,6 @@ public final class PopupVideoPlayer extends Service {
this.getPlaybackPitch(),
this.getPlaybackQuality()
);
if (!isStartedFromNewPipe()) intent.putExtra(VideoPlayer.STARTED_FROM_NEWPIPE, false);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} else {
intent = new Intent(PopupVideoPlayer.this, PlayVideoActivity.class)
@@ -604,7 +556,6 @@ public final class PopupVideoPlayer extends Service {
if (DEBUG) Log.d(TAG, "setupBroadcastReceiver() called with: intentFilter = [" + intentFilter + "]");
intentFilter.addAction(ACTION_CLOSE);
intentFilter.addAction(ACTION_PLAY_PAUSE);
intentFilter.addAction(ACTION_OPEN_CONTROLS);
intentFilter.addAction(ACTION_REPEAT);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
@@ -623,9 +574,6 @@ public final class PopupVideoPlayer extends Service {
case ACTION_PLAY_PAUSE:
onVideoPlayPause();
break;
case ACTION_OPEN_CONTROLS:
NavigationHelper.openPopupPlayerControl(getApplicationContext());
break;
case ACTION_REPEAT:
onRepeatClicked();
break;
@@ -880,69 +828,4 @@ public final class PopupVideoPlayer extends Service {
return true;
}
}
/**
* Fetcher handler used if open by a link out of NewPipe
*/
private class FetcherHandler {
private final int serviceId;
private final String url;
private final Context context;
private final Handler mainHandler;
private FetcherHandler(Context context, int serviceId, String url) {
this.mainHandler = new Handler(PopupVideoPlayer.this.getMainLooper());
this.context = context;
this.url = url;
this.serviceId = serviceId;
}
private void onReceive(final StreamInfo info) {
mainHandler.post(new Runnable() {
@Override
public void run() {
final Intent intent = NavigationHelper.getPlayerIntent(getApplicationContext(),
PopupVideoPlayer.class, new SinglePlayQueue(info));
playerImpl.handleIntent(intent);
}
});
}
private void onError(final Throwable exception) {
if (DEBUG) Log.d(TAG, "onError() called with: exception = [" + exception + "]");
exception.printStackTrace();
mainHandler.post(new Runnable() {
@Override
public void run() {
if (exception instanceof ReCaptchaException) {
onReCaptchaException();
} else if (exception instanceof IOException) {
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.GemaException) {
Toast.makeText(context, R.string.blocked_by_gema, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.LiveStreamException) {
Toast.makeText(context, R.string.live_streams_not_supported, Toast.LENGTH_LONG).show();
} else if (exception instanceof ContentNotAvailableException) {
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
} else {
int errorId = exception instanceof YoutubeStreamExtractor.DecryptException ? R.string.youtube_signature_decryption_error :
exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
ErrorActivity.reportError(mainHandler, context, exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(serviceId), url, errorId));
}
}
});
stopSelf();
}
private void onReCaptchaException() {
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
// Starting ReCaptcha Challenge Activity
Intent intent = new Intent(context, ReCaptchaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
stopSelf();
}
}
}

View File

@@ -1,9 +1,12 @@
package org.schabi.newpipe.player;
import android.content.Intent;
import android.view.MenuItem;
import org.schabi.newpipe.R;
import static org.schabi.newpipe.player.PopupVideoPlayer.ACTION_CLOSE;
public final class PopupVideoPlayerActivity extends ServicePlayerActivity {
private static final String TAG = "PopupVideoPlayerActivity";
@@ -36,4 +39,25 @@ public final class PopupVideoPlayerActivity extends ServicePlayerActivity {
((PopupVideoPlayer.VideoPlayerImpl) player).removeActivityListener(this);
}
}
@Override
public int getPlayerOptionMenuResource() {
return R.menu.menu_play_queue_popup;
}
@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 false;
}
@Override
public Intent getPlayerShutdownIntent() {
return new Intent(ACTION_CLOSE);
}
}

View File

@@ -100,6 +100,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
public abstract void stopPlayerListener();
public abstract int getPlayerOptionMenuResource();
public abstract boolean onPlayerOptionSelected(MenuItem item);
public abstract Intent getPlayerShutdownIntent();
////////////////////////////////////////////////////////////////////////////
// Activity Lifecycle
////////////////////////////////////////////////////////////////////////////
@@ -134,6 +139,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_play_queue, menu);
getMenuInflater().inflate(getPlayerOptionMenuResource(), menu);
return true;
}
@@ -153,8 +159,13 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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 super.onOptionsItemSelected(item);
return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
}
@Override
@@ -163,6 +174,17 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
unbind();
}
protected Intent getSwitchIntent(final Class clazz) {
return NavigationHelper.getPlayerIntent(
getApplicationContext(),
clazz,
this.player.getPlayQueue(),
this.player.getRepeatMode(),
this.player.getPlaybackSpeed(),
this.player.getPlaybackPitch(),
null
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
////////////////////////////////////////////////////////////////////////////
// Service Connection
////////////////////////////////////////////////////////////////////////////
@@ -288,14 +310,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
final float playbackSpeed = BasePlayer.PLAYBACK_SPEEDS[i];
final String formattedSpeed = formatSpeed(playbackSpeed);
final MenuItem item = playbackSpeedPopupMenu.getMenu().add(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedSpeed);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
item.setOnMenuItemClickListener(menuItem -> {
if (player == null) return false;
player.setPlaybackSpeed(playbackSpeed);
return true;
}
player.setPlaybackSpeed(playbackSpeed);
return true;
});
}
}
@@ -308,14 +327,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
final float playbackPitch = BasePlayer.PLAYBACK_PITCHES[i];
final String formattedPitch = formatPitch(playbackPitch);
final MenuItem item = playbackPitchPopupMenu.getMenu().add(PLAYBACK_PITCH_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedPitch);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
item.setOnMenuItemClickListener(menuItem -> {
if (player == null) return false;
player.setPlaybackPitch(playbackPitch);
return true;
}
player.setPlaybackPitch(playbackPitch);
return true;
});
}
}
@@ -323,24 +339,18 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
private void buildItemPopupMenu(final PlayQueueItem item, final View view) {
final PopupMenu menu = new PopupMenu(this, view);
final MenuItem remove = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 0, Menu.NONE, R.string.play_queue_remove);
remove.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
remove.setOnMenuItemClickListener(menuItem -> {
if (player == null) return false;
final int index = player.getPlayQueue().indexOf(item);
if (index != -1) player.getPlayQueue().remove(index);
return true;
}
final int index = player.getPlayQueue().indexOf(item);
if (index != -1) player.getPlayQueue().remove(index);
return true;
});
final MenuItem detail = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 1, Menu.NONE, R.string.play_queue_stream_detail);
detail.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
onOpenDetail(item.getServiceId(), item.getUrl(), item.getTitle());
return true;
}
detail.setOnMenuItemClickListener(menuItem -> {
onOpenDetail(item.getServiceId(), item.getUrl(), item.getTitle());
return true;
});
menu.show();

View File

@@ -39,7 +39,6 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.ProgressBar;
@@ -85,12 +84,6 @@ public abstract class VideoPlayer extends BasePlayer
public static final boolean DEBUG = BasePlayer.DEBUG;
public final String TAG;
/*//////////////////////////////////////////////////////////////////////////
// Intent
//////////////////////////////////////////////////////////////////////////*/
public static final String STARTED_FROM_NEWPIPE = "started_from_newpipe";
/*//////////////////////////////////////////////////////////////////////////
// Player
//////////////////////////////////////////////////////////////////////////*/
@@ -102,7 +95,6 @@ public abstract class VideoPlayer extends BasePlayer
protected String playbackQuality;
private boolean startedFromNewPipe = true;
protected boolean wasPlaying = false;
/*//////////////////////////////////////////////////////////////////////////
@@ -695,14 +687,6 @@ public abstract class VideoPlayer extends BasePlayer
return availableStreams.get(selectedStreamIndex);
}
public boolean isStartedFromNewPipe() {
return startedFromNewPipe;
}
public void setStartedFromNewPipe(boolean startedFromNewPipe) {
this.startedFromNewPipe = startedFromNewPipe;
}
public Handler getControlsVisibilityHandler() {
return controlsVisibilityHandler;
}

View File

@@ -15,6 +15,10 @@ public final class ChannelPlayQueue extends AbstractInfoPlayQueue<ChannelInfo, C
super(item);
}
public ChannelPlayQueue(final ChannelInfo info) {
this(info.getServiceId(), info.getUrl(), info.getNextStreamsUrl(), info.getRelatedStreams(), 0);
}
public ChannelPlayQueue(final int serviceId,
final String url,
final String nextPageUrl,

View File

@@ -15,6 +15,10 @@ public final class PlaylistPlayQueue extends AbstractInfoPlayQueue<PlaylistInfo,
super(item);
}
public PlaylistPlayQueue(final PlaylistInfo info) {
this(info.getServiceId(), info.getUrl(), info.getNextStreamsUrl(), info.getRelatedStreams(), 0);
}
public PlaylistPlayQueue(final int serviceId,
final String url,
final String nextPageUrl,

View File

@@ -44,6 +44,7 @@ import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Vector;
@@ -144,12 +145,7 @@ public class ErrorActivity extends AppCompatActivity {
// async call
public static void reportError(Handler handler, final Context context, final List<Throwable> el,
final Class returnActivity, final View rootView, final ErrorInfo errorInfo) {
handler.post(new Runnable() {
@Override
public void run() {
reportError(context, el, returnActivity, rootView, errorInfo);
}
});
handler.post(() -> reportError(context, el, returnActivity, rootView, errorInfo));
}
public static void reportError(final Context context, final CrashReportData report, final ErrorInfo errorInfo) {
@@ -218,17 +214,13 @@ public class ErrorActivity extends AppCompatActivity {
addGuruMeditaion();
currentTimeStamp = getCurrentTimeStamp();
reportButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
reportButton.setOnClickListener((View v) -> {
Intent i = new Intent(Intent.ACTION_SENDTO);
i.setData(Uri.parse("mailto:" + ERROR_EMAIL_ADDRESS))
.putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT)
.putExtra(Intent.EXTRA_TEXT, buildJson());
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:" + ERROR_EMAIL_ADDRESS))
.putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT)
.putExtra(Intent.EXTRA_TEXT, buildJson());
startActivity(Intent.createChooser(intent, "Send Email"));
}
startActivity(Intent.createChooser(i, "Send Email"));
});
reportButton.setEnabled(false);
@@ -382,7 +374,7 @@ public class ErrorActivity extends AppCompatActivity {
private String getContentLangString() {
return PreferenceManager.getDefaultSharedPreferences(this)
.getString(this.getString(R.string.search_language_key), "none");
.getString(this.getString(R.string.content_country_key), "none");
}
private String getOsString() {

View File

@@ -1,9 +1,14 @@
package org.schabi.newpipe.settings;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import android.widget.Toast;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
@@ -12,91 +17,208 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.FilePickerActivityHelper;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.ZipHelper;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.annotation.Nonnull;
public class ContentSettingsFragment extends BasePreferenceFragment {
private static final int REQUEST_IMPORT_PATH = 8945;
private static final int REQUEST_EXPORT_PATH = 30945;
private String homeDir;
private File databasesDir;
private File newpipe_db;
private File newpipe_db_journal;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
homeDir = getActivity().getApplicationInfo().dataDir;
databasesDir = new File(homeDir + "/databases");
newpipe_db = new File(homeDir + "/databases/newpipe.db");
newpipe_db_journal = new File(homeDir + "/databases/newpipe.db-journal");
addPreferencesFromResource(R.xml.content_settings);
final ListPreference mainPageContentPref = (ListPreference) findPreference(getString(R.string.main_page_content_key));
mainPageContentPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValueO) {
final String newValue = newValueO.toString();
mainPageContentPref.setOnPreferenceChangeListener((Preference preference, Object newValueO) -> {
final String newValue = newValueO.toString();
final String mainPrefOldValue =
defaultPreferences.getString(getString(R.string.main_page_content_key), "blank_page");
final String mainPrefOldSummary = getMainPagePrefSummery(mainPrefOldValue, mainPageContentPref);
final String mainPrefOldValue =
defaultPreferences.getString(getString(R.string.main_page_content_key), "blank_page");
final String mainPrefOldSummary = getMainPagePrefSummery(mainPrefOldValue, mainPageContentPref);
if(newValue.equals(getString(R.string.kiosk_page_key))) {
SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
selectKioskFragment.setOnSelectedLisener(new SelectKioskFragment.OnSelectedLisener() {
@Override
public void onKioskSelected(String kioskId, int service_id) {
defaultPreferences.edit()
.putInt(getString(R.string.main_page_selected_service), service_id).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selectd_kiosk_id), kioskId).apply();
String serviceName = "";
try {
serviceName = NewPipe.getService(service_id).getServiceInfo().name;
} catch (ExtractionException e) {
onError(e);
}
String kioskName = KioskTranslator.getTranslatedKioskName(kioskId,
getContext());
String summary =
String.format(getString(R.string.service_kiosk_string),
serviceName,
kioskName);
mainPageContentPref.setSummary(summary);
}
});
selectKioskFragment.setOnCancelListener(new SelectKioskFragment.OnCancelListener() {
@Override
public void onCancel() {
mainPageContentPref.setSummary(mainPrefOldSummary);
mainPageContentPref.setValue(mainPrefOldValue);
}
});
selectKioskFragment.show(getFragmentManager(), "select_kiosk");
} else if(newValue.equals(getString(R.string.channel_page_key))) {
SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
selectChannelFragment.setOnSelectedLisener(new SelectChannelFragment.OnSelectedLisener() {
@Override
public void onChannelSelected(String url, String name, int service) {
defaultPreferences.edit()
.putInt(getString(R.string.main_page_selected_service), service).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selected_channel_url), url).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selected_channel_name), name).apply();
mainPageContentPref.setSummary(name);
}
});
selectChannelFragment.setOnCancelListener(new SelectChannelFragment.OnCancelListener() {
@Override
public void onCancel() {
mainPageContentPref.setSummary(mainPrefOldSummary);
mainPageContentPref.setValue(mainPrefOldValue);
}
});
selectChannelFragment.show(getFragmentManager(), "select_channel");
} else {
mainPageContentPref.setSummary(getMainPageSummeryByKey(newValue));
}
defaultPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, true).apply();
return true;
if(newValue.equals(getString(R.string.kiosk_page_key))) {
SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
selectKioskFragment.setOnSelectedLisener((String kioskId, int service_id) -> {
defaultPreferences.edit()
.putInt(getString(R.string.main_page_selected_service), service_id).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selectd_kiosk_id), kioskId).apply();
String serviceName = "";
try {
serviceName = NewPipe.getService(service_id).getServiceInfo().name;
} catch (ExtractionException e) {
onError(e);
}
String kioskName = KioskTranslator.getTranslatedKioskName(kioskId,
getContext());
String summary =
String.format(getString(R.string.service_kiosk_string),
serviceName,
kioskName);
mainPageContentPref.setSummary(summary);
});
selectKioskFragment.setOnCancelListener(() -> {
mainPageContentPref.setSummary(mainPrefOldSummary);
mainPageContentPref.setValue(mainPrefOldValue);
});
selectKioskFragment.show(getFragmentManager(), "select_kiosk");
} else if(newValue.equals(getString(R.string.channel_page_key))) {
SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
selectChannelFragment.setOnSelectedLisener((String url, String name, int service) -> {
defaultPreferences.edit()
.putInt(getString(R.string.main_page_selected_service), service).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selected_channel_url), url).apply();
defaultPreferences.edit()
.putString(getString(R.string.main_page_selected_channel_name), name).apply();
mainPageContentPref.setSummary(name);
});
selectChannelFragment.setOnCancelListener(() -> {
mainPageContentPref.setSummary(mainPrefOldSummary);
mainPageContentPref.setValue(mainPrefOldValue);
});
selectChannelFragment.show(getFragmentManager(), "select_channel");
} else {
mainPageContentPref.setSummary(getMainPageSummeryByKey(newValue));
}
defaultPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, true).apply();
return true;
});
Preference importDataPreference = findPreference(getString(R.string.import_data));
importDataPreference.setOnPreferenceClickListener((Preference p) -> {
Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, false)
.putExtra(FilePickerActivityHelper.EXTRA_MODE, FilePickerActivityHelper.MODE_FILE);
startActivityForResult(i, REQUEST_IMPORT_PATH);
return true;
});
Preference exportDataPreference = findPreference(getString(R.string.export_data));
exportDataPreference.setOnPreferenceClickListener((Preference p) -> {
Intent 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);
startActivityForResult(i, REQUEST_EXPORT_PATH);
return true;
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nonnull Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (DEBUG) {
Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");
}
if ((requestCode == REQUEST_IMPORT_PATH || requestCode == REQUEST_EXPORT_PATH)
&& resultCode == Activity.RESULT_OK) {
String path = data.getData().getPath();
if (requestCode == REQUEST_EXPORT_PATH) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
exportDatabase(path + "/NewPipeData-" + sdf.format(new Date()) + ".zip");
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.override_current_data)
.setPositiveButton(android.R.string.ok,
(DialogInterface d, int id) -> importDatabase(path))
.setNegativeButton(android.R.string.cancel,
(DialogInterface d, int id) -> d.cancel());
builder.create().show();
}
}
}
private void exportDatabase(String path) {
try {
ZipOutputStream outZip = new ZipOutputStream(
new BufferedOutputStream(
new FileOutputStream(path)));
ZipHelper.addFileToZip(outZip, newpipe_db.getPath(), "newpipe.db");
ZipHelper.addFileToZip(outZip, newpipe_db_journal.getPath(), "newpipe.db-journal");
outZip.close();
Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT)
.show();
} catch (Exception e) {
onError(e);
}
}
private void importDatabase(String filePath) {
// check if file is supported
ZipFile zipFile = null;
try {
zipFile = new ZipFile(filePath);
} catch (IOException ioe) {
Toast.makeText(getContext(), R.string.no_valid_zip_file, Toast.LENGTH_SHORT)
.show();
return;
} finally {
try {
zipFile.close();
} catch (Exception e){}
}
try {
ZipInputStream zipIn = new ZipInputStream(
new BufferedInputStream(
new FileInputStream(filePath)));
if (!databasesDir.exists() && !databasesDir.mkdir()) {
throw new Exception("Could not create databases dir");
}
if(!(ZipHelper.extractFileFromZip(zipIn, newpipe_db.getPath(), "newpipe.db")
&& ZipHelper.extractFileFromZip(zipIn, newpipe_db_journal.getPath(), "newpipe.db-journal"))) {
Toast.makeText(getContext(), R.string.could_not_import_all_files, Toast.LENGTH_LONG)
.show();
}
zipIn.close();
// restart app to properly load db
//App.restart(getContext());
System.exit(0);
} catch (Exception e) {
onError(e);
}
}
@Override
@@ -117,8 +239,8 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
getString(R.string.main_page_selected_service), 0));
String kioskName = KioskTranslator.getTranslatedKioskName(
defaultPreferences.getString(
getString(R.string.main_page_selectd_kiosk_id), "Trending"),
defaultPreferences.getString(
getString(R.string.main_page_selectd_kiosk_id), "Trending"),
getContext());
String summary =

View File

@@ -46,7 +46,8 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
Log.d(TAG, "onPreferenceTreeClick() called with: preference = [" + preference + "]");
}
if (preference.getKey().equals(DOWNLOAD_PATH_PREFERENCE) || preference.getKey().equals(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
if (preference.getKey().equals(DOWNLOAD_PATH_PREFERENCE)
|| preference.getKey().equals(DOWNLOAD_PATH_AUDIO_PREFERENCE)) {
Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)

View File

@@ -14,21 +14,17 @@ import android.widget.ImageView;
import android.widget.TextView;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.fragments.subscription.SubscriptionService;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.ServiceIconMapper;
import org.schabi.newpipe.util.ServiceHelper;
import java.util.List;
import java.util.Vector;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Created by Christian Schabesberger on 09.10.17.
* SelectKioskFragment.java is part of NewPipe.
@@ -125,13 +121,15 @@ public class SelectKioskFragment extends DialogFragment {
throws Exception {
for(StreamingService service : NewPipe.getServices()) {
//TODO: Multi-service support
if (service.getServiceId() != ServiceList.YouTube.getId()) continue;
for(String kioskId : service.getKioskList().getAvailableKiosks()) {
String name = String.format(getString(R.string.service_kiosk_string),
service.getServiceInfo().name,
KioskTranslator.getTranslatedKioskName(kioskId, getContext()));
kioskList.add(new Entry(
//ServiceIconMapper.getIconResource(service.getServiceId()),
ServiceIconMapper.getIconResource(-1),
ServiceHelper.getIcon(service.getServiceId()),
service.getServiceId(),
kioskId,
name));
@@ -140,9 +138,7 @@ public class SelectKioskFragment extends DialogFragment {
}
public int getItemCount() {
//todo: uncommend this line on multyservice support
//return kioskList.size();
return 1;
return kioskList.size();
}
public SelectKioskItemHolder onCreateViewHolder(ViewGroup parent, int type) {

View File

@@ -43,7 +43,8 @@ public class SettingsActivity extends AppCompatActivity implements BasePreferenc
@Override
protected void onCreate(Bundle savedInstanceBundle) {
ThemeHelper.setTheme(this);
setTheme(ThemeHelper.getSettingsThemeStyle(this));
super.onCreate(savedInstanceBundle);
setContentView(R.layout.settings_layout);
@@ -72,7 +73,9 @@ public class SettingsActivity extends AppCompatActivity implements BasePreferenc
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
finish();
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
finish();
} else getSupportFragmentManager().popBackStack();
}
return true;
}

View File

@@ -19,29 +19,38 @@
package org.schabi.newpipe.util;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.ListExtractor.NextItemsResult;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.search.SearchEngine;
import org.schabi.newpipe.extractor.search.SearchResult;
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.List;
import java.util.concurrent.Callable;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.Single;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
public final class ExtractorHelper {
private static final String TAG = ExtractorHelper.class.getSimpleName();
@@ -57,104 +66,96 @@ public final class ExtractorHelper {
}
}
public static Single<SearchResult> searchFor(final int serviceId, final String query, final int pageNumber, final String searchLanguage, final SearchEngine.Filter filter) {
public static Single<SearchResult> searchFor(final int serviceId,
final String query,
final int pageNumber,
final String contentCountry,
final SearchEngine.Filter filter) {
checkServiceId(serviceId);
return Single.fromCallable(new Callable<SearchResult>() {
@Override
public SearchResult call() throws Exception {
return SearchResult.getSearchResult(NewPipe.getService(serviceId).getSearchEngine(),
query, pageNumber, searchLanguage, filter);
}
});
return Single.fromCallable(() ->
SearchResult.getSearchResult(NewPipe.getService(serviceId).getSearchEngine(),
query, pageNumber, contentCountry, filter)
);
}
public static Single<NextItemsResult> getMoreSearchItems(final int serviceId, final String query, final int nextPageNumber, final String searchLanguage, final SearchEngine.Filter filter) {
public static Single<NextItemsResult> getMoreSearchItems(final int serviceId,
final String query,
final int nextPageNumber,
final String searchLanguage,
final SearchEngine.Filter filter) {
checkServiceId(serviceId);
return searchFor(serviceId, query, nextPageNumber, searchLanguage, filter)
.map(new Function<SearchResult, NextItemsResult>() {
@Override
public NextItemsResult apply(@NonNull SearchResult searchResult) throws Exception {
return new NextItemsResult(searchResult.resultList, nextPageNumber + "", searchResult.errors);
}
});
.map((@NonNull SearchResult searchResult) ->
new NextItemsResult(searchResult.resultList,
nextPageNumber + "",
searchResult.errors));
}
public static Single<List<String>> suggestionsFor(final int serviceId, final String query, final String searchLanguage) {
public static Single<List<String>> suggestionsFor(final int serviceId,
final String query,
final String contentCountry) {
checkServiceId(serviceId);
return Single.fromCallable(new Callable<List<String>>() {
@Override
public List<String> call() throws Exception {
return NewPipe.getService(serviceId).getSuggestionExtractor().suggestionList(query, searchLanguage);
}
});
return Single.fromCallable(() ->
NewPipe.getService(serviceId)
.getSuggestionExtractor()
.suggestionList(query, contentCountry));
}
public static Single<StreamInfo> getStreamInfo(final int serviceId, final String url, boolean forceLoad) {
public static Single<StreamInfo> getStreamInfo(final int serviceId,
final String url,
boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<StreamInfo>() {
@Override
public StreamInfo call() throws Exception {
return StreamInfo.getInfo(NewPipe.getService(serviceId), url);
}
}));
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
StreamInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<ChannelInfo> getChannelInfo(final int serviceId, final String url, boolean forceLoad) {
public static Single<ChannelInfo> getChannelInfo(final int serviceId,
final String url,
boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<ChannelInfo>() {
@Override
public ChannelInfo call() throws Exception {
return ChannelInfo.getInfo(NewPipe.getService(serviceId), url);
}
}));
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
ChannelInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<NextItemsResult> getMoreChannelItems(final int serviceId, final String url, final String nextStreamsUrl) {
public static Single<NextItemsResult> getMoreChannelItems(final int serviceId,
final String url,
final String nextStreamsUrl) {
checkServiceId(serviceId);
return Single.fromCallable(new Callable<NextItemsResult>() {
@Override
public NextItemsResult call() throws Exception {
return ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
}
});
return Single.fromCallable(() ->
ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
}
public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId, final String url, boolean forceLoad) {
public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId,
final String url,
boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<PlaylistInfo>() {
@Override
public PlaylistInfo call() throws Exception {
return PlaylistInfo.getInfo(NewPipe.getService(serviceId), url);
}
}));
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
PlaylistInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<NextItemsResult> getMorePlaylistItems(final int serviceId, final String url, final String nextStreamsUrl) {
public static Single<NextItemsResult> getMorePlaylistItems(final int serviceId,
final String url,
final String nextStreamsUrl) {
checkServiceId(serviceId);
return Single.fromCallable(new Callable<NextItemsResult>() {
@Override
public NextItemsResult call() throws Exception {
return PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
}
});
return Single.fromCallable(() ->
PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
}
public static Single<KioskInfo> getKioskInfo(final int serviceId, final String url, final String contentCountry, boolean forceLoad) {
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<KioskInfo>() {
@Override
public KioskInfo call() throws Exception {
return KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry);
}
}));
public static Single<KioskInfo> getKioskInfo(final int serviceId,
final String url,
final String contentCountry,
boolean forceLoad) {
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry)));
}
public static Single<NextItemsResult> getMoreKioskItems(final int serviceId, final String url, final String nextStreamsUrl) {
return Single.fromCallable(new Callable<NextItemsResult>() {
@Override
public NextItemsResult call() throws Exception {
return KioskInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
}
});
public static Single<NextItemsResult> getMoreKioskItems(final int serviceId,
final String url,
final String nextStreamsUrl,
final String contentCountry) {
return Single.fromCallable(() ->
KioskInfo.getMoreItems(NewPipe.getService(serviceId),
url, nextStreamsUrl, contentCountry));
}
/*//////////////////////////////////////////////////////////////////////////
@@ -162,24 +163,24 @@ public final class ExtractorHelper {
//////////////////////////////////////////////////////////////////////////*/
/**
* Check if we can load it from the cache (forceLoad parameter), if we can't, load from the network (Single loadFromNetwork)
* Check if we can load it from the cache (forceLoad parameter), if we can't,
* load from the network (Single loadFromNetwork)
* and put the results in the cache.
*/
private static <I extends Info> Single<I> checkCache(boolean forceLoad, int serviceId, String url, Single<I> loadFromNetwork) {
private static <I extends Info> Single<I> checkCache(boolean forceLoad,
int serviceId,
String url,
Single<I> loadFromNetwork) {
checkServiceId(serviceId);
loadFromNetwork = loadFromNetwork.doOnSuccess(new Consumer<I>() {
@Override
public void accept(@NonNull I i) throws Exception {
cache.putInfo(i);
}
});
loadFromNetwork = loadFromNetwork.doOnSuccess((@NonNull I i) -> cache.putInfo(i));
Single<I> load;
if (forceLoad) {
cache.removeInfo(serviceId, url);
load = loadFromNetwork;
} else {
load = Maybe.concat(ExtractorHelper.<I>loadFromCache(serviceId, url), loadFromNetwork.toMaybe())
load = Maybe.concat(ExtractorHelper.<I>loadFromCache(serviceId, url),
loadFromNetwork.toMaybe())
.firstElement() //Take the first valid
.toSingle();
}
@@ -192,9 +193,7 @@ public final class ExtractorHelper {
*/
public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url) {
checkServiceId(serviceId);
return Maybe.defer(new Callable<MaybeSource<? extends I>>() {
@Override
public MaybeSource<? extends I> call() throws Exception {
return Maybe.defer(() -> {
//noinspection unchecked
I info = (I) cache.getFromKey(serviceId, url);
if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info);
@@ -205,8 +204,38 @@ public final class ExtractorHelper {
}
return Maybe.empty();
});
}
/**
* A simple and general error handler that show a Toast for known exceptions, and for others, opens the report error activity with the (optional) error message.
*/
public static void handleGeneralException(Context context, int serviceId, String url, Throwable exception, UserAction userAction, String optionalErrorMessage) {
final Handler handler = new Handler(context.getMainLooper());
handler.post(() -> {
if (exception instanceof ReCaptchaException) {
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
// Starting ReCaptcha Challenge Activity
Intent intent = new Intent(context, ReCaptchaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else if (exception instanceof IOException) {
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.GemaException) {
Toast.makeText(context, R.string.blocked_by_gema, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.LiveStreamException) {
Toast.makeText(context, R.string.live_streams_not_supported, Toast.LENGTH_LONG).show();
} else if (exception instanceof ContentNotAvailableException) {
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
} else {
int errorId = exception instanceof YoutubeStreamExtractor.DecryptException ? R.string.youtube_signature_decryption_error :
exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
ErrorActivity.reportError(handler, context, exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(userAction,
serviceId == -1 ? "none" : NewPipe.getNameOfService(serviceId), url + (optionalErrorMessage == null ? "" : optionalErrorMessage), errorId));
}
});
}
/**
@@ -214,21 +243,26 @@ public final class ExtractorHelper {
*
* @see Class#isAssignableFrom(Class)
*/
public static boolean hasAssignableCauseThrowable(Throwable throwable, Class<?>... causesToCheck) {
public static boolean hasAssignableCauseThrowable(Throwable throwable,
Class<?>... causesToCheck) {
// Check if getCause is not the same as cause (the getCause is already the root),
// as it will cause a infinite loop if it is
Throwable cause, getCause = throwable;
// Check if throwable is a subclass of any of the filtered classes
final Class throwableClass = throwable.getClass();
for (Class<?> causesEl : causesToCheck) {
if (throwable.getClass().isAssignableFrom(causesEl)) {
if (causesEl.isAssignableFrom(throwableClass)) {
return true;
}
}
// Iteratively checks if the root cause of the throwable is a subclass of the filtered class
while ((cause = throwable.getCause()) != null && getCause != cause) {
getCause = cause;
final Class causeClass = cause.getClass();
for (Class<?> causesEl : causesToCheck) {
if (cause.getClass().isAssignableFrom(causesEl)) {
if (causesEl.isAssignableFrom(causeClass)) {
return true;
}
}
@@ -265,6 +299,8 @@ public final class ExtractorHelper {
* Check if throwable have Interrupted* exception as one of its causes.
*/
public static boolean isInterruptedCaused(Throwable throwable) {
return ExtractorHelper.hasExactCauseThrowable(throwable, InterruptedIOException.class, InterruptedException.class);
return ExtractorHelper.hasExactCauseThrowable(throwable,
InterruptedIOException.class,
InterruptedException.class);
}
}

View File

@@ -9,6 +9,8 @@ import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.widget.Toast;
import com.nostra13.universalimageloader.core.ImageLoader;
@@ -20,9 +22,11 @@ import org.schabi.newpipe.download.DownloadActivity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
@@ -38,16 +42,21 @@ import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayerActivity;
import org.schabi.newpipe.player.VideoPlayer;
import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.settings.SettingsActivity;
import java.util.ArrayList;
@SuppressWarnings({"unused", "WeakerAccess"})
public class NavigationHelper {
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
public static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
/*//////////////////////////////////////////////////////////////////////////
// Players
//////////////////////////////////////////////////////////////////////////*/
public static Intent getPlayerIntent(final Context context,
final Class targetClazz,
final PlayQueue playQueue,
@@ -67,9 +76,11 @@ public class NavigationHelper {
public static Intent getPlayerEnqueueIntent(final Context context,
final Class targetClazz,
final PlayQueue playQueue) {
final PlayQueue playQueue,
final boolean selectOnAppend) {
return getPlayerIntent(context, targetClazz, playQueue)
.putExtra(BasePlayer.APPEND_ONLY, true);
.putExtra(BasePlayer.APPEND_ONLY, true)
.putExtra(BasePlayer.SELECT_ON_APPEND, selectOnAppend);
}
public static Intent getPlayerIntent(final Context context,
@@ -86,10 +97,37 @@ public class NavigationHelper {
}
public static void playOnMainPlayer(final Context context, final PlayQueue queue) {
context.startActivity(getPlayerIntent(context, MainVideoPlayer.class, queue));
final Intent playerIntent = getPlayerIntent(context, MainVideoPlayer.class, queue);
playerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(playerIntent);
}
public static void playOnOldVideoPlayer(Context context, StreamInfo info) {
ArrayList<VideoStream> videoStreamsList = new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.getVideoStreams(), null, false));
int index = ListHelper.getDefaultResolutionIndex(context, videoStreamsList);
if (index == -1) {
Toast.makeText(context, R.string.video_streams_empty, Toast.LENGTH_SHORT).show();
return;
}
VideoStream videoStream = videoStreamsList.get(index);
Intent intent = new Intent(context, PlayVideoActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(PlayVideoActivity.VIDEO_TITLE, info.getName())
.putExtra(PlayVideoActivity.STREAM_URL, videoStream.getUrl())
.putExtra(PlayVideoActivity.VIDEO_URL, info.getUrl())
.putExtra(PlayVideoActivity.START_POSITION, info.getStartPosition());
context.startActivity(intent);
}
public static void playOnPopupPlayer(final Context context, final PlayQueue queue) {
if (!PermissionHelper.isPopupEnabled(context)) {
PermissionHelper.showPopupEnablementToast(context);
return;
}
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
context.startService(getPlayerIntent(context, PopupVideoPlayer.class, queue));
}
@@ -100,14 +138,91 @@ public class NavigationHelper {
}
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue) {
enqueueOnPopupPlayer(context, queue, false);
}
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue, boolean selectOnAppend) {
if (!PermissionHelper.isPopupEnabled(context)) {
PermissionHelper.showPopupEnablementToast(context);
return;
}
Toast.makeText(context, R.string.popup_playing_append, Toast.LENGTH_SHORT).show();
context.startService(getPlayerEnqueueIntent(context, PopupVideoPlayer.class, queue));
context.startService(getPlayerEnqueueIntent(context, PopupVideoPlayer.class, queue, selectOnAppend));
}
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue) {
Toast.makeText(context, R.string.background_player_append, Toast.LENGTH_SHORT).show();
context.startService(getPlayerEnqueueIntent(context, BackgroundPlayer.class, queue));
enqueueOnBackgroundPlayer(context, queue, false);
}
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, boolean selectOnAppend) {
Toast.makeText(context, R.string.background_player_append, Toast.LENGTH_SHORT).show();
context.startService(getPlayerEnqueueIntent(context, BackgroundPlayer.class, queue, selectOnAppend));
}
/*//////////////////////////////////////////////////////////////////////////
// External Players
//////////////////////////////////////////////////////////////////////////*/
public static void playOnExternalAudioPlayer(Context context, StreamInfo info) {
final int index = ListHelper.getDefaultAudioFormat(context, info.getAudioStreams());
if (index == -1) {
Toast.makeText(context, R.string.audio_streams_empty, Toast.LENGTH_SHORT).show();
return;
}
AudioStream audioStream = info.getAudioStreams().get(index);
playOnExternalPlayer(context, info.getName(), info.getUploaderName(), audioStream);
}
public static void playOnExternalVideoPlayer(Context context, StreamInfo info) {
ArrayList<VideoStream> videoStreamsList = new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.getVideoStreams(), null, false));
int index = ListHelper.getDefaultResolutionIndex(context, videoStreamsList);
if (index == -1) {
Toast.makeText(context, R.string.video_streams_empty, Toast.LENGTH_SHORT).show();
return;
}
VideoStream videoStream = videoStreamsList.get(index);
playOnExternalPlayer(context, info.getName(), info.getUploaderName(), videoStream);
}
public static void playOnExternalPlayer(Context context, String name, String artist, Stream stream) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(stream.getUrl()), stream.getFormat().getMimeType());
intent.putExtra(Intent.EXTRA_TITLE, name);
intent.putExtra("title", name);
intent.putExtra("artist", artist);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
resolveActivityOrAskToInstall(context, intent);
}
public static void resolveActivityOrAskToInstall(Context context, Intent intent) {
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(intent);
} else {
if (context instanceof Activity) {
new AlertDialog.Builder(context)
.setMessage(R.string.no_player_found)
.setPositiveButton(R.string.install, (dialog, which) -> {
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
i.setData(Uri.parse(context.getString(R.string.fdroid_vlc_url)));
context.startActivity(i);
})
.setNegativeButton(R.string.cancel, (dialog, which) -> Log.i("NavigationHelper", "You unlocked a secret unicorn."))
.show();
//Log.e("NavigationHelper", "Either no Streaming player for audio was installed, or something important crashed:");
} else {
Toast.makeText(context, R.string.no_player_found_toast, Toast.LENGTH_LONG).show();
}
}
}
/*//////////////////////////////////////////////////////////////////////////
// Through FragmentManager
//////////////////////////////////////////////////////////////////////////*/
@@ -130,11 +245,21 @@ public class NavigationHelper {
.commit();
}
public static boolean tryGotoSearchFragment(FragmentManager fragmentManager) {
if (MainActivity.DEBUG) {
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
Log.d("NavigationHelper", "tryGoToSearchFragment() [" + i + "] = [" + fragmentManager.getBackStackEntryAt(i) + "]");
}
}
return fragmentManager.popBackStackImmediate(SEARCH_FRAGMENT_TAG, 0);
}
public static void openSearchFragment(FragmentManager fragmentManager, int serviceId, String query) {
fragmentManager.beginTransaction()
.setCustomAnimations(R.animator.custom_fade_in, R.animator.custom_fade_out, R.animator.custom_fade_in, R.animator.custom_fade_out)
.replace(R.id.fragment_holder, SearchFragment.getInstance(serviceId, query))
.addToBackStack(null)
.addToBackStack(SEARCH_FRAGMENT_TAG)
.commit();
}
@@ -261,40 +386,26 @@ public class NavigationHelper {
return true;
}
public static void openBackgroundPlayerControl(final Context context) {
openServicePlayerControl(context, BackgroundPlayerActivity.class);
public static Intent getBackgroundPlayerActivityIntent(final Context context) {
return getServicePlayerActivityIntent(context, BackgroundPlayerActivity.class);
}
public static void openPopupPlayerControl(final Context context) {
openServicePlayerControl(context, PopupVideoPlayerActivity.class);
public static Intent getPopupPlayerActivityIntent(final Context context) {
return getServicePlayerActivityIntent(context, PopupVideoPlayerActivity.class);
}
private static void openServicePlayerControl(final Context context, final Class clazz) {
final Intent intent = new Intent(context, clazz);
private static Intent getServicePlayerActivityIntent(final Context context,
final Class activityClass) {
Intent intent = new Intent(context, activityClass);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
return intent;
}
/*//////////////////////////////////////////////////////////////////////////
// Link handling
//////////////////////////////////////////////////////////////////////////*/
public static boolean openByLink(Context context, String url) {
Intent intentByLink;
try {
intentByLink = getIntentByLink(context, url);
} catch (ExtractionException e) {
return false;
}
intentByLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentByLink.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intentByLink);
return true;
}
private static Intent getOpenIntent(Context context, String url, int serviceId, StreamingService.LinkType type) {
Intent mIntent = new Intent(context, MainActivity.class);
mIntent.putExtra(Constants.KEY_SERVICE_ID, serviceId);
@@ -312,15 +423,14 @@ public class NavigationHelper {
throw new ExtractionException("Service not supported at the moment");
}
int serviceId = service.getServiceId();
StreamingService.LinkType linkType = service.getLinkTypeByUrl(url);
if (linkType == StreamingService.LinkType.NONE) {
throw new ExtractionException("Url not known to service. service=" + serviceId + " url=" + url);
throw new ExtractionException("Url not known to service. service=" + service + " url=" + url);
}
url = getCleanUrl(service, url, linkType);
Intent rIntent = getOpenIntent(context, url, serviceId, linkType);
Intent rIntent = getOpenIntent(context, url, service.getServiceId(), linkType);
switch (linkType) {
case STREAM:
@@ -332,7 +442,7 @@ public class NavigationHelper {
return rIntent;
}
private static String getCleanUrl(StreamingService service, String dirtyUrl, StreamingService.LinkType linkType) throws ExtractionException {
public static String getCleanUrl(StreamingService service, String dirtyUrl, StreamingService.LinkType linkType) throws ExtractionException {
switch (linkType) {
case STREAM:
return service.getStreamUrlIdHandler().cleanUrl(dirtyUrl);
@@ -346,7 +456,6 @@ public class NavigationHelper {
return null;
}
private static Uri openMarketUrl(String packageName) {
return Uri.parse("market://details")
.buildUpon()

View File

@@ -11,11 +11,15 @@ import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.Gravity;
import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.R;
public class PermissionHelper {
public static final int PERMISSION_WRITE_STORAGE = 778;
public static final int PERMISSION_READ_STORAGE = 777;
public static final int PERMISSION_SYSTEM_ALERT_WINDOW = 779;
public static boolean checkStoragePermissions(Activity activity) {
@@ -75,21 +79,31 @@ public class PermissionHelper {
* In order to be able to draw over other apps, the permission android.permission.SYSTEM_ALERT_WINDOW have to be granted.
* <p>
* On < API 23 (MarshMallow) the permission was granted when the user installed the application (via AndroidManifest),
* on > 23, however, it have to start a activity asking the user if he agree.
* on > 23, however, it have to start a activity asking the user if he agrees.
* <p>
* This method just return if canDraw over other apps, if it doesn't, try to get the permission,
* it does not get the result of the startActivityForResult, if the user accept, the next time that he tries to open
* it will return true.
* This method just return if the app has permission to draw over other apps, and if it doesn't, it will try to get the permission.
*
* @param activity context to startActivityForResult
* @return returns {@link Settings#canDrawOverlays(Context)}
**/
@RequiresApi(api = Build.VERSION_CODES.M)
public static boolean checkSystemAlertWindowPermission(Activity activity) {
if (!Settings.canDrawOverlays(activity)) {
Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + activity.getPackageName()));
activity.startActivityForResult(i, PERMISSION_SYSTEM_ALERT_WINDOW);
public static boolean checkSystemAlertWindowPermission(Context context) {
if (!Settings.canDrawOverlays(context)) {
Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
return false;
}else return true;
}
public static boolean isPopupEnabled(Context context) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
PermissionHelper.checkSystemAlertWindowPermission(context);
}
public static void showPopupEnablementToast(Context context) {
Toast toast = Toast.makeText(context, R.string.msg_popup_permission, Toast.LENGTH_LONG);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
}
}

View File

@@ -0,0 +1,48 @@
package org.schabi.newpipe.util;
import android.widget.PopupMenu;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Created by Christian Schabesberger on 20.01.18.
* Copyright 2018 Christian Schabesberger <chris.schabesberger@mailbox.org>
* PopupMenuIconHacker.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class PopupMenuIconHacker {
public static void setShowPopupIcon(PopupMenu menu) throws Exception {
try {
Field[] fields = menu.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(menu);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
} catch (Exception e) {
throw new Exception("Could not make Popup menu show Icons", e);
}
}
}

View File

@@ -0,0 +1,67 @@
package org.schabi.newpipe.util;
import android.content.Context;
import android.preference.PreferenceManager;
import android.support.annotation.DrawableRes;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
public class ServiceHelper {
private static final StreamingService DEFAULT_FALLBACK_SERVICE = ServiceList.YouTube.getService();
@DrawableRes
public static int getIcon(int serviceId) {
switch (serviceId) {
case 0:
return R.drawable.place_holder_youtube;
case 1:
return R.drawable.place_holder_circle;
default:
return R.drawable.service;
}
}
public static int getSelectedServiceId(Context context) {
if (BuildConfig.BUILD_TYPE.equals("release")) return DEFAULT_FALLBACK_SERVICE.getServiceId();
final String serviceName = PreferenceManager.getDefaultSharedPreferences(context)
.getString(context.getString(R.string.current_service_key), context.getString(R.string.default_service_value));
int serviceId;
try {
serviceId = NewPipe.getService(serviceName).getServiceId();
} catch (ExtractionException e) {
serviceId = DEFAULT_FALLBACK_SERVICE.getServiceId();
}
return serviceId;
}
public static void setSelectedServiceId(Context context, int serviceId) {
String serviceName;
try {
serviceName = NewPipe.getService(serviceId).getServiceInfo().name;
} catch (ExtractionException e) {
serviceName = DEFAULT_FALLBACK_SERVICE.getServiceInfo().name;
}
setSelectedServicePreferences(context, serviceName);
}
public static void setSelectedServiceId(Context context, String serviceName) {
int serviceId = NewPipe.getIdOfService(serviceName);
if (serviceId == -1) serviceName = DEFAULT_FALLBACK_SERVICE.getServiceInfo().name;
setSelectedServicePreferences(context, serviceName);
}
private static void setSelectedServicePreferences(Context context, String serviceName) {
PreferenceManager.getDefaultSharedPreferences(context).edit().
putString(context.getString(R.string.current_service_key), serviceName).apply();
}
}

View File

@@ -1,35 +0,0 @@
package org.schabi.newpipe.util;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
/**
* Created by Chrsitian Schabesberger on 09.10.17.
* ServiceIconMapper.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class ServiceIconMapper {
public static int getIconResource(int service_id) {
switch(service_id) {
case 0:
return R.drawable.youtube;
case 1:
return R.drawable.soud_cloud;
default:
return R.drawable.service;
}
}
}

View File

@@ -1,29 +1,38 @@
package org.schabi.newpipe.util;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.PreferenceManager;
import android.support.annotation.AttrRes;
import android.support.annotation.StyleRes;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
public class ThemeHelper {
/**
* Apply the selected theme (on NewPipe settings) in the context
* with the default style (see {@link #setTheme(Context, int)}).
*
* @param context context that the theme will be applied
*/
public static void setTheme(Context context) {
String lightTheme = context.getResources().getString(R.string.light_theme_key);
String darkTheme = context.getResources().getString(R.string.dark_theme_key);
String blackTheme = context.getResources().getString(R.string.black_theme_key);
setTheme(context, -1);
}
String selectedTheme = getSelectedTheme(context);
if (selectedTheme.equals(lightTheme)) context.setTheme(R.style.LightTheme);
else if (selectedTheme.equals(blackTheme)) context.setTheme(R.style.BlackTheme);
else if (selectedTheme.equals(darkTheme)) context.setTheme(R.style.DarkTheme);
// Fallback
else context.setTheme(R.style.DarkTheme);
/**
* Apply the selected theme (on NewPipe settings) in the context,
* themed according with the styles defined for the service .
*
* @param context context that the theme will be applied
* @param serviceId the theme will be styled to the service with this id,
* pass -1 to get the default style
*/
public static void setTheme(Context context, int serviceId) {
context.setTheme(getThemeForService(context, serviceId));
}
/**
@@ -35,9 +44,73 @@ public class ThemeHelper {
return getSelectedTheme(context).equals(context.getResources().getString(R.string.light_theme_key));
}
@StyleRes
public static int getThemeForService(Context context, int serviceId) {
String lightTheme = context.getResources().getString(R.string.light_theme_key);
String darkTheme = context.getResources().getString(R.string.dark_theme_key);
String blackTheme = context.getResources().getString(R.string.black_theme_key);
String selectedTheme = getSelectedTheme(context);
int defaultTheme = R.style.DarkTheme;
if (selectedTheme.equals(lightTheme)) defaultTheme = R.style.LightTheme;
else if (selectedTheme.equals(blackTheme)) defaultTheme = R.style.BlackTheme;
else if (selectedTheme.equals(darkTheme)) defaultTheme = R.style.DarkTheme;
if (serviceId <= -1) {
return defaultTheme;
}
final StreamingService service;
try {
service = NewPipe.getService(serviceId);
} catch (ExtractionException ignored) {
return defaultTheme;
}
String themeName = "DarkTheme";
if (selectedTheme.equals(lightTheme)) themeName = "LightTheme";
else if (selectedTheme.equals(blackTheme)) themeName = "BlackTheme";
else if (selectedTheme.equals(darkTheme)) themeName = "DarkTheme";
themeName += "." + service.getServiceInfo().name;
int resourceId = context.getResources().getIdentifier(themeName, "style", context.getPackageName());
if (resourceId > 0) {
return resourceId;
}
return defaultTheme;
}
public static String getSelectedTheme(Context context) {
String themeKey = context.getString(R.string.theme_key);
String defaultTheme = context.getResources().getString(R.string.default_theme_value);
return PreferenceManager.getDefaultSharedPreferences(context).getString(themeKey, defaultTheme);
}
@StyleRes
public static int getSettingsThemeStyle(Context context) {
String lightTheme = context.getResources().getString(R.string.light_theme_key);
String darkTheme = context.getResources().getString(R.string.dark_theme_key);
String blackTheme = context.getResources().getString(R.string.black_theme_key);
String selectedTheme = getSelectedTheme(context);
if (selectedTheme.equals(lightTheme)) return R.style.LightSettingsTheme;
else if (selectedTheme.equals(blackTheme)) return R.style.BlackSettingsTheme;
else if (selectedTheme.equals(darkTheme)) return R.style.DarkSettingsTheme;
// Fallback
else return R.style.DarkSettingsTheme;
}
/**
* Get a resource id from a resource styled according to the the context's theme.
*/
public static int resolveResourceIdFromAttr(Context context, @AttrRes int attr) {
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr});
int attributeResourceId = a.getResourceId(0, 0);
a.recycle();
return attributeResourceId;
}
}

View File

@@ -0,0 +1,94 @@
package org.schabi.newpipe.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* Created by Christian Schabesberger on 28.01.18.
* Copyright 2018 Christian Schabesberger <chris.schabesberger@mailbox.org>
* ZipHelper.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class ZipHelper {
private static final int BUFFER_SIZE = 2048;
/**
* This function helps to create zip files.
* Caution this will override the original file.
* @param outZip The ZipOutputStream where the data should be stored in
* @param file The path of the file that should be added to zip.
* @param name The path of the file inside the zip.
* @throws Exception
*/
public static void addFileToZip(ZipOutputStream outZip, String file, String name) throws Exception {
byte data[] = new byte[BUFFER_SIZE];
FileInputStream fi = new FileInputStream(file);
BufferedInputStream inputStream = new BufferedInputStream(fi, BUFFER_SIZE);
ZipEntry entry = new ZipEntry(name);
outZip.putNextEntry(entry);
int count;
while((count = inputStream.read(data, 0, BUFFER_SIZE)) != -1) {
outZip.write(data, 0, count);
}
inputStream.close();
}
/**
* This will extract data from Zipfiles.
* Caution this will override the original file.
* @param inZip The ZipOutputStream where the data is stored in
* @param file The path of the file on the disk where the data should be extracted to.
* @param name The path of the file inside the zip.
* @return will return true if the file was found within the zip file
* @throws Exception
*/
public static boolean extractFileFromZip(ZipInputStream inZip, String file, String name) throws Exception {
byte data[] = new byte[BUFFER_SIZE];
boolean found = false;
ZipEntry ze;
while((ze = inZip.getNextEntry()) != null) {
if(ze.getName().equals(name)) {
found = true;
// delete old file first
File oldFile = new File(file);
if(oldFile.exists()) {
if(!oldFile.delete()) {
throw new Exception("Could not delete " + file);
}
}
FileOutputStream outFile = new FileOutputStream(file);
int count = 0;
while((count = inZip.read(data)) != -1) {
outFile.write(data, 0, count);
}
outFile.close();
inZip.closeEntry();
}
}
return true;
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/decelerate_quint">
<alpha
android:duration="150"
android:fromAlpha="0.00"
android:toAlpha="1.0"/>
</set>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_quint">
<alpha
android:duration="350"
android:fromAlpha="1.0"
android:toAlpha="0.00"/>
</set>

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:enterFadeDuration="200" android:exitFadeDuration="200">
<item android:drawable="@color/dark_ripple_color" android:state_checked="true" android:state_pressed="true" />
<item android:drawable="@color/dark_ripple_color" android:state_pressed="true" />
<item android:drawable="@color/dark_selected_color" android:state_checked="true" />
<item android:drawable="@android:color/transparent" />
</selector>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:enterFadeDuration="200" android:exitFadeDuration="200">
<item android:drawable="@color/light_ripple_color" android:state_checked="true" android:state_pressed="true" />
<item android:drawable="@color/light_ripple_color" android:state_pressed="true" />
<item android:drawable="@color/light_selected_color" android:state_checked="true" />
<item android:drawable="@android:color/transparent" />
</selector>

View File

@@ -1,18 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="org.schabi.newpipe.MainActivity">
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"/>
android:orientation="vertical"
tools:context="org.schabi.newpipe.MainActivity">
<FrameLayout
android:id="@+id/fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize" />
<include layout="@layout/toolbar_layout"/>
<include layout="@layout/toolbar_layout" />
</FrameLayout>
</merge>
<android.support.design.widget.NavigationView
android:id="@+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/drawer_items" />
</android.support.v4.widget.DrawerLayout>

View File

@@ -244,7 +244,7 @@
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:src="?attr/options"
android:src="@drawable/ic_more_vert_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"/>
</RelativeLayout>

View File

@@ -31,10 +31,14 @@
android:layout_below="@+id/itemTitleView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_uploader_text_size"
android:visibility="gone"
tools:visibility="visible"
tools:text="TYPE" />
tools:text="UPLOADER" />
</RelativeLayout>

View File

@@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="@color/dark_youtube_primary_color"
android:background="?attr/colorPrimary"
app:tabGravity="fill"/>
<android.support.v4.view.ViewPager

View File

@@ -273,7 +273,7 @@
android:paddingBottom="6dp"
android:paddingTop="6dp"
android:text="@string/controls_background_title"
android:textSize="12sp"/>
android:textSize="12sp" />
</RelativeLayout>
<!--UPLOADER-->

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:button="@null"
android:drawablePadding="24dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:maxLines="2"
android:minHeight="?attr/listPreferredItemHeightSmall"
android:paddingEnd="?attr/listPreferredItemPaddingRight"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:paddingStart="?attr/listPreferredItemPaddingLeft"
android:background="?attr/checked_selector_drawable"
android:textColor="?attr/textColorAlertDialogListItem"
tools:drawableLeft="?attr/play"
tools:text="Lorem ipsum dolor sit amet" />

View File

@@ -11,8 +11,6 @@
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="@color/background_notification_color"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
android:orientation="horizontal">

View File

@@ -6,8 +6,6 @@
android:layout_width="match_parent"
android:layout_height="128dp"
android:background="@color/background_notification_color"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
android:orientation="horizontal">

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="?attr/listPreferredItemPaddingLeft" />

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:id="@+id/menu_services_group">
<item
android:id="@+id/menu_service_youtube"
android:icon="@drawable/place_holder_youtube"
android:title="@string/youtube"/>
<item
android:id="@+id/menu_service_soundcloud"
android:icon="@drawable/place_holder_circle"
android:title="@string/soundcloud"/>
</group>
</menu>

View File

@@ -17,4 +17,9 @@
android:orderInCategory="996"
android:title="@string/play_queue_audio_settings"
app:showAsAction="never"/>
<item android:id="@+id/action_switch_main"
android:orderInCategory="999"
android:title="@string/switch_to_main"
app:showAsAction="never"/>
</menu>

View File

@@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.schabi.newpipe.history.HistoryActivity">
<item android:id="@+id/action_switch_popup"
android:orderInCategory="1999"
android:title="@string/switch_to_popup"
app:showAsAction="never"/>
</menu>

View File

@@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.schabi.newpipe.history.HistoryActivity">
<item android:id="@+id/action_switch_background"
android:orderInCategory="1999"
android:title="@string/switch_to_background"
app:showAsAction="never"/>
</menu>

View File

@@ -4,18 +4,19 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:icon="@drawable/ic_screen_rotation_white"
android:id="@+id/toggleOrientation"
android:title="Toggle orientation"
android:icon="@drawable/ic_screen_rotation_white"
android:title="@string/toggle_orientation"
app:showAsAction="always|withText" />
<item
android:icon="@drawable/ic_fullscreen_exit_white"
android:id="@+id/switchPopup"
android:title="Switch to popup"
android:icon="@drawable/ic_fullscreen_exit_white"
android:title="@string/switch_to_popup"
app:showAsAction="always|withText" />
<item android:icon="?audio"
<item
android:id="@+id/switchBackground"
android:title="Switch to background"
android:icon="?audio"
android:title="@string/switch_to_background"
app:showAsAction="always|withText" />
</menu>

View File

@@ -22,20 +22,20 @@
<string name="err_dir_create">"لا يمكن إنشاء مجلد للتنزيلات في '%1$s'"</string>
<string name="info_dir_created">"تم إنشاء مجلد تنزيلات في '%1$s'"</string>
<string name="install">تثبيت</string>
<string name="kore_not_found">تطبيق Kore غير موجود. هل تريد تثبيته؟</string>
<string name="kore_not_found">تطبيق Kore غير موجود. هل تريد تثبيته ؟</string>
<string name="light_theme_title">مضيء</string>
<string name="list_thumbnail_view_description">صور معاينة الفيديو</string>
<string name="m4a_description">m4a — جودة أفضل</string>
<string name="m4a_description">M4A — جودة أفضل</string>
<string name="network_error">خطأ في الشبكة</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>
<string name="open_in_browser">إفتح في متصفح</string>
<string name="play_audio">الصوت</string>
<string name="play_btn_text">تشغيل</string>
<string name="play_with_kodi_title">تشغيل بواسطة Kodi</string>
<string name="screen_rotation">التدوير</string>
<string name="search">بحث</string>
<string name="search_language_title">لغة المحتوى المفضل</string>
<string name="search_language_title">اللغة الإفتراضية للمحتوى</string>
<string name="settings">الإعدادات</string>
<string name="settings_category_appearance_title">المظهر</string>
<string name="settings_category_other_title">أخرئ</string>
@@ -43,25 +43,25 @@
<string name="share">مشاركة</string>
<string name="share_dialog_title">مشاركة بواسطة</string>
<string name="show_next_and_similar_title">عرض التالي والفيديوهات المشابهة</string>
<string name="show_play_with_kodi_summary">عرض خيار لتشغيل الفيديو بواسطة Kodi Media Center.</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_title">عرض خيار التشغيل بواسطة Kodi</string>
<string name="theme_title">السمة</string>
<string name="upload_date_text">تم نشرها في %1$s</string>
<string name="upload_date_text">نُشِرت في %1$s</string>
<string name="url_not_supported_toast">الرابط غير مدعوم</string>
<string name="use_external_audio_player_title">استخدام مشغل صوت خارجي</string>
<string name="use_external_video_player_title">استخدام مشغل فيديو خارجي</string>
<string name="use_tor_summary">(إختبارية) إجراء التنزيلات من خلال استخدام بروكسي Tor لزيادة الخصوصية ( تشغيل الفيديو المباشر غير مدعوم حتى الأن ).</string>
<string name="use_tor_title">استخدام Tor</string>
<string name="view_count_text">%1$s المشاهدات</string>
<string name="webm_description">صيغة حرة—WebM</string>
<string name="view_count_text">%1$s مشاهدات</string>
<string name="webm_description">WebM—صيغة حرة</string>
<string name="blocked_by_gema">تم حجبه بواسطة GEMA</string>
<string name="content_not_available">المحتوى غير متاح.</string>
<string name="content_not_available">المحتوى غير متاح</string>
<string name="could_not_load_thumbnails">لم يتمكن من تحميل كل صور المعاينة</string>
<string name="general_error">خطأ</string>
<string name="parsing_error">لا يمكن تحليل الموقع.</string>
<string name="youtube_signature_decryption_error">لا يمكن فك تشفير توقيع رابط الفيديو.</string>
<string name="parsing_error">تعذرت عملية تحليل الموقع</string>
<string name="youtube_signature_decryption_error">تعذر فك تشفير توقيع رابط الفيديو</string>
<string name="main_bg_subtitle">انقر على البحث للبدء</string>
<string name="subscribe_button_title">إشترك</string>
<string name="subscribe_button_title">إشتراك</string>
<string name="subscribed_button_title">مشترك</string>
<string name="tab_main">الرئيسية</string>
<string name="tab_subscriptions">الإشتراكات</string>
@@ -84,8 +84,8 @@
<string name="tab_about">عن التطبيق</string>
<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="open_in_popup_mode">إفتح في نافذة منبثقه</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>
@@ -154,7 +154,7 @@
<string name="error_snackbar_action">تقرير</string>
<string name="what_device_headline">معلومات:</string>
<string name="what_happened_headline">ماذا حدث:</string>
<string name="info_labels"></string>
<string name="info_labels">What:\\nRequest:\\nContent Lang:\\nService:\\nGMT Time:\\nPackage:\\nVersion:\\nOS version:\\nGlob. IP range:</string>
<string name="your_comment">تعليقك (باللغة الإنجليزية):</string>
<string name="error_details_headline">تفاصيل:</string>
@@ -176,12 +176,12 @@
<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"></item>
<item quantity="other"></item>
<item quantity="zero">صفر</item>
<item quantity="one">%s مشترك</item>
<item quantity="two">اثنان</item>
<item quantity="few">قليل</item>
<item quantity="many">كثير</item>
<item quantity="other">%s مشتركون</item>
</plurals>
<string name="no_views">لاتوجد مشاهدات</string>
@@ -226,13 +226,13 @@
<string name="tab_licenses">التراخيص</string>
<string name="app_description">واجهة أمامية لليوتوب مجانية مفتوحة المصدر و خفيفة الوزن لنظام التشغيل أندرويد.</string>
<string name="contribution_title">ساهم</string>
<string name="contribution_encouragement">إذا كان لديك أفكار؛ او ترجمة، او تغييرات على التصميم، او تنظيف وتحسين الكود البرمجي ، أو تغييرات ثقيلة على الكود البرمجي، مساعدتك دائما موضع ترحيب. وكلما تم ذلك كلما كان ذلك أفضل!</string>
<string name="contribution_encouragement">إذا كانت لديك أفكار؛ أو ترجمة، أو تغييرات تخص التصميم، أو تنظيف و تحسين الشفرة البرمجية ، أو تعديلات عميقة عليها، فتذكر أنّ مساعدتك دائما موضع ترحيب. وكلما أتممنا شيئا كلما كان ذلك أفضل !</string>
<string name="view_on_github">عرض على GitHub</string>
<string name="donation_title">تبرع</string>
<string name="donation_encouragement">يتم تطوير NewPipe من قبل المتطوعين الذين يقضون وقت فراغهم لتقديم أفضل تجربة لك. الآن حان الوقت لإعطاء مرة أخرى للتأكد من المطورين لدينا يمكن أن تجعل NewPipe أكثر و أفضل بينما نتمتع بكوب من جافا!</string>
<string name="give_back">تبرع</string>
<string name="website_title">الموقع</string>
<string name="website_encouragement">للحصول على مزيد من المعلومات وآخر الأخبار حول NewPipe الرجاء زيارة موقعنا على الانترنت.</string>
<string name="website_encouragement">للحصول على مزيد من المعلومات و آخر الأخبار حول NewPipe الرجاء زيارة موقعنا على الانترنت.</string>
<string name="app_license_title">تراخيص NewPipe</string>
<string name="read_full_license">قراءة الترخيص</string>
@@ -262,4 +262,48 @@
<string name="play_queue_audio_settings">إعدادات الصوت</string>
<string name="start_here_on_main">بدء التشغيل هنا</string>
<string name="start_here_on_popup">تشغيل هنا في وضع النافذة المنبثقة</string>
</resources>
<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">اثنان</item>
<item quantity="few">قليل</item>
<item quantity="many">كثير</item>
<item quantity="other">%s مشاهدات</item>
</plurals>
<plurals name="videos">
<item quantity="zero">صفر</item>
<item quantity="one">%s فيديو</item>
<item quantity="two">اثنان</item>
<item quantity="few">قليل</item>
<item quantity="many">كثير</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="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="preferred_player_share_menu_title">\@string/preferred_player_settings_title</string>
</resources>

View File

@@ -172,7 +172,7 @@ otevření ve vyskakovacím okně</string>
<string name="show_search_suggestions_summary">Zobrazovat návrhy při vyhledávání</string>
<string name="enable_search_history_title">Historie vyhledávání</string>
<string name="enable_search_history_summary">Hledané výrazy lokálně uchovávat</string>
<string name="enable_watch_history_title">Historie</string>
<string name="enable_watch_history_title">Historie sledování</string>
<string name="enable_watch_history_summary">Evidovat zhlédnutá videa</string>
<string name="resume_on_audio_focus_gain_title">Přehrávat po přechodu do popředí</string>
<string name="resume_on_audio_focus_gain_summary">Pokračovat v přehrávání po přerušení (např. hovor)</string>
@@ -204,8 +204,7 @@ otevření ve vyskakovacím okně</string>
<plurals name="subscribers">
<item quantity="one">%s odběratel</item>
<item quantity="few">%s odběratelé</item>
<item quantity="many">%s odběratelů</item>
<item quantity="other"/>
<item quantity="other">%s odběratelů</item>
</plurals>
<string name="no_views">Žádná zhlédnutí</string>
@@ -219,8 +218,7 @@ otevření ve vyskakovacím okně</string>
<plurals name="videos">
<item quantity="one">%s video</item>
<item quantity="few">%s videa</item>
<item quantity="many">%s videí</item>
<item quantity="other"/>
<item quantity="other">%s videí</item>
</plurals>
<string name="settings_category_downloads_title">Stahování</string>
@@ -300,4 +298,13 @@ otevření ve vyskakovacím okně</string>
<string name="give_back">Daruj</string>
<string name="website_title">Webová stránka</string>
<string name="website_encouragement">Pro další informace a poslední novinky o NewPipe navštivte naši stránku.</string>
<string name="default_content_country_title">Země výchozího obsahu</string>
<string name="service_title">Služba</string>
<string name="toggle_orientation">Změna orientaci</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>
</resources>

View File

@@ -145,31 +145,30 @@
<string name="disabled">Deaktiviert</string>
<string name="use_old_player_title">Benutze den alten Player</string>
<string name="open_in_popup_mode">Im Popup-Modus öffnen</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 Popup-Modus ab</string>
<string name="popup_mode_share_menu_title">NewPipe Popup-Modus</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 Popup-Modus erforderlich</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 Popups</string>
<string name="default_popup_resolution_title">Standardauflösung des Pop-ups</string>
<string name="show_higher_resolutions_title">Zeige höhere Auflösungen an</string>
<string name="show_higher_resolutions_summary">Nur einige Geräte unterstützen das Abspielen von 2K-/4K-Videos</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">Popup</string>
<string name="controls_popup_title">Pop-up</string>
<string name="popup_remember_size_pos_title">Größe und Position des Popups merken</string>
<string name="popup_remember_size_pos_title">Größe und Position des Pop-ups merken</string>
<string name="use_external_video_player_summary">Manche Auflösungen werden KEINE Tonspur haben, wenn diese Option eingeschaltet ist</string>
<string name="popup_remember_size_pos_summary">Letzte Größe und Position des Popups merken</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 des Players mit Gesten steuern</string>
<string name="player_gesture_controls_summary">Benutze Gesten um Helligkeit und Lautstärke zu justieren</string>
<string name="show_search_suggestions_title">Durchsuche Vorschläge</string>
<string name="show_search_suggestions_summary">Zeige Vorschläge beim Suchen</string>
<string name="settings_category_popup_title">Popup</string>
<string name="settings_category_popup_title">Pop-up</string>
<string name="filter">Filter</string>
<string name="refresh">Aktualisieren</string>
<string name="clear">Leeren</string>
@@ -224,9 +223,9 @@
<string name="notification_channel_name">NewPipe Benachrichtigung</string>
<string name="notification_channel_description">Benachrichtigungen für NewPipe Hintergrund- und Popup-Player</string>
<string name="notification_channel_description">Benachrichtigungen für NewPipe Hintergrund- und Pop-up Player</string>
<string name="tab_main">Übersicht</string>
<string name="tab_main">Main</string>
<string name="settings_category_player_behavior_title">Verhalten</string>
<string name="settings_category_history_title">Verlauf</string>
<string name="playlist">Playlist</string>
@@ -263,7 +262,7 @@
<string name="select_a_channel">Wähle einen Kanal aus</string>
<string name="no_channel_subscribed_yet">Noch kein Kanal abonniert</string>
<string name="trending">Trends</string>
<string name="popup_playing_append">In der Warteschlange des Popup-Players</string>
<string name="popup_playing_append">In der Warteschlange des Pop-up Players</string>
<string name="play_all">Alles abspielen</string>
<string name="play_queue_remove">Entfernen</string>
@@ -274,7 +273,7 @@
<string name="feed_page_summary">Feed-Seite</string>
<string name="channel_page_summary">Kanal-Seite</string>
<string name="title_activity_background_player">Hintergrund-Player</string>
<string name="title_activity_popup_player">Popup-Player</string>
<string name="title_activity_popup_player">Pop-up Player</string>
<string name="play_queue_stream_detail">Details</string>
<string name="top_50">Top 50</string>
<string name="player_unrecoverable_failure">Nicht behebbarer Wiedergabefehler aufgetreten</string>
@@ -284,11 +283,11 @@
<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ücktgehalten wird</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 und brandheiß</string>
<string name="new_and_hot">Neu &amp; Heiß</string>
<string name="hold_to_append">Halten zum Hinzufügen zur Warteschleife</string>
<string name="show_hold_to_append_title">Gedrückt halten, um Tipp hinzuzufügen anzeigen</string>
<string name="show_hold_to_append_title">\"Gedrückt halten, um Tipp hinzuzufügen\" anzeigen</string>
<string name="unknown_content">[Unbekannt]</string>
<string name="enqueue_on_background">In Warteschlange für Hintergrundwiedergabe</string>
@@ -301,4 +300,32 @@
<string name="website_title">Website</string>
<string name="website_encouragement">Um mehr Informationen und die aktuellsten Nachrichten über NewPipe zu bekommen, besuche unsere Website.</string>
<string name="donation_encouragement">NewPipe wird von Freiwilligen entwickelt, die ihre Freizeit damit verbringen, dir das beste Erlebnis zu bieten. Jetzt ist es an der Zeit, etwas zurückzugeben, um sicherzustellen, dass unsere Entwickler NewPipe noch besser machen können, während sie eine Tasse Java genießen!</string>
</resources>
<string name="service_title">Service</string>
<string name="no_player_found_toast">Kein Streamplayer gefunden (Du kannst VLC installieren, um ihn abzuspielen)</string>
<string name="default_content_country_title">Standard-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">Zu Popup wechseln</string>
<string name="switch_to_main">Zur Hauptseite 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="preferred_player_share_menu_dialog_title">Mit bevorzugtem Player öffnen</string>
<string name="preferred_player_settings_title">Bevorzugter Player</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">Der angeforderte Inhalt wird geladen</string>
</resources>

View File

@@ -34,7 +34,7 @@
<string name="theme_title">Tema</string>
<string name="dark_theme_title">Oscuro</string>
<string name="light_theme_title">Ligero</string>
<string name="light_theme_title">Claro</string>
<string name="settings_category_appearance_title">Apariencia</string>
<string name="settings_category_other_title">Otros</string>
@@ -59,7 +59,7 @@
<string name="youtube_signature_decryption_error">No se pudo descifrar la URL del vídeo</string>
<string name="parsing_error">No se pudo analizar el sitio web</string>
<string name="show_next_and_similar_title">Mostrar vídeos siguientes y similares</string>
<string name="search_language_title">Idioma por defecto del contenido</string>
<string name="search_language_title">Idioma del contenido por defecto</string>
<string name="list_thumbnail_view_description">Vista previa del vídeo</string>
<string name="detail_thumbnail_view_description">Vista previa del vídeo</string>
<string name="detail_likes_img_view_description">Me gusta</string>
@@ -127,7 +127,7 @@
<string name="app_ui_crash">La interfaz de la app dejó de funcionar</string>
<string name="info_labels">Lo sucedido:\\nSolicitud:\\nIdioma del contenido:\\nServicio:\\nHora GMT:\\nPaquete:\\nVersión:\\nVersión del S.O:\\nRango global de la IP:</string>
<string name="black_theme_title">Oscuro</string>
<string name="black_theme_title">Negro</string>
<string name="all">Todo</string>
<string name="channel">Canal</string>
@@ -284,7 +284,7 @@ abrir en modo popup</string>
<string name="title_activity_background_player">Reproductor de fondo</string>
<string name="title_activity_popup_player">Reproductor popup</string>
<string name="play_queue_remove">Remover</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>
@@ -294,12 +294,41 @@ abrir en modo 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">Desplegar consejo \"Mantener para poner en la fila\"</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 fila</string>
<string name="hold_to_append">Mantener para poner en la cola</string>
<string name="donation_title">Donar</string>
<string name="donation_encouragement">NewPipe es desarrollado por voluntarios que emplean su tiempo libre en mejorar tu experiencia. ¡ Ahora puedes devolver el favor para asegurar que los desarrolladores puedan crear un NewPipe aún mejor mientras saborean una taza de Java !</string>
<string name="give_back">Donar</string>
<string name="website_title">Página web</string>
<string name="website_encouragement">Para obtener más información y las últimas noticias sobre NewPipe, visita nuestra web.</string>
</resources>
<string name="default_content_country_title">País del contenido por defecto</string>
<string name="toggle_orientation">Alternar orientación</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 streaming (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="preferred_player_share_menu_title">\@string/preferred_player_settings_title</string>
<string name="preferred_player_share_menu_dialog_title">Abrir con el reproductor preferido</string>
<string name="preferred_player_settings_title">Reproductor preferido</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">El contenido solicitado se está cargando</string>
</resources>

View File

@@ -139,7 +139,7 @@
<string name="start">Hasi</string>
<string name="pause">Pausatu</string>
<string name="view">Ikusi</string>
<string name="view">Jo</string>
<string name="delete">Ezabatu</string>
<string name="checksum">Egiaztaketa-batura</string>
@@ -179,7 +179,7 @@
<string name="app_license_title">NewPipe Lizentzia</string>
<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">Parte hartzea</string>
<string name="contribution_title">Hartu parte</string>
<string name="subscribe_button_title">Harpidetu</string>
<string name="subscribed_button_title">Harpidetuta</string>
<string name="channel_unsubscribed">Kanaletik harpidetza kenduta</string>
@@ -244,4 +244,77 @@
<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_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">Huts egin du jario hau erreproduzitzean</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 bere denbora librea zuri esperientziarik onena ekartzeko ematen duten boluntarioek garatzen dute. Orain zerbait atzera emateko unea da, garatzaileek NewPipe hobetu ahal izan dezaten Javako kafe bat hartzen duten bitartean!</string>
<string name="give_back">Egin dohaintza</string>
<string name="website_title">Webgunea</string>
<string name="website_encouragement">NewPipe aplikazioari buruzko informazio gehiago eta azken berriak jasotzeko bisitatu gure webgunea.</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>
<string name="subscription_page_summary">Harpidetza orria</string>
<string name="feed_page_summary">Jario-orria</string>
<string name="channel_page_summary">Kanal-orria</string>
<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>
<string name="new_and_hot">Berria eta arrakastatsua</string>
<string name="title_activity_background_player">Bigarren planoko erreproduzigailua</string>
<string name="title_activity_popup_player">Laster-leiho erreproduzigailua</string>
<string name="play_queue_remove">Kendu</string>
<string name="play_queue_stream_detail">Xehetasunak</string>
<string name="play_queue_audio_settings">Audio ezarpenak</string>
<string name="hold_to_append">Mantendu ilaran jartzeko</string>
<string name="enqueue_on_background">Jarri ilaran bigarren planoan</string>
<string name="enqueue_on_popup">Jarri ilaran laster-leihoan</string>
<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="preferred_player_share_menu_dialog_title">Ireki gogoko erreproduzigailuarekin</string>
<string name="preferred_player_settings_title">Gogoko erreproduzigailua</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">Eskatutako edukia kargatzen ari da</string>
</resources>

View File

@@ -5,8 +5,8 @@
<string name="default_resolution_title">Résolution par défaut</string>
<string name="did_you_mean">Vouliez-vous dire : %1$s ?</string>
<string name="download">Télécharger</string>
<string name="download_path_title">Chemin de téléchargement</string>
<string name="download_path_dialog_title">Entrer le chemin de téléchargement des vidéos</string>
<string name="download_path_title">Chemin de téléchargement vidéo</string>
<string name="download_path_dialog_title">Entrez le chemin de téléchargement des vidéos</string>
<string name="download_path_summary">Chemin de stockage des vidéos téléchargées</string>
<string name="install">Installer</string>
<string name="kore_not_found">Lapplication Kore est introuvable. L\'installer ?</string>
@@ -29,7 +29,7 @@
<string name="download_dialog_title">Télécharger</string>
<string name="next_video_title">Vidéo suivante</string>
<string name="show_next_and_similar_title">Afficher les vidéos suivantes et similaires</string>
<string name="url_not_supported_toast">URL non pris en charge</string>
<string name="url_not_supported_toast">Lien non pris en charge</string>
<string name="settings_category_video_audio_title">Vidéo et audio</string>
<string name="settings_category_other_title">Autre</string>
@@ -37,7 +37,7 @@
<string name="detail_thumbnail_view_description">Miniature daperçu vidéo</string>
<string name="detail_dislikes_img_view_description">Je naime pas</string>
<string name="detail_likes_img_view_description">Jaime</string>
<string name="search_language_title">Langue par défaut du contenu</string>
<string name="search_language_title">Langue du contenu par défaut</string>
<string name="detail_uploader_thumbnail_view_description">Miniature de lavatar de lutilisateur</string>
<string name="use_external_video_player_title">Utiliser un lecteur vidéo externe</string>
<string name="use_external_audio_player_title">Utiliser un lecteur audio externe</string>
@@ -53,7 +53,7 @@
<string name="settings_category_appearance_title">Apparence</string>
<string name="network_error">Erreur réseau</string>
<string name="download_path_audio_title">Chemin de téléchargement de l\'audio</string>
<string name="download_path_audio_title">Chemin de téléchargement audio</string>
<string name="download_path_audio_summary">Chemin de stockage des fichiers audio téléchargés</string>
<string name="download_path_audio_dialog_title">Entrez le chemin de téléchargement des fichiers audio</string>
@@ -66,12 +66,12 @@
<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">Afficher le contenu soumis à une restriction d\'âge</string>
<string name="duration_live">En direct</string>
<string name="show_age_restricted_content_title">Afficher le contenu avec restriction d\'âge</string>
<string name="duration_live">Direct</string>
<string name="could_not_load_thumbnails">Impossible de charger toutes les miniatures</string>
<string name="youtube_signature_decryption_error">Erreur lors du décryptage du lien</string>
<string name="light_parsing_error">Impossible d\'analyser le site complètement</string>
<string name="youtube_signature_decryption_error">Impossible de déchiffrer la signature du lien</string>
<string name="light_parsing_error">Impossible d\'analyser complètement le site web</string>
<string name="live_streams_not_supported">Il s\'agit d\'un direct, non supporté pour le moment.</string>
<string name="sorry_string">Désolé, une erreur inattendue s\'est produite.</string>
<string name="autoplay_by_calling_app_summary">Lire automatiquement la vidéo lorsque NewPipe est appelée par une autre application</string>
@@ -93,7 +93,7 @@
<string name="user_report">Rapport utilisateur</string>
<string name="error_snackbar_action">SIGNALER</string>
<string name="could_not_setup_download_menu">Impossible de mettre en place le menu de téléchargement</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>
@@ -113,15 +113,15 @@
<string name="msg_error">Erreur</string>
<string name="msg_server_unsupported">Serveur non supporté</string>
<string name="msg_exists">Fichier déjà existant</string>
<string name="msg_url_malform">URL malformée ou internet indisponible</string>
<string name="msg_url_malform">Lien malformé ou internet indisponible</string>
<string name="msg_running">Téléchargement NewPipe</string>
<string name="msg_running_detail">Toucher pour plus de détails</string>
<string name="msg_running_detail">Appuyer pour plus de détails</string>
<string name="msg_wait">Veuillez patienter…</string>
<string name="msg_copied">Copié dans le presse-papier</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">Limage ne peut pas être chargée</string>
<string name="app_ui_crash">Lappli/linterface utilisateur a crashé</string>
<string name="could_not_load_image">Impossible de charger l\'image</string>
<string name="app_ui_crash">Lappli/linterface a crashé</string>
<string name="reCaptchaActivity">reCAPTCHA</string>
<string name="black_theme_title">Noir</string>
@@ -130,13 +130,13 @@
<string name="channel">Chaîne</string>
<string name="reCaptcha_title">Test reCAPTCHA</string>
<string name="recaptcha_request_toast">Test reCAPTCHA demandé</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 dans le lecteur pop-up</string>
<string name="popup_mode_share_menu_title">Lecteur pop-up de NewPipe</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">Lire dans le lecteur pop-up</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>
@@ -147,38 +147,38 @@
<string name="short_thousand">K</string>
<string name="short_million">M</string>
<string name="msg_popup_permission">Cette permission est nécessaire pour
\nutiliser le mode pop-up</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">Pop-up</string>
<string name="controls_popup_title">Fenêtre</string>
<string name="default_popup_resolution_title">Taille du lecteur pop-up</string>
<string name="default_popup_resolution_title">Résolution de la fenêtre par défaut</string>
<string name="show_higher_resolutions_title">Afficher des résolutions plus élevées</string>
<string name="show_higher_resolutions_summary">Seulement certains périphériques supportent la lecture 2K/4K</string>
<string name="show_higher_resolutions_summary">Certains appareils uniquement 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 du lecteur pop-up</string>
<string name="popup_remember_size_pos_summary">Mémoriser le dernier emplacement et la taille du lecteur pop-up</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">Pop-up</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">Md</string>
<string name="short_billion">B</string>
<string name="use_external_video_player_summary">Certaines résolutions n\'auront PAS de son si cette option est activée</string>
<string name="player_gesture_controls_summary">Utilisez les gestes pour contrôler la luminosité et le volume du lecteur</string>
<string name="show_search_suggestions_title">Chercher des suggestions</string>
<string name="show_search_suggestions_summary">Montrer les suggestions pendant la recherche</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="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ésabonner de la chaîne</string>
<string name="channel_unsubscribed">Désabonné de la chaîne</string>
<string name="tab_main">Principal</string>
<string name="tab_subscriptions">Abonnements</string>
@@ -202,8 +202,8 @@
<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">Incapable de changer l\'abonnement</string>
<string name="subscription_update_failed">Incapable de mettre à jour l\'abonnement</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>
@@ -212,11 +212,11 @@
<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">Sauvegarder les recherches sur l\'appareil</string>
<string name="enable_search_history_summary">Conserver les recherches sur l\'appareil</string>
<string name="enable_watch_history_title">Historique</string>
<string name="title_activity_history">Historique</string>
<string name="title_history_search">Recherché</string>
<string name="title_history_view">Vue</string>
<string name="title_history_view">Regardé</string>
<string name="history_disabled">L\'historique est désactivé</string>
<string name="action_history">Historique</string>
<string name="history_empty">L\'historique est vide</string>
@@ -231,10 +231,10 @@
<string name="settings_category_player_behavior_title">Comportement</string>
<string name="settings_category_history_title">Historique</string>
<string name="playlist">Liste de lecture</string>
<string name="notification_channel_description">Notifications pour les lecteurs \"Arrière-plan\" et \"Pop-up\" de NewPipe</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">Rien à voir ici</string>
<string name="empty_subscription_feed_subtitle">Aucun contenu</string>
<string name="no_subscribers">Aucun abonné</string>
<plurals name="subscribers">
@@ -242,10 +242,10 @@
<item quantity="other">%s abonnés</item>
</plurals>
<string name="no_views">Aucun visionnage</string>
<string name="no_views">Aucune vue</string>
<plurals name="views">
<item quantity="one">%s visionnage</item>
<item quantity="other">%s visionnages</item>
<item quantity="one">%s vue</item>
<item quantity="other">%s vues</item>
</plurals>
<string name="no_videos">Aucune vidéo</string>
@@ -256,31 +256,31 @@
<string name="charset_most_special_characters">Caractères spéciaux</string>
<string name="item_deleted">Objet effacé</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="blank_page_summary">Page vide</string>
<string name="subscription_page_summary">Abonnements</string>
<string name="feed_page_summary">Page de Flux</string>
<string name="channel_page_summary">Page de la chaîne</string>
<string name="select_a_channel">Sélectionnez une chaîne</string>
<string name="select_a_channel">Sélectionner une chaîne</string>
<string name="trending">Populaires</string>
<string name="top_50">Top 50</string>
<string name="new_and_hot">Nouveau &amp; populaire</string>
<string name="background_player_append">Mettre en file d\'attente du lecteur en arrière plan</string>
<string name="popup_playing_append">Mettre en file d\'attente du lecteur pop-up</string>
<string name="play_all">Lire tout</string>
<string name="background_player_append">Mis en file d\'attente du lecteur en arrière-plan</string>
<string name="popup_playing_append">Mis en file d\'attente du lecteur en fenêtré</string>
<string name="play_all">Tout lire</string>
<string name="player_stream_failure">Échec de la lecture de cette vidéo</string>
<string name="player_stream_failure">Échec de la lecture de 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">Encore aucune chaîne souscrite</string>
<string name="title_activity_background_player">Lecteur en arrière plan</string>
<string name="title_activity_popup_player">Lecteur pop-up</string>
<string name="title_activity_background_player">Lecteur en arrière-plan</string>
<string name="title_activity_popup_player">Lecteur en fenêtré</string>
<string name="play_queue_remove">Retirer</string>
<string name="play_queue_stream_detail">Détails</string>
<string name="play_queue_audio_settings">Réglages audio</string>
<string name="play_queue_audio_settings">Paramètres audio</string>
<string name="show_hold_to_append_title">Afficher l\'aide \"Appui long pour mettre en file d\'attente\"</string>
<string name="show_hold_to_append_summary">Afficher l\'aide en restant appuyé sur les boutons \"Arrière-plan\" et \"Pop-up\" sur la page de détails d\'une vidéo</string>
<string name="show_hold_to_append_summary">Afficher l\'aide 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>
@@ -290,14 +290,42 @@
<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 fond</string>
<string name="enqueue_on_popup">Mettre en file d\'attente du lecteur pop-up</string>
<string name="enqueue_on_background">Mettre en file d\'attente en arrière-plan</string>
<string name="enqueue_on_popup">Mettre en file d\'attente en fenêtré</string>
<string name="start_here_on_main">Démarrer ici</string>
<string name="start_here_on_background">Démarrer ici en fond</string>
<string name="start_here_on_popup">Démarrer dans le lecteur pop-up</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_encouragement">NewPipe est développé par des volontaires sur leur temps libre afin de vous proposer la meilleur expérience. Maintenant il est temps de leurs 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">Pour obtenir plus d\'informations et les dernières nouvelles à propos de NewPipe, visitez notre site Internet.</string>
<string name="give_back">Donner en retour</string>
<string name="default_content_country_title">Pays du contenu par défaut</string>
<string name="toggle_orientation">Rotation</string>
<string name="switch_to_background">Basculer en arrière-plan</string>
<string name="switch_to_popup">Basculer en fenêtré</string>
<string name="switch_to_main">Basculer en 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="preferred_player_share_menu_dialog_title">Ouvrir avec le lecteur préféré</string>
<string name="preferred_player_settings_title">Lecteur préféré</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">Le contenu demandé est en chargement</string>
</resources>

View File

@@ -178,24 +178,18 @@
<plurals name="subscribers">
<item quantity="one">%s עוקב</item>
<item quantity="two">%s עוקבים</item>
<item quantity="many"></item>
<item quantity="other"></item>
</plurals>
<string name="no_views">אין תצוגות</string>
<plurals name="views">
<item quantity="one">תצוגה %s</item>
<item quantity="two">%s תצוגות</item>
<item quantity="many"></item>
<item quantity="other"></item>
</plurals>
<string name="no_videos">אין סרטונים</string>
<plurals name="videos">
<item quantity="one">סרטון %s</item>
<item quantity="two">%s סרטונים</item>
<item quantity="many"></item>
<item quantity="other"></item>
</plurals>
<string name="start">התחל</string>

View File

@@ -280,4 +280,10 @@
<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>
</resources>
<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>
</resources>

View File

@@ -307,4 +307,33 @@
<string name="website_encouragement">Per ricevere maggiori informazioni e le ultime novità su NewPipe visita il nostro sito web.</string>
<string name="donation_encouragement">NewPipe è sviluppato da volontari che spendono il loro tempo libero per regalarti la migliore esperienza. È tempo di restituire il favore permettendo ai nostri sviluppatori di migliorare ulteriormente NewPipe mentre gustano una tazza di Giava!</string>
<string name="give_back">Restituisci</string>
</resources>
<string name="default_content_country_title">Paese predefinito per i contenuti</string>
<string name="toggle_orientation">Cambia orientamento</string>
<string name="switch_to_background">Cambia in background</string>
<string name="switch_to_popup">Cambia in visualizzazione a comparsa</string>
<string name="switch_to_main">Cambia al menù principale</string>
<string name="service_title">Servizio</string>
<string name="drawer_open">"Apri il menù "</string>
<string name="drawer_close">Chiudi il menù</string>
<string name="no_player_found_toast">Nessun riproduttore 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 riproduttori esterni non supportano questa tipologia di collegamenti</string>
<string name="invalid_url_toast">URL invalido</string>
<string name="video_streams_empty">Nessun flusso video trovato</string>
<string name="audio_streams_empty">Nessun flusso audio trovato</string>
<string name="preferred_player_share_menu_title">Riproduttore preferito</string>
<string name="preferred_player_share_menu_dialog_title">Apri con il riproduttore preferito</string>
<string name="preferred_player_settings_title">Riproduttore preferito</string>
<string name="video_player">Riproduttore video</string>
<string name="background_player">Riproduttore di fondo</string>
<string name="popup_player">Riproduttore a comparsa</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">Il contenuto richiesto sta caricando</string>
</resources>

View File

@@ -1,25 +1,25 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="upload_date_text">%1$s に公開</string>
<string name="no_player_found">ストリームのプレイヤーが見つかりません。VLC を入手しますか</string>
<string name="no_player_found">動画プレイヤーが見つかりません。VLC を入手しますか</string>
<string name="install">入手</string>
<string name="cancel">取り消し</string>
<string name="open_in_browser">ブラウザーで開く</string>
<string name="open_in_browser">ブラウザで開く</string>
<string name="share">共有</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="choose_browser">ブラウザを選択</string>
<string name="screen_rotation">回転</string>
<string name="download_path_title">動画を保存する場所</string>
<string name="download_path_summary">動画を保存する位置</string>
<string name="download_path_summary">動画を保存する場所</string>
<string name="download_path_dialog_title">動画を保存する場所を入力して下さい</string>
<string name="default_resolution_title">基本解像度</string>
<string name="default_resolution_title">デフォルトの解像度</string>
<string name="play_with_kodi_title">Kodi で再生</string>
<string name="kore_not_found">Koreが見つかりません。Kore を入手しますか</string>
<string name="show_play_with_kodi_title">\"Kodi で再生\" 設定を表示</string>
<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>
@@ -31,15 +31,15 @@
<string name="url_not_supported_toast">URLは使用できません</string>
<string name="search_language_title">優先言語</string>
<string name="settings_category_video_audio_title">動画と音楽</string>
<string name="view_count_text">%1$s ビュー</string>
<string name="view_count_text">%1$s ビュー</string>
<string name="list_thumbnail_view_description">動画 プレビュー サムネイル</string>
<string name="detail_thumbnail_view_description">動画 プレビュー サムネイル</string>
<string name="detail_uploader_thumbnail_view_description">アップローダー サムネイル</string>
<string name="detail_dislikes_img_view_description">不適切</string>
<string name="detail_likes_img_view_description">好ましい</string>
<string name="detail_dislikes_img_view_description">低評価</string>
<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="background_player_playing_toast">背後で再生しています</string>
<string name="background_player_playing_toast">バックグラウンドで再生中</string>
<string name="play_btn_text">再生</string>
@@ -51,15 +51,15 @@
<string name="settings_category_appearance_title">外観</string>
<string name="settings_category_other_title">その他</string>
<string name="network_error">通信に異常</string>
<string name="network_error">ネットワークエラー</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="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>
<string name="general_error">エラー</string>
<string name="could_not_load_thumbnails">全てのサムネイルを読み込むことができません</string>
<string name="youtube_signature_decryption_error">動画のURL署名を復号できませんでした</string>
<string name="parsing_error">Webサイトを解析できませんでした</string>
@@ -73,7 +73,7 @@
<string name="content">内容</string>
<string name="show_age_restricted_content_title">年齢制限解除</string>
<string name="show_age_restricted_content_title">年齢制限のあるコンテンツを表示する</string>
<string name="video_is_age_restricted">この動画には、年齢制限があります。設定から制限を解除して下さい。</string>
<string name="light_parsing_error">Webサイトを完全には解析できませんでした</string>
@@ -91,34 +91,34 @@
<string name="video">動画</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="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="duration_live">生放送</string>
<string name="main_bg_subtitle">検索を選択して開始</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="checksum">整合性検査</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_error">エラー</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_detail">詳細はタップ</string>
<string name="msg_wait">暫くお待ちさい</string>
<string name="msg_copied">クリップボードに複製しました</string>
<string name="msg_wait">お待ちください</string>
<string name="msg_copied">クリップボードにコピーしました</string>
<string name="no_available_dir">利用可能な保存場所を選択して下さい</string>
<string name="downloads">保存</string>
@@ -136,13 +136,13 @@
<string name="black_theme_title"></string>
<string name="all"></string>
<string name="channel">チャンネル</string>
<string name="all">すべ</string>
<string name="channel">チャンネル</string>
<string name="short_thousand">K</string>
<string name="short_million">000000</string>
<string name="short_billion">000000000</string>
<string name="short_million">M</string>
<string name="short_billion">B</string>
<string name="yes">はい</string>
<string name="later">後で</string>
@@ -156,10 +156,10 @@
<string name="popup_playing_toast">ポップアップモードで再生中</string>
<string name="use_old_player_title">古いプレーヤーを使用する</string>
<string name="use_old_player_summary">Mediaframework プレーヤーの古いビルド。</string>
<string name="use_old_player_summary">古い内蔵のMediaframeworkプレーヤー</string>
<string name="disabled">無効</string>
<string name="default_video_format_title">お好みのビデオ フォーマット</string>
<string name="default_video_format_title">デフォルトの動画形式</string>
<string name="default_popup_resolution_title">デフォルトのポップアップ解像度</string>
<string name="show_higher_resolutions_title">高い解像度で表示</string>
@@ -172,14 +172,14 @@
<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_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_summary">プレーヤーの明るさと音量をコントロールするのにジェスチャーを使用します</string>
<string name="player_gesture_controls_summary">ジェスチャーを使用してプレーヤーの明るさと音量をコントロールする</string>
<string name="show_search_suggestions_title">検索候補</string>
<string name="show_search_suggestions_summary">検索時に候補を表示します</string>
@@ -187,18 +187,95 @@
<string name="title_activity_about">NewPipe について</string>
<string name="action_settings">設定</string>
<string name="action_about">アプリについて</string>
<string name="action_about">このアプリについて</string>
<string name="title_licenses">サードパーティー ライセンス</string>
<string name="copyright" formatted="true">© %1$s 作者 %2$s ライセンス %3$s</string>
<string name="error_unable_to_load_license">ライセンスをロードできません</string>
<string name="error_unable_to_load_license">ライセンスを読み込めません</string>
<string name="action_open_website">Web サイトを開く</string>
<string name="tab_about">アプリについて</string>
<string name="tab_about">このアプリについて</string>
<string name="tab_contributors">貢献者</string>
<string name="tab_licenses">ライセンス</string>
<string name="app_description">Androidの無料で軽量な Youtube フロントエンド。</string>
<string name="app_description">Android向けの無料で軽量なYouTubeフロントエンド。</string>
<string name="view_on_github">Github で表示</string>
<string name="app_license_title">NewPipe のライセンス</string>
<string name="contribution_encouragement">アイデア、翻訳、デザインの変更、コードのクリーニング、または本当に重いコードの変更がありますか。ヘルプは常に歓迎します。さらに良いものになりますように!</string>
<string name="contribution_encouragement">翻訳、デザインの変更、コードの整理、動作の重いコードの変更など、アイデアをお持ちではありませんか?ヘルプはいつでも歓迎します。より良いものを一緒に作り上げましょう!</string>
<string name="read_full_license">ライセンスを読む</string>
<string name="contribution_title">貢献</string>
</resources>
<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>
<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="settings_category_player_behavior_title">動作</string>
<string name="settings_category_history_title">履歴</string>
<string name="playlist">再生リスト</string>
<string name="undo">元に戻す</string>
<string name="play_all">すべて再生</string>
<string name="notification_channel_name">NewPipeの通知</string>
<string name="unknown_content">[不明]</string>
<string name="player_stream_failure">ストリームの再生に失敗しました</string>
<string name="player_unrecoverable_failure">回復不能な再生エラーが発生しました</string>
<string name="search_no_results">何も見つかりませんでした</string>
<string name="no_subscribers">チャンネル登録なし</string>
<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="charset_letters_and_digits">文字と数字</string>
<string name="charset_most_special_characters">ほとんどの特殊文字</string>
<string name="donation_title">寄付</string>
<string name="donation_encouragement">NewPipeはあなたに最高の経験をもたらすため、自由時間を費やしたボランティアによって開発されています。カップのコーヒー(Java)を楽しんでいる間に、開発者がNewPipeをより良いものにすることが出来るよう、今度はお返しをする時間です</string>
<string name="website_title">Webサイト</string>
<string name="website_encouragement">NewPipeに関する詳しい情報や最新のニュースについては、我々のWebサイトをご覧ください。</string>
<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="action_history">履歴</string>
<string name="history_empty">履歴に何もありません</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="subscription_page_summary">チャンネル登録ページ</string>
<string name="feed_page_summary">フィードページ</string>
<string name="channel_page_summary">チャンネルページ</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="trending">人気</string>
<string name="top_50">トップ50</string>
<string name="title_activity_popup_player">ポップアップ再生</string>
<string name="play_queue_remove">削除</string>
<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>
</resources>

View File

@@ -126,17 +126,15 @@
<string name="use_old_player_summary">Senas įtaisytas media grotuvas</string>
<plurals name="subscribers">
<item quantity="one">%s prenumeratorius</item>
<item quantity="few">%s prenumeratoriai</item>
<item quantity="many"/>
<item quantity="other"/>
<item quantity="one">% prenumeratorius</item>
<item quantity="few">% prenumeratoriai</item>
<item quantity="other">% prenumeratorių</item>
</plurals>
<plurals name="videos">
<item quantity="one">Vaizdo įrašai</item>
<item quantity="few"/>
<item quantity="many"/>
<item quantity="other"/>
<item quantity="one">% vaizdo įrašas</item>
<item quantity="few">% vaizdo įrašai</item>
<item quantity="other">% vaizdo įrašų</item>
</plurals>
<string name="start">Pradėti</string>
@@ -213,10 +211,9 @@
<string name="no_subscribers">Nėra prenumeratorių</string>
<string name="no_views">Nėra peržiūrų</string>
<plurals name="views">
<item quantity="one">%a peržiūra</item>
<item quantity="few"></item>
<item quantity="many"></item>
<item quantity="other"></item>
<item quantity="one">% peržiūra</item>
<item quantity="few">% peržiūros</item>
<item quantity="other">% peržiūrų</item>
</plurals>
<string name="no_videos">Nėra vaizdo įrašų</string>

View File

@@ -296,4 +296,32 @@
<string name="give_back">Bidra</string>
<string name="website_title">Nettside</string>
<string name="website_encouragement">Mer informasjon og siste nytt om NewPipe er å finne på vår nettside.</string>
</resources>
<string name="default_content_country_title">Forvalgt innholdsland</string>
<string name="service_title">Tjeneste</string>
<string name="toggle_orientation">Veksle skjermretning</string>
<string name="switch_to_background">Bytt til bakgrunnsmodus</string>
<string name="switch_to_popup">Bytt til oppsprettsmodus</string>
<string name="switch_to_main">Bytt til hovedmodus</string>
<string name="drawer_open">Åpne skuff</string>
<string name="drawer_close">Lukk skuff</string>
<string name="no_player_found_toast">Ingen strømmespiller installert (du kan installere VLC for å spille den)</string>
<string name="always">Alltid</string>
<string name="just_once">Kun én gang</string>
<string name="external_player_unsupported_link_type">Eksterne avspillere kan ikke spille lenker av disse typene</string>
<string name="invalid_url_toast">Ugyldig nettadresse</string>
<string name="video_streams_empty">Fant ingen videostrømmer</string>
<string name="audio_streams_empty">Fant ingen lydstrømmer</string>
<string name="preferred_player_share_menu_dialog_title">Åpne med foretrukket avspiller</string>
<string name="preferred_player_settings_title">Foretrukket avpsiller</string>
<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">Forespurt innhold innlastes</string>
</resources>

View File

@@ -303,4 +303,33 @@ te openen in pop-upmodus</string>
<string name="give_back">Teruggeven</string>
<string name="website_title">Website</string>
<string name="website_encouragement">Bezoek onze website voor meer informatie en het laatste nieuws over NewPipe.</string>
</resources>
<string name="default_content_country_title">Standaardinhoudsland</string>
<string name="service_title">Dienst</string>
<string name="toggle_orientation">Oriëntatie wijzigen</string>
<string name="switch_to_background">Verplaatsen naar achtergrond</string>
<string name="switch_to_popup">Verplaatsen naar pop-up</string>
<string name="switch_to_main">Verplaatsen naar normaal</string>
<string name="drawer_open">Menu openen</string>
<string name="drawer_close">Menu sluiten</string>
<string name="no_player_found_toast">Geen speler met streamondersteuning gevonden (je kan VLC installeren om het af te spelen)</string>
<string name="always">Altijd</string>
<string name="just_once">Eenmalig</string>
<string name="external_player_unsupported_link_type">Externe spelers ondersteunen deze soorten koppelingen niet</string>
<string name="invalid_url_toast">Ongeldige URL</string>
<string name="video_streams_empty">Geen videostreams gevonden</string>
<string name="audio_streams_empty">Geen audiostreams gevonden</string>
<string name="preferred_player_share_menu_title">Voorkeursspeler</string>
<string name="preferred_player_share_menu_dialog_title">Openen met voorkeursspeler</string>
<string name="preferred_player_settings_title">Voorkeursspeler</string>
<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">Info ophalen…</string>
<string name="preferred_player_fetcher_notification_message">De gevraagde inhoud is aan het laden</string>
</resources>

View File

@@ -42,7 +42,7 @@
<string name="light_theme_title">Jasny</string>
<string name="download_dialog_title">Pobrane</string>
<string name="next_video_title">Następne video</string>
<string name="next_video_title">Następne wideo</string>
<string name="show_next_and_similar_title">Pokaż następne i podobne filmy</string>
<string name="url_not_supported_toast">URL nie obsługiwany</string>
<string name="search_language_title">Preferowany język zawartości</string>
@@ -247,23 +247,18 @@
<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="other"/>
<item quantity="other">%s subskrybentów</item>
</plurals>
<plurals name="views">
<item quantity="one">%s odtworzenie</item>
<item quantity="few"/>
<item quantity="many">%s odtworzeń</item>
<item quantity="other"/>
<item quantity="other">%s odtworzeń</item>
</plurals>
<string name="no_videos">Brak filmów</string>
<plurals name="videos">
<item quantity="one">%s film</item>
<item quantity="few">%s filmów</item>
<item quantity="many"/>
<item quantity="other"/>
</plurals>
<string name="charset_most_special_characters">Większość znaków specjalnych</string>
@@ -301,4 +296,27 @@
<string name="start_here_on_main">Zacznij Odtwarzanie Tutaj</string>
<string name="start_here_on_background">Zacznij Odwarzanie Tutaj — w Tle</string>
<string name="start_here_on_popup">Zacznij Odtwarzanie Tutaj — w Okienku</string>
<string name="no_player_found_toast">Nie znaleziono odtwarzacza strumieniowego (żeby odtworzyć możesz zainstalować VLC)</string>
<string name="default_content_country_title">Domyślny kraj zawartości</string>
<string name="service_title">Usługa</string>
<string name="always">Zawsze</string>
<string name="just_once">Tylko raz</string>
<string name="toggle_orientation">Przełącz orientację</string>
<string name="switch_to_background">Odtwarzaj w tle</string>
<string name="external_player_unsupported_link_type">Zewnętrzne odtwarzacze nie obsługują linków tego typu</string>
<string name="invalid_url_toast">Nieprawidłowy URL</string>
<string name="video_streams_empty">Nie znaleziono strumieni wideo</string>
<string name="audio_streams_empty">Nie znaleziono strumieni audio</string>
<string name="preferred_player_share_menu_title">Preferowany odtwarzacz</string>
<string name="preferred_player_share_menu_dialog_title">Otwórz za pomocą preferowanego odtwarzacza</string>
<string name="preferred_player_settings_title">Preferowany odtwarzacz</string>
<string name="video_player">Odtwarzacz wideo</string>
<string name="background_player">Odtwarzacz w tle</string>
<string name="always_ask_player">Pytaj za każdym razem</string>
<string name="preferred_player_fetcher_notification_title">Informacje…</string>
<string name="preferred_player_fetcher_notification_message">Ładuję żądaną zawartość</string>
</resources>

View File

@@ -284,4 +284,30 @@ abrir em modo popup</string>
<string name="give_back">Retribuir</string>
<string name="website_title">Site oficial</string>
<string name="website_encouragement">Para obter mais informações e as últimas notícias sobre o NewPipe visite nosso Site.</string>
</resources>
<string name="no_player_found_toast">Nenhum reprodudor de stream encontrado (você pode instalar VLC para reproduzir isto)</string>
<string name="default_content_country_title">País do conteúdo padrão</string>
<string name="service_title">Serviço</string>
<string name="always">Sempre</string>
<string name="just_once">Apenas esta vez</string>
<string name="toggle_orientation">Alterar a orientação</string>
<string name="switch_to_background">Alterar para plano de fundo</string>
<string name="switch_to_popup">Alterar para Popup</string>
<string name="switch_to_main">Aletar para principal</string>
<string name="external_player_unsupported_link_type">Reprodutores externos não suportam estes tipos de links</string>
<string name="invalid_url_toast">URL inválida</string>
<string name="video_streams_empty">Nenhum stream de vídeo encontrado</string>
<string name="audio_streams_empty">Nenhum stream de áudio encontrado</string>
<string name="preferred_player_share_menu_dialog_title">Abrir com reprodutor padrão</string>
<string name="preferred_player_settings_title">Reprodutor padrão</string>
<string name="video_player">Reprodutor de vídeo</string>
<string name="background_player">Reprodutor em plano de fundo</string>
<string name="popup_player">Reprodutor popup</string>
<string name="always_ask_player">Sempre perguntar</string>
<string name="preferred_player_fetcher_notification_title">Obtendo informações…</string>
<string name="preferred_player_fetcher_notification_message">O conteúdo solicitado está carregando</string>
</resources>

View File

@@ -76,7 +76,7 @@
<string name="main_bg_subtitle">Apăsați căutare pentru a începe</string>
<string name="autoplay_by_calling_app_title">Redă automat</string>
<string name="autoplay_by_calling_app_summary">Redă automat un videoclip atunci când NewPipe este deschis din altă aplicație</string>
<string name="duration_live">în direct</string>
<string name="duration_live">În direct</string>
<string name="downloads">Descărcări</string>
<string name="downloads_title">Descărcări</string>
<string name="error_report_title">Raport de erori</string>
@@ -168,7 +168,7 @@ pentru a deschide în mod pop-up</string>
<string name="show_search_suggestions_title">Arată sugestii</string>
<string name="show_search_suggestions_summary">Arată sugestii în timpul căutării</string>
<string name="settings_category_popup_title">Pop-up</string>
<string name="settings_category_popup_title">Popup</string>
<string name="filter">Filtrează</string>
<string name="refresh">Reîmprospătare</string>
<string name="clear">Șterge</string>
@@ -192,7 +192,7 @@ pentru a deschide în mod pop-up</string>
<string name="enable_watch_history_summary">Memorează videourile văzute</string>
<string name="resume_on_audio_focus_gain_title">Reia la câștigarea focalizării</string>
<string name="resume_on_audio_focus_gain_summary">Continuă redarea după întreruperi (ex. după apeluri)</string>
<string name="settings_category_player_title">Player</string>
<string name="settings_category_player_title">"Player "</string>
<string name="settings_category_player_behavior_title">Comportament</string>
<string name="settings_category_history_title">Istoric</string>
<string name="playlist">Playlist</string>
@@ -273,4 +273,7 @@ pentru a deschide în mod pop-up</string>
<string name="trending">Trenduri</string>
<string name="top_50">Top 50</string>
<string name="new_and_hot">Tendințe</string>
</resources>
<string name="service_title">Serviciu</string>
<string name="background_player_append">Adăugaţi în playlist fundal</string>
<string name="popup_playing_append">Adăugaţi în playlist pop-up</string>
</resources>

View File

@@ -236,24 +236,21 @@
<plurals name="subscribers">
<item quantity="one">%s подписчик</item>
<item quantity="few">%s подписчика</item>
<item quantity="many">%s подписчиков</item>
<item quantity="other"/>
<item quantity="other">%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>
<item quantity="other"/>
<item quantity="other">%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>
<item quantity="other"/>
<item quantity="other">%s видео</item>
</plurals>
<string name="item_deleted">Элемент удалён</string>

Some files were not shown because too many files have changed in this diff Show More