diff --git a/.gitignore b/.gitignore
index 09cade508..f6e554c09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,8 @@
.gitignore
.gradle
/local.properties
-/.idea/workspace.xml
-/.idea/libraries
.DS_Store
/build
/captures
-.idea/gradle.xml
-.idea/misc.xml
+/app/app.iml
+/.idea
diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index 0c8ef9fd5..000000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-NewPipe
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 96cc43efa..000000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index e7bedf337..000000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/dictionaries/the_scrabi.xml b/.idea/dictionaries/the_scrabi.xml
deleted file mode 100644
index bc8411615..000000000
--- a/.idea/dictionaries/the_scrabi.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index bd4202cb3..000000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 5d1998103..000000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index ff02d86b4..000000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460d8..000000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7f4..000000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/NewPipe.iml b/NewPipe.iml
deleted file mode 100644
index 8d3b0cd6c..000000000
--- a/NewPipe.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 905208166..648a1e695 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
* Download audio only (working but, but it could be better)
* Open a video in Kodi
* Show Next/Related videos
+* Search Youtube in a specific language
## Coming Features
diff --git a/app/.gitignore b/app/.gitignore
index 6bcbd4f70..d9a86a57c 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1,3 +1,3 @@
.gitignore
/build
-app/app.iml
+app.iml
diff --git a/app/app.iml b/app/app.iml
deleted file mode 100644
index 58221a4e6..000000000
--- a/app/app.iml
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateDebugAndroidTestSources
- generateDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 5e17108de..fb41271d9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "org.schabi.newpipe"
minSdkVersion 15
targetSdkVersion 23
- versionCode 5
- versionName "0.5.0"
+ versionCode 6
+ versionName "0.6.0"
}
buildTypes {
release {
diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java
index 5cdecef66..b9bef5cfd 100644
--- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java
+++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java
@@ -77,7 +77,7 @@ public class ActionBarHandler {
int defaultResolutionPos = 0;
for(int i = 0; i < videoStreams.length; i++) {
- itemArray[i] = VideoInfo.getNameById(videoStreams[i].format) + " " + videoStreams[i].resolution;
+ itemArray[i] = MediaFormat.getNameById(videoStreams[i].format) + " " + videoStreams[i].resolution;
if(defaultResolution.equals(videoStreams[i].resolution)) {
defaultResolutionPos = i;
}
@@ -98,17 +98,15 @@ public class ActionBarHandler {
.getString(activity.getString(R.string.defaultAudioFormatPreference), "webm");
if(preferedFormat.equals("webm")) {
for(VideoInfo.AudioStream s : audioStreams) {
- if(s.format == VideoInfo.I_WEBMA) {
+ if(s.format == MediaFormat.WEBMA.id) {
audioStream = s;
}
}
} else if(preferedFormat.equals("m4a")){
for(VideoInfo.AudioStream s : audioStreams) {
- Log.d(TAG, VideoInfo.getMimeById(s.format) + " : " + Integer.toString(s.bandwidth));
- if(s.format == VideoInfo.I_M4A &&
+ if(s.format == MediaFormat.M4A.id &&
(audioStream == null || audioStream.bandwidth > s.bandwidth)) {
audioStream = s;
- Log.d(TAG, "last choosen");
}
}
}
@@ -125,15 +123,8 @@ public class ActionBarHandler {
defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
inflater.inflate(R.menu.videoitem_detail, menu);
- MenuItem playItem = menu.findItem(R.id.menu_item_play);
- MenuItem shareItem = menu.findItem(R.id.menu_item_share);
MenuItem castItem = menu.findItem(R.id.action_play_with_kodi);
- MenuItemCompat.setShowAsAction(playItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS
- | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
- MenuItemCompat.setShowAsAction(shareItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM
- | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
-
castItem.setVisible(defaultPreferences
.getBoolean(activity.getString(R.string.showPlayWidthKodiPreference), false));
@@ -143,9 +134,6 @@ public class ActionBarHandler {
public boolean onItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
- case R.id.menu_item_play:
- playVideo();
- return true;
case R.id.menu_item_share:
if(!videoTitle.isEmpty()) {
Intent intent = new Intent();
@@ -196,7 +184,7 @@ public class ActionBarHandler {
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(videoStreams[selectedStream].url),
- VideoInfo.getMimeById(videoStreams[selectedStream].format));
+ MediaFormat.getMimeById(videoStreams[selectedStream].format));
intent.putExtra(Intent.EXTRA_TITLE, videoTitle);
intent.putExtra("title", videoTitle);
@@ -235,10 +223,9 @@ public class ActionBarHandler {
}
public void downloadVideo() {
- Log.d(TAG, "bla");
if(!videoTitle.isEmpty()) {
- String videoSuffix = "." + VideoInfo.getSuffixById(videoStreams[selectedStream].format);
- String audioSuffix = "." + VideoInfo.getSuffixById(audioStream.format);
+ String videoSuffix = "." + MediaFormat.getSuffixById(videoStreams[selectedStream].format);
+ String audioSuffix = "." + MediaFormat.getSuffixById(audioStream.format);
Bundle args = new Bundle();
args.putString(DownloadDialog.FILE_SUFFIX_VIDEO, videoSuffix);
args.putString(DownloadDialog.FILE_SUFFIX_AUDIO, audioSuffix);
@@ -297,7 +284,7 @@ public class ActionBarHandler {
try {
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(audioStream.url),
- VideoInfo.getMimeById(audioStream.format));
+ MediaFormat.getMimeById(audioStream.format));
intent.putExtra(Intent.EXTRA_TITLE, videoTitle);
intent.putExtra("title", videoTitle);
activity.startActivity(intent); // HERE !!!
@@ -321,7 +308,7 @@ public class ActionBarHandler {
}
});
builder.create().show();
- Log.d(TAG, "Either no Streaming player for audio was installed, or something important crashed:");
+ Log.e(TAG, "Either no Streaming player for audio was installed, or something important crashed:");
e.printStackTrace();
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java
index edf839ac2..b6d22c44e 100644
--- a/app/src/main/java/org/schabi/newpipe/Downloader.java
+++ b/app/src/main/java/org/schabi/newpipe/Downloader.java
@@ -1,6 +1,7 @@
package org.schabi.newpipe;
import java.io.BufferedReader;
+import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
@@ -29,12 +30,25 @@ import java.net.UnknownHostException;
public class Downloader {
private static final String USER_AGENT = "Mozilla/5.0";
- public static String download(String siteUrl) {
- StringBuffer response = new StringBuffer();
+ public static String download(String siteUrl, String language) {
+ String ret = "";
try {
URL url = new URL(siteUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ con.setRequestProperty("Accept-Language", language);
+ ret = dl(con);
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ private static String dl(HttpURLConnection con) {
+ StringBuffer response = new StringBuffer();
+
+ try {
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", USER_AGENT);
@@ -57,4 +71,20 @@ public class Downloader {
}
return response.toString();
}
+
+
+ public static String download(String siteUrl) {
+ String ret = "";
+
+ try {
+ URL url = new URL(siteUrl);
+ HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ ret = dl(con);
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+
+ return ret;
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/MediaFormat.java b/app/src/main/java/org/schabi/newpipe/MediaFormat.java
new file mode 100644
index 000000000..6a37c3fd7
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/MediaFormat.java
@@ -0,0 +1,64 @@
+package org.schabi.newpipe;
+
+/**
+ * Created by Adam Howard on 08/11/15.
+ *
+ * Copyright (c) Christian Schabesberger
+ * and Adam Howard 2015
+ *
+ * VideoListAdapter.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 .
+ */
+public enum MediaFormat {
+ // id name suffix mime type
+ MPEG_4 (0x0, "MPEG-4", "mp4", "video/mp4"),
+ v3GPP (0x1, "3GPP", "3gp", "video/3gpp"),
+ WEBM (0x2, "WebM", "webm", "video/webm"),
+ M4A (0x3, "m4a", "m4a", "audio/mp4"),
+ WEBMA (0x4, "WebM", "webm", "audio/webm");
+
+ public final int id;
+ public final String name;
+ public final String suffix;
+ public final String mimeType;
+
+ MediaFormat(int id, String name, String suffix, String mimeType) {
+ this.id = id;
+ this.name = name;
+ this.suffix = suffix;
+ this.mimeType = mimeType;
+ }
+
+ public static String getNameById(int ident) {
+ for (MediaFormat vf : MediaFormat.values()) {
+ if(vf.id == ident) return vf.name;
+ }
+ return "";
+ }
+
+ public static String getSuffixById(int ident) {
+ for (MediaFormat vf : MediaFormat.values()) {
+ if(vf.id == ident) return vf.suffix;
+ }
+ return "";
+ }
+
+ public static String getMimeById(int ident) {
+ for (MediaFormat vf : MediaFormat.values()) {
+ if(vf.id == ident) return vf.mimeType;
+ }
+ return "";
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java
index 81a8aec33..d05f721a2 100644
--- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java
@@ -253,10 +253,9 @@ public class PlayVideoActivity extends AppCompatActivity {
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- } else {
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
private void adjustMediaControlMetrics() {
diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfo.java b/app/src/main/java/org/schabi/newpipe/VideoInfo.java
index 0e0e149dc..2b8dfc8e9 100644
--- a/app/src/main/java/org/schabi/newpipe/VideoInfo.java
+++ b/app/src/main/java/org/schabi/newpipe/VideoInfo.java
@@ -1,5 +1,11 @@
package org.schabi.newpipe;
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import java.util.Date;
+import java.util.Vector;
+
/**
* Created by Christian Schabesberger on 26.08.15.
*
@@ -20,82 +26,36 @@ package org.schabi.newpipe;
* along with NewPipe. If not, see .
*/
-import android.graphics.Bitmap;
-import android.util.Log;
-
-import java.util.Vector;
public class VideoInfo {
+ public String id = "";
+ public String title = "";
+ public String uploader = "";
+ public String thumbnail_url = "";
+ public Bitmap thumbnail = null;
+ public String webpage_url = "";
+ public String upload_date = "";
+ public long view_count = 0;
+
+ public String uploader_thumbnail_url = "";
+ public Bitmap uploader_thumbnail = null;
+ public String description = "";
+ public int duration = -1;
+ public int age_limit = 0;
+ public int like_count = 0;
+ public int dislike_count = 0;
+ public String average_rating = "";
+ public VideoStream[] videoStreams = null;
+ public AudioStream[] audioStreams = null;
+ public VideoInfoItem nextVideo = null;
+ public VideoInfoItem[] relatedVideos = null;
+ public int videoAvailableStatus = VIDEO_AVAILABLE;
private static final String TAG = VideoInfo.class.toString();
- // format identifier
- public static final int I_MPEG_4 = 0x0;
- public static final int I_3GPP = 0x1;
- public static final int I_WEBM = 0x2;
- public static final int I_M4A = 0x3;
- public static final int I_WEBMA = 0x4;
-
- // format name
- public static final String F_MPEG_4 = "MPEG-4";
- public static final String F_3GPP = "3GPP";
- public static final String F_WEBM = "WebM";
- public static final String F_M4A = "m4a";
- public static final String F_WEBMA = "WebM";
-
- // file suffix
- public static final String C_MPEG_4 = "mp4";
- public static final String C_3GPP = "3gp";
- public static final String C_WEBM = "webm";
- public static final String C_M4A = "m4a";
- public static final String C_WEBMA = "webm";
-
- // mimeType
- public static final String M_MPEG_4 = "video/mp4";
- public static final String M_3GPP = "video/3gpp";
- public static final String M_WEBM = "video/webm";
- public static final String M_M4A = "audio/mp4";
- public static final String M_WEBMA = "audio/webm";
-
public static final int VIDEO_AVAILABLE = 0x00;
public static final int VIDEO_UNAVAILABLE = 0x01;
- public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;//German DRM organisation; sound pretty draconian
-
- public static String getNameById(int id) {
- switch(id) {
- case I_MPEG_4: return F_MPEG_4;
- case I_3GPP: return F_3GPP;
- case I_WEBM: return F_WEBM;
- case I_M4A: return F_M4A;
- case I_WEBMA: return F_WEBMA;
- default: formatNotKnown(id);
- }
- return "";
- }
-
- public static String getSuffixById(int id) {
- switch(id) {
- case I_MPEG_4: return C_MPEG_4;
- case I_3GPP: return C_3GPP;
- case I_WEBM: return C_WEBM;
- case I_M4A: return C_M4A;
- case I_WEBMA: return C_WEBMA;
- default: formatNotKnown(id);
- }
- return "";
- }
-
- public static String getMimeById(int id) {
- switch(id) {
- case I_MPEG_4: return M_MPEG_4;
- case I_3GPP: return M_3GPP;
- case I_WEBM: return M_WEBM;
- case I_M4A: return M_M4A;
- case I_WEBMA: return M_WEBMA;
- default: formatNotKnown(id);
- }
- return "";
- }
+ public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;//German DRM organisation
public static class VideoStream {
public VideoStream(String url, int format, String res) {
@@ -106,11 +66,6 @@ public class VideoInfo {
public String resolution = "";
}
- protected static void formatNotKnown(int id) {
- Log.e(TAG, "format not known: \"" +
- Integer.toString(id) + "\". Call the programmers, they messed it up!");
- }
-
public static class AudioStream {
public AudioStream(String url, int format, int bandwidth, int samplingRate) {
this.url = url; this.format = format;
@@ -120,28 +75,5 @@ public class VideoInfo {
public int format = -1;
public int bandwidth = -1;
public int samplingRate = -1;
-
}
-
- public String id = "";
- public String uploader = "";
- public String upload_date = "";
- public String uploader_thumbnail_url = "";
- public Bitmap uploader_thumbnail = null;
- public String title = "";
- public String thumbnail_url = "";
- public Bitmap thumbnail = null;
- public String description = "";
- public int duration = -1;
- public int age_limit = 0;
- public String webpage_url = "";
- public String view_count = "";
- public String like_count = "";
- public String dislike_count = "";
- public String average_rating = "";
- public VideoStream[] videoStreams = null;
- public AudioStream[] audioStreams = null;
- public VideoInfoItem nextVideo = null;
- public VideoInfoItem[] relatedVideos = null;
- public int videoAvailableStatus = VIDEO_AVAILABLE;
}
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java
index e34f064b1..dca5f0edc 100644
--- a/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java
+++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java
@@ -28,13 +28,14 @@ public class VideoInfoItem implements Parcelable {
public String id = "";
public String title = "";
public String uploader = "";
- public String duration = "";
public String thumbnail_url = "";
public Bitmap thumbnail = null;
public String webpage_url = "";
public String upload_date = "";
public String view_count = "";
+ public String duration = "";
+
protected VideoInfoItem(Parcel in) {
id = in.readString();
title = in.readString();
diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java
index e6618ddbf..d15d6b86a 100644
--- a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java
+++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java
@@ -51,7 +51,7 @@ public class VideoInfoItemViewCreator {
}
if(info.thumbnail == null) {
- holder.itemThumbnailView.setImageResource(R.drawable.dummi_thumbnail);
+ holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
} else {
holder.itemThumbnailView.setImageBitmap(info.thumbnail);
}
diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java
index 370ac2fb2..2ba09c189 100644
--- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java
@@ -5,6 +5,7 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -60,6 +61,7 @@ public class VideoItemDetailActivity extends AppCompatActivity {
// this means the video was called though another app
if (getIntent().getData() != null) {
videoUrl = getIntent().getData().toString();
+ Log.i(TAG, "video URL passed:\"" + videoUrl + "\"");
StreamingService[] serviceList = ServiceList.getServices();
Extractor extractor = null;
for (int i = 0; i < serviceList.length; i++) {
@@ -67,8 +69,7 @@ public class VideoItemDetailActivity extends AppCompatActivity {
arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, i);
try {
currentStreamingService = i;
- extractor = ServiceList.getService(i)
- .getExtractorInstance();
+ extractor = ServiceList.getService(i).getExtractorInstance();
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java
index aab57e23f..e27d02278 100644
--- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java
@@ -2,6 +2,7 @@ package org.schabi.newpipe;
import android.app.Activity;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
@@ -29,6 +30,11 @@ import android.widget.TextView;
import android.view.MenuItem;
import java.net.URL;
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
import java.util.Vector;
@@ -216,12 +222,31 @@ public class VideoItemDetailFragment extends Fragment {
case VideoInfo.VIDEO_AVAILABLE: {
videoTitleView.setText(info.title);
uploaderView.setText(info.uploader);
- viewCountView.setText(info.view_count
+
+ Locale locale = getPreferredLocale();
+ NumberFormat nf = NumberFormat.getInstance(locale);
+ String localisedViewCount = nf.format(info.view_count);
+ viewCountView.setText(localisedViewCount
+ " " + activity.getString(R.string.viewSufix));
- thumbsUpView.setText(info.like_count);
- thumbsDownView.setText(info.dislike_count);
+
+
+ thumbsUpView.setText(nf.format(info.like_count));
+ thumbsDownView.setText(nf.format(info.dislike_count));
+
+ //this is horribly convoluted
+ //TODO: find a better way to convert YYYY-MM-DD to a locale-specific date
+ //suggestions welcome
+ int year = Integer.parseInt(info.upload_date.substring(0, 4));
+ int month = Integer.parseInt(info.upload_date.substring(5, 7));
+ int date = Integer.parseInt(info.upload_date.substring(8, 10));
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, date);
+ Date datum = cal.getTime();
+ DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
+
+ String localisedDate = df.format(datum);
uploadDateView.setText(
- activity.getString(R.string.uploadDatePrefix) + " " + info.upload_date);
+ activity.getString(R.string.uploadDatePrefix) + " " + localisedDate);
descriptionView.setText(Html.fromHtml(info.description));
descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
@@ -369,6 +394,23 @@ public class VideoItemDetailFragment extends Fragment {
}
}
+ public Locale getPreferredLocale() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+ String languageKey = getContext().getString(R.string.searchLanguage);
+ String languageCode = "en";//i know the following lines defaults languageCode to "en", but java is picky about uninitialised values
+ languageCode = sp.getString(languageKey, "en");
+
+ if(languageCode.length() == 2) {
+ return new Locale(languageCode);
+ }
+ else if(languageCode.contains("_")) {
+ String country = languageCode
+ .substring(languageCode.indexOf("_"), languageCode.length());
+ return new Locale(languageCode.substring(0, 2), country);
+ }
+ return Locale.getDefault();
+ }
+
public boolean checkIfLandscape() {
DisplayMetrics displayMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java
index ffb1c9697..856497649 100644
--- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java
@@ -103,7 +103,7 @@ public class VideoItemListActivity extends AppCompatActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_videoitem_list);
- //-------- remove this line when multiservice support is implemented ----------
+ //------ todo: remove this line when multiservice support is implemented ------
currentStreamingServiceId = ServiceList.getIdOfService("Youtube");
//-----------------------------------------------------------------------------
diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java
index 8de38c102..c9f6c0cd7 100644
--- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java
@@ -93,10 +93,10 @@ public class VideoItemListFragment extends ListFragment {
public void run() {
try {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
- String contentCountryKey = getContext().getString(R.string.contentCountry);
- String contentCountry = sp.getString(contentCountryKey, "");
- SearchEngine.Result result = engine.search(query, page, contentCountry);
- Log.i(TAG, "countryCode passed:\""+contentCountry+"\"");
+ String searchLanguageKey = getContext().getString(R.string.searchLanguage);
+ String searchLanguage = sp.getString(searchLanguageKey, "en");
+ SearchEngine.Result result = engine.search(query, page, searchLanguage);
+ Log.i(TAG, "language code passed:\""+searchLanguage+"\"");
if(run) {
h.post(new ResultRunnable(result, requestId));
}
diff --git a/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java
index 8ba344361..6d23ae038 100644
--- a/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java
+++ b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java
@@ -3,7 +3,6 @@ package org.schabi.newpipe.youtube;
import android.util.Log;
import android.util.Xml;
-import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@@ -14,12 +13,14 @@ import org.mozilla.javascript.Function;
import org.mozilla.javascript.ScriptableObject;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.Extractor;
+import org.schabi.newpipe.MediaFormat;
import org.schabi.newpipe.VideoInfo;
import org.schabi.newpipe.VideoInfoItem;
import org.xmlpull.v1.XmlPullParser;
import java.io.StringReader;
import java.net.URI;
+import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
@@ -57,16 +58,16 @@ public class YoutubeExtractor implements Extractor {
public static int resolveFormat(int itag) {
switch(itag) {
// video
- case 17: return VideoInfo.I_3GPP;
- case 18: return VideoInfo.I_MPEG_4;
- case 22: return VideoInfo.I_MPEG_4;
- case 36: return VideoInfo.I_3GPP;
- case 37: return VideoInfo.I_MPEG_4;
- case 38: return VideoInfo.I_MPEG_4;
- case 43: return VideoInfo.I_WEBM;
- case 44: return VideoInfo.I_WEBM;
- case 45: return VideoInfo.I_WEBM;
- case 46: return VideoInfo.I_WEBM;
+ case 17: return MediaFormat.v3GPP.id;
+ case 18: return MediaFormat.MPEG_4.id;
+ case 22: return MediaFormat.MPEG_4.id;
+ case 36: return MediaFormat.v3GPP.id;
+ case 37: return MediaFormat.MPEG_4.id;
+ case 38: return MediaFormat.MPEG_4.id;
+ case 43: return MediaFormat.WEBM.id;
+ case 44: return MediaFormat.WEBM.id;
+ case 45: return MediaFormat.WEBM.id;
+ case 46: return MediaFormat.WEBM.id;
default:
//Log.i(TAG, "Itag " + Integer.toString(itag) + " not known or not supported.");
return -1;
@@ -113,7 +114,7 @@ public class YoutubeExtractor implements Extractor {
JSONObject jsonObj = new JSONObject(jsonString);
//----------------------------------
- // load an parse description code
+ // load and parse description code
//----------------------------------
if (decryptionCode.isEmpty()) {
JSONObject ytAssets = jsonObj.getJSONObject("assets");
@@ -132,38 +133,27 @@ public class YoutubeExtractor implements Extractor {
@Override
public String getVideoId(String videoUrl) {
- try {
- URI uri = new URI(videoUrl);
- if(uri.getHost().contains("youtube")) {
- String query = uri.getFragment();
- if(query == null) {
- query = uri.getQuery();
- } else {
- query = query.replace("/watch?", "");
- }
- String queryElements[] = query.split("&");
- Map queryArguments = new HashMap<>();
- for (String e : queryElements) {
- String[] s = e.split("=");
- queryArguments.put(s[0], s[1]);
- }
- return queryArguments.get("v");
- } else if(uri.getHost().contains("youtu.be")) {
- // uri.getRawPath() does somehow not return the last character.
- // so we do a workaround instead.
- //return uri.getRawPath();
- String url[] = videoUrl.split("/");
- return url[url.length-1];
- } else {
- Log.e(TAG, "Error could not parse url: " + videoUrl);
+ String id = "";
+ Pattern pat;
- }
- } catch(Exception e) {
+ if(videoUrl.contains("youtube")) {
+ pat = Pattern.compile("youtube\\.com/watch\\?v=([\\-a-zA-Z0-9_]{11})");
+ }
+ else if(videoUrl.contains("youtu.be")) {
+ pat = Pattern.compile("youtu\\.be/([a-zA-Z0-9_-]{11})");
+ }
+ else {
Log.e(TAG, "Error could not parse url: " + videoUrl);
- e.printStackTrace();
return "";
}
- return null;
+ Matcher mat = pat.matcher(videoUrl);
+ boolean foundMatch = mat.find();
+ if(foundMatch){
+ id = mat.group(1);
+ Log.i(TAG, "string \""+videoUrl+"\" matches!");
+ }
+ Log.i(TAG, "string \""+videoUrl+"\" does not match.");
+ return id;
}
@Override
@@ -178,12 +168,11 @@ public class YoutubeExtractor implements Extractor {
Document doc = Jsoup.parse(site, siteUrl);
- videoInfo.id = matchGroup1("v=([0-9a-zA-Z]*)", siteUrl);
+ videoInfo.id = matchGroup1("v=([0-9a-zA-Z_-]{11})", siteUrl);
videoInfo.age_limit = 0;
videoInfo.webpage_url = siteUrl;
-
initService(site);
//-------------------------------------
@@ -224,7 +213,7 @@ public class YoutubeExtractor implements Extractor {
videoInfo.uploader = playerArgs.getString("author");
videoInfo.title = playerArgs.getString("title");
- //first attempt gating a small image version
+ //first attempt getting a small image version
//in the html extracting part we try to get a thumbnail with a higher resolution
videoInfo.thumbnail_url = playerArgs.getString("thumbnail_url");
videoInfo.duration = playerArgs.getInt("length_seconds");
@@ -243,7 +232,7 @@ public class YoutubeExtractor implements Extractor {
}
int itag = Integer.parseInt(tags.get("itag"));
- String streamUrl = terrible_unescape_workaround_fuck(tags.get("url"));
+ String streamUrl = URLDecoder.decode(tags.get("url"), "UTF-8");
// if video has a signature: decrypt it and add it to the url
if(tags.get("s") != null) {
@@ -281,35 +270,37 @@ public class YoutubeExtractor implements Extractor {
videoInfo.thumbnail_url = doc.select("link[itemprop=\"thumbnailUrl\"]").first()
.attr("abs:href");
} catch(Exception e) {
- Log.i(TAG, "Could not find high res Thumbnail. Use low res instead");
+ Log.i(TAG, "Could not find high res Thumbnail. Using low res instead");
}
// upload date
- videoInfo.upload_date = doc.select("strong[class=\"watch-time-text\"").first()
- .text();
+ videoInfo.upload_date = doc.select("meta[itemprop=datePublished]").attr("content");
+
+ //TODO: Format date locale-specifically
- // Try to only use date not the text around it
- videoInfo.upload_date = matchGroup1("([0-9.]*$)", videoInfo.upload_date);
// description
- videoInfo.description = doc.select("p[id=\"eow-description\"]").first()
- .html();
-
+ videoInfo.description = doc.select("p[id=\"eow-description\"]").first().html();
+ String likesString = "";
+ String dislikesString = "";
try {
// likes
- videoInfo.like_count = doc.select("span[class=\"like-button-renderer \"]").first()
- .getAllElements().select("button")
- .select("span").get(0).text();
-
-
+ likesString = doc.select("button.like-button-renderer-like-button").first()
+ .select("span.yt-uix-button-content").first().text();
+ videoInfo.like_count = Integer.parseInt(likesString.replaceAll("[^\\d]", ""));
// dislikes
- videoInfo.dislike_count = doc.select("span[class=\"like-button-renderer \"]").first()
- .getAllElements().select("button")
- .select("span").get(2).text();
+ dislikesString = doc.select("button.like-button-renderer-dislike-button").first()
+ .select("span.yt-uix-button-content").first().text();
+
+ videoInfo.dislike_count = Integer.parseInt(dislikesString.replaceAll("[^\\d]", ""));
+ } catch(NumberFormatException nfe) {
+ Log.e(TAG, "failed to parse likesString \""+likesString+"\" and dislikesString \""+
+ dislikesString+"\" as integers");
} catch(Exception e) {
// if it fails we know that the video does not offer dislikes.
- videoInfo.like_count = "0";
- videoInfo.dislike_count = "0";
+ e.printStackTrace();
+ videoInfo.like_count = 0;
+ videoInfo.dislike_count = 0;
}
// uploader thumbnail
@@ -317,21 +308,20 @@ public class YoutubeExtractor implements Extractor {
.select("img").first()
.attr("abs:data-thumb");
- // view count
- videoInfo.view_count = doc.select("div[class=\"watch-view-count\"]").first().text();
+ // view count TODO: locale-specific formatting
+ String viewCountString = doc.select("meta[itemprop=interactionCount]").attr("content");
+ videoInfo.view_count = Integer.parseInt(viewCountString);
// next video
videoInfo.nextVideo = extractVideoInfoItem(doc.select("div[class=\"watch-sidebar-section\"]").first()
.select("li").first());
- int i = 0;
// related videos
Vector relatedVideos = new Vector<>();
for(Element li : doc.select("ul[id=\"watch-related\"]").first().children()) {
// first check if we have a playlist. If so leave them out
if(li.select("a[class*=\"content-link\"]").first() != null) {
relatedVideos.add(extractVideoInfoItem(li));
- i++;
}
}
videoInfo.relatedVideos = relatedVideos.toArray(new VideoInfoItem[relatedVideos.size()]);
@@ -377,13 +367,13 @@ public class YoutubeExtractor implements Extractor {
if(currentTagIsBaseUrl &&
(currentMimeType.contains("audio"))) {
int format = -1;
- if(currentMimeType.equals(VideoInfo.M_WEBMA)) {
- format = VideoInfo.I_WEBMA;
- } else if(currentMimeType.equals(VideoInfo.M_M4A)) {
- format = VideoInfo.I_M4A;
+ if(currentMimeType.equals(MediaFormat.WEBMA.mimeType)) {
+ format = MediaFormat.WEBMA.id;
+ } else if(currentMimeType.equals(MediaFormat.M4A.mimeType)) {
+ format = MediaFormat.M4A.id;
}
audioStreams.add(new VideoInfo.AudioStream(parser.getText(),
- format, currentBandwidth, currentSamplingRate));
+ format, currentBandwidth, currentSamplingRate));
}
case XmlPullParser.END_TAG:
if(tagName.equals("AdaptationSet")) {
@@ -412,6 +402,7 @@ public class YoutubeExtractor implements Extractor {
e.printStackTrace();
}
+ //todo: check NullPointerException causing
info.title = li.select("span[class=\"title\"]").first().text();
info.view_count = li.select("span[class*=\"view-count\"]").first().text();
info.uploader = li.select("span[class=\"g-hovercard\"]").first().text();
@@ -431,19 +422,6 @@ public class YoutubeExtractor implements Extractor {
return info;
}
- private String terrible_unescape_workaround_fuck(String shit) {
- String[] splitAtEscape = shit.split("%");
- String retval = "";
- retval += splitAtEscape[0];
- for(int i = 1; i < splitAtEscape.length; i++) {
- String escNum = splitAtEscape[i].substring(0, 2);
- char c = (char) Integer.parseInt(escNum,16);
- retval += c;
- retval += splitAtEscape[i].substring(2);
- }
- return retval;
- }
-
private String loadDecryptionCode(String playerUrl) {
String playerCode = Downloader.download(playerUrl);
String decryptionFuncName = "";
@@ -456,12 +434,13 @@ public class YoutubeExtractor implements Extractor {
try {
decryptionFuncName = matchGroup1("\\.sig\\|\\|([a-zA-Z0-9$]+)\\(", playerCode);
- String functionPattern = "(function " + decryptionFuncName.replace("$", "\\$") + "\\([a-zA-Z0-9_]*\\)\\{.+?\\})";
+ String functionPattern = "(var "+ decryptionFuncName.replace("$", "\\$") +"=function\\([a-zA-Z0-9_]*\\)\\{.+?\\})";
decryptionFunc = matchGroup1(functionPattern, playerCode);
+ decryptionFunc += ";";
helperObjectName = matchGroup1(";([A-Za-z0-9_\\$]{2})\\...\\(", decryptionFunc);
- String helperPattern = "(var " + helperObjectName.replace("$", "\\$") + "=\\{.+?\\}\\};)function";
+ String helperPattern = "(var " + helperObjectName.replace("$", "\\$") + "=\\{.+?\\}\\};)";
helperObject = matchGroup1(helperPattern, playerCode);
} catch (Exception e) {
@@ -474,13 +453,13 @@ public class YoutubeExtractor implements Extractor {
return decryptionCode;
}
- private String decryptSignature(String encryptedSig, String decryptoinCode) {
+ private String decryptSignature(String encryptedSig, String decryptionCode) {
Context context = Context.enter();
context.setOptimizationLevel(-1);
Object result = null;
try {
ScriptableObject scope = context.initStandardObjects();
- context.evaluateString(scope, decryptoinCode, "decryptionCode", 1, null);
+ context.evaluateString(scope, decryptionCode, "decryptionCode", 1, null);
Function decryptionFunc = (Function) scope.get("decrypt", scope);
result = decryptionFunc.call(context, scope, scope, new Object[]{encryptedSig});
} catch (Exception e) {
@@ -498,7 +477,7 @@ public class YoutubeExtractor implements Extractor {
return mat.group(1);
}
else {
- Log.e(TAG, "failed to find pattern \""+pattern+"\"");
+ Log.e(TAG, "failed to find pattern \""+pattern+"\" inside of \""+input+"\"");
new Exception("failed to find pattern \""+pattern+"\"").printStackTrace();
return "";
}
diff --git a/app/src/main/java/org/schabi/newpipe/youtube/YoutubeSearchEngine.java b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeSearchEngine.java
index b2b1beeac..18bbf4337 100644
--- a/app/src/main/java/org/schabi/newpipe/youtube/YoutubeSearchEngine.java
+++ b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeSearchEngine.java
@@ -49,7 +49,7 @@ public class YoutubeSearchEngine implements SearchEngine {
private static final String TAG = YoutubeSearchEngine.class.toString();
@Override
- public Result search(String query, int page, String countryCode) {
+ public Result search(String query, int page, String languageCode) {
//String contentCountry = PreferenceManager.getDefaultSharedPreferences(this).getString(getString(R.string., "");
Uri.Builder builder = new Uri.Builder();
builder.scheme("https")
@@ -59,20 +59,18 @@ public class YoutubeSearchEngine implements SearchEngine {
.appendQueryParameter("page", Integer.toString(page))
.appendQueryParameter("filters", "video");
- //if we've been passed a valid, non-empty country code, append it to the URL
- if(countryCode.length() > 0) {
- if(countryCode.length() == 2) {
- builder.appendQueryParameter("gl", countryCode);
- builder.appendQueryParameter("persist_gl", "1");
- Log.i(TAG, "URI: \""+builder+"\"");
- }
- else {
- Log.e(TAG, "invalid country code passed to search(): \""+countryCode+"\"");
- }
- }
+ String site;
String url = builder.build().toString();
+ //if we've been passed a valid language code, append it to the URL
+ if(languageCode.length() > 0) {
+ //assert Pattern.matches("[a-z]{2}(-([A-Z]{2}|[0-9]{1,3}))?", languageCode);
+ site = Downloader.download(url, languageCode);
+ }
+ else {
+ site = Downloader.download(url);
+ }
+
- String site = Downloader.download(url);
Document doc = Jsoup.parse(site, url);
Result result = new Result();
Element list = doc.select("ol[class=\"item-section\"]").first();
diff --git a/app/src/main/res/drawable/budy.png b/app/src/main/res/drawable/buddy.png
similarity index 100%
rename from app/src/main/res/drawable/budy.png
rename to app/src/main/res/drawable/buddy.png
diff --git a/app/src/main/res/drawable/dummi_thumbnail.png b/app/src/main/res/drawable/dummy_thumbnail.png
similarity index 100%
rename from app/src/main/res/drawable/dummi_thumbnail.png
rename to app/src/main/res/drawable/dummy_thumbnail.png
diff --git a/app/src/main/res/drawable/ic_file_download_black.png b/app/src/main/res/drawable/ic_file_download_black.png
new file mode 100644
index 000000000..8c83bffa7
Binary files /dev/null and b/app/src/main/res/drawable/ic_file_download_black.png differ
diff --git a/app/src/main/res/layout-land/fragment_videoitem_detail.xml b/app/src/main/res/layout-land/fragment_videoitem_detail.xml
index 9e1d2885d..c0c4938d1 100644
--- a/app/src/main/res/layout-land/fragment_videoitem_detail.xml
+++ b/app/src/main/res/layout-land/fragment_videoitem_detail.xml
@@ -33,7 +33,7 @@
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
- android:src="@drawable/dummi_thumbnail"/>
+ android:src="@drawable/dummy_thumbnail"/>
+ android:src="@drawable/buddy" />
+ android:src="@drawable/dummy_thumbnail"/>
+ android:src="@drawable/buddy" />
+ android:src="@drawable/dummy_thumbnail"/>
+ android:text="Video title placeholder"/>
+ android:src="@drawable/buddy" />
+ android:textStyle="bold"
+ android:textSize="@dimen/text_video_uploader_size"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="username" />
+ android:text="81,754 views" />
+ android:text="100" />
+ android:text="20" />
+ android:text="Published on Jan 01 1975" />
@@ -209,5 +219,5 @@
android:layout_height="wrap_content"
app:backgroundTint="@color/primaryColorYoutube"
android:src="@drawable/ic_play_arrow_black"
- android:layout_margin="16dip"/>
+ android:layout_margin="20dp"/>
\ No newline at end of file
diff --git a/app/src/main/res/layout/video_item.xml b/app/src/main/res/layout/video_item.xml
index d25f524b6..e20e38ce2 100644
--- a/app/src/main/res/layout/video_item.xml
+++ b/app/src/main/res/layout/video_item.xml
@@ -12,7 +12,7 @@
android:scaleType="centerCrop"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
- android:src="@drawable/dummi_thumbnail"/>
+ android:src="@drawable/dummy_thumbnail"/>
-
+
+
-
-
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index b444b0725..93a3a82d1 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,7 +1,7 @@
- #dd0000
- #bb0000
+ #cd322e
+ #bc211d
#000000
#66000000
\ No newline at end of file
diff --git a/app/src/main/res/values/dimentxt.xml b/app/src/main/res/values/dimentxt.xml
index 916afd036..135a0e1cd 100644
--- a/app/src/main/res/values/dimentxt.xml
+++ b/app/src/main/res/values/dimentxt.xml
@@ -4,4 +4,10 @@
11sp
12sp
12sp
+ 14sp
+ 14sp
+ 12sp
+ 14sp
+ 14sp
+ 14sp
\ No newline at end of file
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index d427b7022..3c4b90e65 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -24,183 +24,163 @@
m4a
show_next_video
- content_country
+ search_language
-
-
- - US
- - DZ
- - AR
- - AU
- - AT
- - AZ
- - BH
- - BY
- - BE
- - BA
- - BR
- - BG
- - CA
- - CL
- - CO
- - HR
- - CZ
- - DK
- - EG
- - EE
- - FI
- - FR
- - GE
- - DE
- - GH
- - GR
- - HK
- - HU
- - IS
- - IN
- - ID
- - IE
- - IL
- - IT
- - JP
- - JO
- - KZ
- - KE
- - KW
- - LV
- - LB
- - LY
- - LT
- - LU
- - MK
- - MY
- - MX
- - ME
- - MA
- - NL
- - NZ
- - NG
- - NO
- - OM
- - PE
- - PH
- - PL
- - PT
- - PR
- - QA
- - RO
- - RU
- - SA
- - SN
- - RS
- - SG
- - SK
- - SI
- - ZA
- - KR
- - ES
- - SE
- - CH
- - TW
- - TZ
- - TH
- - TN
- - TR
- - UG
- - UA
- - AE
- - GB
- - VN
- - YE
- - ZW
+
+ - af
+ - az
+ - id
+ - ms
+ - ca
+ - cs
+ - da
+ - de
+ - et
+ - en-GB
+ - en
+ - es
+ - es-419
+ - eu
+ - fil
+ - fr
+ - fr-CA
+ - gl
+ - hr
+ - zu
+ - is
+ - it
+ - sw
+ - lv
+ - lt
+ - hu
+ - nl
+ - no
+ - uz
+ - pl
+ - pt-PT
+ - pt
+ - ro
+ - sq
+ - sk
+ - sl
+ - fi
+ - sv
+ - vi
+ - tr
+ - bg
+ - ky
+ - kk
+ - mk
+ - mn
+ - ru
+ - sr
+ - uk
+ - el
+ - hy
+ - iw
+ - ur
+ - ar
+ - fa
+ - ne
+ - mr
+ - hi
+ - bn
+ - pa
+ - gu
+ - ta
+ - te
+ - kn
+ - ml
+ - si
+ - th
+ - lo
+ - my
+ - ka
+ - am
+ - km
+ - zh-CN
+ - zh-TW
+ - zh-HK
+ - ja
+ - ko
-
- - (None)
- - Worldwide (USA)
- - Algeria
- - Argentina
- - Australia
- - Austria
- - Azerbaijan
- - Bahrain
- - Belarus
- - Belgium
- - Bosnia and Herzegovina
- - Brazil
- - Bulgaria
- - Canada
- - Chile
- - Colombia
- - Croatia
- - Czech Republic
- - Denmark
- - Egypt
- - Estonia
- - Finland
- - France
- - Georgia
- - Germany
- - Ghana
- - Greece
- - Hong Kong
- - Hungary
- - Iceland
- - India
- - Indonesia
- - Ireland
- - Israel
- - Italy
- - Japan
- - Jordan
- - Kazakhstan
- - Kenya
- - Kuwait
- - Latvia
- - Lebanon
- - Libya
- - Lithuania
- - Luxembourg
- - Macedonia
- - Malaysia
- - Mexico
- - Montenegro
- - Morocco
- - Netherlands
- - New Zealand
- - Nigeria
- - Norway
- - Oman
- - Peru
- - Philippines
- - Poland
- - Portugal
- - Puerto Rico
- - Qatar
- - Romania
- - Russia
- - Saudi Arabia
- - Senegal
- - Serbia
- - Singapore
- - Slovakia
- - Slovenia
- - South Africa
- - South Korea
- - Spain
- - Sweden
- - Switzerland
- - Taiwan
- - Tanzania
- - Thailand
- - Tunisia
- - Turkey
- - Uganda
- - Ukraine
- - United Arab Emirates
- - United Kingdom
- - Vietnam
- - Yemen
- - Zimbabwe
+
+ - Afrikaans
+ - Azərbaycan
+ - Bahasa Indonesia
+ - Bahasa Malaysia
+ - Català
+ - Čeština
+ - Dansk
+ - Deutsch
+ - Eesti
+ - English (UK)
+ - English (US)
+ - Español (España)
+ - Español (Latinoamérica)
+ - Euskara
+ - Filipino
+ - Français
+ - Français (Canada)
+ - Galego
+ - Hrvatski
+ - IsiZulu
+ - Íslenska
+ - Italiano
+ - Kiswahili
+ - Latviešu valoda
+ - Lietuvių
+ - Magyar
+ - Nederlands
+ - Norsk
+ - O‘zbek
+ - Polski
+ - Português
+ - Português (Brasil)
+ - Română
+ - Shqip
+ - Slovenčina
+ - Slovenščina
+ - Suomi
+ - Svenska
+ - Tiếng Việt
+ - Türkçe
+ - Български
+ - Кыргызча
+ - Қазақ Тілі
+ - Македонски
+ - Монгол
+ - Русский
+ - Српски
+ - Українська
+ - Ελληνικά
+ - Հայերեն
+ - עברית
+ - اردو
+ - العربية
+ - فارسی
+ - नेपाली
+ - मराठी
+ - हिन्दी
+ - বাংলা
+ - ਪੰਜਾਬੀ
+ - ગુજરાતી
+ - தமிழ்
+ - తెలుగు
+ - ಕನ್ನಡ
+ - മലയാളം
+ - සිංහල
+ - ภาษาไทย
+ - ລາວ
+ - ဗမာ
+ - ქართული
+ - አማርኛ
+ - ខ្មែរ
+ - 中文 (简体)
+ - 中文 (繁體)
+ - 中文 (香港)
+ - 日本語
+ - 한국어
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 41f6b5530..a86ea5544 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,7 +4,7 @@
NewPipe
Nothing found
views
- Uploaded at:
+ Published on
No StreamPlayer found. You may want to install one.
Install one
Cancel
@@ -45,9 +45,9 @@
- Video
- Audio
- Next Video
- Show next and similar Videos.
- Url not Supported.
- Similar Videos
- Video Content Country
+ Next video
+ Show next and similar videos
+ URL not supported.
+ Similar videos
+ Preferable content language
\ No newline at end of file
diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml
index 180b226a3..a72dc87df 100644
--- a/app/src/main/res/xml/settings_screen.xml
+++ b/app/src/main/res/xml/settings_screen.xml
@@ -51,12 +51,11 @@
android:title="@string/showNextAndSimilarTitle"
android:defaultValue="true" />
-
- -->
+ android:key="@string/searchLanguage"
+ android:title="@string/searchLanguageTitle"
+ android:entries="@array/languageNames"
+ android:entryValues="@array/languageCodes"
+ android:defaultValue="en" />
+
\ No newline at end of file