diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..528b5edd3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +language: android +android: + components: + # The BuildTools version used by NewPipe + - build-tools-23.0.1 + + # The SDK version used to compile NewPipe + - android-23 + + # Additional components + - extra-android-support + - extra-android-m2repository + + # Emulators + - sys-img-armeabi-v7a-android-21 + - sys-img-armeabi-v7a-android-19 + - sys-img-armeabi-v7a-android-15 + +env: + global: + - ADB_INSTALL_TIMEOUT=8 # minutes (2 by default) + matrix: + - ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a + +before_script: + - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI + - emulator -avd test -no-skin -no-audio -no-window & + - android-wait-for-emulator + - adb shell input keyevent 82 & diff --git a/README.md b/README.md index 648a1e695..987cd4b29 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,39 @@ # NewPipe +NewPipe: A free lightweight Youtube frontend for Android. +[![NewPipe](app/src/main/res/mipmap-xhdpi/ic_launcher.png)](http://dasochan.nl/newpipe/) + +Project status: [![Translation Status](https://hosted.weblate.org/widgets/NewPipe/-/svg-badge.svg)](https://hosted.weblate.org/engage/NewPipe/) +[![Build Status](https://travis-ci.org/theScrabi/NewPipe.svg)](https://travis-ci.org/theScrabi/NewPipe) -[![NewPipe](https://f-droid.org/repo/icons/org.schabi.newpipe.5.png)](http://dasochan.nl/newpipe/) -NewPipe: A free lightweight Youtube frontend for Android. +## Get NewPipe [![F-Droid](https://f-droid.org/wiki/images/0/06/F-Droid-button_get-it-on.png)](https://f-droid.org/repository/browse/?fdfilter=newpipe&fdid=org.schabi.newpipe) +## Screenshots + +[](assets/screenshot_1.png) +[](assets/screenshot_2.png) + ## Description -NewPipe does not use any Google framework libraries, or the YouTube API. It only parses the website in order to gain the information it needs. Therefore this app can be used on devices without G-services installed. Also NewPipe does not store data on the YouTube website (no login), and it's free software. +NewPipe does not use any Google framework libraries, or the YouTube API. It only parses the website in order to gain the information it needs. Therefore this app can be used on devices without Google Services installed. Also, you don't need a YouTube account to use NewPipe, and it's FLOSS. -## Features +### Features * Search videos * Display general information about a video -* Watch Youtube videos -* Listen to Youtube videos (audio only streaming) +* Watch YouTube videos +* Listen to YouTube videos (audio only streaming) * Select the streaming player to watch the video with * Download videos (working, but it could be better) -* Download audio only (working but, but it could be better) +* Download audio only (working, but it could be better) * Open a video in Kodi * Show Next/Related videos -* Search Youtube in a specific language +* Search YouTube in a specific language -## Coming Features +### Coming Features * Improved Downloading * Bookmarks @@ -37,10 +46,20 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only * Search/Watch Playlists * ... and many more -### Multi service support -Generally NewPipe is designed to not only support YouTube, but many more streaming services. However, right now NewPipe is not stable enough to support more than only YouTube. But if all works as planned, NewPipe will get such support by the version 2.0. - -# Help is always welcome !!! -Whether it's about ideas, translation, design changes, code cleaning, or real heavy code changes. Help is always welcome. +### Multiservice support +Although NewPipe only supports YouTube at the moment, it's designed to support many more streaming services. The plan is, that NewPipe will get such support by the version 2.0. +## Contribution +Whether you have ideas, translation, design changes, code cleaning, or real heavy code changes, help is always welcome. The more is done the better it gets! + +Join our [Slack group](http://invite.chschtsch.ml/) if you like to get involved. + +## License +[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html) + +NewPipe is Free Software: You can use, study share and improve it at your +will. Specifically you can redistribute and/or modify it under the terms of the +[GNU General Public License](https://www.gnu.org/licenses/gpl.html) as +published by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. diff --git a/app/build.gradle b/app/build.gradle index fb41271d9..324224856 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,13 +17,20 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + + lintOptions { + checkReleaseBuilds false + // Or, if you prefer, you can continue to check for errors in release builds, + // but continue the build even when errors are found: + abortOnError false + } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:appcompat-v7:23.1.0' - compile 'com.android.support:support-v4:23.1.0' - compile 'com.android.support:design:23.1.0' + compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:support-v4:23.1.1' + compile 'com.android.support:design:23.1.1' compile 'org.jsoup:jsoup:1.8.3' compile 'org.mozilla:rhino:1.7.7' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 23bce5eab..9102e261d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -11,7 +12,8 @@ android:icon="@mipmap/ic_launcher" android:logo="@mipmap/ic_launcher" android:label="@string/app_name" - android:theme="@style/AppTheme" > + android:theme="@style/AppTheme" + tools:ignore="AllowBackup"> @@ -68,9 +70,9 @@ + tools:ignore="UnusedAttribute"> . */ -public class ActionBarHandler { + +class ActionBarHandler { private static final String TAG = ActionBarHandler.class.toString(); private static final String KORE_PACKET = "org.xbmc.kore"; @@ -47,10 +47,11 @@ public class ActionBarHandler { private int selectedStream = -1; private String videoTitle = ""; - SharedPreferences defaultPreferences = null; + private SharedPreferences defaultPreferences = null; private int startPosition; - class FormatItemSelectListener implements ActionBar.OnNavigationListener { + @SuppressWarnings("deprecation") + private class FormatItemSelectListener implements ActionBar.OnNavigationListener { @Override public boolean onNavigationItemSelected(int itemPosition, long itemId) { selectFormatItem((int)itemId); @@ -62,11 +63,17 @@ public class ActionBarHandler { this.activity = activity; } + @SuppressWarnings({"deprecation", "ConstantConditions"}) public void setupNavMenu(AppCompatActivity activity) { this.activity = activity; - activity.getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + try { + activity.getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + } catch(NullPointerException e) { + e.printStackTrace(); + } } + @SuppressWarnings("deprecation") public void setStreams(VideoInfo.VideoStream[] videoStreams, VideoInfo.AudioStream[] audioStreams) { this.videoStreams = videoStreams; selectedStream = 0; @@ -84,12 +91,14 @@ public class ActionBarHandler { } } - ArrayAdapter itemAdapter = new ArrayAdapter(activity.getBaseContext(), + ArrayAdapter itemAdapter = new ArrayAdapter<>(activity.getBaseContext(), android.R.layout.simple_spinner_dropdown_item, itemArray); if(activity != null) { ActionBar ab = activity.getSupportActionBar(); - ab.setListNavigationCallbacks(itemAdapter - ,new FormatItemSelectListener()); + assert ab != null : "Could not get actionbar"; + ab.setListNavigationCallbacks(itemAdapter + , new FormatItemSelectListener()); + ab.setSelectedNavigationItem(defaultResolutionPos); } @@ -117,7 +126,7 @@ public class ActionBarHandler { selectedStream = i; } - public boolean setupMenu(Menu menu, MenuInflater inflater) { + public void setupMenu(Menu menu, MenuInflater inflater) { // CAUTION set item properties programmatically otherwise it would not be accepted by // appcompat itemsinflater.inflate(R.menu.videoitem_detail, menu); @@ -128,8 +137,6 @@ public class ActionBarHandler { castItem.setVisible(defaultPreferences .getBoolean(activity.getString(R.string.showPlayWidthKodiPreference), false)); - - return true; } public boolean onItemSelected(MenuItem item) { @@ -229,7 +236,7 @@ public class ActionBarHandler { this.startPosition = startPositionSeconds; } - public void downloadVideo() { + private void downloadVideo() { if(!videoTitle.isEmpty()) { String videoSuffix = "." + MediaFormat.getSuffixById(videoStreams[selectedStream].format); String audioSuffix = "." + MediaFormat.getSuffixById(audioStream.format); @@ -245,7 +252,7 @@ public class ActionBarHandler { } } - public void openInBrowser() { + private void openInBrowser() { if(!videoTitle.isEmpty()) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); @@ -255,7 +262,7 @@ public class ActionBarHandler { } } - public void playWithKodi() { + private void playWithKodi() { if(!videoTitle.isEmpty()) { try { Intent intent = new Intent(Intent.ACTION_VIEW); @@ -292,6 +299,7 @@ public class ActionBarHandler { if (b)//internal (background) music player: explicit intent { intent = new Intent(activity, BackgroundPlayer.class); + intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse(audioStream.url), MediaFormat.getMimeById(audioStream.format)); diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index 01479b642..fa79e5f82 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -8,6 +8,7 @@ import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; import android.util.Log; @@ -42,8 +43,9 @@ public class DownloadDialog extends DialogFragment { public static final String FILE_SUFFIX_VIDEO = "file_suffix_video"; public static final String AUDIO_URL = "audio_url"; public static final String VIDEO_URL = "video_url"; - Bundle arguments; + private Bundle arguments; + @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { arguments = getArguments(); diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index 9c2fa2948..f0a19cfc5 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -50,8 +50,8 @@ public class Downloader { return ret; } /**Common functionality between download(String url) and download(String url, String language)*/ - private static String dl(HttpURLConnection con) { - StringBuffer response = new StringBuffer(); + private static String dl(HttpURLConnection con) throws IOException { + StringBuilder response = new StringBuilder(); try { con.setRequestMethod("GET"); @@ -71,9 +71,7 @@ public class Downloader { uhe.printStackTrace(); //Toast.makeText(getActivity(), uhe.getMessage(), Toast.LENGTH_LONG).show(); } - catch (Exception e) { - e.printStackTrace(); - } + return response.toString(); } diff --git a/app/src/main/java/org/schabi/newpipe/MediaFormat.java b/app/src/main/java/org/schabi/newpipe/MediaFormat.java index c9af7b8b7..f3f6348f0 100644 --- a/app/src/main/java/org/schabi/newpipe/MediaFormat.java +++ b/app/src/main/java/org/schabi/newpipe/MediaFormat.java @@ -23,6 +23,7 @@ package org.schabi.newpipe; */ /**Static data about various media formats support by Newpipe, eg mime type, extension*/ + public enum MediaFormat { // id name suffix mime type MPEG_4 (0x0, "MPEG-4", "mp4", "video/mp4"), @@ -32,7 +33,9 @@ public enum MediaFormat { WEBMA (0x4, "WebM", "webm", "audio/webm"); public final int id; + @SuppressWarnings("WeakerAccess") public final String name; + @SuppressWarnings("WeakerAccess") public final String suffix; public final String mimeType; diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index cf1593903..825f69949 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -84,6 +84,7 @@ public class PlayVideoActivity extends AppCompatActivity { hasSoftKeys = checkIfHasSoftKeys(); actionBar = getSupportActionBar(); + assert actionBar != null; actionBar.setDisplayHomeAsUpEnabled(true); Intent intent = getIntent(); if(mediaController == null) { @@ -291,11 +292,9 @@ public class PlayVideoActivity extends AppCompatActivity { } private boolean checkIfHasSoftKeys(){ - if(Build.VERSION.SDK_INT >= 17) { - return getNavigationBarHeight() != 0 || getNavigationBarWidth() != 0; - } else { - return true; - } + return Build.VERSION.SDK_INT >= 17 || + getNavigationBarHeight() != 0 || + getNavigationBarWidth() != 0; } private int getNavigationBarHeight() { @@ -332,7 +331,7 @@ public class PlayVideoActivity extends AppCompatActivity { } } - public boolean checkIfLandscape() { + private boolean checkIfLandscape() { DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.heightPixels < displayMetrics.widthPixels; @@ -348,6 +347,6 @@ public class PlayVideoActivity extends AppCompatActivity { } SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(PREF_IS_LANDSCAPE, isLandscape); - editor.commit(); + editor.apply(); } } diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index 705978801..b434b53d8 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -9,10 +9,9 @@ import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.support.annotation.LayoutRes; -import android.support.annotation.Nullable; +import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatDelegate; -import android.support.v7.widget.Toolbar; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; @@ -70,14 +69,11 @@ public class SettingsActivity extends PreferenceActivity { getDelegate().onPostCreate(savedInstanceState); } - public ActionBar getSupportActionBar() { + private ActionBar getSupportActionBar() { return getDelegate().getSupportActionBar(); } - public void setSupportActionBar(@Nullable Toolbar toolbar) { - getDelegate().setSupportActionBar(toolbar); - } - + @NonNull @Override public MenuInflater getMenuInflater() { return getDelegate().getMenuInflater(); @@ -162,7 +158,7 @@ public class SettingsActivity extends PreferenceActivity { Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe"; spEditor.putString(context.getString(R.string.downloadPathPreference) , newPipeDownloadStorage); - spEditor.commit(); + spEditor.apply(); } } } diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfo.java b/app/src/main/java/org/schabi/newpipe/VideoInfo.java index 5b8321a61..c7c051945 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 org.schabi.newpipe.services.AbstractVideoInfo; + import java.util.List; /** @@ -56,6 +58,7 @@ public class VideoInfo extends AbstractVideoInfo { /**Creates a new VideoInfo object from an existing AbstractVideoInfo. * All the shared properties are copied to the new VideoInfo.*/ + @SuppressWarnings("WeakerAccess") public VideoInfo(AbstractVideoInfo avi) { this.id = avi.id; this.title = avi.title; @@ -74,7 +77,6 @@ public class VideoInfo extends AbstractVideoInfo { int seconds = Integer.parseInt(dur.substring(dur.indexOf(":")+1, dur.length())); this.duration = (minutes*60)+seconds; } - } public static class VideoStream { diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java index 19064c211..efd752788 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java @@ -26,10 +26,10 @@ import android.widget.TextView; * along with NewPipe. If not, see . */ -public class VideoInfoItemViewCreator { +class VideoInfoItemViewCreator { private static final String TAG = VideoInfoItemViewCreator.class.toString(); - LayoutInflater inflater; + private final LayoutInflater inflater; public VideoInfoItemViewCreator(LayoutInflater inflater) { this.inflater = inflater; @@ -57,12 +57,12 @@ public class VideoInfoItemViewCreator { } holder.itemVideoTitleView.setText(info.title); holder.itemUploaderView.setText(info.uploader); - holder.itemDurationView.setText(""+info.duration); + holder.itemDurationView.setText(info.duration); if(!info.upload_date.isEmpty()) { holder.itemUploadDateView.setText(info.upload_date); } else { //tweak if necessary: This is a hack to prevent having white space in the layout :P - holder.itemUploadDateView.setText(""+info.view_count); + holder.itemUploadDateView.setText(String.format("%d", info.view_count)); } return convertView; diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java index 0b87b7b7f..4a553241f 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java @@ -10,7 +10,6 @@ import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; -import org.schabi.newpipe.services.Extractor; import org.schabi.newpipe.services.ServiceList; import org.schabi.newpipe.services.StreamingService; @@ -37,7 +36,7 @@ public class VideoItemDetailActivity extends AppCompatActivity { private static final String TAG = VideoItemDetailActivity.class.toString(); - VideoItemDetailFragment fragment; + private VideoItemDetailFragment fragment; private String videoUrl; private int currentStreamingService = -1; @@ -47,7 +46,13 @@ public class VideoItemDetailActivity extends AppCompatActivity { setContentView(R.layout.activity_videoitem_detail); // Show the Up button in the action bar. - getSupportActionBar().setDisplayHomeAsUpEnabled(true); + try { + //noinspection ConstantConditions + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } catch(Exception e) { + Log.d(TAG, "Could not get SupportActionBar"); + e.printStackTrace(); + } // savedInstanceState is non-null when there is fragment state // saved from previous configurations of this activity @@ -64,14 +69,13 @@ 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; + //VideoExtractor videoExtractor = null; for (int i = 0; i < serviceList.length; i++) { if (serviceList[i].acceptUrl(videoUrl)) { arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, i); currentStreamingService = i; - //extractor = ServiceList.getService(i).getExtractorInstance(); + //videoExtractor = ServiceList.getService(i).getExtractorInstance(); break; } } @@ -80,7 +84,7 @@ public class VideoItemDetailActivity extends AppCompatActivity { .show(); } //arguments.putString(VideoItemDetailFragment.VIDEO_URL, - // extractor.getVideoUrl(extractor.getVideoId(videoUrl)));//cleans URL + // videoExtractor.getVideoUrl(videoExtractor.getVideoId(videoUrl)));//cleans URL arguments.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl); arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index c883e7f8d..84009069a 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -1,8 +1,10 @@ package org.schabi.newpipe; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; @@ -39,7 +41,7 @@ import java.util.Date; import java.util.Locale; import java.util.Vector; -import org.schabi.newpipe.services.Extractor; +import org.schabi.newpipe.services.VideoExtractor; import org.schabi.newpipe.services.ServiceList; import org.schabi.newpipe.services.StreamingService; @@ -79,7 +81,6 @@ public class VideoItemDetailFragment extends Fragment { private ActionBarHandler actionBarHandler; private boolean autoPlayEnabled = false; - private Thread extractorThread = null; private VideoInfo currentVideoInfo = null; private boolean showNextVideoItem = false; @@ -89,21 +90,21 @@ public class VideoItemDetailFragment extends Fragment { private OnInvokeCreateOptionsMenuListener onInvokeCreateOptionsMenuListener = null; - private class ExtractorRunnable implements Runnable { - private Handler h = new Handler(); - private Extractor extractor; - private StreamingService service; - private String videoUrl; + private class VideoExtractorRunnable implements Runnable { + private final Handler h = new Handler(); + private VideoExtractor videoExtractor; + private final StreamingService service; + private final String videoUrl; - public ExtractorRunnable(String videoUrl, StreamingService service, VideoItemDetailFragment f) { + public VideoExtractorRunnable(String videoUrl, StreamingService service) { this.service = service; this.videoUrl = videoUrl; } @Override public void run() { try { - this.extractor = service.getExtractorInstance(videoUrl); - VideoInfo videoInfo = extractor.getVideoInfo(); + this.videoExtractor = service.getExtractorInstance(videoUrl); + VideoInfo videoInfo = videoExtractor.getVideoInfo(); h.post(new VideoResultReturnedRunnable(videoInfo)); if (videoInfo.videoAvailableStatus == VideoInfo.VIDEO_AVAILABLE) { h.post(new SetThumbnailRunnable( @@ -135,7 +136,7 @@ public class VideoItemDetailFragment extends Fragment { } private class VideoResultReturnedRunnable implements Runnable { - private VideoInfo videoInfo; + private final VideoInfo videoInfo; public VideoResultReturnedRunnable(VideoInfo videoInfo) { this.videoInfo = videoInfo; } @@ -151,8 +152,8 @@ public class VideoItemDetailFragment extends Fragment { public static final int VIDEO_THUMBNAIL = 1; public static final int CHANNEL_THUMBNAIL = 2; public static final int NEXT_VIDEO_THUMBNAIL = 3; - private Bitmap thumbnail; - private int thumbnailId; + private final Bitmap thumbnail; + private final int thumbnailId; public SetThumbnailRunnable(Bitmap thumbnail, int id) { this.thumbnail = thumbnail; this.thumbnailId = id; @@ -163,9 +164,9 @@ public class VideoItemDetailFragment extends Fragment { } } - public void updateThumbnail(Bitmap thumbnail, int id) { + private void updateThumbnail(Bitmap thumbnail, int id) { Activity a = getActivity(); - ImageView thumbnailView = null; + ImageView thumbnailView; try { switch (id) { case SetThumbnailRunnable.VIDEO_THUMBNAIL: @@ -194,8 +195,9 @@ public class VideoItemDetailFragment extends Fragment { } } - public void updateInfo(VideoInfo info) { + private void updateInfo(VideoInfo info) { currentVideoInfo = info; + Resources res = activity.getResources(); try { VideoInfoItemViewCreator videoItemViewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(getActivity())); @@ -234,13 +236,17 @@ public class VideoItemDetailFragment extends Fragment { Locale locale = getPreferredLocale(); NumberFormat nf = NumberFormat.getInstance(locale); String localisedViewCount = nf.format(info.view_count); - viewCountView.setText(localisedViewCount - + " " + activity.getString(R.string.viewSufix)); + viewCountView.setText( + String.format( + res.getString(R.string.viewCountText), localisedViewCount)); + /*viewCountView.setText(localisedViewCount + + " " + activity.getString(R.string.viewSufix)); */ thumbsUpView.setText(nf.format(info.like_count)); thumbsDownView.setText(nf.format(info.dislike_count)); + @SuppressLint("SimpleDateFormat") SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Date datum = null; try { @@ -253,7 +259,7 @@ public class VideoItemDetailFragment extends Fragment { String localisedDate = df.format(datum); uploadDateView.setText( - activity.getString(R.string.uploadDatePrefix) + " " + localisedDate); + String.format(res.getString(R.string.uploadDateText), localisedDate)); descriptionView.setText(Html.fromHtml(info.description)); descriptionView.setMovementMethod(LinkMovementMethod.getInstance()); @@ -323,8 +329,6 @@ public class VideoItemDetailFragment extends Fragment { * Mandatory empty constructor for the fragment manager to instantiate the * fragment (e.g. upon screen orientation changes). */ - public VideoItemDetailFragment() { - } @Override public void onCreate(Bundle savedInstanceState) { @@ -360,11 +364,11 @@ public class VideoItemDetailFragment extends Fragment { try { StreamingService streamingService = ServiceList.getService( getArguments().getInt(STREAMING_SERVICE)); - extractorThread = new Thread(new ExtractorRunnable( - getArguments().getString(VIDEO_URL), streamingService, this)); + Thread videoExtractorThread = new Thread(new VideoExtractorRunnable( + getArguments().getString(VIDEO_URL), streamingService)); autoPlayEnabled = getArguments().getBoolean(AUTO_PLAY); - extractorThread.start(); + videoExtractorThread.start(); } catch (Exception e) { e.printStackTrace(); } @@ -409,10 +413,12 @@ public class VideoItemDetailFragment extends Fragment { /**Returns the java.util.Locale object which corresponds to the locale set in NewPipe's preferences. * Currently not affected by the device's locale.*/ - public Locale getPreferredLocale() { + private Locale getPreferredLocale() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); String languageKey = getContext().getString(R.string.searchLanguage); - String languageCode = "en";//i know the following line defaults languageCode to "en", but java is picky about uninitialised values + //i know the following line defaults languageCode to "en", but java is picky about uninitialised values + // Schabi: well lint tels me the value is redundant. I'll suppress it for now. + @SuppressWarnings("UnusedAssignment") String languageCode = "en"; languageCode = sp.getString(languageKey, "en"); if(languageCode.length() == 2) { @@ -426,7 +432,7 @@ public class VideoItemDetailFragment extends Fragment { return Locale.getDefault(); } - public boolean checkIfLandscape() { + private boolean checkIfLandscape() { DisplayMetrics displayMetrics = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.heightPixels < displayMetrics.widthPixels; diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java index 7a89682f3..37bf67333 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -6,6 +6,7 @@ import android.os.Bundle; import android.support.v4.app.NavUtils; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -56,9 +57,9 @@ public class VideoItemListActivity extends AppCompatActivity private VideoItemListFragment listFragment; private VideoItemDetailFragment videoFragment = null; - Menu menu = null; + private Menu menu = null; - public class SearchVideoQueryListener implements SearchView.OnQueryTextListener { + private class SearchVideoQueryListener implements SearchView.OnQueryTextListener { @Override public boolean onQueryTextSubmit(String query) { @@ -69,8 +70,14 @@ public class VideoItemListActivity extends AppCompatActivity // hide virtual keyboard InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - inputManager.hideSoftInputFromWindow( - getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + try { + //noinspection ConstantConditions + inputManager.hideSoftInputFromWindow( + getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } catch(NullPointerException e) { + Log.e(TAG, "Could not get widget with focus"); + e.printStackTrace(); + } // clear focus // 1. to not open up the keyboard after switching back to this // 2. It's a workaround to a seeming bug by the Android OS it self, causing @@ -116,7 +123,13 @@ public class VideoItemListActivity extends AppCompatActivity ArrayList p = arguments.getParcelableArrayList(VIDEO_INFO_ITEMS); if(p != null) { mode = PRESENT_VIDEOS_MODE; - getSupportActionBar().setDisplayHomeAsUpEnabled(true); + try { + //noinspection ConstantConditions + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } catch (NullPointerException e) { + Log.e(TAG, "Could not get SupportActionBar"); + e.printStackTrace(); + } listFragment.present(p); } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index 2c8cb6de9..fb2ba14a7 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -64,8 +64,8 @@ public class VideoItemListFragment extends ListFragment { private ListView list; private class ResultRunnable implements Runnable { - private SearchEngine.Result result; - private int requestId; + private final SearchEngine.Result result; + private final int requestId; public ResultRunnable(SearchEngine.Result result, int requestId) { this.result = result; this.requestId = requestId; @@ -77,12 +77,12 @@ public class VideoItemListFragment extends ListFragment { } private class SearchRunnable implements Runnable { - private SearchEngine engine; - private String query; - private int page; - Handler h = new Handler(); + private final SearchEngine engine; + private final String query; + private final int page; + final Handler h = new Handler(); private volatile boolean run = true; - private int requestId; + private final int requestId; public SearchRunnable(SearchEngine engine, String query, int page, int requestId) { this.engine = engine; this.query = query; @@ -116,11 +116,11 @@ public class VideoItemListFragment extends ListFragment { } private class LoadThumbsRunnable implements Runnable { - private Vector thumbnailUrlList = new Vector<>(); - private Vector downloadedList; - Handler h = new Handler(); + private final Vector thumbnailUrlList = new Vector<>(); + private final Vector downloadedList; + final Handler h = new Handler(); private volatile boolean run = true; - private int requestId; + private final int requestId; public LoadThumbsRunnable(Vector videoList, Vector downloadedList, int requestId) { for(VideoPreviewInfo item : videoList) { @@ -139,7 +139,7 @@ public class VideoItemListFragment extends ListFragment { public void run() { for(int i = 0; i < thumbnailUrlList.size() && run; i++) { if(!downloadedList.get(i)) { - Bitmap thumbnail = null; + Bitmap thumbnail; try { thumbnail = BitmapFactory.decodeStream( new URL(thumbnailUrlList.get(i)).openConnection().getInputStream()); @@ -153,9 +153,9 @@ public class VideoItemListFragment extends ListFragment { } private class SetThumbnailRunnable implements Runnable { - private int index; - private Bitmap thumbnail; - private int requestId; + private final int index; + private final Bitmap thumbnail; + private final int requestId; public SetThumbnailRunnable(int index, Bitmap thumbnail, int requestId) { this.index = index; this.thumbnail = thumbnail; @@ -164,7 +164,7 @@ public class VideoItemListFragment extends ListFragment { @Override public void run() { if(requestId == currentRequestId) { - videoListAdapter.updateDownloadedThumbnailList(index, true); + videoListAdapter.updateDownloadedThumbnailList(index); videoListAdapter.setThumbnail(index, thumbnail); } } @@ -188,7 +188,7 @@ public class VideoItemListFragment extends ListFragment { getListView().smoothScrollToPosition(0); } - public void nextPage() { + private void nextPage() { lastPage++; Log.d(TAG, getString(R.string.searchPage) + Integer.toString(lastPage)); startSearch(query, lastPage); @@ -207,7 +207,7 @@ public class VideoItemListFragment extends ListFragment { this.streamingService = streamingService; } - public void updateListOnResult(SearchEngine.Result result, int requestId) { + private void updateListOnResult(SearchEngine.Result result, int requestId) { if(requestId == currentRequestId) { setListShown(true); if (result.resultList.isEmpty()) { @@ -237,7 +237,7 @@ public class VideoItemListFragment extends ListFragment { } } - public void terminateThreads() { + private void terminateThreads() { if(loadThumbsRunnable != null && loadThumbsRunnable.isRunning()) { loadThumbsRunnable.terminate(); try { @@ -276,12 +276,7 @@ public class VideoItemListFragment extends ListFragment { void onItemSelected(String id); } - Callbacks mCallbacks = null; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } + private Callbacks mCallbacks = null; @Override public void onViewCreated(View view, Bundle savedInstanceState) { @@ -333,11 +328,6 @@ public class VideoItemListFragment extends ListFragment { mCallbacks = (Callbacks) context; } - @Override - public void onDetach() { - super.onDetach(); - } - @Override public void onListItemClick(ListView listView, View view, int position, long id) { super.onListItemClick(listView, view, position, id); @@ -345,22 +335,11 @@ public class VideoItemListFragment extends ListFragment { mCallbacks.onItemSelected(Long.toString(id)); } - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - /* - if (mActivatedPosition != ListView.INVALID_POSITION) { - // Serialize and persist the activated item position. - outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); - } - */ - } - /** * Turns on activate-on-click mode. When this mode is on, list items will be * given the 'activated' state when touched. */ - public void setActivateOnItemClick(boolean activateOnItemClick) { + public void setActivateOnItemClick(@SuppressWarnings("SameParameterValue") boolean activateOnItemClick) { // When setting CHOICE_MODE_SINGLE, ListView will automatically // give items the 'activated' state when touched. getListView().setChoiceMode(activateOnItemClick diff --git a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java index 6f20a92db..6f06430d3 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java @@ -32,19 +32,17 @@ import java.util.Vector; * along with NewPipe. If not, see . */ -public class VideoListAdapter extends BaseAdapter { +class VideoListAdapter extends BaseAdapter { private static final String TAG = VideoListAdapter.class.toString(); - private Context context; - private VideoInfoItemViewCreator viewCreator; + private final Context context; + private final VideoInfoItemViewCreator viewCreator; private Vector videoList = new Vector<>(); private Vector downloadedThumbnailList = new Vector<>(); - VideoItemListFragment videoListFragment; - ListView listView; + private final ListView listView; public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) { viewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(context)); - this.videoListFragment = videoListFragment; this.listView = videoListFragment.getListView(); this.context = context; } @@ -67,8 +65,8 @@ public class VideoListAdapter extends BaseAdapter { return videoList; } - public void updateDownloadedThumbnailList(int index, boolean val) { - downloadedThumbnailList.set(index, val); + public void updateDownloadedThumbnailList(int index) { + downloadedThumbnailList.set(index, true); } public Vector getDownloadedThumbnailList() { diff --git a/app/src/main/java/org/schabi/newpipe/VideoPreviewInfo.java b/app/src/main/java/org/schabi/newpipe/VideoPreviewInfo.java index f49bd0a0e..0832114e0 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoPreviewInfo.java +++ b/app/src/main/java/org/schabi/newpipe/VideoPreviewInfo.java @@ -4,6 +4,8 @@ import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; +import org.schabi.newpipe.services.AbstractVideoInfo; + /** * Created by Christian Schabesberger on 26.08.15. * @@ -27,6 +29,7 @@ import android.os.Parcelable; /**Info object for previews of unopened videos, eg search results, related videos*/ public class VideoPreviewInfo extends AbstractVideoInfo implements Parcelable { public String duration = ""; + @SuppressWarnings("WeakerAccess") protected VideoPreviewInfo(Parcel in) { id = in.readString(); title = in.readString(); diff --git a/app/src/main/java/org/schabi/newpipe/AbstractVideoInfo.java b/app/src/main/java/org/schabi/newpipe/services/AbstractVideoInfo.java similarity index 92% rename from app/src/main/java/org/schabi/newpipe/AbstractVideoInfo.java rename to app/src/main/java/org/schabi/newpipe/services/AbstractVideoInfo.java index 43839b1f0..72d43ebde 100644 --- a/app/src/main/java/org/schabi/newpipe/AbstractVideoInfo.java +++ b/app/src/main/java/org/schabi/newpipe/services/AbstractVideoInfo.java @@ -1,4 +1,4 @@ -package org.schabi.newpipe; +package org.schabi.newpipe.services; import android.graphics.Bitmap; diff --git a/app/src/main/java/org/schabi/newpipe/services/SearchEngine.java b/app/src/main/java/org/schabi/newpipe/services/SearchEngine.java index 4feda4edc..42b0fed6c 100644 --- a/app/src/main/java/org/schabi/newpipe/services/SearchEngine.java +++ b/app/src/main/java/org/schabi/newpipe/services/SearchEngine.java @@ -31,7 +31,7 @@ public interface SearchEngine { class Result { public String errorMessage = ""; public String suggestion = ""; - public Vector resultList = new Vector<>(); + public final Vector resultList = new Vector<>(); } ArrayList suggestionList(String query); diff --git a/app/src/main/java/org/schabi/newpipe/services/ServiceList.java b/app/src/main/java/org/schabi/newpipe/services/ServiceList.java index f0522a9cd..53bba3ffb 100644 --- a/app/src/main/java/org/schabi/newpipe/services/ServiceList.java +++ b/app/src/main/java/org/schabi/newpipe/services/ServiceList.java @@ -42,7 +42,7 @@ public class ServiceList { } public static int getIdOfService(String serviceName) { for(int i = 0; i < services.length; i++) { - if(services[i].getServiceInfo().name == serviceName) { + if(services[i].getServiceInfo().name.equals(serviceName)) { return i; } } diff --git a/app/src/main/java/org/schabi/newpipe/services/StreamingService.java b/app/src/main/java/org/schabi/newpipe/services/StreamingService.java index fbcd31f10..acf887b57 100644 --- a/app/src/main/java/org/schabi/newpipe/services/StreamingService.java +++ b/app/src/main/java/org/schabi/newpipe/services/StreamingService.java @@ -25,7 +25,7 @@ public interface StreamingService { public String name = ""; } ServiceInfo getServiceInfo(); - Extractor getExtractorInstance(String url); + VideoExtractor getExtractorInstance(String url); SearchEngine getSearchEngineInstance(); /**When a VIEW_ACTION is caught this function will test if the url delivered within the calling diff --git a/app/src/main/java/org/schabi/newpipe/services/Extractor.java b/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java similarity index 76% rename from app/src/main/java/org/schabi/newpipe/services/Extractor.java rename to app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java index a38b13f13..01ff361ef 100644 --- a/app/src/main/java/org/schabi/newpipe/services/Extractor.java +++ b/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java @@ -4,7 +4,7 @@ package org.schabi.newpipe.services; * Created by Christian Schabesberger on 10.08.15. * * Copyright (C) Christian Schabesberger 2015 - * Extractor.java is part of NewPipe. + * VideoExtractor.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 @@ -23,11 +23,12 @@ package org.schabi.newpipe.services; import org.schabi.newpipe.VideoInfo; /**Scrapes information from a video streaming service (eg, YouTube).*/ -public abstract class Extractor { - public String pageUrl; - public VideoInfo videoInfo; +public abstract class VideoExtractor { + protected final String pageUrl; + protected VideoInfo videoInfo; - public Extractor(String url) { + @SuppressWarnings("WeakerAccess") + public VideoExtractor(String url) { this.pageUrl = url; } @@ -99,17 +100,17 @@ public abstract class Extractor { return videoInfo; } - public abstract String getVideoUrl(String videoId); - public abstract String getVideoId(String siteUrl); - public abstract int getTimeStamp(); - public abstract String getTitle(); - public abstract String getDescription(); - public abstract String getUploader(); - public abstract int getLength(); - public abstract int getViews(); - public abstract String getUploadDate(); - public abstract String getThumbnailUrl(); - public abstract String getUploaderThumbnailUrl(); - public abstract VideoInfo.AudioStream[] getAudioStreams(); - public abstract VideoInfo.VideoStream[] getVideoStreams(); + protected abstract String getVideoUrl(String videoId); + protected abstract String getVideoId(String siteUrl); + protected abstract int getTimeStamp(); + protected abstract String getTitle(); + protected abstract String getDescription(); + protected abstract String getUploader(); + protected abstract int getLength(); + protected abstract int getViews(); + protected abstract String getUploadDate(); + protected abstract String getThumbnailUrl(); + protected abstract String getUploaderThumbnailUrl(); + protected abstract VideoInfo.AudioStream[] getAudioStreams(); + protected abstract VideoInfo.VideoStream[] getVideoStreams(); } diff --git a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeSearchEngine.java b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeSearchEngine.java index d01718ed2..a6d6e31c3 100644 --- a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeSearchEngine.java +++ b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeSearchEngine.java @@ -95,20 +95,18 @@ public class YoutubeSearchEngine implements SearchEngine { // both types of spell correction item if(!((el = item.select("div[class*=\"spell-correction\"]").first()) == null)) { result.suggestion = el.select("a").first().text(); - // search message item + // search message item } else if(!((el = item.select("div[class*=\"search-message\"]").first()) == null)) { result.errorMessage = el.text(); - // video item type + // video item type } else if(!((el = item.select("div[class*=\"yt-lockup-video\"").first()) == null)) { - //todo: de-duplicate this with YoutubeExtractor.getVideoPreviewInfo() VideoPreviewInfo resultItem = new VideoPreviewInfo(); Element dl = el.select("h3").first().select("a").first(); resultItem.webpage_url = dl.attr("abs:href"); try { Pattern p = Pattern.compile("v=([0-9a-zA-Z-]*)"); Matcher m = p.matcher(resultItem.webpage_url); - m.find(); resultItem.id=m.group(1); } catch (Exception e) { e.printStackTrace(); @@ -134,6 +132,7 @@ public class YoutubeSearchEngine implements SearchEngine { } result.resultList.add(resultItem); } else { + //noinspection ConstantConditions Log.e(TAG, "unexpected element found:\""+el+"\""); } } diff --git a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeService.java b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeService.java index e606c805d..576d8c065 100644 --- a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeService.java +++ b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeService.java @@ -1,7 +1,7 @@ package org.schabi.newpipe.services.youtube; import org.schabi.newpipe.services.StreamingService; -import org.schabi.newpipe.services.Extractor; +import org.schabi.newpipe.services.VideoExtractor; import org.schabi.newpipe.services.SearchEngine; @@ -33,9 +33,9 @@ public class YoutubeService implements StreamingService { return serviceInfo; } @Override - public Extractor getExtractorInstance(String url) { + public VideoExtractor getExtractorInstance(String url) { if(acceptUrl(url)) { - return new YoutubeExtractor(url); + return new YoutubeVideoExtractor(url); } else { throw new IllegalArgumentException("supplied String is not a valid Youtube URL"); diff --git a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeExtractor.java b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractor.java similarity index 97% rename from app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeExtractor.java rename to app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractor.java index cca460902..3112d7f0c 100644 --- a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractor.java @@ -13,7 +13,7 @@ import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.ScriptableObject; import org.schabi.newpipe.Downloader; -import org.schabi.newpipe.services.Extractor; +import org.schabi.newpipe.services.VideoExtractor; import org.schabi.newpipe.MediaFormat; import org.schabi.newpipe.VideoInfo; import org.schabi.newpipe.VideoPreviewInfo; @@ -31,7 +31,7 @@ import java.util.regex.Pattern; * Created by Christian Schabesberger on 06.08.15. * * Copyright (C) Christian Schabesberger 2015 - * YoutubeExtractor.java is part of NewPipe. + * YoutubeVideoExtractor.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 @@ -47,11 +47,10 @@ import java.util.regex.Pattern; * along with NewPipe. If not, see . */ -public class YoutubeExtractor extends Extractor { +public class YoutubeVideoExtractor extends VideoExtractor { - private static final String TAG = YoutubeExtractor.class.toString(); - private String pageContents; - private Document doc; + private static final String TAG = YoutubeVideoExtractor.class.toString(); + private final Document doc; private JSONObject jsonObj; private JSONObject playerArgs; @@ -62,9 +61,9 @@ public class YoutubeExtractor extends Extractor { private static volatile String decryptionCode = ""; - public YoutubeExtractor(String pageUrl) { + public YoutubeVideoExtractor(String pageUrl) { super(pageUrl);//most common videoInfo fields are now set in our superclass, for all services - pageContents = Downloader.download(cleanUrl(pageUrl)); + String pageContents = Downloader.download(cleanUrl(pageUrl)); doc = Jsoup.parse(pageContents, pageUrl); //attempt to load the youtube js player JSON arguments @@ -266,6 +265,8 @@ public class YoutubeExtractor extends Extractor { /**These lists only contain itag formats that are supported by the common Android Video player. However if you are looking for a list showing all itag formats, look at https://github.com/rg3/youtube-dl/issues/1687 */ + + @SuppressWarnings("WeakerAccess") public static int resolveFormat(int itag) { switch(itag) { // video @@ -285,6 +286,7 @@ public class YoutubeExtractor extends Extractor { } } + @SuppressWarnings("WeakerAccess") public static String resolveResolutionString(int itag) { switch(itag) { case 17: return "144p"; @@ -303,6 +305,7 @@ public class YoutubeExtractor extends Extractor { } } + @SuppressWarnings("WeakerAccess") @Override public String getVideoId(String url) { String id; @@ -327,6 +330,7 @@ public class YoutubeExtractor extends Extractor { return ""; } + @SuppressWarnings("WeakerAccess") @Override public String getVideoUrl(String videoId) { return "https://www.youtube.com/watch?v=" + videoId; @@ -579,7 +583,10 @@ public class YoutubeExtractor extends Extractor { e.printStackTrace(); } Context.exit(); - return result.toString(); + if(result != null) + return result.toString(); + else + return ""; } private String cleanUrl(String complexUrl) { diff --git a/app/src/main/res/drawable/buddy.png b/app/src/main/res/drawable-nodpi/buddy.png similarity index 100% rename from app/src/main/res/drawable/buddy.png rename to app/src/main/res/drawable-nodpi/buddy.png diff --git a/app/src/main/res/drawable/dummy_thumbnail.png b/app/src/main/res/drawable-nodpi/dummy_thumbnail.png similarity index 100% rename from app/src/main/res/drawable/dummy_thumbnail.png rename to app/src/main/res/drawable-nodpi/dummy_thumbnail.png diff --git a/app/src/main/res/drawable/gruese_die_gema_unangebracht.png b/app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png similarity index 100% rename from app/src/main/res/drawable/gruese_die_gema_unangebracht.png rename to app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png diff --git a/app/src/main/res/drawable/ic_cast_black.png b/app/src/main/res/drawable-nodpi/ic_cast_black.png similarity index 100% rename from app/src/main/res/drawable/ic_cast_black.png rename to app/src/main/res/drawable-nodpi/ic_cast_black.png diff --git a/app/src/main/res/drawable/ic_file_download_black.png b/app/src/main/res/drawable-nodpi/ic_file_download_black.png similarity index 100% rename from app/src/main/res/drawable/ic_file_download_black.png rename to app/src/main/res/drawable-nodpi/ic_file_download_black.png diff --git a/app/src/main/res/drawable/ic_headset_black.png b/app/src/main/res/drawable-nodpi/ic_headset_black.png similarity index 100% rename from app/src/main/res/drawable/ic_headset_black.png rename to app/src/main/res/drawable-nodpi/ic_headset_black.png diff --git a/app/src/main/res/drawable/ic_play_arrow_black.png b/app/src/main/res/drawable-nodpi/ic_play_arrow_black.png similarity index 100% rename from app/src/main/res/drawable/ic_play_arrow_black.png rename to app/src/main/res/drawable-nodpi/ic_play_arrow_black.png diff --git a/app/src/main/res/drawable/ic_screen_rotation_white.png b/app/src/main/res/drawable-nodpi/ic_screen_rotation_white.png similarity index 100% rename from app/src/main/res/drawable/ic_screen_rotation_white.png rename to app/src/main/res/drawable-nodpi/ic_screen_rotation_white.png diff --git a/app/src/main/res/drawable/ic_share_black.png b/app/src/main/res/drawable-nodpi/ic_share_black.png similarity index 100% rename from app/src/main/res/drawable/ic_share_black.png rename to app/src/main/res/drawable-nodpi/ic_share_black.png diff --git a/app/src/main/res/drawable/not_available_monkey.png b/app/src/main/res/drawable-nodpi/not_available_monkey.png similarity index 100% rename from app/src/main/res/drawable/not_available_monkey.png rename to app/src/main/res/drawable-nodpi/not_available_monkey.png diff --git a/app/src/main/res/drawable/thumbs_down.png b/app/src/main/res/drawable-nodpi/thumbs_down.png similarity index 100% rename from app/src/main/res/drawable/thumbs_down.png rename to app/src/main/res/drawable-nodpi/thumbs_down.png diff --git a/app/src/main/res/drawable/thumbs_up.png b/app/src/main/res/drawable-nodpi/thumbs_up.png similarity index 100% rename from app/src/main/res/drawable/thumbs_up.png rename to app/src/main/res/drawable-nodpi/thumbs_up.png diff --git a/app/src/main/res/drawable/gruese_die_gema_original.png b/app/src/main/res/drawable/gruese_die_gema_original.png deleted file mode 100644 index d40f6a86e..000000000 Binary files a/app/src/main/res/drawable/gruese_die_gema_original.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_arrow_back_white.png b/app/src/main/res/drawable/ic_arrow_back_white.png deleted file mode 100644 index cc78ba339..000000000 Binary files a/app/src/main/res/drawable/ic_arrow_back_white.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_share_white.png b/app/src/main/res/drawable/ic_share_white.png deleted file mode 100644 index e351c7beb..000000000 Binary files a/app/src/main/res/drawable/ic_share_white.png and /dev/null differ diff --git a/app/src/main/res/drawable/new_pipe_watermark.png b/app/src/main/res/drawable/new_pipe_watermark.png deleted file mode 100644 index 1401aa306..000000000 Binary files a/app/src/main/res/drawable/new_pipe_watermark.png and /dev/null 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 0ff3bfe19..02201f9f4 100644 --- a/app/src/main/res/layout-land/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout-land/fragment_videoitem_detail.xml @@ -31,10 +31,12 @@ android:layout_height="wrap_content"> @@ -52,17 +54,19 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:textStyle="bold" android:paddingBottom="5dp" android:textSize="@dimen/text_video_title_land_size" - android:textAppearance="?android:attr/textAppearanceLarge" - android:text="Video title placeholder"/> + android:textAppearance="?android:attr/textAppearanceLarge"/> + android:textAppearance="?android:attr/textAppearanceLarge" /> + android:textAppearance="?android:attr/textAppearanceLarge"/> + android:paddingRight="5dp" + android:paddingLeft="5dp" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:textAppearance="?android:attr/textAppearanceLarge" /> + android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -150,6 +162,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:paddingLeft="6dp" android:paddingRight="6dp" android:paddingTop="20dp" @@ -191,6 +204,7 @@ + android:focusable="false" + tools:ignore="InconsistentLayout" /> + android:layout_height="match_parent" + tools:ignore="InconsistentLayout" /> diff --git a/app/src/main/res/layout-sw600dp/fragment_videoitem_detail.xml b/app/src/main/res/layout-sw600dp/fragment_videoitem_detail.xml index 33edf8ab9..9bf507fef 100644 --- a/app/src/main/res/layout-sw600dp/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout-sw600dp/fragment_videoitem_detail.xml @@ -31,10 +31,12 @@ android:layout_height="wrap_content"> @@ -52,17 +54,19 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:textStyle="bold" android:paddingBottom="5dp" android:textSize="@dimen/text_video_title_sw600dp_size" - android:textAppearance="?android:attr/textAppearanceLarge" - android:text="Video title placeholder"/> + android:textAppearance="?android:attr/textAppearanceLarge"/> + android:textAppearance="?android:attr/textAppearanceLarge"/> + android:textAppearance="?android:attr/textAppearanceLarge"/> + android:paddingRight="5dp" + android:paddingLeft="5dp" + android:textAppearance="?android:attr/textAppearanceMedium"/> + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:textAppearance="?android:attr/textAppearanceLarge" /> + android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -150,6 +162,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:paddingLeft="6dp" android:paddingRight="6dp" android:paddingTop="20dp" @@ -190,6 +203,7 @@ @@ -25,4 +24,4 @@ android:layout_gravity="center" android:focusable="false"/> - + diff --git a/app/src/main/res/layout/fragment_videoitem_detail.xml b/app/src/main/res/layout/fragment_videoitem_detail.xml index f8e3224c0..02f7a0eb9 100644 --- a/app/src/main/res/layout/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout/fragment_videoitem_detail.xml @@ -31,10 +31,12 @@ android:layout_height="wrap_content"> @@ -52,17 +54,19 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:textStyle="bold" android:paddingBottom="3dp" android:textSize="@dimen/text_video_title_size" - android:textAppearance="?android:attr/textAppearanceLarge" - android:text="Video title placeholder"/> + android:textAppearance="?android:attr/textAppearanceLarge"/> + android:textAppearance="?android:attr/textAppearanceLarge" /> + android:textAppearance="?android:attr/textAppearanceLarge" /> + android:paddingRight="5dp" + android:paddingLeft="5dp" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:textAppearance="?android:attr/textAppearanceMedium"/> + android:textAppearance="?android:attr/textAppearanceLarge" /> + android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -155,6 +167,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:textSize="@dimen/text_video_upload_date_size" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@android:color/black" diff --git a/app/src/main/res/layout/video_item.xml b/app/src/main/res/layout/video_item.xml index eb376c53f..bac7d7964 100644 --- a/app/src/main/res/layout/video_item.xml +++ b/app/src/main/res/layout/video_item.xml @@ -7,11 +7,14 @@ android:padding="6dp"> @@ -19,26 +22,25 @@ android:layout_width="wrap_content" android:layout_height="36dp" android:layout_toRightOf="@id/itemThumbnailView" + android:layout_toEndOf="@id/itemThumbnailView" android:layout_alignParentTop="true" android:textAppearance="?android:attr/textAppearanceLarge" - android:textSize="@dimen/text_search_title_size" - android:text="title" - /> + android:textSize="@dimen/text_search_title_size"/> + android:textSize="@dimen/text_search_uploader_size"/> + android:textColor="@color/durationText"/> \ No newline at end of file diff --git a/app/src/main/res/menu/videoitem_list.xml b/app/src/main/res/menu/videoitem_list.xml index cd85a2053..54d582dc6 100644 --- a/app/src/main/res/menu/videoitem_list.xml +++ b/app/src/main/res/menu/videoitem_list.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7a93ed30d..5d197db07 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -2,20 +2,17 @@ NewPipe NewPipe - Nichts gefunden - Aufrufe - Hochgeladen am + %1$s Aufrufe + Hochgeladen am %1$s Keinen Streamplayer gefunden. Vielleicht möchtest du einen installieren. Jetzt installieren Abbrechen https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc In Browser öffnen Teilen - Play Download Suchen Einstellungen - Senden mit Meintest du: Suchseite: Teilen mit: @@ -35,7 +32,7 @@ https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore Zeige \"Mit Kodi abspielen\" Option Zeigt eine Option an, über die man Videos mit dem Kodi Mediacenter abspielen kann. - Zeige play button auf der linken seite. + Play-Button auf der linken Seite. Audio Bevorzugtes Audio Format WebM - freies Format @@ -49,4 +46,13 @@ Zeige nächstes und ähnliche Videos URL wird nicht unterstützt. Ähnliche Videos + VIDEO & AUDIO + INFO + ETC +Bevorzugte Sprache + Video-Vorschau-Bild + Video-Vorschau-Bild + Nutzerbild + gefällt nicht + gefällt diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9bed1ea7b..02b2e49aa 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -2,20 +2,17 @@ NewPipe NewPipe - No se ha encontrado nada - visitas - Subido el + %1$s visitas + Subido el %1$s No se ha encontrado ningún reproductor de vídeo. Quizás quieras instalar alguno. Instalarlo Cancelar https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Abrir en el navegador Compartir - Reproducir Descargar Buscar Ajustes - Enviar con "¿Querías decir?: " Buscar página: Compartir con: @@ -23,7 +20,7 @@ rotación Ajustes Usar reproductor externo - Descargar en... + Descargar en… Ruta donde guardar los vídeos descargados. Localización del directorio de descargas Reproducción automática @@ -42,8 +39,6 @@ m4a - mejor calidad Descargar Siguiente vídeo - Mostrar la opción \"Siguiente vídeo\". URL no soportada. Vídeos similares - País del contenido del vídeo diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index b24529f59..171c95453 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -2,20 +2,17 @@ NewPipe NewPipe - چیزی پیدا نشد - نماها - بارگذاری‌شده در: + %1$s نماها + بارگذاری‌شده در: %1$s هیچ پخش‌کننده‌ی جریانی یافت نشد. ممکن است بخواهید یکی نصب کنید. نصب کنید انصراف https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc بازکردن در مرورگر هم‌رسانی - پخش بارگیری جستجو تنظیمات - فرستادن با منظورتان این است: صفحه‌ی جستجو: هم‌رسانی با: @@ -46,6 +43,5 @@ صدا ویدئوی بعدی - نمایش گزینه‌ی «ویدئوی بعدی». پیوند پشتیبانی نمی‌شود. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index a7be73ba3..682b6653f 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -16,15 +16,12 @@ Installer Kore L\'application Kore est introuvable. Kore est nécessaire afin de lire des vidéos dans Kodi media center. Aucun lecteur de streaming détecté. Vous devriez en installer un. - Aucun résultat Ouvrir dans le navigateur - Lire Lecture automatique via Intent Lire avec Kodi rotation Chercher Chercher dans la page: - Envoyer avec Paramètres Partager Partager avec: @@ -32,10 +29,10 @@ Afficher l\'option \"Lire avec Kodi\" Paramètres NewPipe - Mise en ligne le + Mise en ligne le %1$s Utiliser un lecteur externe - vues -Afficher le bouton de lecture sur la gauche. + %1$s vues + Afficher le bouton de lecture sur la gauche. Audio Format audio par défaut WebM- format libre diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index d95ebf03a..440743000 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -2,20 +2,17 @@ NewPipe NewPipe - Nincs találat - megtekintés - Feltöltve: + %1$s megtekintés + Feltöltve: %1$s Nem található lejátszó. Telepítsen egyet! Telepítsen egyet Mégse https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Megnyitás böngészőben Megosztás - Lejátszás Letöltés Keresés Beállítások - Küldés ezzel: Erre gondolt: Keresési lap: Megosztás ezzel: @@ -46,7 +43,6 @@ Hang Következő videó - \"Következő videó\" elem mutatása A webcím nem támogatott. Hasonló videók diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index bc567885f..56159b96f 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,48 +1,57 @@ -ニューパイプ - ニューパイプ +NewPipe + NewPipe 何も見つかりません 表示 - "アップロード: " - StreamPlayer が見つかりませんでした。インストールが必要になるかもしれません. - インストール - キャンセル + "アップロード: "%1$s + StreamPlayer が見つかりませんでした。インストールが必要になるかもしれません。 + インストール + 取り消し https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc - ブラウザーで開く + ブラウザーで開く 共有 再生 - ダウンロード + ダウンロード 検索 設定 - …送信 + 送信 "この意味ですか: " - "検索ページ: " + "検索ページ: " …共有: - ブラウザーを選択: + ブラウザーを選択: 回転 設定 - 外部プレーヤーを使用する - ダウンロード場所 - ダウンロードしたビデオを保存する場所のパス. - ダウンロードのパスを入力してください - インテントで自動再生 - 別のアプリケーションから呼び出されたとき、自動的にビデオを開始します. - デフォルトの解像度 + 外部プレーヤーを使用する + ダウンロードする場所 + ダウンロードした動画を保存する場所のパス。 + ダウンロードのパスを入力してください。 + インテントで自動再生 + 他のアプリケーションから呼び出されたとき、自動的に動画再生を開始します。 + 基本の解像度 Kodi で再生 - Kore アプリが見つかりません。 Kodi メディアセンターでビデオを再生するには Kore が必要です。 - Kore をインストール + Kore アプリが見つかりません。 Kodi メディアセンターで動画を再生するには、 Kore が必要です。 + Kore をインストール https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore - \"Kodi で再生\" オプションを表示 - Kodi メディアセンター経由でビデオを再生するためのオプションを表示します. - 左側に再生ボタンを表示. - オーディオ - デフォルトのオーディオ フォーマット - WebM - フリーフォーマット - m4a - より良い品質 - ダウンロード - 次のビデオ - 次の同様のビデオを表示します - URL はサポートされていません。 - 同様のビデオ - 望ましいコンテンツ言語 + \"Kodi で再生\" 設定を表示 + Kodi メディアセンター経由で動画を再生するための設定を表示します. + 左側に再生ボタンを表示. + オーディオ + 基本のオーディオフォーマット + .WebM - フリーフォーマット + .m4a - より良い品質 + ダウンロード + 次の動画 + 次の同様の動画を表示します。 + URL は使用できません。 + 同様の動画 + 優先される言語 + 動画とオーディオ + 情報 + その他 +%1$s ビュー + ビデオ プレビュー サムネイル + ビデオ プレビュー サムネイル + アップローダー サムネイル + いいね解除 + いいね diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index f096ffc82..834101e85 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -2,20 +2,17 @@ NewPipe NewPipe - Geen resultaten - keer bekeken - Geüpload op + %1$s keer bekeken + Geüpload op %1$s Geen speler met streaming ondersteuning gevonden. Misschien wil je er een installeren. Installeer speler Annuleer https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Open in browser Deel - Speel af Download Zoek Instellingen - Verstuur met Bedoelde je: Zoekpagina: Deel met: @@ -35,15 +32,13 @@ https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore Toon \"Speel af met Kodi\" optie Toont een optie om een video op een Kodi media center af te spelen. -Video inhoud land -Afspeel knop aan de linker kant weergeven. + Afspeel knop aan de linker kant weergeven. Audio Standaard audio formaat Webam - open formaat m4a - betere kwaliteit Download Volgende video - \"Volgende video\" weergeven URL wordt niet ondersteund. Vergelijkbare videos Laat volgende en vergelijkbare videos zien diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 000000000..08634ea9e --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,56 @@ + +NewPipe + NewPipe + Brak wyników + wyświetleń + "Opublikowany " + Nie znaleziono odtwarzacza strumieniowego. + Zainstaluj + Anuluj + Otwórz w przeglądarce + Udostępnij + Odtwórz + Pobierz + Szukaj + Ustawienia + Wyślij za pośrednictwem + "Czy chodziło Ci o: " + Udostępnij za pośrednictwem: + Wybierz przeglądarkę: + obrót + Ustawienia + Użyj zewnętrznego odtwarzacza + Miejsce zapisu pobieranych plików + Ścieżka folderu do zapisywania pobieranego wideo. + Wprowadź ścieżkę folderu dla pobieranych plików + Automatycznie odtwarzaj przez Intent + Automatycznie odtwarza wideo po wywołaniu z innej aplikacji. + Domyślna rozdzielczość + Odtwarzaj za pośrednictwem Kodi + Aplikacja Kore nie została znaleziona. Wymagana jest do odtwarzania w Kodi. + Zainstaluj Kore + Wyświetlaj opcję \"Odtwarzaj za pośrednictwem Kodi\" + Wyświetla opcję do odtwarzania wideo przez aplikację Kodi. + Wyświetl przycisk odtwarzania po lewej stronie. + Dźwięk + Domyślny format dźwięku + WebM - otwarty format + m4a - lepsza jakość + Pobierz + Następne wideo + Wyświetl następne i podobne wideo + Niewspierany URL. + Podobne wideo + Preferowany język zawartości + WIDEO & DŹWIĘK + INFO + INNE +"Szukaj strony: " + %1$s wyświetleń + Opublikowany %1$s + Miniaturka podglądowa wideo + Miniaturka podglądowa wideo + Miniaturka wysyłającego + łapek w dół + polubień + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 73475f175..350b72c16 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -2,20 +2,17 @@ NewPipe NewPipe - Ничего не найдено - просмотров - Опубликовано: + %1$s просмотров + Опубликовано: %1$s Ни одного потокового проигрывателя не было найдено. Установить? Установить Отмена https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Открыть в браузере Поделиться - Воспроизвести Скачать Найти Настройки - Отправить с помощью Возможно, вы имели в виду: Страница поиска: Поделиться с помощью: @@ -46,9 +43,8 @@ Аудио Следующее видео - Показать \"Следующее видео\". URL не поддерживается. Похожие видео -Показывать следующее и предложенные видео + Показывать следующее и предложенные видео Предпочитаемый язык контента diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 89e4d4ce1..5cede012b 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -2,20 +2,17 @@ Јутјуб цев Јутјуб цев - Ништа није нађено - приказа - "Отпремљен " + %1$s приказа + "Отпремљен "%1$s Нема плејера токова. Можда желите да га инсталирате. Инсталирај Одустани https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Отвори у прегледачу Дели - Пусти Преузми Тражи Поставке - Пошаљи помоћу Да ли сте мислили: Страница претраге: Подели помоћу: @@ -45,10 +42,17 @@ Видео Аудио -Следећи видео - Приказ ставке „Следећи видео“. + Следећи видео УРЛ није подржан. -Прикажи следећи и слични видео + Прикажи следећи и слични видео Слични видео Пожељни језик садржаја +ВИДЕО И АУДИО + ПОДАЦИ + ОСТАЛО +Сличица видео прегледа + Сличица видео прегледа + Сличица отпремаоца + Несвиђања + Свиђања diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index 7a7d2adb6..6c4c1939d 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -16,17 +16,18 @@ @color/primaryColorYoutube - - - -