diff --git a/src/main/java/it/auties/whatsapp/api/Whatsapp.java b/src/main/java/it/auties/whatsapp/api/Whatsapp.java index 0c997cda..5c25ece7 100644 --- a/src/main/java/it/auties/whatsapp/api/Whatsapp.java +++ b/src/main/java/it/auties/whatsapp/api/Whatsapp.java @@ -33,7 +33,7 @@ import it.auties.whatsapp.model.media.AttachmentType; import it.auties.whatsapp.model.media.MediaFile; import it.auties.whatsapp.model.message.model.*; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.model.message.server.ProtocolMessage; import it.auties.whatsapp.model.message.server.ProtocolMessageBuilder; import it.auties.whatsapp.model.message.standard.CallMessageBuilder; @@ -1835,27 +1835,68 @@ public CompletableFuture queryBusinessCollections(JidProvider contact) { } /** - * Downloads a media from Whatsapp's servers. If the media is available, it will be returned - * asynchronously. Otherwise, a retry request will be issued. If that also fails, an exception - * will be thrown + * Downloads a media from Whatsapp's servers. + * If the media was already downloaded, the cached version will be returned. + * If the download fails because the media is too old/invalid, a reupload request will be sent to Whatsapp. + * If the latter fails as well, an empty optional will be returned. * * @param info the non-null message info wrapping the media * @return a CompletableFuture */ - public CompletableFuture downloadMedia(ChatMessageInfo info) { + public CompletableFuture> downloadMedia(ChatMessageInfo info) { if (!(info.message().content() instanceof MediaMessage mediaMessage)) { throw new IllegalArgumentException("Expected media message, got: " + info.message().category()); } - if (!(mediaMessage instanceof LocalMediaMessage uploadedMediaMessage)) { - throw new IllegalArgumentException("This message wasn't uploaded yet"); + return downloadMedia(mediaMessage).thenCompose(result -> { + if(result.isPresent()) { + return CompletableFuture.completedFuture(result); + } + + return requireMediaReupload(info) + .thenCompose(ignored -> downloadMedia(mediaMessage)); + }); + } + + /** + * Downloads a media from Whatsapp's servers. + * If the media was already downloaded, the cached version will be returned. + * If the download fails because the media is too old/invalid, an empty optional will be returned. + * + * @param info the non-null message info wrapping the media + * @return a CompletableFuture + */ + public CompletableFuture> downloadMedia(NewsletterMessageInfo info) { + if (!(info.message().content() instanceof MediaMessage mediaMessage)) { + throw new IllegalArgumentException("Expected media message, got: " + info.message().category()); } - return uploadedMediaMessage.decodedMedia() - .map(CompletableFuture::completedFuture) - .orElseGet(() -> requireMediaReupload(info) - .thenApplyAsync(ignored -> uploadedMediaMessage.decodedMedia() - .orElseThrow(() -> new RuntimeException("Media reupload failed")))); + return downloadMedia(mediaMessage); + } + + /** + * Downloads a media from Whatsapp's servers. + * If the media was already downloaded, the cached version will be returned. + * If the download fails because the media is too old/invalid, an empty optional will be returned. + * + * @param mediaMessage the non-null media + * @return a CompletableFuture + */ + public CompletableFuture> downloadMedia(MediaMessage mediaMessage) { + if (!(mediaMessage instanceof ExtendedMediaMessage extendedMediaMessage)) { + return Medias.downloadAsync(mediaMessage); + } + + var decodedMedia = extendedMediaMessage.decodedMedia(); + if(decodedMedia.isPresent()) { + return CompletableFuture.completedFuture(decodedMedia); + } + + + return Medias.downloadAsync(mediaMessage).thenApply(result -> { + result.ifPresent(extendedMediaMessage::setDecodedMedia); + return result; + }); } /** @@ -1864,7 +1905,7 @@ public CompletableFuture downloadMedia(ChatMessageInfo info) { * @param info the non-null message info wrapping the media * @return a CompletableFuture */ - public CompletableFuture requireMediaReupload(ChatMessageInfo info) { + public CompletableFuture requireMediaReupload(ChatMessageInfo info) { if (!(info.message().content() instanceof MediaMessage mediaMessage)) { throw new IllegalArgumentException("Expected media message, got: " + info.message().category()); } @@ -1884,10 +1925,10 @@ public CompletableFuture requireMediaReupload(ChatMessageInfo i var node = Node.of("receipt", Map.of("id", info.key().id(), "to", jidOrThrowError() .withoutDevice(), "type", "server-error"), Node.of("encrypt", Node.of("enc_p", ciphertext), Node.of("enc_iv", retryIv)), Node.of("rmr", rmrAttributes)); return socketHandler.send(node, result -> result.hasDescription("notification")) - .thenApplyAsync(result -> parseMediaReupload(info, mediaMessage, retryKey, retryIdData, result)); + .thenAcceptAsync(result -> parseMediaReupload(info, mediaMessage, retryKey, retryIdData, result)); } - private ChatMessageInfo parseMediaReupload(ChatMessageInfo info, MediaMessage mediaMessage, byte[] retryKey, byte[] retryIdData, Node node) { + private void parseMediaReupload(ChatMessageInfo info, MediaMessage mediaMessage, byte[] retryKey, byte[] retryIdData, Node node) { Validate.isTrue(!node.hasNode("error"), "Erroneous response from media reupload: %s", node.attributes() .getInt("code")); var encryptNode = node.findNode("encrypt") @@ -1904,7 +1945,6 @@ private ChatMessageInfo parseMediaReupload(ChatMessageInfo info, MediaMessage .orElseThrow(() -> new RuntimeException("Media reupload failed")); mediaMessage.setMediaUrl(Medias.createMediaUrl(directPath)); mediaMessage.setMediaDirectPath(directPath); - return info; } /** diff --git a/src/main/java/it/auties/whatsapp/model/message/model/MediaMessage.java b/src/main/java/it/auties/whatsapp/model/message/model/MediaMessage.java index d6eceb8f..44510540 100644 --- a/src/main/java/it/auties/whatsapp/model/message/model/MediaMessage.java +++ b/src/main/java/it/auties/whatsapp/model/message/model/MediaMessage.java @@ -3,7 +3,7 @@ import it.auties.whatsapp.model.info.ChatMessageInfo; import it.auties.whatsapp.model.media.AttachmentType; import it.auties.whatsapp.model.media.MutableAttachmentProvider; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.model.message.payment.PaymentInvoiceMessage; import it.auties.whatsapp.model.message.standard.*; @@ -15,7 +15,7 @@ * A media message * Read its content using {@link it.auties.whatsapp.api.Whatsapp#downloadMedia(ChatMessageInfo)} */ -public sealed interface MediaMessage> extends ContextualMessage, MutableAttachmentProvider permits LocalMediaMessage, PaymentInvoiceMessage, AudioMessage, DocumentMessage, ImageMessage, StickerMessage, VideoOrGifMessage { +public sealed interface MediaMessage> extends ContextualMessage, MutableAttachmentProvider permits ExtendedMediaMessage, PaymentInvoiceMessage, AudioMessage, DocumentMessage, ImageMessage, StickerMessage, VideoOrGifMessage { /** * Returns the timestampSeconds, that is the seconds elapsed since {@link java.time.Instant#EPOCH}, for{@link MediaMessage#mediaKey()} * diff --git a/src/main/java/it/auties/whatsapp/model/message/model/reserved/LocalMediaMessage.java b/src/main/java/it/auties/whatsapp/model/message/model/reserved/ExtendedMediaMessage.java similarity index 78% rename from src/main/java/it/auties/whatsapp/model/message/model/reserved/LocalMediaMessage.java rename to src/main/java/it/auties/whatsapp/model/message/model/reserved/ExtendedMediaMessage.java index e361b5df..b6fe3260 100644 --- a/src/main/java/it/auties/whatsapp/model/message/model/reserved/LocalMediaMessage.java +++ b/src/main/java/it/auties/whatsapp/model/message/model/reserved/ExtendedMediaMessage.java @@ -5,7 +5,7 @@ import java.util.Optional; -public abstract sealed class LocalMediaMessage> implements MediaMessage permits AudioMessage, DocumentMessage, ImageMessage, StickerMessage, VideoOrGifMessage { +public abstract sealed class ExtendedMediaMessage> implements MediaMessage permits AudioMessage, DocumentMessage, ImageMessage, StickerMessage, VideoOrGifMessage { private byte[] decodedMedia; private String handle; diff --git a/src/main/java/it/auties/whatsapp/model/message/standard/AudioMessage.java b/src/main/java/it/auties/whatsapp/model/message/standard/AudioMessage.java index 12722eb3..cfcb8e47 100644 --- a/src/main/java/it/auties/whatsapp/model/message/standard/AudioMessage.java +++ b/src/main/java/it/auties/whatsapp/model/message/standard/AudioMessage.java @@ -9,7 +9,7 @@ import it.auties.whatsapp.model.media.AttachmentType; import it.auties.whatsapp.model.message.model.MediaMessage; import it.auties.whatsapp.model.message.model.MediaMessageType; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.util.Clock; import it.auties.whatsapp.util.Medias; @@ -20,7 +20,7 @@ import java.util.OptionalLong; @ProtobufMessageName("Message.AudioMessage") -public final class AudioMessage extends LocalMediaMessage implements MediaMessage { +public final class AudioMessage extends ExtendedMediaMessage implements MediaMessage { @ProtobufProperty(index = 1, type = ProtobufType.STRING) private String mediaUrl; diff --git a/src/main/java/it/auties/whatsapp/model/message/standard/DocumentMessage.java b/src/main/java/it/auties/whatsapp/model/message/standard/DocumentMessage.java index 465c13f3..edff64de 100644 --- a/src/main/java/it/auties/whatsapp/model/message/standard/DocumentMessage.java +++ b/src/main/java/it/auties/whatsapp/model/message/standard/DocumentMessage.java @@ -12,7 +12,7 @@ import it.auties.whatsapp.model.message.button.ButtonsMessageHeader; import it.auties.whatsapp.model.message.model.MediaMessage; import it.auties.whatsapp.model.message.model.MediaMessageType; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.util.Clock; import it.auties.whatsapp.util.Medias; import it.auties.whatsapp.util.Specification; @@ -29,7 +29,7 @@ /** * A model class that represents a message holding a document inside */ -public final class DocumentMessage extends LocalMediaMessage +public final class DocumentMessage extends ExtendedMediaMessage implements MediaMessage, InteractiveHeaderAttachment, ButtonsMessageHeader, HighlyStructuredFourRowTemplateTitle, HydratedFourRowTemplateTitle { @ProtobufProperty(index = 1, type = ProtobufType.STRING) private String mediaUrl; diff --git a/src/main/java/it/auties/whatsapp/model/message/standard/ImageMessage.java b/src/main/java/it/auties/whatsapp/model/message/standard/ImageMessage.java index 0608cd64..b47a58a7 100644 --- a/src/main/java/it/auties/whatsapp/model/message/standard/ImageMessage.java +++ b/src/main/java/it/auties/whatsapp/model/message/standard/ImageMessage.java @@ -15,7 +15,7 @@ import it.auties.whatsapp.model.message.button.ButtonsMessageHeader; import it.auties.whatsapp.model.message.model.MediaMessage; import it.auties.whatsapp.model.message.model.MediaMessageType; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.util.Clock; import it.auties.whatsapp.util.Medias; @@ -30,7 +30,7 @@ * A model class that represents a message holding an image inside */ @ProtobufMessageName("Message.ImageMessage") -public final class ImageMessage extends LocalMediaMessage +public final class ImageMessage extends ExtendedMediaMessage implements MediaMessage, InteractiveHeaderAttachment, ButtonsMessageHeader, HighlyStructuredFourRowTemplateTitle, HydratedFourRowTemplateTitle { @ProtobufProperty(index = 1, type = ProtobufType.STRING) private String mediaUrl; diff --git a/src/main/java/it/auties/whatsapp/model/message/standard/StickerMessage.java b/src/main/java/it/auties/whatsapp/model/message/standard/StickerMessage.java index 5adb4b83..2357df66 100644 --- a/src/main/java/it/auties/whatsapp/model/message/standard/StickerMessage.java +++ b/src/main/java/it/auties/whatsapp/model/message/standard/StickerMessage.java @@ -8,7 +8,7 @@ import it.auties.whatsapp.model.info.ContextInfo; import it.auties.whatsapp.model.message.model.MediaMessage; import it.auties.whatsapp.model.message.model.MediaMessageType; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.util.Clock; import it.auties.whatsapp.util.Medias; @@ -26,7 +26,7 @@ * A model class that represents a message holding a sticker inside */ @ProtobufMessageName("Message.StickerMessage") -public final class StickerMessage extends LocalMediaMessage implements MediaMessage { +public final class StickerMessage extends ExtendedMediaMessage implements MediaMessage { @ProtobufProperty(index = 1, type = ProtobufType.STRING) private String mediaUrl; diff --git a/src/main/java/it/auties/whatsapp/model/message/standard/VideoOrGifMessage.java b/src/main/java/it/auties/whatsapp/model/message/standard/VideoOrGifMessage.java index 7167ff6d..5f0d4fd8 100644 --- a/src/main/java/it/auties/whatsapp/model/message/standard/VideoOrGifMessage.java +++ b/src/main/java/it/auties/whatsapp/model/message/standard/VideoOrGifMessage.java @@ -14,7 +14,7 @@ import it.auties.whatsapp.model.message.button.ButtonsMessageHeader; import it.auties.whatsapp.model.message.model.MediaMessage; import it.auties.whatsapp.model.message.model.MediaMessageType; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.util.Clock; import it.auties.whatsapp.util.Medias; import it.auties.whatsapp.util.Validate; @@ -29,7 +29,7 @@ * A model class that represents a message holding a video inside */ @ProtobufMessageName("Message.VideoMessage") -public final class VideoOrGifMessage extends LocalMediaMessage +public final class VideoOrGifMessage extends ExtendedMediaMessage implements MediaMessage, InteractiveHeaderAttachment, ButtonsMessageHeader, HighlyStructuredFourRowTemplateTitle, HydratedFourRowTemplateTitle { @ProtobufProperty(index = 1, type = ProtobufType.STRING) private String mediaUrl; diff --git a/src/main/java/it/auties/whatsapp/socket/AppStateHandler.java b/src/main/java/it/auties/whatsapp/socket/AppStateHandler.java index 6bfeda55..150a9b39 100644 --- a/src/main/java/it/auties/whatsapp/socket/AppStateHandler.java +++ b/src/main/java/it/auties/whatsapp/socket/AppStateHandler.java @@ -366,7 +366,7 @@ private Optional parseSync(Node sync) { private Optional decodeSnapshot(Node snapshot) { return snapshot == null ? Optional.empty() : snapshot.contentAsBytes() .map(ExternalBlobReferenceSpec::decode) - .map(Medias::download) + .map(Medias::downloadAsync) .flatMap(CompletableFuture::join) .map(SnapshotSyncSpec::decode); } @@ -524,7 +524,7 @@ private SyncRecord decodePatches(Jid jid, PatchType name, List patche private MutationsRecord decodePatch(Jid jid, PatchType patchType, CompanionHashState newState, PatchSync patch) { if (patch.hasExternalMutations()) { - Medias.download(patch.externalMutations()) + Medias.downloadAsync(patch.externalMutations()) .join() .ifPresent(blob -> handleExternalMutation(patch, blob)); } diff --git a/src/main/java/it/auties/whatsapp/socket/MessageHandler.java b/src/main/java/it/auties/whatsapp/socket/MessageHandler.java index 4c609089..dbe1d9ca 100644 --- a/src/main/java/it/auties/whatsapp/socket/MessageHandler.java +++ b/src/main/java/it/auties/whatsapp/socket/MessageHandler.java @@ -22,7 +22,7 @@ import it.auties.whatsapp.model.media.MutableAttachmentProvider; import it.auties.whatsapp.model.message.button.*; import it.auties.whatsapp.model.message.model.*; -import it.auties.whatsapp.model.message.model.reserved.LocalMediaMessage; +import it.auties.whatsapp.model.message.model.reserved.ExtendedMediaMessage; import it.auties.whatsapp.model.message.payment.PaymentOrderMessage; import it.auties.whatsapp.model.message.server.DeviceSentMessage; import it.auties.whatsapp.model.message.server.ProtocolMessage; @@ -121,7 +121,7 @@ private CompletableFuture prepareOutgoingChatMessage(MessageInfo messageIn } return switch (messageInfo.message().content()) { - case LocalMediaMessage mediaMessage -> attributeMediaMessage(messageInfo.parentJid(), mediaMessage); + case ExtendedMediaMessage mediaMessage -> attributeMediaMessage(messageInfo.parentJid(), mediaMessage); case ButtonMessage buttonMessage -> attributeButtonMessage(messageInfo.parentJid(), buttonMessage); case TextMessage textMessage -> attributeTextMessage(textMessage); case PollCreationMessage pollCreationMessage when messageInfo instanceof ChatMessageInfo pollCreationInfo -> // I guess they will be supported some day in newsletters @@ -214,7 +214,7 @@ private LinkPreviewMedia compareDimensions(LinkPreviewMedia first, LinkPreviewMe return first.width() * first.height() > second.width() * second.height() ? first : second; } - private CompletableFuture attributeMediaMessage(Jid chatJid, LocalMediaMessage mediaMessage) { + private CompletableFuture attributeMediaMessage(Jid chatJid, ExtendedMediaMessage mediaMessage) { var media = mediaMessage.decodedMedia() .orElseThrow(() -> new IllegalArgumentException("Missing media to upload")); var attachmentType = getAttachmentType(chatJid, mediaMessage); @@ -223,7 +223,7 @@ private CompletableFuture attributeMediaMessage(Jid chatJid, LocalMediaMes .thenAccept(upload -> attributeMediaMessage(mediaMessage, upload)); } - private AttachmentType getAttachmentType(Jid chatJid, LocalMediaMessage mediaMessage) { + private AttachmentType getAttachmentType(Jid chatJid, ExtendedMediaMessage mediaMessage) { if (!chatJid.hasServer(JidServer.NEWSLETTER)) { return mediaMessage.attachmentType(); } @@ -240,8 +240,8 @@ private AttachmentType getAttachmentType(Jid chatJid, LocalMediaMessage media private MutableAttachmentProvider attributeMediaMessage(MutableAttachmentProvider mediaMessage, MediaFile upload) { - if (mediaMessage instanceof LocalMediaMessage localMediaMessage) { - localMediaMessage.setHandle(upload.handle()); + if (mediaMessage instanceof ExtendedMediaMessage extendedMediaMessage) { + extendedMediaMessage.setHandle(upload.handle()); } return mediaMessage.setMediaSha256(upload.fileSha256()) @@ -307,15 +307,15 @@ private CompletableFuture attributePollUpdateMessage(ChatMessageInfo info, private CompletableFuture attributeButtonMessage(Jid chatJid, ButtonMessage buttonMessage) { return switch (buttonMessage) { case ButtonsMessage buttonsMessage when buttonsMessage.header().isPresent() - && buttonsMessage.header().get() instanceof LocalMediaMessage mediaMessage -> + && buttonsMessage.header().get() instanceof ExtendedMediaMessage mediaMessage -> attributeMediaMessage(chatJid, mediaMessage); case TemplateMessage templateMessage when templateMessage.format().isPresent() -> { var templateFormatter = templateMessage.format().get(); yield switch (templateFormatter) { case HighlyStructuredFourRowTemplate highlyStructuredFourRowTemplate - when highlyStructuredFourRowTemplate.title().isPresent() && highlyStructuredFourRowTemplate.title().get() instanceof LocalMediaMessage fourRowMedia -> + when highlyStructuredFourRowTemplate.title().isPresent() && highlyStructuredFourRowTemplate.title().get() instanceof ExtendedMediaMessage fourRowMedia -> attributeMediaMessage(chatJid, fourRowMedia); - case HydratedFourRowTemplate hydratedFourRowTemplate when hydratedFourRowTemplate.title().isPresent() && hydratedFourRowTemplate.title().get() instanceof LocalMediaMessage hydratedFourRowMedia -> + case HydratedFourRowTemplate hydratedFourRowTemplate when hydratedFourRowTemplate.title().isPresent() && hydratedFourRowTemplate.title().get() instanceof ExtendedMediaMessage hydratedFourRowMedia -> attributeMediaMessage(chatJid, hydratedFourRowMedia); case null, default -> CompletableFuture.completedFuture(null); }; @@ -323,7 +323,7 @@ yield switch (templateFormatter) { case InteractiveMessage interactiveMessage when interactiveMessage.header().isPresent() && interactiveMessage.header().get().attachment().isPresent() - && interactiveMessage.header().get().attachment().get() instanceof LocalMediaMessage interactiveMedia -> + && interactiveMessage.header().get().attachment().get() instanceof ExtendedMediaMessage interactiveMedia -> attributeMediaMessage(chatJid, interactiveMedia); default -> CompletableFuture.completedFuture(null); }; @@ -354,11 +354,11 @@ private CompletableFuture encodeNewsletterMessage(MessageSendRequest.Newsl private String getPlainMessageHandle(MessageSendRequest.Newsletter request) { var message = request.info().message().content(); - if (!(message instanceof LocalMediaMessage localMediaMessage)) { + if (!(message instanceof ExtendedMediaMessage extendedMediaMessage)) { return null; } - return localMediaMessage.handle().orElse(null); + return extendedMediaMessage.handle().orElse(null); } private Node getPlainMessageNode(MessageContainer message) { @@ -1121,7 +1121,7 @@ private CompletableFuture downloadHistorySync(ProtocolMessage proto private CompletableFuture downloadHistorySyncNotification(HistorySyncNotification notification) { return notification.initialHistBootstrapInlinePayload() .map(result -> CompletableFuture.completedFuture(HistorySyncSpec.decode(BytesHelper.decompress(result)))) - .orElseGet(() -> Medias.download(notification) + .orElseGet(() -> Medias.downloadAsync(notification) .thenApplyAsync(entry -> entry.orElseThrow(() -> new NoSuchElementException("Cannot download history sync"))) .thenApplyAsync(result -> HistorySyncSpec.decode(BytesHelper.decompress(result)))); } diff --git a/src/main/java/it/auties/whatsapp/socket/SocketHandler.java b/src/main/java/it/auties/whatsapp/socket/SocketHandler.java index 2fba5e6d..0c9c1b9b 100644 --- a/src/main/java/it/auties/whatsapp/socket/SocketHandler.java +++ b/src/main/java/it/auties/whatsapp/socket/SocketHandler.java @@ -849,8 +849,12 @@ public void onUserPictureChanged(URI newPicture, URI oldPicture) { public void updateUserName(String newName, String oldName) { if (oldName != null && !Objects.equals(newName, oldName)) { + var wasOnline = store().online(); sendWithNoResponse(Node.of("presence", Map.of("name", oldName, "type", "unavailable"))); sendWithNoResponse(Node.of("presence", Map.of("name", newName, "type", "available"))); + if(!wasOnline) { + sendWithNoResponse(Node.of("presence", Map.of("name", oldName, "type", "unavailable"))); + } onUserNameChanged(newName, oldName); } var self = store.jid() diff --git a/src/main/java/it/auties/whatsapp/util/Medias.java b/src/main/java/it/auties/whatsapp/util/Medias.java index c44415b4..e0d0b7c6 100644 --- a/src/main/java/it/auties/whatsapp/util/Medias.java +++ b/src/main/java/it/auties/whatsapp/util/Medias.java @@ -72,22 +72,19 @@ public static byte[] getProfilePic(byte[] file) { } } - public static CompletableFuture downloadAsync(String imageUrl) { - return downloadAsync(URI.create(imageUrl)); - } - public static Optional download(URI imageUri) { - return downloadAsync(imageUri) - .thenApplyAsync(Optional::ofNullable) - .exceptionally(ignored -> Optional.empty()) - .join(); + try { + return Optional.ofNullable(downloadAsync(imageUri).join()); + }catch (Throwable throwable) { + return Optional.empty(); + } } public static CompletableFuture downloadAsync(URI imageUri) { return downloadAsync(imageUri, true); } - public static CompletableFuture downloadAsync(URI imageUri, boolean userAgent) { + private static CompletableFuture downloadAsync(URI imageUri, boolean userAgent) { try { if (imageUri == null) { return CompletableFuture.completedFuture(null); @@ -165,7 +162,7 @@ private static byte[] calculateMac(byte[] encryptedMedia, MediaKeys keys) { return Arrays.copyOf(hmac, 10); } - public static CompletableFuture> download(MutableAttachmentProvider provider) { + public static CompletableFuture> downloadAsync(MutableAttachmentProvider provider) { try { var url = provider.mediaUrl() .or(() -> provider.mediaDirectPath().map(Medias::createMediaUrl)) diff --git a/src/main/java/it/auties/whatsapp/util/Specification.java b/src/main/java/it/auties/whatsapp/util/Specification.java index 746910ef..ba34ec39 100644 --- a/src/main/java/it/auties/whatsapp/util/Specification.java +++ b/src/main/java/it/auties/whatsapp/util/Specification.java @@ -32,8 +32,8 @@ public final static class Whatsapp { public static final int MAX_COMPANIONS = 5; public static final int THUMBNAIL_WIDTH = 480; public static final int THUMBNAIL_HEIGHT = 339; - public static final String MOBILE_DOWNLOAD_URL = "https://www.whatsapp.com/android/current/WhatsApp.apk"; - public static final String MOBILE_BUSINESS_DOWNLOAD_URL = "https://d.apkpure.com/b/APK/com.whatsapp.w4b?version=latest"; + public static final URI MOBILE_DOWNLOAD_URL = URI.create("https://www.whatsapp.com/android/current/WhatsApp.apk"); + public static final URI MOBILE_BUSINESS_DOWNLOAD_URL = URI.create("https://d.apkpure.com/b/APK/com.whatsapp.w4b?version=latest"); public static final byte[] MOBILE_ANDROID_SALT = Base64.getDecoder().decode("PkTwKSZqUfAUyR0rPQ8hYJ0wNsQQ3dW1+3SCnyTXIfEAxxS75FwkDf47wNv/c8pP3p0GXKR6OOQmhyERwx74fw1RYSU10I4r1gyBVDbRJ40pidjM41G1I1oN"); public static final byte[] REGISTRATION_PUBLIC_KEY = HexFormat.of().parseHex("8e8c0f74c3ebc5d7a6865c6c3c843856b06121cce8ea774d22fb6f122512302d"); public static final String MOBILE_IOS_STATIC = "0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM";