From 67ba12660266100aef1b8b2fc7b29792ff1f569d Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Wed, 11 Nov 2015 16:23:22 +0000 Subject: [PATCH] implemented locale-specific formatting of view, like and dislike counts, and video published date --- .../java/org/schabi/newpipe/VideoInfo.java | 15 ++--- .../newpipe/VideoItemDetailActivity.java | 2 + .../newpipe/VideoItemDetailFragment.java | 50 +++++++++++++++-- .../schabi/newpipe/VideoItemListActivity.java | 2 +- .../newpipe/youtube/YoutubeExtractor.java | 56 +++++++++++-------- 5 files changed, 86 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfo.java b/app/src/main/java/org/schabi/newpipe/VideoInfo.java index 55aa3c8ee..2b8dfc8e9 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfo.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfo.java @@ -2,6 +2,8 @@ package org.schabi.newpipe; import android.graphics.Bitmap; import android.util.Log; + +import java.util.Date; import java.util.Vector; /** @@ -33,15 +35,15 @@ public class VideoInfo { public Bitmap thumbnail = null; public String webpage_url = ""; public String upload_date = ""; - public String view_count = ""; + 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 String like_count = ""; - public String dislike_count = ""; + public int like_count = 0; + public int dislike_count = 0; public String average_rating = ""; public VideoStream[] videoStreams = null; public AudioStream[] audioStreams = null; @@ -64,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; @@ -78,7 +75,5 @@ public class VideoInfo { public int format = -1; public int bandwidth = -1; public int samplingRate = -1; - } - } \ No newline at end of file diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java index 34d491233..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++) { 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/youtube/YoutubeExtractor.java b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java index 3eb825a92..fe49cd97c 100644 --- a/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java @@ -133,22 +133,27 @@ public class YoutubeExtractor implements Extractor { @Override public String getVideoId(String videoUrl) { - //https://www.youtube.com/watch?v=laF2D3QyAFQ - String id; + String id = ""; Pattern pat; + if(videoUrl.contains("youtube")) { - pat = Pattern.compile("youtube\\.com/watch\\?v=([a-zA-Z0-9_]{11})"); + 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})"); + pat = Pattern.compile("youtu\\.be/([a-zA-Z0-9_-]{11})"); } else { Log.e(TAG, "Error could not parse url: " + videoUrl); return ""; } Matcher mat = pat.matcher(videoUrl); - id = mat.group(1); - return (id == null ? "" : id); + 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 @@ -163,7 +168,7 @@ public class YoutubeExtractor implements Extractor { Document doc = Jsoup.parse(site, siteUrl); - videoInfo.id = matchGroup1("v=([0-9a-zA-Z]{10,})", siteUrl); + videoInfo.id = matchGroup1("v=([0-9a-zA-Z_-]{11})", siteUrl); videoInfo.age_limit = 0; videoInfo.webpage_url = siteUrl; @@ -173,7 +178,7 @@ public class YoutubeExtractor implements Extractor { //------------------------------------- // extracting form player args //------------------------------------- - JSONObject playerArgs; + JSONObject playerArgs = null; { try { String jsonString = matchGroup1("ytplayer.config\\s*=\\s*(\\{.*?\\});", site); @@ -185,8 +190,6 @@ public class YoutubeExtractor implements Extractor { // If we fail in this part the video is most likely not available. // Determining why is done later. videoInfo.videoAvailableStatus = VideoInfo.VIDEO_UNAVAILABLE; - //exit early, since we can't extract other args - return videoInfo; } } @@ -277,23 +280,27 @@ public class YoutubeExtractor implements Extractor { // 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.replace(",", "")); // 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.replace(",", "")); + } 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 @@ -301,8 +308,9 @@ public class YoutubeExtractor implements Extractor { .select("img").first() .attr("abs:data-thumb"); - // view count TODO: format locale-specifically - videoInfo.view_count = doc.select("meta[itemprop=interactionCount]").attr("content"); + // 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()