diff --git a/.gitignore b/.gitignore index 42caadb93..2b3c40d66 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /app/app.iml /.idea /*.iml +gradle.properties diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 149c4ba54..ede4461a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,11 @@ -#Contributing +#Contribution This document contains guidelines on making contributions to NewPipe. ## Programming * Follow the [Google Style Guidelines](https://google.github.io/styleguide/javaguide.html) -* Make a new feature on a seperate branch, not on the master branch +* Make a new feature on a separate branch, not on the master branch * Make a [pull request](https://github.com/theScrabi/NewPipe/pulls) if you're done with your changes * When submitting changes, you agree that your code will be GPLv3 licensed @@ -16,7 +16,7 @@ This document contains guidelines on making contributions to NewPipe. compatibility with all git tools * [This guide](http://chris.beams.io/posts/git-commit/) goes more in depth on what makes a good commit message -## Translating +## Translation * NewPipe can be translated on [weblate](https://hosted.weblate.org/projects/newpipe/strings/) @@ -30,4 +30,4 @@ This document contains guidelines on making contributions to NewPipe. ## Communication * For the time being, [Slack](http://invite.chschtsch.ml/) is being used for project communication -* Feel free to post suggestions, changes ideas etc! +* Feel free to post suggestions, changes, ideas etc! diff --git a/README.md b/README.md index e6d1d9498..b24ed14af 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only * Open a video in Kodi * Show Next/Related videos * Search YouTube in a specific language +* Orbot/Tor support (no streaming yet) ### Coming Features diff --git a/app/build.gradle b/app/build.gradle index 871a98a9d..5eaf3a6c4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "org.schabi.newpipe" minSdkVersion 15 targetSdkVersion 23 - versionCode 9 - versionName "0.7.0" + versionCode 11 + versionName "0.7.2" } buildTypes { release { @@ -17,7 +17,7 @@ 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, @@ -35,4 +35,5 @@ dependencies { compile 'com.android.support:recyclerview-v7:23.1.1' compile 'org.jsoup:jsoup:1.8.3' compile 'org.mozilla:rhino:1.7.7' + compile 'info.guardianproject.netcipher:netcipher:1.2' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 05eda83c5..2f2ec061b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + - + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + android:label="@string/background_player_name" + android:exported="false" /> + android:label="@string/settings_activity_title" > + + + + + + + diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java index c8b4061f7..490b8d6f4 100644 --- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java +++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java @@ -99,8 +99,8 @@ class ActionBarHandler { defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity); String[] itemArray = new String[videoStreams.length]; String defaultResolution = defaultPreferences - .getString(activity.getString(R.string.defaultResolutionPreference), - activity.getString(R.string.defaultResolutionListItem)); + .getString(activity.getString(R.string.default_resolution_key), + activity.getString(R.string.default_resolution_value)); int defaultResolutionPos = 0; for(int i = 0; i < videoStreams.length; i++) { @@ -124,7 +124,7 @@ class ActionBarHandler { // set audioStream audioStream = null; String preferedFormat = defaultPreferences - .getString(activity.getString(R.string.defaultAudioFormatPreference), "webm"); + .getString(activity.getString(R.string.default_audio_format_key), "webm"); if(preferedFormat.equals("webm")) { for(VideoInfo.AudioStream s : audioStreams) { if(s.format == MediaFormat.WEBMA.id) { @@ -158,7 +158,7 @@ class ActionBarHandler { MenuItem castItem = menu.findItem(R.id.action_play_with_kodi); castItem.setVisible(defaultPreferences - .getBoolean(activity.getString(R.string.showPlayWithKodiPreference), false)); + .getBoolean(activity.getString(R.string.show_play_with_kodi_key), false)); } public boolean onItemSelected(MenuItem item) { @@ -170,7 +170,7 @@ class ActionBarHandler { intent.setAction(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, websiteUrl); intent.setType("text/plain"); - activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.shareDialogTitle))); + activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.share_dialog_title))); return true; } case R.id.menu_item_openInBrowser: { @@ -210,7 +210,7 @@ class ActionBarHandler { // ----------- THE MAGIC MOMENT --------------- if(!videoTitle.isEmpty()) { if (PreferenceManager.getDefaultSharedPreferences(activity) - .getBoolean(activity.getString(R.string.useExternalVideoPlayer), false)) { + .getBoolean(activity.getString(R.string.use_external_video_player_key), false)) { // External Player Intent intent = new Intent(); @@ -226,13 +226,13 @@ class ActionBarHandler { } catch (Exception e) { e.printStackTrace(); AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setMessage(R.string.noPlayerFound) - .setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() { + builder.setMessage(R.string.no_player_found) + .setPositiveButton(R.string.install, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(activity.getString(R.string.fdroidVLCurl))); + intent.setData(Uri.parse(activity.getString(R.string.fdroid_vlc_url))); activity.startActivity(intent); } }) @@ -284,7 +284,7 @@ class ActionBarHandler { intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse(websiteUrl)); - activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.chooseBrowser))); + activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.choose_browser))); } } @@ -298,13 +298,13 @@ class ActionBarHandler { } catch (Exception e) { e.printStackTrace(); AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setMessage(R.string.koreNotFound) - .setPositiveButton(R.string.installeKore, new DialogInterface.OnClickListener() { + builder.setMessage(R.string.kore_not_found) + .setPositiveButton(R.string.install, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(activity.getString(R.string.fdroidKoreUrl))); + intent.setData(Uri.parse(activity.getString(R.string.fdroid_kore_url))); activity.startActivity(intent); } }) @@ -322,7 +322,7 @@ class ActionBarHandler { public void playAudio() { boolean externalAudioPlayer = PreferenceManager.getDefaultSharedPreferences(activity) - .getBoolean(activity.getString(R.string.useExternalAudioPlayer), false); + .getBoolean(activity.getString(R.string.use_external_audio_player_key), false); Intent intent; if (!externalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 18) { @@ -356,13 +356,13 @@ class ActionBarHandler { } catch (Exception e) { e.printStackTrace(); AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setMessage(R.string.noPlayerFound) - .setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() { + builder.setMessage(R.string.no_player_found) + .setPositiveButton(R.string.install, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(activity.getString(R.string.fdroidVLCurl))); + intent.setData(Uri.parse(activity.getString(R.string.fdroid_vlc_url))); activity.startActivity(intent); } }) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java new file mode 100644 index 000000000..d842e3f0a --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -0,0 +1,71 @@ +package org.schabi.newpipe; + +import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import info.guardianproject.netcipher.NetCipher; +import info.guardianproject.netcipher.proxy.OrbotHelper; + +/** + * Copyright (C) Hans-Christoph Steiner 2016 + * App.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 class App extends Application { + + private static boolean useTor; + + @Override + public void onCreate() { + super.onCreate(); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + if(prefs.getBoolean(getString(R.string.use_tor_key), false)) { + OrbotHelper.requestStartTor(this); + configureTor(true); + } else { + configureTor(false); + } + + // DO NOT REMOVE THIS FUNCTION!!! + // Otherwise downloadPathPreference has invalid value. + SettingsActivity.initSettings(this); + } + + /** + * Set the proxy settings based on whether Tor should be enabled or not. + */ + static void configureTor(boolean enabled) { + useTor = enabled; + if (useTor) { + NetCipher.useTor(); + } else { + NetCipher.setProxy(null); + } + } + + static void checkStartTor(Context context) { + if (useTor) { + OrbotHelper.requestStartTor(context); + } + } + + static boolean isUsingTor() { + return useTor; + } +} diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 5573e2771..cf0f88d05 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -17,6 +17,7 @@ import android.os.IBinder; import android.os.PowerManager; import android.support.v7.app.NotificationCompat; import android.util.Log; +import android.widget.RemoteViews; import android.widget.Toast; import java.io.IOException; @@ -74,7 +75,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } @Override public int onStartCommand(Intent intent, int flags, int startId) { - Toast.makeText(this, R.string.backgroundPlayerStartPlayingToast, + Toast.makeText(this, R.string.background_player_playing_toast, Toast.LENGTH_SHORT).show(); String source = intent.getDataString(); @@ -113,9 +114,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare private int noteID = TAG.hashCode(); private BackgroundPlayer owner; private NotificationManager noteMgr; - private NotificationCompat.Builder noteBuilder; private WifiManager.WifiLock wifiLock; private Bitmap videoThumbnail = null; + private NotificationCompat.Builder noteBuilder; public PlayerThread(String src, String title, BackgroundPlayer owner) { this.source = src; @@ -124,10 +125,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } + @Override public void run() { - Resources res = getApplicationContext().getResources(); - mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock try { mediaPlayer.setDataSource(source); @@ -135,9 +135,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare //so calling the blocking prepare() method should be ok mediaPlayer.prepare(); - //alternatively: - //mediaPlayer.setOnPreparedListener(this); - //mediaPlayer.prepareAsync(); //prepare async to not block main thread } catch (IOException ioe) { ioe.printStackTrace(); Log.e(TAG, "video source:" + source); @@ -177,63 +174,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare filter.addAction(ACTION_STOP); registerReceiver(broadcastReceiver, filter); - PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, - new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); - - NotificationCompat.Action playButton = new NotificationCompat.Action.Builder - (R.drawable.ic_play_arrow_white_48dp, "Play", playPI).build(); - - /* - NotificationCompat.Action pauseButton = new NotificationCompat.Action.Builder - (R.drawable.ic_pause_white_24dp, "Pause", playPI).build(); - */ - - PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID, - new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT); - - noteBuilder = new NotificationCompat.Builder(owner); - noteBuilder - .setContentTitle(title) - //really? Id like to put something more helpful here. - //.setContentText("NewPipe is playing in the background") - .setContentText(channelName) - //.setAutoCancel(!mediaPlayer.isPlaying()) - .setOngoing(true) - .setDeleteIntent(stopPI) - //doesn't fit with Notification.MediaStyle - //.setProgress(vidLength, 0, false) - .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp) - .setLargeIcon(videoThumbnail) - .setTicker( - String.format(res.getString( - R.string.backgroundPlayerTickerText), title)) - .addAction(playButton); - //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - //.setLargeIcon(cover) - if(android.os.Build.VERSION.SDK_INT >= 16) - noteBuilder.setPriority(Notification.PRIORITY_LOW); - if(android.os.Build.VERSION.SDK_INT >= 21) - noteBuilder.setCategory(Notification.CATEGORY_TRANSPORT); - - noteBuilder.setStyle(new NotificationCompat.MediaStyle() - //.setMediaSession(mMediaSession.getSessionToken()) - .setShowActionsInCompactView(new int[]{0}) - .setShowCancelButton(true) - .setCancelButtonIntent(stopPI)); - if(videoThumbnail != null) { - noteBuilder.setLargeIcon(videoThumbnail); - } - - Notification note = noteBuilder.build(); - - Intent openDetailView = new Intent(getApplicationContext(), - VideoItemDetailActivity.class); - openDetailView.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, serviceId); - openDetailView.putExtra(VideoItemDetailFragment.VIDEO_URL, webUrl); - openDetailView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - note.contentIntent = PendingIntent.getActivity(getApplicationContext(), - noteID, openDetailView, - PendingIntent.FLAG_UPDATE_CURRENT); + Notification note = buildNotification(); startForeground(noteID, note); @@ -252,9 +193,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare Log.d(TAG, "sleep failure"); } }*/ - } + /**Handles button presses from the notification. */ private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -265,7 +206,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare mediaPlayer.pause(); } else { - //reacquire CPU lock after releasing it on pause + //reacquire CPU lock after auto-releasing it on pause mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); mediaPlayer.start(); } @@ -279,8 +220,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare }; private void afterPlayCleanup() { - //noteBuilder.setProgress(0, 0, false); //remove progress bar + //noteBuilder.setProgress(0, 0, false); + //remove notification noteMgr.cancel(noteID); unregisterReceiver(broadcastReceiver); @@ -289,7 +231,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare //release wifilock wifiLock.release(); - //remove foreground status of service; make us killable + //remove foreground status of service; make BackgroundPlayer killable stopForeground(true); stopSelf(); @@ -306,5 +248,110 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare afterPlayCleanup(); } } + + private Notification buildNotification() { + Notification note; + Resources res = getApplicationContext().getResources(); + noteBuilder = new NotificationCompat.Builder(owner); + + PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, + new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID, + new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT); + /* + NotificationCompat.Action pauseButton = new NotificationCompat.Action.Builder + (R.drawable.ic_pause_white_24dp, "Pause", playPI).build(); + */ + + //build intent to return to video, on tapping notification + Intent openDetailView = new Intent(getApplicationContext(), + VideoItemDetailActivity.class); + openDetailView.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, serviceId); + openDetailView.putExtra(VideoItemDetailFragment.VIDEO_URL, webUrl); + openDetailView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + noteBuilder + .setOngoing(true) + .setDeleteIntent(stopPI) + //doesn't fit with Notification.MediaStyle + //.setProgress(vidLength, 0, false) + .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp) + .setTicker( + String.format(res.getString( + R.string.background_player_time_text), title)) + .setContentIntent(PendingIntent.getActivity(getApplicationContext(), + noteID, openDetailView, + PendingIntent.FLAG_UPDATE_CURRENT)); + + + if (android.os.Build.VERSION.SDK_INT < 21) { + + NotificationCompat.Action playButton = new NotificationCompat.Action.Builder + (R.drawable.ic_play_arrow_white_48dp, + res.getString(R.string.play_btn_text), playPI).build(); + + noteBuilder + .setContentTitle(title) + //really? Id like to put something more helpful here. + //was more of a placeholder than anything else. -medavox + //.setContentText("NewPipe is playing in the background") + .setContentText(channelName) + //.setAutoCancel(!mediaPlayer.isPlaying()) + .setDeleteIntent(stopPI) + //doesn't fit with Notification.MediaStyle + //.setProgress(vidLength, 0, false) + .setLargeIcon(videoThumbnail) + .addAction(playButton); + //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + //.setLargeIcon(cover) + + //is wrapping this in an SDK version check really necessary, + // if we're using NotificationCompat? + // the compat libraries should handle this, right? -medavox + if (android.os.Build.VERSION.SDK_INT >= 16) + noteBuilder.setPriority(Notification.PRIORITY_LOW); + + noteBuilder.setStyle(new NotificationCompat.MediaStyle() + //.setMediaSession(mMediaSession.getSessionToken()) + .setShowActionsInCompactView(new int[]{0}) + .setShowCancelButton(true) + .setCancelButtonIntent(stopPI)); + if (videoThumbnail != null) { + noteBuilder.setLargeIcon(videoThumbnail); + } + note = noteBuilder.build(); + } else { + RemoteViews view = + new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification); + view.setImageViewBitmap(R.id.backgroundCover, videoThumbnail); + view.setTextViewText(R.id.backgroundSongName, title); + view.setTextViewText(R.id.backgroundArtist, channelName); + view.setOnClickPendingIntent(R.id.backgroundStop, stopPI); + view.setOnClickPendingIntent(R.id.backgroundPlayPause, playPI); + + //possibly found the expandedView problem, + //but can't test it as I don't have a 5.0 device. -medavox + RemoteViews expandedView = + new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification_expanded); + expandedView.setImageViewBitmap(R.id.backgroundCover, videoThumbnail); + expandedView.setTextViewText(R.id.backgroundSongName, title); + expandedView.setTextViewText(R.id.backgroundArtist, channelName); + expandedView.setOnClickPendingIntent(R.id.backgroundStop, stopPI); + expandedView.setOnClickPendingIntent(R.id.backgroundPlayPause, playPI); + + noteBuilder.setCategory(Notification.CATEGORY_TRANSPORT); + + //Make notification appear on lockscreen + noteBuilder.setVisibility(Notification.VISIBILITY_PUBLIC); + + note = noteBuilder.build(); + note.contentView = view; + + //todo: This never shows up. I was not able to figure out why: + note.bigContentView = expandedView; + } + + return note; + } } } diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index 903251e58..aa56c9349 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -52,49 +52,58 @@ public class DownloadDialog extends DialogFragment { arguments = getArguments(); super.onCreateDialog(savedInstanceState); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.downloadDialogTitle) - .setItems(R.array.downloadOptions, new DialogInterface.OnClickListener() { + builder.setTitle(R.string.download_dialog_title) + .setItems(R.array.download_options, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Context context = getActivity(); - SharedPreferences defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); String suffix = ""; String title = arguments.getString(TITLE); String url = ""; + String downloadFolder = Environment.DIRECTORY_DOWNLOADS; switch(which) { case 0: // Video suffix = arguments.getString(FILE_SUFFIX_VIDEO); url = arguments.getString(VIDEO_URL); + downloadFolder = Environment.DIRECTORY_MOVIES; break; case 1: suffix = arguments.getString(FILE_SUFFIX_AUDIO); url = arguments.getString(AUDIO_URL); + downloadFolder = Environment.DIRECTORY_MUSIC; break; default: Log.d(TAG, "lolz"); } - //to avoid hard-coded string like "/storage/emulated/0/NewPipe" - final File dir = new File(defaultPreferences.getString( - "download_path_preference", - Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe")); + //to avoid hard-coded string like "/storage/emulated/0/Movies" + String downloadPath = prefs.getString(getString(R.string.download_path_key), + Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + downloadFolder); + final File dir = new File(downloadPath); if(!dir.exists()) { - boolean mkdir = dir.mkdir(); //attempt to create directory + //attempt to create directory + boolean mkdir = dir.mkdir(); if(!mkdir && !dir.isDirectory()) { Log.e(TAG, "Cant' create directory named " + dir.toString()); //TODO notify user "download directory should be changed" ? } } - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Request request = new DownloadManager.Request( - Uri.parse(url)); - request.setDestinationUri(Uri.fromFile(new File( - defaultPreferences.getString("download_path_preference", "/storage/emulated/0/NewPipe") - + "/" + title + suffix))); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - try { - dm.enqueue(request); - } catch (Exception e) { - e.printStackTrace(); + + String saveFilePath = dir + "/" + title + suffix; + if (App.isUsingTor()) { + // if using Tor, do not use DownloadManager because the proxy cannot be set + Downloader.downloadFile(getContext(), url, saveFilePath); + } else { + DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager.Request request = new DownloadManager.Request( + Uri.parse(url)); + request.setDestinationUri(Uri.fromFile(new File(saveFilePath))); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + try { + dm.enqueue(request); + } catch (Exception e) { + 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 f0a19cfc5..cbc4c26c2 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -1,12 +1,30 @@ package org.schabi.newpipe; + +import android.app.NotificationManager; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.preference.PreferenceManager; +import android.support.v4.app.NotificationCompat; +import android.util.Log; + +import java.io.BufferedInputStream; import java.io.BufferedReader; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.UnknownHostException; +import javax.net.ssl.HttpsURLConnection; + +import info.guardianproject.netcipher.NetCipher; + /** * Created by Christian Schabesberger on 14.08.15. * @@ -28,7 +46,7 @@ import java.net.UnknownHostException; */ public class Downloader { - + public static final String TAG = "Downloader"; private static final String USER_AGENT = "Mozilla/5.0"; /**Download the text file at the supplied URL as in download(String), @@ -40,7 +58,7 @@ public class Downloader { String ret = ""; try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); con.setRequestProperty("Accept-Language", language); ret = dl(con); } @@ -49,8 +67,9 @@ public class Downloader { } return ret; } + /**Common functionality between download(String url) and download(String url, String language)*/ - private static String dl(HttpURLConnection con) throws IOException { + private static String dl(HttpsURLConnection con) throws IOException { StringBuilder response = new StringBuilder(); try { @@ -84,7 +103,7 @@ public class Downloader { try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + HttpsURLConnection con = NetCipher.getHttpsURLConnection(url); ret = dl(con); } catch(Exception e) { @@ -93,4 +112,92 @@ public class Downloader { return ret; } + + /** + * Downloads a file from a URL in the background using an {@link AsyncTask}. + * + * @param fileURL HTTP URL of the file to be downloaded + * @param saveFilePath path of the directory to save the file + * @throws IOException + */ + public static void downloadFile(final Context context, final String fileURL, final String saveFilePath) { + new AsyncTask() { + + private NotificationManager nm; + private NotificationCompat.Builder builder; + private int notifyId = 0x1234; + private int fileSize = 0xffffffff; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + Drawable icon = context.getResources().getDrawable(R.mipmap.ic_launcher); + builder = new NotificationCompat.Builder(context) + .setSmallIcon(android.R.drawable.stat_sys_download) + .setLargeIcon(((BitmapDrawable) icon).getBitmap()) + .setContentTitle(saveFilePath.substring(saveFilePath.lastIndexOf('/') + 1)) + .setContentText(saveFilePath) + .setProgress(fileSize, 0, false); + nm.notify(notifyId, builder.build()); + } + + @Override + protected Void doInBackground(Void... voids) { + HttpsURLConnection con = null; + try { + con = NetCipher.getHttpsURLConnection(fileURL); + int responseCode = con.getResponseCode(); + + // always check HTTP response code first + if (responseCode == HttpURLConnection.HTTP_OK) { + fileSize = con.getContentLength(); + InputStream inputStream = new BufferedInputStream(con.getInputStream()); + FileOutputStream outputStream = new FileOutputStream(saveFilePath); + + int bufferSize = 8192; + int downloaded = 0; + + int bytesRead = -1; + byte[] buffer = new byte[bufferSize]; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + downloaded += bytesRead; + if (downloaded % 50000 < bufferSize) { + publishProgress(downloaded); + } + } + + outputStream.close(); + inputStream.close(); + publishProgress(bufferSize); + + } else { + Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (con != null) { + con.disconnect(); + con = null; + } + } + return null; + } + + @Override + protected void onProgressUpdate(Integer... progress) { + builder.setProgress(fileSize, progress[0], false); + nm.notify(notifyId, builder.build()); + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + nm.cancel(notifyId); + } + }.execute(); + } + } diff --git a/app/src/main/java/org/schabi/newpipe/ExitActivity.java b/app/src/main/java/org/schabi/newpipe/ExitActivity.java new file mode 100644 index 000000000..6e14cfd9f --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/ExitActivity.java @@ -0,0 +1,54 @@ + +package org.schabi.newpipe; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; + +/** + * Copyright (C) Hans-Christoph Steiner 2016 + * ExitActivity.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 class ExitActivity extends Activity { + + @SuppressLint("NewApi") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (Build.VERSION.SDK_INT >= 21) { + finishAndRemoveTask(); + } else { + finish(); + } + + System.exit(0); + } + + public static void exitAndRemoveFromRecentApps(Activity activity) { + Intent intent = new Intent(activity, ExitActivity.class); + + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION); + + activity.startActivity(intent); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/Localization.java b/app/src/main/java/org/schabi/newpipe/Localization.java new file mode 100644 index 000000000..0f448777e --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/Localization.java @@ -0,0 +1,93 @@ +package org.schabi.newpipe; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.preference.PreferenceManager; + +import java.text.DateFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * Created by chschtsch on 12/29/15. + * + * Copyright (C) Gregory Arkhipov 2015 + * Localization.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 class Localization { + + public static Locale getPreferredLocale(Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + + String languageCode = sp.getString(String.valueOf(R.string.search_language_key), + context.getString(R.string.default_language_value)); + + 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 static String localizeViewCount(long viewCount, Context context) { + Locale locale = getPreferredLocale(context); + + Resources res = context.getResources(); + String viewsString = res.getString(R.string.view_count_text); + + NumberFormat nf = NumberFormat.getInstance(locale); + String formattedViewCount = nf.format(viewCount); + return String.format(viewsString, formattedViewCount); + } + + public static String localizeNumber(long number, Context context) { + Locale locale = getPreferredLocale(context); + NumberFormat nf = NumberFormat.getInstance(locale); + return nf.format(number); + } + + private static String formatDate(String date, Context context) { + Locale locale = getPreferredLocale(context); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date datum = null; + try { + datum = formatter.parse(date); + } catch (ParseException e) { + e.printStackTrace(); + } + + DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); + + return df.format(datum); + } + + public static String localizeDate(String date, Context context) { + Resources res = context.getResources(); + String dateString = res.getString(R.string.upload_date_text); + + String formattedDate = formatDate(date, context); + return String.format(dateString, formattedDate); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java b/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java new file mode 100644 index 000000000..8a36f5d5e --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java @@ -0,0 +1,50 @@ + +package org.schabi.newpipe; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; + +/** + * Copyright (C) Hans-Christoph Steiner 2016 + * PanicResponderActivity.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 class PanicResponderActivity extends Activity { + + public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER"; + + @SuppressLint("NewApi") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) { + // TODO explicitly clear the search results once they are restored when the app restarts + // or if the app reloads the current video after being killed, that should be cleared also + ExitActivity.exitAndRemoveFromRecentApps(this); + } + + if (Build.VERSION.SDK_INT >= 21) { + finishAndRemoveTask(); + } else { + finish(); + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index d5fea8c3e..ce1cf64cd 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -187,6 +187,18 @@ public class PlayVideoActivity extends AppCompatActivity { videoView.pause(); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + prefs = getPreferences(Context.MODE_PRIVATE); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); @@ -199,7 +211,7 @@ public class PlayVideoActivity extends AppCompatActivity { intent.setAction(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, videoUrl); intent.setType("text/plain"); - startActivity(Intent.createChooser(intent, getString(R.string.shareDialogTitle))); + startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title))); break; case R.id.menu_item_screen_rotation: toggleOrientation(); diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index b434b53d8..52f4a17a3 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -1,10 +1,15 @@ package org.schabi.newpipe; +import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Bundle; import android.os.Environment; +import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.ListPreference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; @@ -17,6 +22,8 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import info.guardianproject.netcipher.proxy.OrbotHelper; + /** * Created by Christian Schabesberger on 31.08.15. * @@ -37,8 +44,9 @@ import android.view.ViewGroup; * along with NewPipe. If not, see . */ -public class SettingsActivity extends PreferenceActivity { +public class SettingsActivity extends PreferenceActivity { + private static final int REQUEST_INSTALL_ORBOT = 0x1234; private AppCompatDelegate mDelegate = null; @Override @@ -55,12 +63,100 @@ public class SettingsActivity extends PreferenceActivity { } - public static class SettingsFragment extends PreferenceFragment { + public static class SettingsFragment extends PreferenceFragment{ + SharedPreferences.OnSharedPreferenceChangeListener prefListener; + + // get keys + String DEFAULT_RESOLUTION_PREFERENCE; + String DEFAULT_AUDIO_FORMAT_PREFERENCE; + String SEARCH_LANGUAGE_PREFERENCE; + String DOWNLOAD_PATH_PREFERENCE; + String USE_TOR_KEY; + + private ListPreference defaultResolutionPreference; + private ListPreference defaultAudioFormatPreference; + private ListPreference searchLanguagePreference; + private EditTextPreference downloadPathPreference; + private CheckBoxPreference useTorCheckBox; + private SharedPreferences defaultPreferences; + + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.settings_screen); + addPreferencesFromResource(R.xml.settings); + + final Activity activity = getActivity(); + + defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity); + + // get keys + DEFAULT_RESOLUTION_PREFERENCE =getString(R.string.default_resolution_key); + DEFAULT_AUDIO_FORMAT_PREFERENCE =getString(R.string.default_audio_format_key); + SEARCH_LANGUAGE_PREFERENCE =getString(R.string.search_language_key); + DOWNLOAD_PATH_PREFERENCE = getString(R.string.download_path_key); + USE_TOR_KEY = getString(R.string.use_tor_key); + + // get pref objects + defaultResolutionPreference = + (ListPreference) findPreference(DEFAULT_RESOLUTION_PREFERENCE); + defaultAudioFormatPreference = + (ListPreference) findPreference(DEFAULT_AUDIO_FORMAT_PREFERENCE); + searchLanguagePreference = + (ListPreference) findPreference(SEARCH_LANGUAGE_PREFERENCE); + downloadPathPreference = + (EditTextPreference) findPreference(DOWNLOAD_PATH_PREFERENCE); + useTorCheckBox = (CheckBoxPreference) findPreference(USE_TOR_KEY); + + prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + Activity a = getActivity(); + updateSummary(); + + if (defaultPreferences.getBoolean(USE_TOR_KEY, false)) { + if (OrbotHelper.isOrbotInstalled(a)) { + App.configureTor(true); + OrbotHelper.requestStartTor(a); + } else { + Intent intent = OrbotHelper.getOrbotInstallIntent(a); + a.startActivityForResult(intent, REQUEST_INSTALL_ORBOT); + } + } else { + App.configureTor(false); + } + } + }; + defaultPreferences.registerOnSharedPreferenceChangeListener(prefListener); + + updateSummary(); } + + // This is used to show the status of some preference in the description + private void updateSummary() { + defaultResolutionPreference.setSummary( + defaultPreferences.getString(DEFAULT_RESOLUTION_PREFERENCE, + getString(R.string.default_resolution_value))); + defaultAudioFormatPreference.setSummary( + defaultPreferences.getString(DEFAULT_AUDIO_FORMAT_PREFERENCE, + getString(R.string.default_audio_format_value))); + searchLanguagePreference.setSummary( + defaultPreferences.getString(SEARCH_LANGUAGE_PREFERENCE, + getString(R.string.default_language_value))); + downloadPathPreference.setSummary( + defaultPreferences.getString(DOWNLOAD_PATH_PREFERENCE, + getString(R.string.download_path_summary))); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + // try to start tor regardless of resultCode since clicking back after + // installing the app does not necessarily return RESULT_OK + App.configureTor(requestCode == REQUEST_INSTALL_ORBOT + && OrbotHelper.requestStartTor(this)); } @Override @@ -150,13 +246,13 @@ public class SettingsActivity extends PreferenceActivity { } public static void initSettings(Context context) { - PreferenceManager.setDefaultValues(context, R.xml.settings_screen, false); + PreferenceManager.setDefaultValues(context, R.xml.settings, false); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - if(sp.getString(context.getString(R.string.downloadPathPreference), "").isEmpty()){ + if(sp.getString(context.getString(R.string.download_path_key), "").isEmpty()){ SharedPreferences.Editor spEditor = sp.edit(); String newPipeDownloadStorage = Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe"; - spEditor.putString(context.getString(R.string.downloadPathPreference) + spEditor.putString(context.getString(R.string.download_path_key) , newPipeDownloadStorage); spEditor.apply(); } diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java index b7eaa4285..c2bbb069e 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java @@ -1,5 +1,6 @@ package org.schabi.newpipe; +import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -33,7 +34,7 @@ class VideoInfoItemViewCreator { this.inflater = inflater; } - public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info) { + public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info, Context context) { ViewHolder holder; if(convertView == null) { convertView = inflater.inflate(R.layout.video_item, parent, false); @@ -59,8 +60,7 @@ class VideoInfoItemViewCreator { 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(String.format("%d", info.view_count)); + holder.itemUploadDateView.setText(Localization.localizeViewCount(info.view_count, context)); } 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 4a553241f..bf28549b3 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java @@ -80,7 +80,7 @@ public class VideoItemDetailActivity extends AppCompatActivity { } } if(currentStreamingService == -1) { - Toast.makeText(this, R.string.urlNotSupportedText, Toast.LENGTH_LONG) + Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG) .show(); } //arguments.putString(VideoItemDetailFragment.VIDEO_URL, @@ -89,7 +89,7 @@ public class VideoItemDetailActivity extends AppCompatActivity { arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, PreferenceManager.getDefaultSharedPreferences(this) - .getBoolean(getString(R.string.autoPlayThroughIntent), false)); + .getBoolean(getString(R.string.autoplay_through_intent_key), false)); } else { videoUrl = getIntent().getStringExtra(VideoItemDetailFragment.VIDEO_URL); currentStreamingService = getIntent().getIntExtra(VideoItemDetailFragment.STREAMING_SERVICE, -1); @@ -113,6 +113,12 @@ public class VideoItemDetailActivity extends AppCompatActivity { .commit(); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + @Override public void onSaveInstanceState(Bundle outState) { outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index 0173c07de..03ec4e5aa 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -1,9 +1,7 @@ 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; @@ -35,13 +33,7 @@ import android.view.MenuItem; import android.widget.Toast; import java.net.URL; -import java.text.DateFormat; -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; -import java.util.Locale; import java.util.Vector; import org.schabi.newpipe.services.VideoExtractor; @@ -235,7 +227,7 @@ public class VideoItemDetailFragment extends Fragment { switch (info.errorCode) { case VideoInfo.NO_ERROR: { View nextVideoView = videoItemViewCreator - .getViewFromVideoInfoItem(null, nextVideoFrame, info.nextVideo); + .getViewFromVideoInfoItem(null, nextVideoFrame, info.nextVideo, getContext()); nextVideoFrame.addView(nextVideoView); @@ -253,31 +245,20 @@ public class VideoItemDetailFragment extends Fragment { uploaderView.setText(info.uploader); actionBarHandler.setChannelName(info.uploader); - Locale locale = getPreferredLocale(); - NumberFormat nf = NumberFormat.getInstance(locale); - String localisedViewCount = nf.format(info.view_count); - viewCountView.setText( - String.format( - res.getString(R.string.viewCountText), localisedViewCount)); + String localizedViewCount = Localization.localizeViewCount(info.view_count, getContext()); + viewCountView.setText(localizedViewCount); - thumbsUpView.setText(nf.format(info.like_count)); - thumbsDownView.setText(nf.format(info.dislike_count)); + String localizedLikeCount = Localization.localizeNumber(info.like_count, getContext()); + thumbsUpView.setText(localizedLikeCount); - @SuppressLint("SimpleDateFormat") - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - Date datum = null; - try { - datum = formatter.parse(info.upload_date); - } catch (ParseException e) { - e.printStackTrace(); - } + String localizedDislikeCount = Localization.localizeNumber(info.dislike_count, getContext()); + thumbsDownView.setText(localizedDislikeCount); - DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); + String localizedDate = Localization.localizeDate(info.upload_date, getContext()); + uploadDateView.setText(localizedDate); - String localisedDate = df.format(datum); - uploadDateView.setText( - String.format(res.getString(R.string.uploadDateText), localisedDate)); descriptionView.setText(Html.fromHtml(info.description)); + descriptionView.setMovementMethod(LinkMovementMethod.getInstance()); actionBarHandler.setServiceId(streamingServiceId); @@ -306,7 +287,7 @@ public class VideoItemDetailFragment extends Fragment { VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); */ detailIntent.putExtra( VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url); - //todo: make id dynamic the following line is crap + detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId); startActivity(detailIntent); } @@ -315,13 +296,13 @@ public class VideoItemDetailFragment extends Fragment { break; case VideoInfo.ERROR_BLOCKED_BY_GEMA: thumbnailView.setImageBitmap(BitmapFactory.decodeResource( - getResources(), R.drawable.gruese_die_gema_unangebracht)); + getResources(), R.drawable.gruese_die_gema)); backgroundButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(activity.getString(R.string.c3sUrl))); + intent.setData(Uri.parse(activity.getString(R.string.c3s_url))); activity.startActivity(intent); } }); @@ -364,7 +345,7 @@ public class VideoItemDetailFragment extends Fragment { super.onCreate(savedInstanceState); activity = (AppCompatActivity) getActivity(); showNextVideoItem = PreferenceManager.getDefaultSharedPreferences(getActivity()) - .getBoolean(activity.getString(R.string.showNextVideo), true); + .getBoolean(activity.getString(R.string.show_next_video_key), true); } @@ -458,30 +439,6 @@ 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.*/ - private Locale getPreferredLocale() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - String languageKey = getContext().getString(R.string.searchLanguage); - //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) { - 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(); - } - private 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 6aaf10d41..446b916b5 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -3,6 +3,7 @@ package org.schabi.newpipe; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; @@ -171,7 +172,13 @@ public class VideoItemListActivity extends AppCompatActivity } } - SettingsActivity.initSettings(this); + PreferenceManager.setDefaultValues(this, R.xml.settings, false); + } + + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); } /** diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index 93c6074b2..bea1c6111 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -66,6 +66,9 @@ public class VideoItemListFragment extends ListFragment { private View footer; + // used to suppress request for loading a new page while another page is already loading. + private boolean loadingNextPage = true; + private class ResultRunnable implements Runnable { private final SearchEngine.Result result; private final int requestId; @@ -76,6 +79,9 @@ public class VideoItemListFragment extends ListFragment { @Override public void run() { updateListOnResult(result, requestId); + if (android.os.Build.VERSION.SDK_INT >= 19) { + getListView().removeFooterView(footer); + } } } @@ -84,7 +90,7 @@ public class VideoItemListFragment extends ListFragment { private final String query; private final int page; final Handler h = new Handler(); - private volatile boolean run = true; + private volatile boolean runs = true; private final int requestId; public SearchRunnable(SearchEngine engine, String query, int page, int requestId) { this.engine = engine; @@ -93,17 +99,18 @@ public class VideoItemListFragment extends ListFragment { this.requestId = requestId; } void terminate() { - run = false; + runs = false; } @Override public void run() { try { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - String searchLanguageKey = getContext().getString(R.string.searchLanguage); - String searchLanguage = sp.getString(searchLanguageKey, "en"); + String searchLanguageKey = getContext().getString(R.string.search_language_key); + String searchLanguage = sp.getString(searchLanguageKey, + getString(R.string.default_language_value)); SearchEngine.Result result = engine.search(query, page, searchLanguage); Log.i(TAG, "language code passed:\""+searchLanguage+"\""); - if(run) { + if(runs) { h.post(new ResultRunnable(result, requestId)); } } catch(Exception e) { @@ -111,19 +118,11 @@ public class VideoItemListFragment extends ListFragment { h.post(new Runnable() { @Override public void run() { - Toast.makeText(getActivity(), "Network Error", Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), getString(R.string.network_error), + Toast.LENGTH_SHORT).show(); } }); } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - if (android.os.Build.VERSION.SDK_INT >= 19) { - getListView().removeFooterView(footer); - } - } - }); - } } @@ -203,8 +202,9 @@ public class VideoItemListFragment extends ListFragment { } private void nextPage() { + loadingNextPage = true; lastPage++; - Log.d(TAG, getString(R.string.searchPage) + Integer.toString(lastPage)); + Log.d(TAG, getString(R.string.search_page) + Integer.toString(lastPage)); startSearch(query, lastPage); } @@ -228,7 +228,7 @@ public class VideoItemListFragment extends ListFragment { Toast.makeText(getActivity(), result.errorMessage, Toast.LENGTH_LONG).show(); } else { if (!result.suggestion.isEmpty()) { - Toast.makeText(getActivity(), getString(R.string.didYouMean) + result.suggestion + " ?", + Toast.makeText(getActivity(), getString(R.string.did_you_mean) + result.suggestion + " ?", Toast.LENGTH_LONG).show(); } updateList(result.resultList); @@ -248,6 +248,8 @@ public class VideoItemListFragment extends ListFragment { Log.w(TAG, "Trying to set value while activity doesn't exist anymore."); } catch(Exception e) { e.printStackTrace(); + } finally { + loadingNextPage = false; } } @@ -297,7 +299,8 @@ public class VideoItemListFragment extends ListFragment { super.onViewCreated(view, savedInstanceState); list = getListView(); videoListAdapter = new VideoListAdapter(getActivity(), this); - footer = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.paginate_footer, null, false); + footer = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)) + .inflate(R.layout.paginate_footer, null, false); setListAdapter(videoListAdapter); @@ -318,13 +321,15 @@ public class VideoItemListFragment extends ListFragment { } @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { if (mode != PRESENT_VIDEOS_MODE && list.getChildAt(0) != null && list.getLastVisiblePosition() == list.getAdapter().getCount() - 1 && list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) { long time = System.currentTimeMillis(); - if ((time - lastScrollDate) > 200) { + if ((time - lastScrollDate) > 200 + && !loadingNextPage) { lastScrollDate = time; getListView().addFooterView(footer); nextPage(); diff --git a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java index e85e74e22..de08b2f03 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java @@ -96,10 +96,10 @@ class VideoListAdapter extends BaseAdapter { @Override public View getView(int position, View convertView, ViewGroup parent) { - convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position)); + convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position), context); if(listView.isItemChecked(position)) { - convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.primaryColorYoutube)); + convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.light_youtube_primary_color)); } else { convertView.setBackgroundColor(0); } diff --git a/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java b/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java index 7fd8a58cc..f57ef0894 100644 --- a/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java @@ -106,7 +106,7 @@ public abstract class VideoExtractor { return videoInfo; } - + //todo: add licence field public abstract int getErrorCode(); public abstract String getErrorMessage(); diff --git a/app/src/main/res/drawable-hdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_close_white_24dp.png new file mode 100644 index 000000000..ceb1a1eeb Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_close_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_close_white_24dp.png new file mode 100644 index 000000000..af7f8288d Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_close_white_24dp.png differ diff --git a/app/src/main/res/drawable-nodpi/gruese_die_gema.png b/app/src/main/res/drawable-nodpi/gruese_die_gema.png new file mode 100644 index 000000000..d6e2af3d5 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/gruese_die_gema.png differ diff --git a/app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png b/app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png deleted file mode 100644 index e19491b7b..000000000 Binary files a/app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_close_white_24dp.png new file mode 100644 index 000000000..b7c7ffd0e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_close_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png new file mode 100644 index 000000000..6b717e0dd Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png new file mode 100644 index 000000000..396419219 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png differ diff --git a/app/src/main/res/layout-v18/fragment_videoitem_detail.xml b/app/src/main/res/layout-v18/fragment_videoitem_detail.xml index 91cfea986..cbb5652ca 100644 --- a/app/src/main/res/layout-v18/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout-v18/fragment_videoitem_detail.xml @@ -11,7 +11,7 @@ android:id="@+id/videoitem_detail"> @@ -69,7 +69,7 @@ android:layout_height="wrap_content" android:padding="@dimen/video_item_detail_info_text_padding" android:layout_below="@id/detailVideoThumbnailWindowLayout" - android:background="@color/background_gray"> + android:background="@color/light_background_color"> + android:text="@string/similar_videos_btn_text"/> diff --git a/app/src/main/res/layout-v21/fragment_videoitem_detail.xml b/app/src/main/res/layout-v21/fragment_videoitem_detail.xml index 8d19e1fee..b7919dbe8 100644 --- a/app/src/main/res/layout-v21/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout-v21/fragment_videoitem_detail.xml @@ -11,7 +11,7 @@ android:id="@+id/videoitem_detail"> @@ -71,7 +71,7 @@ android:layout_height="wrap_content" android:padding="@dimen/video_item_detail_info_text_padding" android:layout_below="@id/detailVideoThumbnailWindowLayout" - android:background="@color/background_gray"> + android:background="@color/light_background_color"> + android:text="@string/similar_videos_btn_text"/> diff --git a/app/src/main/res/layout/fragment_videoitem_detail.xml b/app/src/main/res/layout/fragment_videoitem_detail.xml index 987c416ec..611a5aa14 100644 --- a/app/src/main/res/layout/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout/fragment_videoitem_detail.xml @@ -28,7 +28,7 @@ android:background="?attr/selectableItemBackground"> @@ -69,7 +69,7 @@ android:layout_height="wrap_content" android:padding="@dimen/video_item_detail_info_text_padding" android:layout_below="@id/detailVideoThumbnailWindowLayout" - android:background="@color/background_gray"> + android:background="@color/light_background_color"> + android:text="@string/similar_videos_btn_text"/> diff --git a/app/src/main/res/layout/paginate_footer.xml b/app/src/main/res/layout/paginate_footer.xml index 8e5d7571d..b3757c1af 100644 --- a/app/src/main/res/layout/paginate_footer.xml +++ b/app/src/main/res/layout/paginate_footer.xml @@ -8,7 +8,7 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/player_notification_expanded.xml b/app/src/main/res/layout/player_notification_expanded.xml new file mode 100644 index 000000000..3fd379a6b --- /dev/null +++ b/app/src/main/res/layout/player_notification_expanded.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + \ 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 1c7caac60..cff3a4224 100644 --- a/app/src/main/res/layout/video_item.xml +++ b/app/src/main/res/layout/video_item.xml @@ -32,7 +32,7 @@ tools:ignore="RtlHardcoded"> + android:background="@color/duration_dackground_color" + android:textColor="@color/duration_text_color"/> diff --git a/app/src/main/res/menu/video_player.xml b/app/src/main/res/menu/video_player.xml index f82730139..c79217adc 100644 --- a/app/src/main/res/menu/video_player.xml +++ b/app/src/main/res/menu/video_player.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> \ No newline at end of file diff --git a/app/src/main/res/menu/videoitem_detail.xml b/app/src/main/res/menu/videoitem_detail.xml index 4fed67637..f10a0a63e 100644 --- a/app/src/main/res/menu/videoitem_detail.xml +++ b/app/src/main/res/menu/videoitem_detail.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> @@ -18,7 +18,7 @@ android:icon="@drawable/ic_share_black"/> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d17fae7bd..fdef2ba3e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,53 +1,59 @@ - %1$s Aufrufe - Hochgeladen am %1$s - Keinen Streamplayer gefunden. Vielleicht möchtest du einen installieren. - Jetzt installieren + %1$s Aufrufe + Hochgeladen am %1$s + Keinen Streamplayer gefunden. Vielleicht möchtest du einen installieren. + Jetzt installieren Abbrechen In Browser öffnen Teilen Download Suchen Einstellungen - Meintest du: - Suchseite: - Teilen mit: - Browser: - Rotation - Einstellungen + Meintest du: + Suchseite: + Teilen mit: + Browser: + Rotation + Einstellungen Externen Player benutzen - Downloadverzeichnis - Verzeichnis in dem heruntergeladene Videos gespeichert werden. - Download Verzeichnis eingeben - Automatisches Abspielen durch Intent - Startet ein Video automatisch wenn es von einer anderen App aufgerufen wurde. - Standard Auflösung - Mit Kodi abspielen - Kore app wurde nicht gefunden. Kore wird benötigt, um Videos mit Kodi wieder zu geben. + Downloadverzeichnis + Verzeichnis in dem heruntergeladene Videos gespeichert werden. + Download Verzeichnis eingeben + Automatisches Abspielen durch Intent + Startet ein Video automatisch wenn es von einer anderen App aufgerufen wurde. + Standard Auflösung + Mit Kodi abspielen + Kore app wurde nicht gefunden. Kore wird benötigt, um Videos mit Kodi wieder zu geben. Kore installieren - Zeige \"Mit Kodi abspielen\" Option - Zeigt eine Option an, über die man Videos mit dem Kodi Mediacenter abspielen kann. - Audio - Bevorzugtes Audio Format - WebM - freies Format - m4a - bessere Qualität - Herunterladen + Zeige \"Mit Kodi abspielen\" Option + Zeigt eine Option an, über die man Videos mit dem Kodi Mediacenter abspielen kann. + Audio + Bevorzugtes Audio Format + WebM — freies Format + m4a — bessere Qualität + Herunterladen Video Audio - Nächstes Video - 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 + Nächstes Video + Zeige nächstes und ähnliche Videos + URL wird nicht unterstützt. + Ähnliche Videos + Video & Audio + Bevorzugte Sprache des Inhalts + Video-Vorschau-Bild + Video-Vorschau-Bild + Nutzerbild + Gefällt nicht + Gefällt + Lade + Benutze externen Videoabspieler + Benutze externen Audioabspieler + Spiele im Hintergrund ab + Abspielen + + Benutze TOR + Erzwinge das Herunterladen durch TOR für verbesserte Privatsphäre (Videostream noch nicht unterstützt) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bcf25e8fa..3b91eb0d4 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,39 +1,39 @@ - %1$s visitas - Subido el %1$s - No se ha encontrado ningún reproductor de vídeo. Quizás quieras instalar alguno. - Instalarlo + %1$s visitas + Subido el %1$s + No se ha encontrado ningún reproductor de vídeo. Quizás quieras instalar alguno. + Instalarlo Cancelar Abrir en el navegador Compartir Descargar Buscar Ajustes - "¿Querías decir?: " - Buscar página: - Compartir con: - Selecciona navegador: - rotación - Ajustes + "¿Querías decir?: " + Buscar página: + Compartir con: + Selecciona navegador: + rotación + Ajustes Usar reproductor externo - Descargar en… - Ruta donde guardar los vídeos descargados. - Localización del directorio de descargas - Reproducción automática - Reproducir los vídeos automaticamente cuando se llama desde otra aplicación. - Resolución por defecto - Reproducir con Kodi - Aplicación Kore no encontrada. Kore es necesario para reproducir vídeos con Kodi media center. + Descargar en… + Ruta donde guardar los vídeos descargados. + Localización del directorio de descargas + Reproducción automática + Reproducir los vídeos automaticamente cuando se llama desde otra aplicación. + Resolución por defecto + Reproducir con Kodi + Aplicación Kore no encontrada. Kore es necesario para reproducir vídeos con Kodi media center. Instalar Kore - Mostrar la opción \"Reproducir con Kodi\" - Muestra una opción para reproducir el vídeo con Kodi media center. - Audio - Formato de audio por defecto - WebM - formato libre - m4a - mejor calidad - Descargar - Siguiente vídeo - URL no soportada. - Vídeos similares + Mostrar la opción \"Reproducir con Kodi\" + Muestra una opción para reproducir el vídeo con Kodi media center. + Audio + Formato de audio por defecto + WebM — formato libre + m4a — mejor calidad + Descargar + Siguiente vídeo + URL no soportada. + Vídeos similares diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml new file mode 100644 index 000000000..7d0a7710e --- /dev/null +++ b/app/src/main/res/values-eu/strings.xml @@ -0,0 +1,54 @@ + +%1$s ikustaldi + Argitaratze-data: %1$s + Instalatu + Utzi + Nabigatzailean ireki + Partekatu + Kargatzen + Deskargatu + Bilatu + Ezarpenak + Partekatu honekin: + Nabigatzailea aukeratu: + biratzea + Ezarpenak + Deskargatzeko kokapena + Deskargatutako bideoak gordetzeko lekua. + Sar ezazu deskargatzeko lekua + Lehenetsitako bereizmena + Kodirekin erreproduzitu + Kore aplikazioa ez da aurkitu. Kore beharrezkoa da Kodi multimedia zentroarekin bideoak erreproduzitzeko. + Kore instalatu + \"Kodirekin erreproduzitu\" aukera erakutsi + Kodi multimedia zentroarekin bideoa erreproduzitzeko aukera erakusten du. + Audioa + Audio formatu lehenetsia + WebM — formatu askea + m4a — kalitate hobea + Deskargatu + Hurrengo bideoa + Hurrengo bideoa eta antzekoak erakutsi + URLa ez da onartzen. + Antzeko bideoak + Edukiaren hizkuntz lehenetsia + Bideoa eta Audioa + Erreproduzitu + + Bideoaren aurreikuspen argazkitxoa + Bideoaren aurreikuspen argazkitxoa + Igotzailearen argazkitxoa + Ez dute gustoko + Gustoko dute + Tor erabili + Trafikoa Tor bidez deskargatzea behartzen du pribatutasuna hobetzeko (jario bideoak ez daude oraindik onartuta) + NewPipe atzeko planoko erreproduzitzailea + Jario erreproduzitzailerik ez da aurkitu. Agian bat instalatu nahi dezakezu. + "Hau esan nahi al zenuen: " + "Orrialdea bilatu: " + Kanpoko bideo erreproduzitzailea erabili + Kanpoko audio erreproduzitzailea erabili + Intent bidez automatikoki erreproduzitu + Bideoa automatikoki hasten du beste aplikazio batetik deitu denean. + Atzeko planoan erreproduzitzen + diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 8951a6ee4..0d9b54a04 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -1,42 +1,42 @@ - %1$s نماها - بارگذاری‌شده در: %1$s - هیچ پخش‌کننده‌ی جریانی یافت نشد. ممکن است بخواهید یکی نصب کنید. - نصب کنید + %1$s نماها + بارگذاری‌شده در: %1$s + هیچ پخش‌کننده‌ی جریانی یافت نشد. ممکن است بخواهید یکی نصب کنید. + نصب کنید انصراف بازکردن در مرورگر هم‌رسانی بارگیری جستجو تنظیمات - منظورتان این است: - صفحه‌ی جستجو: - هم‌رسانی با: - مرورگر را برگزینید: - چرخش - تنظیمات + منظورتان این است: + صفحه‌ی جستجو: + هم‌رسانی با: + مرورگر را برگزینید: + چرخش + تنظیمات استفاده از پخش‌کننده‌ی خارجی - محل بارگیری - مسیری که ویدئوهای دریافت شده در آن ذخیره می‌شوند. - مسیر دریافت را وارد کنید - پخش خودکار از Intent - ویدئو هنگامی که از برنامه‌ی دیگری فراخوانده شد خودکار پخش می‌شود. - وضوح پیش‌فرض - پخش با Kodi - برنامه‌ی Kore نصب نیست. برای پخش کردن ویدئوها با مرکز رسانه‌ی Kodi، به Kore نیاز دارید. + محل بارگیری + مسیری که ویدئوهای دریافت شده در آن ذخیره می‌شوند. + مسیر دریافت را وارد کنید + پخش خودکار از Intent + ویدئو هنگامی که از برنامه‌ی دیگری فراخوانده شد خودکار پخش می‌شود. + وضوح پیش‌فرض + پخش با Kodi + برنامه‌ی Kore نصب نیست. برای پخش کردن ویدئوها با مرکز رسانه‌ی Kodi، به Kore نیاز دارید. نصب Kore - نمایش گزینه‌ی «پخش با Kodi» - گزینه‌ای برای پخش کردن ویدئو با مرکز رسانه‌ی Kodi نشان می‌دهد. - صدا - قالب پیش‌فرض صدا - WebM - قالبی آزاد - m4a - کیفیت بهتر - دریافت + نمایش گزینه‌ی «پخش با Kodi» + گزینه‌ای برای پخش کردن ویدئو با مرکز رسانه‌ی Kodi نشان می‌دهد. + صدا + قالب پیش‌فرض صدا + WebM — قالبی آزاد + m4a — کیفیت بهتر + دریافت ویدئو صدا - ویدئوی بعدی - پیوند پشتیبانی نمی‌شود. + ویدئوی بعدی + پیوند پشتیبانی نمی‌شود. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4800a7493..d0d04db68 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,52 +1,58 @@ - Démarrer automatiquement la vidéo si elle a été appelée depuis une autre application. + Démarrer automatiquement la vidéo si elle a été appelée depuis une autre application. Annuler - Choisir un navigateur : - Résolution par défaut - "S\'agirait-il de : " + Choisir un navigateur : + Résolution par défaut + "S\'agirait-il de : " Télécharger - Emplacement des téléchargements - Entrez l\'emplacement du téléchargement - Emplacement des vidéos téléchargées. - Installer + Emplacement des téléchargements + Entrez l\'emplacement du téléchargement + Emplacement des vidéos téléchargées. + Installer 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. + 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. Ouvrir dans le navigateur - Lecture automatique via Intent - Lire avec Kodi - rotation + Lecture automatique via Intent + Lire avec Kodi + rotation Rechercher - "Rechercher dans la page : " + "Rechercher dans la page : " Paramètres Partager - Partager avec : - Afficher une option pour lire la vidéo avec Kodi media center. - Afficher l\'option \"Lire avec Kodi\" - Paramètres - Mise en ligne le %1$s + Partager avec : + Afficher une option pour lire la vidéo avec Kodi media center. + Afficher l\'option \"Lire avec Kodi\" + Paramètres + Mise en ligne le %1$s Utiliser un lecteur externe - %1$s vues - Audio - Format audio par défaut - WebM- format libre - m4a - meilleur qualité - Télécharger - Vidéo suivante - Afficher les vidéos suivantes et similaires - URL non supportée. - Vidéos similaires - VIDÉO & AUDIO - INFORMATION - DIVERS + %1$s vues + Audio + Format audio par défaut + WebM — format libre + m4a — meilleur qualité + Télécharger + Vidéo suivante + Afficher les vidéos suivantes et similaires + URL non supportée. + Vidéos similaires + Vidéo & Audio + Divers - Miniature d\'aperçu vidéo - Miniature d\'aperçu vidéo - Je n\'aime pas - J\'aime -Langue du contenu - Avatar de l\'utilisateur - Utiliser un lecteur vidéo externe - Utiliser un lecteur audio externe - + Miniature d\'aperçu vidéo + Miniature d\'aperçu vidéo + Je n\'aime pas + J\'aime + Langue du contenu + Avatar de l\'utilisateur + Utiliser un lecteur vidéo externe + Utiliser un lecteur audio externe + Lecture en arrière-plan + Lecteur en arrière-plan NewPipe + Chargement + Lecture + + Utiliser Tor + Forcer le trafic de téléchargement via Tor pour plus de confidentialité (vidéos streaming non supporté) + diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml new file mode 100644 index 000000000..060b70ede --- /dev/null +++ b/app/src/main/res/values-he/strings.xml @@ -0,0 +1,10 @@ + +%1$s צפיות + הועלה בתאריך %1$s + שתף + חפש + הבא + הורדה + הגדרות + הגדרות + diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index d6dc6d25f..330b387ff 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -1,43 +1,43 @@ - %1$s megtekintés - Feltöltve: %1$s - Nem található lejátszó. Telepítsen egyet! - Telepítsen egyet + %1$s megtekintés + Feltöltve: %1$s + Nem található lejátszó. Telepítsen egyet! + Telepítsen egyet Mégse Megnyitás böngészőben Megosztás Letöltés Keresés Beállítások - Erre gondolt: - Keresési lap: - Megosztás ezzel: - Válasszon böngészőt: - forgatás - Beállítások + Erre gondolt: + Keresési lap: + Megosztás ezzel: + Válasszon böngészőt: + forgatás + Beállítások Külső lejátszó használata - Letöltések helye - Útvonal a letöltött videók tárolásához - Adja meg a letöltési útvonalat - Automatikus lejátszás Intent-en keresztül - Automatikusan elindítja a videót, ha az külső alkalmazásból volt hívva - Alapértelmezett felbontás - Lejátszás Kodi-val - A Kore alkalmazás nem található. A Kore szükséges a videók Kodi médiaközponttal való lejátszásához. + Letöltések helye + Útvonal a letöltött videók tárolásához + Adja meg a letöltési útvonalat + Automatikus lejátszás Intent-en keresztül + Automatikusan elindítja a videót, ha az külső alkalmazásból volt hívva + Alapértelmezett felbontás + Lejátszás Kodi-val + A Kore alkalmazás nem található. A Kore szükséges a videók Kodi médiaközponttal való lejátszásához. Kore telepítése - \"Lejátszás Kodi-val\" opció mutatása - Mutat egy opciót a videók Kodi médiaközponttal való lejátszására - Hang - Alapértelmezett hang formátum - WebM - szabad formátum - m4a - jobb minőség - Letöltés + \"Lejátszás Kodi-val\" opció mutatása + Mutat egy opciót a videók Kodi médiaközponttal való lejátszására + Hang + Alapértelmezett hang formátum + WebM — szabad formátum + m4a — jobb minőség + Letöltés Videó Hang -Következő videó - A webcím nem támogatott. -Hasonló videók - + Következő videó + A webcím nem támogatott. + Hasonló videók + diff --git a/app/src/main/res/values-id b/app/src/main/res/values-id new file mode 120000 index 000000000..9ea8dda4b --- /dev/null +++ b/app/src/main/res/values-id @@ -0,0 +1 @@ +values-in \ No newline at end of file diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml new file mode 100644 index 000000000..9c5ad89af --- /dev/null +++ b/app/src/main/res/values-in/strings.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 931afc6c2..95c7815c3 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,49 +1,49 @@ -%1$s visite - Caricato in %1$s - Nessun riproduttore trovato. Dovresti installarne uno. - Installa +%1$s visite + Caricato in %1$s + Nessun riproduttore trovato. Dovresti installarne uno. + Installa Cancella Apri nel browser Condividi Scarica Cerca Impostazioni - "Intendevi: " - "Cerca pagina: " - Condividi con: - Scegli browser: - rotazione - Impostazioni + "Intendevi: " + "Cerca pagina: " + Condividi con: + Scegli browser: + rotazione + Impostazioni Usa un riproduttore video esterno - Cartella di download - Percorso dove memorizzare i video scaricati. - Inserisci il percorso di download - Auto riproduzione attraverso internet - Avvia automaticamente un video quando è stato chiamato da un\'altra applicazione. - Risoluzione predefinita - Riproduci con Kodi - Kore app non trovata. Kore è richiesto per riprodurre video con Kodi media center. + Cartella di download + Percorso dove memorizzare i video scaricati. + Inserisci il percorso di download + Auto riproduzione attraverso internet + Avvia automaticamente un video quando è stato chiamato da un\'altra applicazione. + Risoluzione predefinita + Riproduci con Kodi + Kore app non trovata. Kore è richiesto per riprodurre video con Kodi media center. Installa Kore - Mostra l\'opzione \"Riproduci con Kodi\" - Mostra un opzione per riprodurre un video attraverso Kodi media center. - Audio - Formato audio predefinito - WedM - formato libero - m4a - qualità migliore - Scarica - Prossimo video - Mostra i video successivi e simili - URL non supportato. - Video simili - Lingua preferita dei contenuti - VIDEO & AUDIO + Mostra l\'opzione \"Riproduci con Kodi\" + Mostra un opzione per riprodurre un video attraverso Kodi media center. + Audio + Formato audio predefinito + WedM — formato libero + m4a — qualità migliore + Scarica + Prossimo video + Mostra i video successivi e simili + URL non supportato. + Video simili + Lingua preferita dei contenuti + VIDEO & AUDIO INFO ETC - Anteprima video - Anteprima video - Miniatura caricata - Non mi piace - Mi piace + Anteprima video + Anteprima video + Miniatura caricata + Non mi piace + Mi piace diff --git a/app/src/main/res/values-iw b/app/src/main/res/values-iw new file mode 120000 index 000000000..57bf91954 --- /dev/null +++ b/app/src/main/res/values-iw @@ -0,0 +1 @@ +values-he \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 558918270..aca6ff616 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,53 +1,57 @@ - "アップロード: "%1$s - StreamPlayer が見つかりませんでした。インストールが必要になるかもしれません。 - インストール + "アップロード: "%1$s + StreamPlayer が見つかりませんでした。インストールが必要になるかもしれません。 + インストール 取り消し ブラウザーで開く 共有 ダウンロード 検索 設定 - "この意味ですか: " - "検索ページ: " - …共有: - ブラウザーを選択: - 回転 - 設定 + "この意味ですか: " + "検索ページ: " + …共有: + ブラウザーを選択: + 回転 + 設定 外部プレーヤーを使用する - ダウンロードする場所 - ダウンロードした動画を保存する場所のパス。 - ダウンロードのパスを入力してください。 - インテントで自動再生 - 他のアプリケーションから呼び出されたとき、自動的に動画再生を開始します。 - 基本の解像度 - Kodi で再生 - Kore アプリが見つかりません。 Kodi メディアセンターで動画を再生するには、 Kore が必要です。 + ダウンロードする場所 + ダウンロードした動画を保存する場所のパス。 + ダウンロードのパスを入力してください。 + インテントで自動再生 + 他のアプリケーションから呼び出されたとき、自動的に動画再生を開始します。 + 基本の解像度 + Kodi で再生 + Kore アプリが見つかりません。 Kodi メディアセンターで動画を再生するには、 Kore が必要です。 Kore をインストール - \"Kodi で再生\" 設定を表示 - Kodi メディアセンター経由で動画を再生するための設定を表示します. - オーディオ - 基本のオーディオフォーマット - .WebM - フリーフォーマット - .m4a - より良い品質 - ダウンロード - 次の動画 - 次の同様の動画を表示します。 - URL は使用できません。 - 同様の動画 - 優先される言語 - 動画とオーディオ - 情報 - その他 -%1$s ビュー - ビデオ プレビュー サムネイル - ビデオ プレビュー サムネイル - アップローダー サムネイル - 残念だね - いいね -外部ビデオ プレイヤーを使用する - 外部オーディオ プレイヤーを使用する - バックグラウンドで再生しています + \"Kodi で再生\" 設定を表示 + Kodi メディアセンター経由で動画を再生するための設定を表示します. + オーディオ + 基本のオーディオフォーマット + WebM — フリーフォーマット + m4a — より良い品質 + ダウンロード + 次の動画 + 次の同様の動画を表示します。 + URL は使用できません。 + 同様の動画 + 優先される言語 + 動画とオーディオ + %1$s ビュー + ビデオ プレビュー サムネイル + ビデオ プレビュー サムネイル + アップローダー サムネイル + 残念だね + いいね + 外部ビデオ プレイヤーを使用する + 外部オーディオ プレイヤーを使用する + バックグラウンドで再生しています - + NewPipe バックグラウンド プレーヤー + 読み込み中 + 再生 + + Tor を使用する + 強制的に Tor を経由したプライバシーを高めたトラフィックでダウンロードします (ビデオのストリーミングはまだサポートされていません) + diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index bdb8b1084..ceaf8df6f 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,49 +1,49 @@ -시청 횟수 %1$s - %1$s에 업로드됨 - 스트리밍 플레이어가 발견되지 않았습니다. 플레이어를 설치하시기 바랍니다. - 설치 +시청 횟수 %1$s + %1$s에 업로드됨 + 스트리밍 플레이어가 발견되지 않았습니다. 플레이어를 설치하시기 바랍니다. + 설치 취소 브라우저에서 열기 공유 다운로드 검색 설정 - "혹시 이것을 검색하셨습니까? " - "검색 페이지: " - 다음으로 공유: - 브라우저 선택: - 회전 - 설정 + "혹시 이것을 검색하셨습니까? " + "검색 페이지: " + 다음으로 공유: + 브라우저 선택: + 회전 + 설정 외부 플레이어 사용 - 다운로드 위치 - 다운로드된 비디오가 저장될 경로를 선택하세요. - 다운로드 경로 입력 - 인텐트로 경유할 경우 자동 재생 - 다른 앱으로부터 호출되었을 경우에 비디오를 자동으로 재생합니다. - 기본 해상도 - Kodi로 재생 - Kore 앱이 발견되지 않았습니다. Kodi media center로 비디오를 재생하려면 Kore가 필요합니다. + 다운로드 위치 + 다운로드된 비디오가 저장될 경로를 선택하세요. + 다운로드 경로 입력 + 인텐트로 경유할 경우 자동 재생 + 다른 앱으로부터 호출되었을 경우에 비디오를 자동으로 재생합니다. + 기본 해상도 + Kodi로 재생 + Kore 앱이 발견되지 않았습니다. Kodi media center로 비디오를 재생하려면 Kore가 필요합니다. Kore 설치 - \"Kodi로 재생\" 옵션 표시 - 비디오를 Kodi media center를 사용해 재생하는 옵션을 표시합니다. - 오디오 - 기본 오디오 포맷 - WebM - 무료 자유 포맷입니다 - m4a - 보다 나은 품질 - 다운로드 - 다음 비디오 - 다음 및 유사한 비디오 표시 - 지원하지 않는 URL 입니다. - 유사한 비디오 - 선호하는 컨텐츠 언어 - 비디오 & 오디오 + \"Kodi로 재생\" 옵션 표시 + 비디오를 Kodi media center를 사용해 재생하는 옵션을 표시합니다. + 오디오 + 기본 오디오 포맷 + WebM — 무료 자유 포맷입니다 + m4a — 보다 나은 품질 + 다운로드 + 다음 비디오 + 다음 및 유사한 비디오 표시 + 지원하지 않는 URL 입니다. + 유사한 비디오 + 선호하는 컨텐츠 언어 + 비디오 & 오디오 정보 기타 - 비디오 미리보기 썸네일 - 비디오 미리보기 썸네일 - 업로더 썸네일 - 싫어요 - 좋아요 + 비디오 미리보기 썸네일 + 비디오 미리보기 썸네일 + 업로더 썸네일 + 싫어요 + 좋아요 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 0cf3b0dec..b63369b49 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -1,51 +1,49 @@ - %1$s keer bekeken - Geüpload op %1$s - Geen speler met streaming ondersteuning gevonden. Misschien wil je er een installeren. - Installeer speler + %1$s keer bekeken + Geüpload op %1$s + Geen speler met streaming ondersteuning gevonden. Misschien wil je er een installeren. + Installeer speler Annuleer Open in browser Deel Download Zoek Instellingen - Bedoelde je: - Zoekpagina: - Deel met: - Kies browser: - rotatie - Instellingen + Bedoelde je: + Zoekpagina: + Deel met: + Kies browser: + rotatie + Instellingen Gebruik externe speler - Downloadlocatie - Locatie om gedownloadde videos in op te slaan. - Voer downloadlocatie is - Speel automatisch via Intent - Speel een video automatisch af indien geopend vanuit een andere app. - Standaardresolutie - Speel af met Kodi - Kore app niet gevonden. Kore is nodig om videos op Kodi af te spelen. + Downloadlocatie + Locatie om gedownloadde videos in op te slaan. + Voer downloadlocatie is + Speel automatisch via Intent + Speel een video automatisch af indien geopend vanuit een andere app. + Standaardresolutie + Speel af met Kodi + Kore app niet gevonden. Kore is nodig om videos op Kodi af te spelen. Installeer Kore - Toon \"Speel af met Kodi\" optie - Toont een optie om een video op een Kodi media center af te spelen. - Audio - Standaard audio formaat - Webam - open formaat - m4a - betere kwaliteit - Download - Volgende video - URL wordt niet ondersteund. - Vergelijkbare videos - Laat volgende en vergelijkbare videos zien - Voorkeurs content taal -Gebruik externe videospeler - Gebruik externe audiospeler - VIDEO & GELUID - INFO - ETC. + Toon \"Speel af met Kodi\" optie + Toont een optie om een video op een Kodi media center af te spelen. + Audio + Standaard audio formaat + WebM — open formaat + m4a — betere kwaliteit + Download + Volgende video + URL wordt niet ondersteund. + Vergelijkbare videos + Laat volgende en vergelijkbare videos zien + Voorkeurs content taal + Gebruik externe videospeler + Gebruik externe audiospeler + Video & Geluid - Videovoorbeeld thumbnail - Videovoorbeeld thumbnail - Uploader miniatuur - Dislikes + Videovoorbeeld thumbnail + Videovoorbeeld thumbnail + Uploader miniatuur + Dislikes diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 348a2e689..9142bca7f 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,51 +1,50 @@ - Nie znaleziono odtwarzacza strumieniowego. - Zainstaluj + Nie znaleziono odtwarzacza strumieniowego. + Zainstaluj Anuluj Otwórz w przeglądarce Udostępnij Pobierz Szukaj Ustawienia - "Czy chodziło Ci o: " - Udostępnij za pośrednictwem: - Wybierz przeglądarkę: - obrót - Ustawienia + "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. + 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. - 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ń -Użyj zewnętrznego odtwarzacza wideo - Użyj zewnętrznego odtwarzacza audio - + Wyświetlaj opcję \"Odtwarzaj za pośrednictwem Kodi\" + Wyświetla opcję do odtwarzania wideo przez aplikację Kodi. + 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 + + "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ń + Użyj zewnętrznego odtwarzacza wideo + Użyj zewnętrznego odtwarzacza audio + diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 0a6cbe3c4..d78107d70 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,50 +1,50 @@ -%1$s visualizações - Carregado em %1$s - Reprodutor não disponível. Deve instalar um reprodutor. - Instalar +%1$s visualizações + Carregado em %1$s + Reprodutor não disponível. Deve instalar um reprodutor. + Instalar Cancelar Abrir no navegador Partilhar Descarregar Pesquisar Definições - "Será que queria dizer: " - "Página de pesquisa: " - Partilhar com: - Escolher navegador: - rotação - Definições - Utilizar reprodutor de vídeo externo - Utilizar reprodutor de áudio externo - Local para a descarga - Local para guardar os vídeos descarregados. - Digite o caminho - Reproduzir via Intent - Iniciar automaticamente o vídeo se for invocado por outra aplicação. - Resolução padrão - Reproduzir com Kodi - Aplicação não encontrada. Necessita do Kore para reproduzir vídeos no Kodi. + "Será que queria dizer: " + "Página de pesquisa: " + Partilhar com: + Escolher navegador: + rotação + Definições + Utilizar reprodutor de vídeo externo + Utilizar reprodutor de áudio externo + Local para a descarga + Local para guardar os vídeos descarregados. + Digite o caminho + Reproduzir via Intent + Iniciar automaticamente o vídeo se for invocado por outra aplicação. + Resolução padrão + Reproduzir com Kodi + Aplicação não encontrada. Necessita do Kore para reproduzir vídeos no Kodi. Instalar o Kore - Mostrar opção \"Reproduzir com Kodi\" - Mostra uma opção para reproduzir o vídeo com o Kodi. - Áudio - Formato áudio padrão - WebM - formato livre - m4a - melhor qualidade - Descarregar - Vídeo seguinte - Mostrar vídeos seguintes e similares - URL não suportado. - Vídeos similares - Idioma preferencial do conteúdo - Vídeo e áudio + Mostrar opção \"Reproduzir com Kodi\" + Mostra uma opção para reproduzir o vídeo com o Kodi. + Áudio + Formato áudio padrão + WebM — formato livre + m4a — melhor qualidade + Descarregar + Vídeo seguinte + Mostrar vídeos seguintes e similares + URL não suportado. + Vídeos similares + Idioma preferencial do conteúdo + Vídeo e áudio Informações Outras - Miniatura de vídeos - Miniatura de vídeos - Carregador de miniaturas - Não gosto - Gosto + Miniatura de vídeos + Miniatura de vídeos + Carregador de miniaturas + Não gosto + Gosto diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a2dbdd50f..8d8da5a8e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,54 +1,57 @@ - %1$s просмотров - Опубликовано %1$s - Ни одного потокового проигрывателя не было найдено. Установить? - Установить + %1$s просмотров + Опубликовано %1$s + Ни одного потокового проигрывателя не было найдено. Установить? + Установить Отмена Открыть в браузере Поделиться Скачать Найти Настройки - Возможно, вы имели в виду: - Страница поиска: - Поделиться с помощью: - Выбрать браузер: - поворот - Настройки + Возможно, вы имели в виду: + Страница поиска: + Поделиться с помощью: + Выбрать браузер: + поворот + Настройки Использовать внешний проигрыватель - Место для загрузок - Папка для хранения загруженных файлов. - Введите путь к папке для загрузок - Автопроигрывание через интернет - Автоматически воспроизводить видео когда оно открыто через другое приложение. - Разрешение по-умолчанию - Воспроизвести с помощью Kodi - Приложение Kore не наидено. Чтобы проигрывать видео через Kodi media center, нужен Kore. + Место для загрузок + Папка для хранения загруженных файлов. + Введите путь к папке для загрузок + Автопроигрывание через интернет + Автоматически воспроизводить видео когда оно открыто через другое приложение. + Разрешение по-умолчанию + Воспроизвести с помощью Kodi + Приложение Kore не наидено. Чтобы проигрывать видео через Kodi media center, нужен Kore. Установить Kore - Показывать опцию \"Воспроизвести с помощью Kodi\" - Показать опцию воспроизведения видео через Kodi media center. - Аудио - Формат аудио по-умолчанию - WebM - свободный формат - m4a - лучшее качество - Скачать + Показывать опцию \"Воспроизвести с помощью Kodi\" + Показать опцию воспроизведения видео через Kodi media center. + Аудио + Формат аудио по-умолчанию + WebM — свободный формат + m4a — лучшее качество + Скачать Видео Аудио - Следующее видео - URL не поддерживается. - Похожие видео - Показывать следующее и предложенные видео - Предпочитаемый язык контента -ВИДЕО И АУДИО - ИНФОРМАЦИЯ - ПРОЧЕЕ + Следующее видео + URL не поддерживается. + Похожие видео + Показывать следующее и предложенные видео + Предпочитаемый язык контента + Видео и Аудио + Внешний вид + Другое - Миниатюра видео-превью - Миниатюра видео-превью - Миниатюра аватара пользователся - Дислайки - Лайки - + Миниатюра видео-превью + Миниатюра видео-превью + Миниатюра аватара пользователся + Дислайки + Лайки +Использовать внешний проигрыватель для видео + Использовать внешний проигрыватель для аудио + Проигрывание в фоновом режиме + diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 91f54dc11..7a557d8a7 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -1,50 +1,64 @@ -%1$s pogledov - Poslano %1$s - Predvajalnika pretoka ni mogoče najti. Tak program lahko namestite ločeno. - Namesti +%1$s pogledov + Poslano %1$s + Predvajalnika pretoka ni mogoče najti. Tak program lahko namestite ločeno. + Namesti Prekliči Odpri v brskalniku Omogoči souporabo Prejmi Poišči Nastavitve - "Ste mislili vpisati: " - "Stran iskanja: " - Omogoči souporabo z: - Izbor brskalnika: - usmerjenost - Nastavitve - Uporabi zunanji predvajalnik videa - Uporabi zunanji predvajalnik zvoka - Mapa za prejem - Pot do mape za prejem datotek. - Vpis poti za prejem - Privzeta ločljivost - Predvajaj s Kodi - Programa Kore ni mogoče najti. Program omogoča predvajanje video posnetkov prek predstavnega središča Kodi. + "Ste mislili vpisati: " + "Stran iskanja: " + Omogoči souporabo z: + Izbor brskalnika: + usmerjenost + Nastavitve + Uporabi zunanji predvajalnik videa + Uporabi zunanji predvajalnik zvoka + Mapa za prejem + Pot do mape za prejem datotek. + Vpis poti za prejem + Privzeta ločljivost + Predvajaj s Kodi + Programa Kore ni mogoče najti. Program omogoča predvajanje video posnetkov prek predstavnega središča Kodi. Namesti program Kore - Pokaži možnost \"Predvajaj s Kodi\" - Privzet zapis zvoka - Zvok - WebM - prost zapis - m4a - višja kakovost posnetkov - Prejem - Naslednji video - Pokaži naslednji video in podobne posnetke - Zapis naslova URL ni podprt. - Podobni posnetki - Prednostni jezik vsebine - Video in Zvok - Podrobnosti - Sličica predogleda videa - Sličica predogleda videa - Sličica pošiljalnika - Samodejno predvajaj prek vmesnika Intent - Začne samodejno predvajanje videa, ko je zagnan prek drugega programa. - Pokaže možnost predvajanja videa preko predstavnega središča Kodi. + Pokaži možnost \"Predvajaj s Kodi\" + Privzet zapis zvoka + Zvok + WebM — prost zapis + m4a — višja kakovost posnetkov + Prejem + Naslednji video + Pokaži naslednji video in podobne posnetke + Zapis naslova URL ni podprt. + Podobni posnetki + Prednostni jezik vsebine + Video in Zvok + Sličica predogleda videa + Sličica predogleda videa + Sličica pošiljalnika + Samodejno predvajaj prek vmesnika Intent + Začne samodejno predvajanje videa, ko je zagnan prek drugega programa. + Pokaže možnost predvajanja videa preko predstavnega središča Kodi. Drugo - Všeč mi je -Ni mi všeč - + Všeč mi je +Ni mi všeč + Ozadnji predvajalnik NewPipe + Nalaganje ... + Predvajanje v ozadju + Predvajaj + + Tema + Temna + Svetla + + Videz + Drugo + Omrežna napaka + + Uporabi Tor + Vsili prenos prejema preko sistema Tor za povečanje zasebnosti (pretakanje videa ni še podprto) + diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 7ab3d8eaa..d58914743 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -1,57 +1,69 @@ - %1$s приказа - "Отпремљен "%1$s - Нема плејера токова. Можда желите да га инсталирате. - Инсталирај + %1$s приказа + "Отпремљен "%1$s + Нема плејера токова. Можда желите да га инсталирате. + Инсталирај Одустани Отвори у прегледачу Дели Преузми Тражи Поставке - Да ли сте мислили: - Страница претраге: - Подели помоћу: - Отвори помоћу: - ротација - Поставке + Да ли сте мислили: + Страница претраге: + Подели помоћу: + Отвори помоћу: + ротација + Поставке Користи спољашњи плејер - Одредиште преузимања - Путања за упис преузетих видеа. - Унесите путању за преузимања - Аутопуштање преко Интента - Аутоматски почиње пушта видео по позиву из друге апликације. - Подразумевана резолуција - Пусти помоћу Кодија - Апликација Кор није нађена. Кор (Kore) је потребан да бисте пуштали видее у Коди медија центру. + Одредиште преузимања + Путања за упис преузетих видеа. + Унесите путању за преузимања + Аутопуштање преко Интента + Аутоматски почиње пушта видео по позиву из друге апликације. + Подразумевана резолуција + Пусти помоћу Кодија + Апликација Кор није нађена. Кор (Kore) је потребан да бисте пуштали видее у Коди медија центру. Инсталирај Кор - Прикажи „Пусти помоћу Кодија“ - Приказ опције за пуштање видеа у Коди медија центру. - Аудио - Подразумевани формат звука - WebM - слободни формат - m4a - бољи квалитет - Преузми + Прикажи „Пусти помоћу Кодија“ + Приказ опције за пуштање видеа у Коди медија центру. + Аудио + Подразумевани формат звука + WebM — слободни формат + m4a — бољи квалитет + Преузми Видео Аудио - Следећи видео - УРЛ није подржан. - Прикажи следећи и слични видео - Слични видео - Пожељни језик садржаја -ВИДЕО И АУДИО - ПОДАЦИ - ОСТАЛО -Сличица видео прегледа - Сличица видео прегледа - Сличица отпремаоца - Несвиђања - Свиђања -Користи спољашњи видео плејер - Користи спољашњи аудио плејер - Пуштам у позадини + Следећи видео + УРЛ није подржан. + Прикажи следећи и слични видео + Слични видео + Пожељни језик садржаја + Видео и Аудио + Остало + Сличица видео прегледа + Сличица видео прегледа + Сличица отпремаоца + Несвиђања + Свиђања + Користи спољашњи видео плејер + Користи спољашњи аудио плејер + Пуштам у позадини + + Позадински плејер за Јутјуб цев + Учитавам + Пусти + + Користи Тор + Принудно преусмерење саобраћаја кроз Тор за доданту приватност (токови још нису подржани) +Тема + Тамна + Светла + + Изглед + Грешка мреже diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index 1f056cfb5..75d058e50 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -3,18 +3,18 @@ \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index e14ee9606..963a49bcc 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,10 +1,20 @@ - #cd322e - #bc211d - #000 - #a000 - #efff - #6000 - #EEEEEE + + #EEEEEE + #CD322E + #BC211D + #000000 + + + #222222 + #CD322E + #BC211D + #FFFFFF + + + #AA000000 + #EEFFFFFF + #66000000 + #323232 \ 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 8d33b8cbe..6f83e31a5 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -1,38 +1,54 @@ - settings_categoery_video_audio - settings_category_video_info - settings_category_etc + settings_category_video_audio + settings_category_appearance + settings_category_other - download_path_preference - use_external_video_player - use_external_audio_player - autoplay_through_intent - default_resolution_preference - + download_path + use_external_video_player + use_external_audio_player + autoplay_through_intent + + default_resolution_preference + 360p + 720p 360p 240p 144p - 360p - show_play_with_kodi_preference - default_audio_format - - @string/webMAudioDescription - @string/m4aAudioDescription + + show_play_with_kodi + + theme + 0 + + @string/dark_theme_title + @string/light_theme_title - + + 0 + 1 + + + default_audio_format + m4a + + @string/webm_description + @string/m4a_description + + webm m4a - m4a - show_next_video - search_language + + show_next_video + en + search_language - + af az id @@ -71,6 +87,7 @@ sl fi sv + bo vi tr bg @@ -110,7 +127,7 @@ ja ko - + Afrikaans Azərbaycan Bahasa Indonesia @@ -149,6 +166,7 @@ Slovenščina Suomi Svenska + Tibetan བོད་སྐད། Tiếng Việt Türkçe Български @@ -188,4 +206,5 @@ 日本語 한국어 + use_tor \ 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 177280277..d7a551fcd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,63 +1,72 @@ NewPipe + NewPipe Background Player NewPipe - %1$s views - Uploaded on %1$s - No stream player found. You may want to install one. - Install + %1$s views + Uploaded on %1$s + No stream player found. Install VLC? + Install Cancel - https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc + https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Open in browser Share + Loading Download Search Settings - Did you mean: - Search page: - Share with: - Choose browser: - rotation - Settings - Use external video player - Use external audio player - Download location - Path to store downloaded videos in. - Enter download path - Autoplay through Intent - Automatically starts a video when it was called from another app. - Default Resolution - Play with Kodi - Kore app not found. Kore is needed to play videos with Kodi media center. - Install Kore - https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore - Show \"Play with Kodi\" option - Displays an option to play a video via Kodi media center. - Audio - Default audio format - WebM - free format - m4a - better quality - Download - + Did you mean: + Search page: + Share with: + Choose browser: + rotation + Settings + Use external video player + Use external audio player + Download path + Path to store downloaded videos in + Enter download path + Autoplay through Intent + Automatically play a video when it\'s called from another app + Default Resolution + Play with Kodi + Kore app not found. Install Kore? + https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore + Show \"Play with Kodi\" option + Display an option to play a video via Kodi media center + Audio + Default audio format + WebM — free format + m4a — better quality + Theme + Dark + Light + + Download + Video Audio - Next video - Show next and similar videos - URL not supported. - Similar videos - Preferable content language - VIDEO & AUDIO - INFO - ETC - %1$s - NewPipe - Playing in background - https://www.c3s.cc/ + Next video + Show next and similar videos + URL not supported + Similar videos + Preferable content language + Video & Audio + Appearance + Other + %1$s - NewPipe + Playing in background + https://www.c3s.cc/ + Play + Network Error - Video preview thumbnail - Video preview thumbnail - Uploader thumbnail - Dislikes - Likes + Video preview thumbnail + Video preview thumbnail + Uploader\'s userpic thumbnail + Likes + Dislikes + Use Tor + Force download traffic through Tor for increased privacy (streaming videos not yet supported) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8d27cc3df..8abacc2e8 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -3,17 +3,17 @@ \ No newline at end of file diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml new file mode 100644 index 000000000..22f9644fe --- /dev/null +++ b/app/src/main/res/xml/settings.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml deleted file mode 100644 index 98399f778..000000000 --- a/app/src/main/res/xml/settings_screen.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/assets/gruese_die_gema.svg b/assets/gruese_die_gema.svg index 48ebc8db0..eace7bf44 100644 --- a/assets/gruese_die_gema.svg +++ b/assets/gruese_die_gema.svg @@ -7,7 +7,6 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="426" @@ -16,7 +15,10 @@ id="svg2" version="1.1" inkscape:version="0.91 r13725" - sodipodi:docname="gruese_die_gema_unangebracht.svg"> + sodipodi:docname="gruese_die_gema.svg" + inkscape:export-filename="/home/the-scrabi/Projects/NewPipe/assets/gruese_die_gema.png" + inkscape:export-xdpi="216.33803" + inkscape:export-ydpi="216.33803"> + inkscape:window-width="1015" + inkscape:window-height="417" + inkscape:window-x="287" + inkscape:window-y="491" + inkscape:window-maximized="0" /> @@ -46,7 +48,7 @@ image/svg+xml - + @@ -56,129 +58,155 @@ id="layer1" transform="translate(0,-812.36212)"> - - - - - - - - - - - - - - - - - - - - - + id="g4230" + transform="matrix(0.67525011,0,0,0.67525011,-14.086916,282.00859)"> + + + + + + + + + + + + + + + + + + + + + + + + + - + Genervt? Gib der Alternative c3s + + eine Chance. diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 1d3591c8a..000000000 --- a/gradle.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file