From b2f56364d6965f058daeb9daf85ed7284e841318 Mon Sep 17 00:00:00 2001 From: Javi Rueda Date: Wed, 24 Feb 2021 16:23:33 +0100 Subject: [PATCH 1/3] Use commentron instead of Comment SDK calls (#1149) * Use commentron instead of Comment SDK calls * Use current timestamp as 'id' for comment server request --- .../lbry/browser/tasks/CommentCreateTask.java | 65 ++++++------ .../lbry/browser/tasks/CommentListTask.java | 7 +- .../java/io/lbry/browser/utils/Comments.java | 99 +++++++++++++++++++ 3 files changed, 131 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/io/lbry/browser/utils/Comments.java diff --git a/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java b/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java index 54f810e6..5cdce1d9 100644 --- a/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java @@ -7,29 +7,18 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; -import java.math.BigDecimal; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.TimeUnit; +import java.util.Objects; import io.lbry.browser.exceptions.ApiCallException; import io.lbry.browser.model.Comment; +import io.lbry.browser.utils.Comments; import io.lbry.browser.utils.Helper; -import io.lbry.browser.utils.Lbry; -import io.lbry.browser.utils.Lbryio; -import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.Response; public class CommentCreateTask extends AsyncTask { - private static final String STATUS_ENDPOINT = "https://comments.lbry.com"; - - private Comment comment; - private View progressView; - private CommentCreateWithTipHandler handler; + private final Comment comment; + private final View progressView; + private final CommentCreateWithTipHandler handler; private Exception error; public CommentCreateTask(Comment comment, View progressView, CommentCreateWithTipHandler handler) { @@ -46,29 +35,31 @@ public class CommentCreateTask extends AsyncTask { Comment createdComment = null; try { // check comments status endpoint - Request request = new Request.Builder().url(STATUS_ENDPOINT).build(); - OkHttpClient client = new OkHttpClient.Builder(). - writeTimeout(30, TimeUnit.SECONDS). - readTimeout(30, TimeUnit.SECONDS). - build(); - Response response = client.newCall(request).execute(); - JSONObject status = new JSONObject(response.body().string()); - String statusText = Helper.getJSONString("text", null, status); - boolean isRunning = Helper.getJSONBoolean("is_running", false, status); - if (!"ok".equalsIgnoreCase(statusText) || !isRunning) { - throw new ApiCallException("The comment server is not available at this time. Please try again later."); + Comments.checkCommentsEndpointStatus(); + + JSONObject comment_body = new JSONObject(); + comment_body.put("comment", comment.getText()); + comment_body.put("claim_id", comment.getClaimId()); + if (!Helper.isNullOrEmpty(comment.getParentId())) { + comment_body.put("parent_id", comment.getParentId()); + } + comment_body.put("channel_id", comment.getChannelId()); + comment_body.put("channel_name", comment.getChannelName()); + + JSONObject jsonChannelSign = Comments.channelSign(comment_body, comment.getChannelId(), comment.getChannelName()); + + if (jsonChannelSign.has("signature") && jsonChannelSign.has("signing_ts")) { + comment_body.put("signature", jsonChannelSign.getString("signature")); + comment_body.put("signing_ts", jsonChannelSign.getString("signing_ts")); } - Map options = new HashMap<>(); - options.put("comment", comment.getText()); - options.put("claim_id", comment.getClaimId()); - options.put("channel_id", comment.getChannelId()); - options.put("channel_name", comment.getChannelName()); - if (!Helper.isNullOrEmpty(comment.getParentId())) { - options.put("parent_id", comment.getParentId()); - } - JSONObject jsonObject = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_CREATE, options); - createdComment = Comment.fromJSONObject(jsonObject); + Response resp = Comments.performRequest(comment_body, "comment.Create"); + String responseString = Objects.requireNonNull(resp.body()).string(); + resp.close(); + JSONObject jsonResponse = new JSONObject(responseString); + + if (jsonResponse.has("result")) + createdComment = Comment.fromJSONObject(jsonResponse.getJSONObject("result")); } catch (ApiCallException | ClassCastException | IOException | JSONException ex) { error = ex; } diff --git a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java index 2833e003..36cf3131 100644 --- a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.Map; import io.lbry.browser.model.Comment; +import io.lbry.browser.utils.Comments; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbry; @@ -21,8 +22,8 @@ public class CommentListTask extends AsyncTask> { private final int page; private final int pageSize; private final String claim; - private ProgressBar progressBar; - private CommentListHandler handler; + private final ProgressBar progressBar; + private final CommentListHandler handler; private Exception error; public CommentListTask(int page, int pageSize, String claim, ProgressBar progressBar, CommentListHandler handler) { @@ -52,7 +53,7 @@ public class CommentListTask extends AsyncTask> { options.put("skip_validation", true); options.put("visible", true); - JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_LIST, options); + JSONObject result = (JSONObject) Lbry.parseResponse(Comments.performRequest(Lbry.buildJsonParams(options), "comment.List")); JSONArray items = result.getJSONArray("items"); List children = new ArrayList<>(); diff --git a/app/src/main/java/io/lbry/browser/utils/Comments.java b/app/src/main/java/io/lbry/browser/utils/Comments.java new file mode 100644 index 00000000..47d86fc6 --- /dev/null +++ b/app/src/main/java/io/lbry/browser/utils/Comments.java @@ -0,0 +1,99 @@ +package io.lbry.browser.utils; + +import android.os.Build; + +import org.apache.commons.codec.binary.Hex; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import io.lbry.browser.exceptions.ApiCallException; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +public class Comments { + private static final String STATUS_ENDPOINT = "https://comments.lbry.com"; + public static final String COMMENT_SERVER_ENDPOINT = "https://comments.lbry.com/api/v2"; + + public static JSONObject channelSign(JSONObject commentBody, String channelId, String channelName) throws ApiCallException, JSONException { + byte[] commentBodyBytes = commentBody.getString("comment").getBytes(StandardCharsets.UTF_8); + String encodedCommentBody; + + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) + encodedCommentBody = Hex.encodeHexString(commentBodyBytes, false); + else + encodedCommentBody = new String(Hex.encodeHex(commentBodyBytes)); + + Map signingParams = new HashMap<>(3); + signingParams.put("hexdata", encodedCommentBody); + signingParams.put("channel_id", channelId); + signingParams.put("channel_name", channelName); + + return (JSONObject) Lbry.genericApiCall("channel_sign", signingParams); + } + + /** + * Performs request to default Comment Server + * @param params JSON containing parameters to send to the server + * @param method One of the available methods for comments + * @return Response from the server + * @throws IOException throwable from OkHttpClient execute() + */ + public static Response performRequest(JSONObject params, String method) throws IOException { + return performRequest(COMMENT_SERVER_ENDPOINT, params, method); + } + + /** + * Performs the request to Comment Server + * @param commentServer Url where to direct the request + * @param params JSON containing parameters to send to the server + * @param method One of the available methods for comments + * @return Response from the server + * @throws IOException throwable from OkHttpClient execute() + */ + public static Response performRequest(String commentServer, JSONObject params, String method) throws IOException { + final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + + Map requestParams = new HashMap<>(4); + requestParams.put("jsonrpc", "2.0"); + requestParams.put("id", TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); + requestParams.put("method", method); + requestParams.put("params", params); + + RequestBody requestBody = RequestBody.create(Lbry.buildJsonParams(requestParams).toString(), JSON); + + Request commentCreateRequest = new Request.Builder() + .url(commentServer.concat("?m=").concat(method)) + .post(requestBody) + .build(); + + OkHttpClient client = new OkHttpClient.Builder().writeTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + + return client.newCall(commentCreateRequest).execute(); + } + + public static void checkCommentsEndpointStatus() throws IOException, JSONException, ApiCallException { + Request request = new Request.Builder().url(STATUS_ENDPOINT).build(); + OkHttpClient client = new OkHttpClient.Builder().writeTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + Response response = client.newCall(request).execute(); + JSONObject status = new JSONObject(Objects.requireNonNull(response.body()).string()); + String statusText = Helper.getJSONString("text", null, status); + boolean isRunning = Helper.getJSONBoolean("is_running", false, status); + if (!"ok".equalsIgnoreCase(statusText) || !isRunning) { + throw new ApiCallException("The comment server is not available at this time. Please try again later."); + } + } +} -- 2.45.2 From f9a65d427793b59cc002bfd49d8248e91e118f95 Mon Sep 17 00:00:00 2001 From: Javi Rueda Date: Thu, 25 Feb 2021 17:27:16 +0100 Subject: [PATCH 2/3] Allow media to be played automatically --- app/src/main/java/io/lbry/browser/MainActivity.java | 6 ++++++ .../lbry/browser/ui/findcontent/FileViewFragment.java | 11 ++++++----- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/settings.xml | 5 +++++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 522e1cdf..fcd34261 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -336,6 +336,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener // preference keys public static final String PREFERENCE_KEY_BACKGROUND_PLAYBACK = "io.lbry.browser.preference.userinterface.BackgroundPlayback"; + public static final String PREFERENCE_KEY_MEDIA_AUTOPLAY = "io.lbry.browser.preference.userinterface.MediaAutoplay"; public static final String PREFERENCE_KEY_DARK_MODE = "io.lbry.browser.preference.userinterface.DarkMode"; public static final String PREFERENCE_KEY_SHOW_MATURE_CONTENT = "io.lbry.browser.preference.userinterface.ShowMatureContent"; public static final String PREFERENCE_KEY_SHOW_URL_SUGGESTIONS = "io.lbry.browser.preference.userinterface.UrlSuggestions"; @@ -680,6 +681,11 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener return sp.getBoolean(PREFERENCE_KEY_BACKGROUND_PLAYBACK, true); } + public boolean isMediaAutoplayEnabled() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + return sp.getBoolean(PREFERENCE_KEY_MEDIA_AUTOPLAY, true); + } + public boolean initialSubscriptionMergeDone() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); return sp.getBoolean(PREFERENCE_KEY_INTERNAL_INITIAL_SUBSCRIPTION_MERGE_DONE, false); diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java index e04e5068..ed8703dc 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java @@ -12,7 +12,6 @@ import android.graphics.Color; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Handler; import android.text.Editable; import android.text.TextWatcher; import android.text.format.DateUtils; @@ -98,6 +97,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -284,7 +284,7 @@ public class FileViewFragment extends BaseFragment implements fileViewPlayerListener = new Player.EventListener() { @Override - public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + public void onPlaybackStateChanged(@Player.State int playbackState) { if (playbackState == Player.STATE_READY) { elapsedDuration = MainActivity.appPlayer.getCurrentPosition(); totalDuration = MainActivity.appPlayer.getDuration() < 0 ? 0 : MainActivity.appPlayer.getDuration(); @@ -303,7 +303,7 @@ public class FileViewFragment extends BaseFragment implements hideBuffering(); if (loadingNewClaim) { - MainActivity.appPlayer.setPlayWhenReady(true); + MainActivity.appPlayer.setPlayWhenReady(Objects.requireNonNull((MainActivity) (getActivity())).isMediaAutoplayEnabled()); loadingNewClaim = false; } } else if (playbackState == Player.STATE_BUFFERING) { @@ -1762,7 +1762,7 @@ public class FileViewFragment extends BaseFragment implements ((MainActivity) context).setNowPlayingClaim(claim, currentUrl); } - MainActivity.appPlayer.setPlayWhenReady(true); + MainActivity.appPlayer.setPlayWhenReady(Objects.requireNonNull((MainActivity) (getActivity())).isMediaAutoplayEnabled()); String userAgent = Util.getUserAgent(context, getString(R.string.app_name)); String mediaSourceUrl = getStreamingUrl(); MediaSource mediaSource = new ProgressiveMediaSource.Factory( @@ -1770,7 +1770,8 @@ public class FileViewFragment extends BaseFragment implements new DefaultExtractorsFactory() ).setLoadErrorHandlingPolicy(new StreamLoadErrorPolicy()).createMediaSource(Uri.parse(mediaSourceUrl)); - MainActivity.appPlayer.prepare(mediaSource, true, true); + MainActivity.appPlayer.setMediaSource(mediaSource, true); + MainActivity.appPlayer.prepare(); } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7463513e..5c4da9f9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -247,6 +247,7 @@ Content & User interface Other Enable background playback + Autoplay media files Enable dark theme Show mature content Show URL suggestions diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index 6348a2d9..9f588829 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -10,6 +10,11 @@ app:defaultValue="true" app:title="@string/enable_background_playback" app:iconSpaceReserved="false" /> + Date: Thu, 25 Feb 2021 19:02:52 +0100 Subject: [PATCH 3/3] Fix for media been always autoplayed when opened from miniplayer --- .../io/lbry/browser/ui/findcontent/FileViewFragment.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java index ed8703dc..b2248c62 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java @@ -291,7 +291,6 @@ public class FileViewFragment extends BaseFragment implements if (!playbackStarted) { logPlay(currentUrl, startTimeMillis); playbackStarted = true; - isPlaying = true; long lastPosition = loadLastPlaybackPosition(); if (lastPosition > -1) { @@ -340,6 +339,11 @@ public class FileViewFragment extends BaseFragment implements hideBuffering(); } } + + @Override + public void onIsPlayingChanged(boolean isPlayng) { + isPlaying = isPlayng; + } }; return root; -- 2.45.2