diff --git a/app/build.gradle b/app/build.gradle index 89ae00ea..0d9a362b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -132,8 +132,8 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - __32bitImplementation 'io.lbry:lbrysdk32:0.91.0' - __64bitImplementation 'io.lbry:lbrysdk64:0.91.0' + __32bitImplementation 'io.lbry:lbrysdk32:0.94.1' + __64bitImplementation 'io.lbry:lbrysdk64:0.94.1' } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/io/lbry/browser/model/Claim.java b/app/src/main/java/io/lbry/browser/model/Claim.java index 88dd197e..45c03840 100644 --- a/app/src/main/java/io/lbry/browser/model/Claim.java +++ b/app/src/main/java/io/lbry/browser/model/Claim.java @@ -137,6 +137,14 @@ public class Claim { return null; } + public boolean hasSource() { + if (value instanceof StreamMetadata) { + StreamMetadata metadata = (StreamMetadata) value; + return metadata.getSource() != null; + } + return false; + } + public boolean isPlayable() { if (value instanceof StreamMetadata) { StreamMetadata metadata = (StreamMetadata) value; diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java index 19d0043a..756c9d1f 100644 --- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java @@ -230,7 +230,8 @@ public class ChannelContentFragment extends Fragment implements DownloadActionLi 0, 0, currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage, - Helper.CONTENT_PAGE_SIZE); + Helper.CONTENT_PAGE_SIZE, + true); } private List getContentSortOrder() { diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/AllContentFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/AllContentFragment.java index df62198e..353fefae 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/AllContentFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/AllContentFragment.java @@ -421,7 +421,8 @@ public class AllContentFragment extends BaseFragment implements DownloadActionLi 0, 0, currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage, - Helper.CONTENT_PAGE_SIZE); + Helper.CONTENT_PAGE_SIZE, + true); } private List getContentSortOrder() { diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java index 2a041e11..8026f0bf 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java @@ -79,7 +79,8 @@ public class EditorsChoiceFragment extends BaseFragment { Arrays.asList(Claim.ORDER_BY_RELEASE_TIME), null, 1, - 99); + 99, + true); } public void onResume() { 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 5c7fbfd2..9c93dc7b 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 @@ -1626,7 +1626,7 @@ public class FileViewFragment extends BaseFragment implements root.findViewById(R.id.file_view_open_external_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - openClaimExternally(claim, claim.getMediaType()); + openClaimExternally(claim, claim.getMediaType(), !claim.hasSource()); } }); @@ -1684,12 +1684,16 @@ public class FileViewFragment extends BaseFragment implements restoreMainActionButton(); } - if (Lbry.SDK_READY && !claim.isPlayable() && !claim.isViewable() && Helper.isNullOrEmpty(commentHash)) { - if (claim.getFile() == null) { - loadFile(); - } else { - // file already loaded, but it's unsupported + if (Lbry.SDK_READY) { + if (!claim.hasSource()) { showUnsupportedView(); + } else if (!claim.isPlayable() && !claim.isViewable() && Helper.isNullOrEmpty(commentHash)) { + if (claim.getFile() == null) { + loadFile(); + } else { + // file already loaded, but it's unsupported + showUnsupportedView(); + } } } @@ -1733,13 +1737,19 @@ public class FileViewFragment extends BaseFragment implements if (root != null) { root.findViewById(R.id.file_view_exoplayer_container).setVisibility(View.GONE); root.findViewById(R.id.file_view_unsupported_container).setVisibility(View.VISIBLE); - String fileNameString = ""; - if (claim.getFile() != null && !Helper.isNullOrEmpty(claim.getFile().getDownloadPath())) { - LbryFile lbryFile = claim.getFile(); - File file = new File(lbryFile.getDownloadPath()); - fileNameString = String.format("\"%s\" ", file.getName()); + if (claim.hasSource()) { + String fileNameString = ""; + if (claim.getFile() != null && !Helper.isNullOrEmpty(claim.getFile().getDownloadPath())) { + LbryFile lbryFile = claim.getFile(); + File file = new File(lbryFile.getDownloadPath()); + fileNameString = String.format("\"%s\" ", file.getName()); + } + ((TextView) root.findViewById(R.id.file_view_unsupported_text)).setText(getString(R.string.unsupported_content_desc, fileNameString)); + ((MaterialButton) root.findViewById(R.id.file_view_open_external_button)).setText(getString(R.string.open)); + } else { + ((TextView) root.findViewById(R.id.file_view_unsupported_text)).setText(getString(R.string.unsupported_content_to_odysee_desc)); + ((MaterialButton) root.findViewById(R.id.file_view_open_external_button)).setText(getString(R.string.open_on_odysee_com)); } - ((TextView) root.findViewById(R.id.file_view_unsupported_text)).setText(getString(R.string.unsupported_content_desc, fileNameString)); } } @@ -2191,7 +2201,7 @@ public class FileViewFragment extends BaseFragment implements handled = true; } } else { - openClaimExternally(claim, mediaType); + openClaimExternally(claim, mediaType, false); } } @@ -2275,15 +2285,25 @@ public class FileViewFragment extends BaseFragment implements " "; } - private void openClaimExternally(Claim claim, String mediaType) { - Uri fileUri = Uri.parse(claim.getFile().getDownloadPath()); + private void openClaimExternally(Claim claim, String mediaType, boolean odyseeLink) { + if (odyseeLink) { + try { + LbryUri lbryUri = LbryUri.parse(claim.getCanonicalUrl()); + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(lbryUri.toOdyseeString())); + startActivity(intent); + } catch (LbryUriException e) { + e.printStackTrace(); + } + } else { + Uri fileUri = Uri.parse(claim.getFile().getDownloadPath()); - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.setDataAndType(fileUri, mediaType.toLowerCase()); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - Intent chooser = Intent.createChooser(intent, getString(R.string.choose_app)); - startActivityForResult(chooser, 419); + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.setDataAndType(fileUri, mediaType.toLowerCase()); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + Intent chooser = Intent.createChooser(intent, getString(R.string.choose_app)); + startActivityForResult(chooser, 419); + } } public void showError(String message) { diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/FollowingFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/FollowingFragment.java index cc89d882..e3111820 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/FollowingFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/FollowingFragment.java @@ -415,7 +415,8 @@ public class FollowingFragment extends BaseFragment implements Arrays.asList(Claim.ORDER_BY_EFFECTIVE_AMOUNT), null, currentSuggestedPage == 0 ? 1 : currentSuggestedPage, - SUGGESTED_PAGE_SIZE); + SUGGESTED_PAGE_SIZE, + true); } private Map buildContentOptions() { @@ -437,7 +438,8 @@ public class FollowingFragment extends BaseFragment implements 0, 0, currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage, - Helper.CONTENT_PAGE_SIZE); + Helper.CONTENT_PAGE_SIZE, + true); } private List getChannelIds() { diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java index 0d980c4e..8650ec0a 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java @@ -210,7 +210,8 @@ public class ShuffleFragment extends BaseFragment { 121, // 2 minutes or less 1, currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage, - PAGE_SIZE); + PAGE_SIZE, + true); } public void onStart() { diff --git a/app/src/main/java/io/lbry/browser/utils/Lbry.java b/app/src/main/java/io/lbry/browser/utils/Lbry.java index b727948f..39381dc4 100644 --- a/app/src/main/java/io/lbry/browser/utils/Lbry.java +++ b/app/src/main/java/io/lbry/browser/utils/Lbry.java @@ -373,7 +373,7 @@ public final class Lbry { // build claim search for surf mode public static Map buildClaimSearchOptions( - String claimType, List notTags, List channelIds, List orderBy, long maxDuration, int limitClaimsPerChannel, int page, int pageSize) { + String claimType, List notTags, List channelIds, List orderBy, long maxDuration, int limitClaimsPerChannel, int page, int pageSize, boolean hasSource) { return buildClaimSearchOptions( Collections.singletonList(claimType), null, @@ -385,7 +385,8 @@ public final class Lbry { maxDuration, limitClaimsPerChannel, page, - pageSize); + pageSize, + hasSource); } public static Map buildClaimSearchOptions( @@ -397,7 +398,8 @@ public final class Lbry { List orderBy, String releaseTime, int page, - int pageSize) { + int pageSize, + boolean hasSource) { return buildClaimSearchOptions( Collections.singletonList(claimType), anyTags, @@ -409,7 +411,8 @@ public final class Lbry { 0, 0, page, - pageSize); + pageSize, + hasSource); } public static Map buildClaimSearchOptions( @@ -423,7 +426,8 @@ public final class Lbry { long maxDuration, int limitClaimsPerChannel, int page, - int pageSize) { + int pageSize, + boolean hasSource) { Map options = new HashMap<>(); if (claimType != null && claimType.size() > 0) { options.put("claim_type", claimType); @@ -441,6 +445,12 @@ public final class Lbry { options.put("limit_claims_per_channel", limitClaimsPerChannel); } + if (hasSource) { + options.put("has_source", true); + } else { + options.put("has_no_source", true); + } + addClaimSearchListOption("any_tags", anyTags, options); addClaimSearchListOption("not_tags", notTags, options); addClaimSearchListOption("channel_ids", channelIds, options); diff --git a/app/src/main/java/io/lbry/browser/utils/LbryUri.java b/app/src/main/java/io/lbry/browser/utils/LbryUri.java index a55dd0f2..1570ab96 100644 --- a/app/src/main/java/io/lbry/browser/utils/LbryUri.java +++ b/app/src/main/java/io/lbry/browser/utils/LbryUri.java @@ -16,6 +16,7 @@ import static org.apache.commons.codec.CharEncoding.UTF_8; @Data public class LbryUri { public static final String LBRY_TV_BASE_URL = "https://lbry.tv/"; + public static final String ODYSEE_COM_BASE_URL = "https://odysee.com/"; public static final String PROTO_DEFAULT = "lbry://"; public static final String REGEX_INVALID_URI = "[ =&#:$@%?;/\\\\\"<>%\\{\\}|^~\\[\\]`\u0000-\u0008\u000b-\u000c\u000e-\u001F\uD800-\uDFFF\uFFFE-\uFFFF]"; public static final String REGEX_ADDRESS = "^(b)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$"; @@ -202,7 +203,7 @@ public class LbryUri { } String primaryClaimName = null; - if (protocol.equals(LBRY_TV_BASE_URL) && Helper.isNullOrEmpty(formattedChannelName)) { + if ((protocol.equals(LBRY_TV_BASE_URL) || protocol.equals(ODYSEE_COM_BASE_URL)) && Helper.isNullOrEmpty(formattedChannelName)) { try { primaryClaimName = URLEncoder.encode(claimName, UTF_8); } catch (UnsupportedEncodingException e) { @@ -241,7 +242,7 @@ public class LbryUri { secondaryClaimName = contentName; } if (Helper.isNullOrEmpty(secondaryClaimName)) { - if (protocol.equals(LBRY_TV_BASE_URL)) { + if (protocol.equals(LBRY_TV_BASE_URL) || protocol.equals(ODYSEE_COM_BASE_URL)) { try { secondaryClaimName = !Helper.isNullOrEmpty(formattedChannelName) ? URLEncoder.encode(streamName, UTF_8) : null; } catch (UnsupportedEncodingException e) { @@ -254,7 +255,7 @@ public class LbryUri { String secondaryClaimId = !Helper.isNullOrEmpty(secondaryClaimName) ? streamClaimId : null; if (!Helper.isNullOrEmpty(primaryClaimId)) { - if (protocol.equals(LBRY_TV_BASE_URL)) + if (protocol.equals(LBRY_TV_BASE_URL) || protocol.equals(ODYSEE_COM_BASE_URL)) sb.append(':').append(primaryClaimId); else sb.append('#').append(primaryClaimId); @@ -269,7 +270,7 @@ public class LbryUri { } if (!Helper.isNullOrEmpty(secondaryClaimId)) { - if (protocol.equals(LBRY_TV_BASE_URL)) + if (protocol.equals(LBRY_TV_BASE_URL) || protocol.equals(ODYSEE_COM_BASE_URL)) sb.append(':').append(secondaryClaimId); else sb.append('#').append(secondaryClaimId); @@ -289,6 +290,9 @@ public class LbryUri { public String toTvString() { return build(true, LBRY_TV_BASE_URL, false); } + public String toOdyseeString() { + return build(true, ODYSEE_COM_BASE_URL, false); + } public String toVanityString() { return build(true, PROTO_DEFAULT, true); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8b4bce94..6fda4756 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,6 +57,7 @@ Delete Download Open + Open on ODYSEE.COM Report Loading decentralized data… Related Content @@ -71,6 +72,7 @@ Play Unsupported Content Sorry, we are unable to display this content in the app. You can find the file %1$sin your downloads folder. + Sorry, we are unable to display this content in the app. Click the button to open it on the Odysee website. There\'s nothing at this location. In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. <a href="https://lbry.com/faq/dmca">Read more</a> In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this channel from our applications. <a href="https://lbry.com/faq/dmca">Read more</a> diff --git a/app/src/test/java/io/lbry/browser/utils/LbryUriTest.java b/app/src/test/java/io/lbry/browser/utils/LbryUriTest.java index 7dfa46af..45c0c943 100644 --- a/app/src/test/java/io/lbry/browser/utils/LbryUriTest.java +++ b/app/src/test/java/io/lbry/browser/utils/LbryUriTest.java @@ -178,6 +178,19 @@ public class LbryUriTest { assertEquals("https://lbry.tv/@test:1/La-Peur%2C-Nos-Attentats%2C-c%27est-VOTRE-Se%CC%81curite%CC%81%21-Les-Guignols:6", obtained.toTvString()); } + @Test + public void lbryToOdyseeString() { + LbryUri obtained = new LbryUri(); + + try { + obtained = LbryUri.parse("lbry://@lbry#3f/lbryturns4#6",false); + } catch (LbryUriException e) { + e.printStackTrace(); + } + + assertEquals("https://odysee.com/@lbry:3f/lbryturns4:6", obtained.toOdyseeString()); + } + @NotNull private LbryUri sinthesizeExpected() { LbryUri expectedForChannel = new LbryUri(); diff --git a/build.gradle b/build.gradle index b7173582..2ff4ab4a 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,7 @@ allprojects { google() jcenter() maven { url "https://jitpack.io" } + maven { url "https://dl.bintray.com/lbryio/io.lbry" } } }