From ae89116a4e97bd5e2f387ecd28672bd260ed8b6e Mon Sep 17 00:00:00 2001 From: Rahil khan <65817230+ErrorxCode@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:03:12 +0530 Subject: [PATCH] re-written --- EasyInsta/build.gradle | 6 +- .../java/com/xcoder/easyinsta/Instagram.java | 936 ++++++++++++------ .../main/java/com/xcoder/easyinsta/Task.java | 5 +- .../main/java/com/xcoder/easyinsta/Utils.java | 138 ++- .../exceptions/IGLoginException.java | 14 + .../exceptions/InstagramException.java | 14 + .../xcoder/easyinsta/exceptions/Reasons.java | 18 + build.gradle | 3 + 8 files changed, 806 insertions(+), 328 deletions(-) create mode 100644 EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/IGLoginException.java create mode 100644 EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/InstagramException.java create mode 100644 EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/Reasons.java diff --git a/EasyInsta/build.gradle b/EasyInsta/build.gradle index c8ab5db..09010b2 100644 --- a/EasyInsta/build.gradle +++ b/EasyInsta/build.gradle @@ -9,11 +9,9 @@ android { defaultConfig { minSdkVersion 24 targetSdkVersion 30 - versionCode 2 - versionName "2.0" + versionCode 25 + versionName "2.5" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles "consumer-rules.pro" } buildTypes { diff --git a/EasyInsta/src/main/java/com/xcoder/easyinsta/Instagram.java b/EasyInsta/src/main/java/com/xcoder/easyinsta/Instagram.java index 3ef9949..a9dcc92 100644 --- a/EasyInsta/src/main/java/com/xcoder/easyinsta/Instagram.java +++ b/EasyInsta/src/main/java/com/xcoder/easyinsta/Instagram.java @@ -1,28 +1,38 @@ package com.xcoder.easyinsta; import com.github.instagram4j.instagram4j.IGClient; -import com.github.instagram4j.instagram4j.models.user.Profile; +import com.github.instagram4j.instagram4j.models.direct.IGThread; +import com.github.instagram4j.instagram4j.models.direct.item.ThreadItem; +import com.github.instagram4j.instagram4j.models.direct.item.ThreadTextItem; import com.github.instagram4j.instagram4j.models.user.User; +import com.github.instagram4j.instagram4j.requests.direct.DirectCreateGroupThreadRequest; +import com.github.instagram4j.instagram4j.requests.direct.DirectInboxRequest; import com.github.instagram4j.instagram4j.requests.direct.DirectThreadsBroadcastRequest; -import com.github.instagram4j.instagram4j.requests.feed.FeedUserStoryRequest; +import com.github.instagram4j.instagram4j.requests.direct.DirectThreadsDeleteItemRequest; +import com.github.instagram4j.instagram4j.requests.direct.DirectThreadsMarkItemSeenRequest; import com.github.instagram4j.instagram4j.requests.friendships.FriendshipsActionRequest; import com.github.instagram4j.instagram4j.requests.friendships.FriendshipsPendingRequest; import com.github.instagram4j.instagram4j.responses.IGResponse; import com.github.instagram4j.instagram4j.responses.accounts.LoginResponse; -import com.github.instagram4j.instagram4j.responses.feed.FeedUserStoryResponse; import com.github.instagram4j.instagram4j.responses.feed.FeedUsersResponse; import com.github.instagram4j.instagram4j.responses.media.MediaResponse; import com.github.instagram4j.instagram4j.utils.IGChallengeUtils; +import com.github.instagram4j.instagram4j.utils.IGUtils; +import com.xcoder.easyinsta.exceptions.IGLoginException; +import com.xcoder.easyinsta.exceptions.InstagramException; +import com.xcoder.easyinsta.exceptions.Reasons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.net.InetSocketAddress; import java.net.Proxy; +import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; @@ -31,75 +41,72 @@ import java.util.function.Consumer; import java.util.function.Function; -import okhttp3.OkHttpClient; - /** * This is an easy implementation of instagram private api in java. This class include various methods to perform instagram operation like - * direct messages,adding stories,posting photos,scrapping profile data like posts,followers,followings etc. + * direct messages,adding stories,posting photos,scrapping profile data like posts,followers,followings etc. All the methods runs synchronously. + * * @author Rahil khan - * @version 1.0 + * @version 1.5 */ public class Instagram { private static IGClient client; - private Utils utils; - - - private Instagram(IGClient cachedClient){ - client = cachedClient; + private static Utils utils; + private static final int MESSAGE_ALL = 0; + private static final int FREQUENCY_ALL = 0; + private static final int FREQUENCY_FIRST = 1; + private static final int FREQUENCY_SECOND = 2; + private static final int FREQUENCY_THIRD = 3; + + private Instagram(IGClient client) { utils = new Utils(client); + Instagram.client = client; } - /** - * Loges in to your instagram account with the provided username and password. If your account has two-factor authentication, - * then use second constructor which takes a {@link Callable} as an argument. - * @param username Username of the account. - * @param password Password of the account. - */ - public Instagram(@NotNull String username, @NotNull String password) throws IGLoginException{ - this(username,password, (InetSocketAddress) null); - } /** * Loges in to your instagram account with the provided username and password. If your account has two-factor authentication, - * then use second constructor which takes a {@link Callable} as an argument. + * then use static {@code loginOrCache()} method which takes a {@link Callable} as an argument. + * * @param username Username of the account to log in. * @param password Password of the account associated with this username. - * @param proxy Proxy to use (only http), another constructor otherwise. + * @param proxy Proxy to use (only http), null otherwise. */ - public Instagram(@NotNull String username, @NotNull String password,InetSocketAddress proxy) throws IGLoginException { + public static Instagram login(@NotNull String username, @NotNull String password, @Nullable Proxy proxy) throws IGLoginException { try { IGClient.Builder builder = IGClient.builder(); builder.username(username).password(password); if (proxy != null) - builder.client(new OkHttpClient.Builder().proxy(new Proxy(Proxy.Type.HTTP,proxy)).build()); - client = builder.login(); + builder.client(IGUtils.defaultHttpClientBuilder().proxy(proxy).build()); utils = new Utils(client); + return new Instagram(builder.login()); } catch (com.github.instagram4j.instagram4j.exceptions.IGLoginException e) { if (e.getLoginResponse().getTwo_factor_info() != null) { throw new IGLoginException("This account requires 2-factor-authentication. Use second constructor for this type of login passing a callback as third argument.", Reasons.REQUIRE_2_FACTOR_AUTHENTICATION); } else if (e.getMessage().contains("few minutes")) throw new IGLoginException("Please wait for few minutes before trying again. Instagram blocks requests that are coming from same IP", Reasons.LOGIN_TOO_FREQUENTLY); else if (e.getMessage().contains("password")) - throw new IGLoginException("Username or password is incorrect",Reasons.INVALID_CREDENTIALS); + throw new IGLoginException("Username or password is incorrect", Reasons.INVALID_CREDENTIALS); else if (e.getMessage().contains("challenge")) - throw new IGLoginException("You account is temporary suspended by instagram. Open https://i.instagram.com/challenge to verify your account. Use loadInstance() method instead of using constructor every time to avoid this type of problem",Reasons.CHALLENGE_REQUIRED); + throw new IGLoginException("You account is temporary suspended by instagram. Open https://i.instagram.com/challenge to verify your account. Use loadInstance() method instead of using constructor every time to avoid this type of problem", Reasons.CHALLENGE_REQUIRED); else if (e.getMessage().contains("SocketException")) - throw new IGLoginException("There is a problem with your proxy. Try different proxy or else don't use it",Reasons.PROXY_ERROR); + throw new IGLoginException("There is a problem with your proxy. Try different proxy or else don't use it", Reasons.PROXY_ERROR); else - throw new IGLoginException("An unknown error occured. This must not happen in most of the case. If this problem persist, then please create a issue on github regarding this exception",Reasons.LOGIN_ERROR_UNKNOWN); + throw new IGLoginException("An unknown error occured. This must not happen in most of the case. If this problem persist, then please create a issue on github regarding this exception", Reasons.LOGIN_ERROR_UNKNOWN); } } /** + * Notice : Unimplemented ! * Loges in to your instagram account with the provided username and password and then authenticate using two-factor-authentication. + * * @param username Username of the account to log in. * @param password Password of the account associated with this username. - * @param callback The callback that will be invoked when verification code is sent. This will wait until you call {@link Instagram#verifyCode()}. You have to return the verification code. + * @param callback The callback that will be invoked when verification code is sent. This will wait until you call. You have to return the verification code. */ - public static Instagram login2factor(@NotNull String username, @NotNull String password, @NotNull Callable callback) { + private static Instagram login2factor(@NotNull String username, @NotNull String password, @NotNull Callable callback) throws IGLoginException { try { - client = IGClient.builder() + return new Instagram(IGClient.builder() .username(username) .password(password) .onTwoFactor(new IGClient.Builder.LoginHandler() { @@ -108,238 +115,482 @@ public LoginResponse accept(IGClient client, LoginResponse t) { return IGChallengeUtils.resolveTwoFactor(client, t, new Callable() { @Override public String call() throws Exception { - client.wait(5*1000*60); - return callback.call(); + // have to impliment + return null; } }); } - }).login(); - return new Instagram(client); + }).login()); } catch (com.github.instagram4j.instagram4j.exceptions.IGLoginException e) { + e.printStackTrace(); if (e.getMessage().contains("few minutes")) - throw new RuntimeException(new IGLoginException("Please wait for few minutes before trying again. Instagram blocks requests that are coming from same IP", Reasons.LOGIN_TOO_FREQUENTLY)); + throw new IGLoginException("Please wait for few minutes before trying again. Instagram blocks requests that are coming from same IP", Reasons.LOGIN_TOO_FREQUENTLY); else if (e.getMessage().contains("password")) - throw new RuntimeException(new IGLoginException("Username or password is incorrect",Reasons.INVALID_CREDENTIALS)); + throw new IGLoginException("Username or password is incorrect", Reasons.INVALID_CREDENTIALS); else if (e.getMessage().contains("challenge")) - throw new RuntimeException(new IGLoginException("You account is temporary suspended by instagram. Open https://i.instagram.com/challenge to verify your account. Use loadInstance() method instead of using constructor every time to avoid this type of problem",Reasons.CHALLENGE_REQUIRED)); + throw new IGLoginException("You account is temporary suspended by instagram. Open https://i.instagram.com/challenge to verify your account. Use loadInstance() method instead of using constructor every time to avoid this type of problem", Reasons.CHALLENGE_REQUIRED); else - throw new RuntimeException(new IGLoginException("An unknown error occured. This must not happen in most of the case. If this problem persist, then please create a issue on github regarding this exception",Reasons.LOGIN_ERROR_UNKNOWN)); + throw new IGLoginException("An unknown error occured. This must not happen in most of the case. If this problem persist, then please create a issue on github regarding this exception", Reasons.LOGIN_ERROR_UNKNOWN); } } - public static void verifyCode(){ - new Thread(new Runnable() { - @Override - public void run() { - client.notifyAll(); - } - }).start(); - } - - /** - * Serialize instagram object to a file. This will cache the current instagram object and writes it to a file. - * Using this, you can avoid logging in every time the program starts. - * @param directory The directory on the filesystem where the cache should be saved. - * @throws InstagramException - if the provided file is not a directory or is not writable. + * Returns pre-logged in instagram instance from the cache. If no cache exist, It first perform login & then cache it so it can be used in future. + * + * @param dir The cache directory of the application. See {@link android.content.Context#getCacheDir()} + * @param username Username of the account + * @param password Password of the account + * @return {@link Instagram} instance. + * @throws IGLoginException If the dir is not a directory or if an IO error occured while serializing/deserializing the class. */ - public void saveInstance(File directory) throws InstagramException { + public static Instagram loginOrCache(@NotNull File dir, @NotNull String username, @NotNull String password) throws IGLoginException, IOException { try { - if (directory.isDirectory()) - client.serialize(new File(directory,"object"),new File(directory,"cookie")); - else - throw new InstagramException("IOException : File is not a directory",Reasons.SERIALIZATION_ERROR); - } catch (IOException e) { - throw new InstagramException(e.getLocalizedMessage(),Reasons.SERIALIZATION_ERROR); - } - } - - public static Instagram loadInstance(File directory){ - try { - if (directory.isDirectory()) - return new Instagram(IGClient.deserialize(new File(directory,"object"),new File(directory,"cookie"))); - else - throw new InstagramException("IOException : File is not a directory",Reasons.DESERIALIZATION_ERROR); - } catch (ClassNotFoundException | IOException e) { - throw new InstagramException(e.getLocalizedMessage(),Reasons.DESERIALIZATION_ERROR); + File client = new File(dir, "ClientObject.cache"); + File cookie = new File(dir, "LoginSession.cache"); + if (client.exists() && cookie.exists()) + return new Instagram(IGClient.deserialize(client, cookie)); + else { + Instagram instagram = login(username, password, null); + Instagram.client.serialize(client, cookie); + return instagram; + } + } catch (ClassNotFoundException e) { + throw new InstagramException(e.getLocalizedMessage(), Reasons.CACHING_ERROR); } } - /** - * Sends a direct message to a user - * @param username The username of the user. - * @param message The text to send. - * @return A {@link Task} holding response of the request. + * Caches the current instagram session, Overwrite if already exist. There is no guarantee that it will always cache. It may fail sometimes (0.1% chance) + * + * @param dir The cache directory of the application. See {@link android.content.Context#getCacheDir()} */ - public Task directMessage(@NotNull String username, @NotNull String message) { + public void cache(@NotNull File dir) { + File client = new File(dir, "ClientObject.cache"); + File cookie = new File(dir, "LoginSession.cache"); try { - User user = client.actions().users().findByUsername(username).get().getUser(); - DirectThreadsBroadcastRequest.BroadcastTextPayload payload = new DirectThreadsBroadcastRequest.BroadcastTextPayload(message, user.getPk()); - return utils.request(new DirectThreadsBroadcastRequest(payload)); - } catch (ExecutionException | InterruptedException | CompletionException e) { - return new Task<>(e); + Instagram.client.serialize(client, cookie); + } catch (IOException e) { + e.printStackTrace(); } } - /** - * Sends a photo to the user. - * @param username The username of the user. - * @param photo The photo to send. - * @return A {@link Task} holding response of the request. + * Clears the instagram cache if exist. + * @param dir The directory where cache is stored. */ - public Task directMessage(@NotNull String username, @NotNull File photo) { - if (photo.getName().endsWith(".mp4")) - throw new InstagramException("Uploading or sending video is not currently supported",Reasons.UNSUPPORTED_FILE_FORMAT); - try { - User user = client.actions().users().findByUsername(username).get().getUser(); - DirectThreadsBroadcastRequest.BroadcastPayload payload = new DirectThreadsBroadcastRequest.BroadcastConfigurePhotoPayload(photo.getName(), user.getPk()); - return utils.request(new DirectThreadsBroadcastRequest(payload)); - } catch (ExecutionException | InterruptedException | CompletionException e) { - return new Task<>(e); - } + public void clearCache(@NotNull File dir){ + File client = new File(dir, "ClientObject.cache"); + File cookie = new File(dir, "LoginSession.cache"); + client.delete(); + cookie.delete(); } /** - * Follows the user. - * @param username Username of the user to follow. - * @return A {@link Task} holding response of the request. + * Gets the profile of the user. This profile include all the methods related to it. + * @param username Username of the user for getting her/his profile + * @return {@link Profile} of the user. */ - public Task follow(@NotNull String username) { - return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.CREATE); + public Profile getProfile(@NotNull String username){ + return new Profile(username); } - /** - * Unfollows the user. - * @param username Username of the user to unfollow. - * @return A {@link Task} holding response of the request. + * Gets your feeds. This feed include all the methods related to your feed. + * @return {@link Feed} your home feed */ - public Task unfollow(@NotNull String username) { - return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.DESTROY); + public Feed getFeed(){ + return new Feed(); } - /** - * Accept the pending follow request, if had any. - * @param username Username of the user who had requested. - * @return A {@link Task} holding response of the request. + * Gets yours direct inbox of This direct include all the methods related to direct messaging. + * @param username Username of the user in your inbox, whole you want to send message or read message. + * @return {@link Direct} Your direct inbox. */ - public Task accept(@NotNull String username) { - return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.APPROVE); + public Direct getDirect(@NotNull String username){ + return new Direct(username); } - /** - * Ignores the pending follow request, if had any. - * @param username Username of the user who had requested. - * @return A {@link Task} holding response of the request. + * Gets wrapper of all the common action of instagram. + * @return {@link Actions} */ - public Task ignore(@NotNull String username) { - return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.IGNORE); + public Actions actions(){ + return new Actions(); } + + + public interface OnProgressListener { + void onProgress(int percentage); + } + /** - * Remove the user from your followers. - * @param username Username of the user to remove. - * @return A {@link Task} holding response of the request. + * Interface for handling callbacks of spam messages. */ - public Task removeFollower(@NotNull String username) { - return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.REMOVE_FOLLOWER); + public interface OnMessageActionCallback { + void onSuccess(String message); + void onFailed(Exception exception); + void onProgress(int percentage); } + + + /** - * Post a new picture. - * @param photo The photo to post - * @param caption Caption for the post - * @return A {@link Task} holding response of the request. + * This class includes all the methods related to chat & messaging. */ - public Task postPhoto(@NotNull File photo, String caption) { - if (photo.getName().endsWith(".mp4")) - throw new InstagramException("Uploading or sending video is not currently supported",Reasons.UNSUPPORTED_FILE_FORMAT); + public static final class Direct { + private final String username; - Task task = new Task<>(); - CompletableFuture response = client.actions().timeline().uploadPhoto(photo, caption == null ? "Uploaded using EasyInsta library" : caption); - try { - response.thenAccept(new Consumer() { - @Override - public void accept(MediaResponse.MediaConfigureTimelineResponse response) { - task.value = response.getMessage(); + + private Direct(String username){ + this.username = username; + } + + + /** + * Sends a direct message to a user + * @param message The text to send. + * @return A {@link Task} indication success or failure of the method + */ + public Task directMessage(@NotNull String message) { + try { + User user = client.actions().users().findByUsername(username).get().getUser(); + DirectThreadsBroadcastRequest.BroadcastTextPayload payload = new DirectThreadsBroadcastRequest.BroadcastTextPayload(message, user.getPk()); + return utils.request(new DirectThreadsBroadcastRequest(payload)); + } catch (ExecutionException | InterruptedException | CompletionException e) { + return new Task<>(e); + } + } + + + /** + * Sends a photo to the user. + * @param photo The photo to send. + * @return A {@link Task} indication success or failure of the request + */ + public Task directMessage(@NotNull File photo) { + if (!photo.getName().endsWith(".jpg") || !photo.getName().endsWith(".png") || !photo.getName().endsWith("jpeg")) + throw new InstagramException("Unsupported file format. Only photos with jpg/png/jpeg extensions are allowed", Reasons.UNSUPPORTED_FILE_FORMAT); + try { + User user = client.actions().users().findByUsername(username).get().getUser(); + DirectThreadsBroadcastRequest.BroadcastPayload payload = new DirectThreadsBroadcastRequest.BroadcastConfigurePhotoPayload(photo.getName(), user.getPk()); + return utils.request(new DirectThreadsBroadcastRequest(payload)); + } catch (ExecutionException | InterruptedException | CompletionException e) { + return new Task<>(e); + } + } + + /** + * Marks message as seen that was sent by the username. + * @return A {@link Task} indication success or failure of the request + */ + @NotNull + public Task seeMessage() { + try { + User user = client.actions().users().findByUsername(username).get().getUser(); + return utils.request(new DirectThreadsMarkItemSeenRequest("340282366841710300949128131112046895852", "30300890545456593390597190992265216")); + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + return new Task<>(e); + } + } + + + /** + * Retrieve messages from a particular chat from last till number specified. + * @param howMany The number of messages to get. (including recipient chat). 0 for all + * @param listener A listener for tracking progress. only works when count > 20 + * @return A {@link Task} holding list of messages. + * @throws IllegalArgumentException if howMany is negative. + */ + private Task> getChatMessages(int howMany,@Nullable OnProgressListener listener){ + Task> task = new Task<>(); + try { + List items = utils.getThreadItem(username, howMany,false,listener); + List messages = new ArrayList<>(); + for (ThreadItem item : items){ + if (item instanceof ThreadTextItem) + messages.add(utils.isMessageSent(item) ? "You : " + ((ThreadTextItem) item).getText() : username + " : " + ((ThreadTextItem) item).getText()); + else + messages.add(utils.isMessageSent(item) ? "You : [\uD83C\uDFA5] ---[ Shared a post ] ---" : username + " : [\uD83C\uDFA5] ---[ Shared a post ] ---"); } - }).exceptionally(new Function() { - @Override - public Void apply(Throwable throwable) { - task.exception = throwable; - return null; + Collections.reverse(messages); + task.value = messages; + } catch (InterruptedException | ExecutionException e) { + task.exception = e; + } + return task; + } + + /** + * Retrieve messages from a particular chat from a particular message till last. + * @param fromMessage The message from where to start fetching messages. This is case-sensitive + * @param frequency If 'fromMessage' is occured multiple time, then pass the no. from where to consider. + * For example, To retrieve messages from 'hey' and if there are 3 more same messages (exact equal) like 'hay' + * then pass 1 to get from last 'hey' or 2 or 3 from the top second or first 'hey'. + * @return A {@link Task} holding list of messages. + * @throws IllegalArgumentException if frequency is negative. + */ + @NotNull + public Task> getChatMessagesFrom(@NotNull String fromMessage,int frequency){ + Task> task = new Task<>(); + try { + List messages = new ArrayList<>(); + List items = utils.getThreadItem(username, fromMessage,frequency,false,null); + for (ThreadItem item : items){ + if (item instanceof ThreadTextItem) + messages.add(utils.isMessageSent(item) ? "You : " + ((ThreadTextItem) item).getText() : username + " : " + ((ThreadTextItem) item).getText()); + else + messages.add(utils.isMessageSent(item) ? "You : [\uD83C\uDFA5] ---[ Shared a post ] ---" : username + " : [\uD83C\uDFA5] ---[ Shared a post ] ---"); } - }).join(); + Collections.reverse(messages); + task.value = messages; + } catch (InterruptedException | ExecutionException | IllegalArgumentException e) { + task.exception = e; + } return task; - } catch (CompletionException e){ - return new Task<>(e); } - } - /** - * Currently not working. (Unimplemented) - * @param pic The photo to replace - */ - private void setDp(@NotNull File pic) { - throw new UnsupportedOperationException("Don't try to be over smart"); - } + /** + * Broadcast a text message in a direct chat group. + * @param message The message to broadcast. + * @param adminUsername The username of any one admin of the group. If the same user is admin of 2 or more group then the top first + * group will be selected. + * @return A {@link Task} indication success or failure of the request + */ + @NotNull + public Task groupMessage(@NotNull String message,@NotNull String adminUsername){ + try { + List threads = client.sendRequest(new DirectInboxRequest()).get().getInbox().getThreads(); + Long pk = client.actions().users().findByUsername(adminUsername).get().getUser().getPk(); + for (IGThread thread : threads){ + if (thread.is_group() && thread.getAdmin_user_ids().contains(String.valueOf(pk))) { + DirectThreadsBroadcastRequest request = new DirectThreadsBroadcastRequest(new DirectThreadsBroadcastRequest.BroadcastTextPayload(message,thread.getThread_id())); + return utils.request(request); + } + } + return new Task<>(new InstagramException(adminUsername + " is not admin of any group in your inbox",Reasons.NO_SUCH_ADMIN)); + } catch (ExecutionException | InterruptedException e) { + return new Task<>(e); + } + } - /** - * Sets the bio of your profile - * @param bio The bio to set. - * @return A {@link Task} holding response of the request. - */ - public Task setBio(@NotNull String bio) { - if (bio.length() > 150) - throw new InstagramException("Bio must be of less then 150 characters", Reasons.BIO_LENGTH_EXCEEDED); - - Task task = new Task<>(); - CompletableFuture response = client.actions().account().setBio(bio); - try{ - response.thenAccept(new Consumer() { - @Override - public void accept(IGResponse response) { - task.value = response.getMessage(); - } - }).exceptionally(new Function() { - @Override - public Void apply(Throwable throwable) { - task.exception = throwable; - return null; + /** + * Unimplemented ! + * @param groupName The title of the group + * @param usernames The usernames of the members to add in the group. + * @return A {@link Task} indication success or failure of the request + */ + @NotNull + private Task createGroup(@NotNull String groupName,@NotNull String... usernames){ + String[] pks = new String[usernames.length]; + try { + for (int i = 0; i < pks.length; i++) { + pks[i] = String.valueOf(client.actions().users().findByUsername(usernames[i]).get().getUser().getPk()); } - }).join(); - return task; - } catch (CancellationException e){ - return new Task<>(e); + DirectCreateGroupThreadRequest request = new DirectCreateGroupThreadRequest(groupName,pks); + return utils.request(request); + } catch (ExecutionException | InterruptedException e) { + return new Task<>(new InstagramException("One of the username is not valid.",Reasons.INVALID_USERNAME)); + } + } + + + /** + * Send mass messages to a user at a single time (also called spamming) + * @param count The no. of message to sent + * @param messages list of String containing messages to sent. a random message picked will be sent from this list. + * @param callback Callback indication success and failure of each message. + */ + public void spamDM(int count,@NotNull String[] messages,@Nullable OnMessageActionCallback callback){ + for (int i = 0; i < count; i++) { + String message = messages[new Random().nextInt(messages.length)]; + directMessage(message).addOnCompleteListener(new Task.OnCompletionListener() { + @Override + public void onComplete(Task task) { + if (callback != null){ + if (task.isSuccessful()) + callback.onSuccess(message); + else + callback.onFailed((Exception) task.getException()); + } + } + }); + } + } + + + /** + * Send mass messages to a group at a single time (also called spamming) + * @param count The no. of message to sent + * @param adminUsername Username of admin of the group. If this user is also admin of another group, then the Top first group in your inbox will be considered. + * @param messages list of String containing messages to sent. a random message picked will be sent from this list. + * @param callback Callback indication success and failure of each message. + */ + public void spamGroup(int count,@NotNull String adminUsername,@NotNull String[] messages,@Nullable OnMessageActionCallback callback){ + for (int i = 0; i < count; i++) { + String message = messages[new Random().nextInt(messages.length)]; + groupMessage(message,adminUsername).addOnCompleteListener(new Task.OnCompletionListener() { + @Override + public void onComplete(Task task) { + if (callback != null){ + if (task.isSuccessful()) + callback.onSuccess(message); + else + callback.onFailed((Exception) task.getException()); + } + } + }); + } + } + + /** + * Deletes the messages from the last till the particular number. + * @param howMany The no. of messages (including recipient message) to delete. For example, + * if there are last 2 message from him/her and then 3 messages from you, + * so you have to pass 5 here to delete your 3 messages. Pass 0 to delete all. + * @param callback The callback indication success or failure of each delete message request. + *@throws IllegalArgumentException if howMany is negative. + */ + public void deleteMessages(int howMany,@Nullable OnMessageActionCallback callback){ + try { + for (ThreadItem item : utils.getThreadItem(username, howMany,true,null)) + utils.request(new DirectThreadsDeleteItemRequest(utils.getThread(username).getThread_id(),item.getItem_id())).addOnCompleteListener(new Task.OnCompletionListener() { + @Override + public void onComplete(Task task) { + if (callback != null){ + if (task.isSuccessful()){ + if (item.getItem_type().equals("text")) + callback.onSuccess("\"" + ((ThreadTextItem) item).getText() + "\""); + else + callback.onSuccess("[!] A shared post"); + } else { + callback.onFailed((Exception) task.getException()); + } + } + } + }); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + + + + public void deleteMessagesFrom(@NotNull String fromMessage,int frequency,@Nullable OnMessageActionCallback callback){ + try { + for (ThreadItem item : utils.getThreadItem(username,fromMessage,frequency,true,null)) + utils.request(new DirectThreadsDeleteItemRequest(utils.getThread(username).getThread_id(),item.getItem_id())).addOnCompleteListener(new Task.OnCompletionListener() { + @Override + public void onComplete(Task task) { + if (callback != null){ + if (task.isSuccessful()){ + if (item.getItem_type().equals("text")) + callback.onSuccess("\"" + ((ThreadTextItem) item).getText() + "\""); + else + callback.onSuccess("[!] A shared post"); + } else { + callback.onFailed((Exception) task.getException()); + } + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } } } + + /** - * Adds a photo to your story. - * @param photo The photo to add as story. - * @return A {@link Task} holding response of the request. + * This class includes all the methods related to profile of the user. */ - public Task addStory(@NotNull File photo) { - if (photo.getName().endsWith(".mp4")) - throw new InstagramException("Uploading or sending video is not currently supported",Reasons.UNSUPPORTED_FILE_FORMAT); + public static final class Profile { + private final String username; - Task task = new Task<>(); - CompletableFuture response = client.actions().story().uploadPhoto(photo); - try { - response.thenAccept(new Consumer() { + private Profile(String username){ + this.username = username; + } + + + /** + * Currently not working. (Unimplemented) + * + * @param pic The photo to replace + */ + private void setDp(@NotNull File pic) { + throw new UnsupportedOperationException("Don't try to be over smart"); + } + + + /** + * Sets the bio of your profile + * + * @param bio The bio to set. + * @return A {@link Task} indication success or failure of the request + */ + public Task setBio(@NotNull String bio) { + if (bio.length() > 150) + throw new InstagramException("Bio must be of less then 150 characters", Reasons.BIO_LENGTH_EXCEEDED); + + Task task = new Task<>(); + try { + client.actions().account().setBio(bio).exceptionally(new Function() { + @Override + public IGResponse apply(Throwable throwable) { + task.exception = throwable; + return null; + } + }).join(); + return task; + } catch (CancellationException e) { + return new Task<>(e); + } + } + + + /** + * Scraps 100 followers of the account associated with the username. Empty list if none found but Never null. + * @return A {@link Task} holding list of the followers. + */ + public @NotNull Task> getFollowers() { + return utils.getFeeds(client.actions().users().findByUsername(username), true); + } + + + /** + * Scraps 100 followings of the account associated with the provided username. Empty list if none found but Never null. + * @return A {@link Task} holding list of the followings. + */ + public @NotNull Task> getFollowings() { + return utils.getFeeds(client.actions().users().findByUsername(username), false); + } + + + /** + * Gets the pending follow requests of yours. + * @return A {@link Task} holding usernames of the requests. + */ + public @NotNull Task> getFollowRequests() { + List usernames = new ArrayList<>(); + Task> task = new Task<>(); + CompletableFuture response = client.sendRequest(new FriendshipsPendingRequest()); + response.thenAccept(new Consumer() { @Override - public void accept(MediaResponse.MediaConfigureToStoryResponse response) { - task.value = response.getMessage(); + public void accept(FeedUsersResponse feedUsersResponse) { + for (com.github.instagram4j.instagram4j.models.user.Profile user : feedUsersResponse.getUsers()) { + usernames.add(user.getUsername()); + } + task.value = usernames; } }).exceptionally(new Function() { @Override @@ -349,146 +600,223 @@ public Void apply(Throwable throwable) { } }).join(); return task; - } catch (CancellationException e){ - return new Task<>(e); } - } - /** - * Scraps followers of the account associated with the username. Empty list if none found but Never null. - * @param username The username of the account from which you want to scrap. - * @return A {@link Task} holding list of the followers. - */ - public @NotNull Task> getFollowers(@NotNull String username) { - return utils.getFeeds(client.actions().users().findByUsername(username),true); - } + /** + * Gets the bio of the account associated with the provided username. + * @return A {@link Task} holding bio of the user. + */ + public @NotNull Task getBio() { + Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username), "bio"); + Task task = new Task<>(); + if (object instanceof Throwable) + task.exception = (Throwable) object; + else + task.value = (String) object; - /** - * Scraps followings of the account associated with the provided username. Empty list if none found but Never null. - * @param username The username of the account from which you want to scrap. - * @return A {@link Task} holding list of the followings. - */ - public @NotNull Task> getFollowings(@NotNull String username) { - return utils.getFeeds(client.actions().users().findByUsername(username),false); - } + return task; + } - /** - * Gets the pending follow requests. Empty list if none found but Never null. - * @return A {@link Task} holding usernames of the requests. - */ - public @NotNull Task> getFollowRequests() { - List usernames = new ArrayList<>(); - Task> task = new Task<>(); - CompletableFuture response = client.sendRequest(new FriendshipsPendingRequest()); - response.thenAccept(new Consumer() { - @Override - public void accept(FeedUsersResponse feedUsersResponse) { - for (Profile user : feedUsersResponse.getUsers()) { - usernames.add(user.getUsername()); - } - task.value = usernames; - } - }).exceptionally(new Function() { - @Override - public Void apply(Throwable throwable) { - task.exception = throwable; - return null; - } - }).join(); - return task; - } + /** + * Gets the profile photo link of the account associated with the username provided. + * @return A {@link Task} holding url of profile picture of the user. + */ + public @NotNull Task getProfilePicUrl() { + Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username), "dp"); + Task task = new Task<>(); + if (object instanceof Throwable) + task.exception = (Throwable) object; + else + task.value = (String) object; - /** - * Gets the bio of the account associated with the username. - * @param username The username of the account. - * @return A {@link Task} holding bio of the user. - */ - public Task getBio(@NotNull String username) { - Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username),"bio"); - Task task = new Task<>(); + return task; + } - if (object instanceof Throwable) - task.exception = (Throwable) object; - else - task.value = (String) object; - return task; - } + /** + * Gets the follower count of the account associated with the username. + * @return A {@link Task} holding number of followers of the user. + */ + @NotNull + public Task getFollowersCount() { + Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username), "followers"); + Task task = new Task<>(); + if (object instanceof Throwable) + task.exception = (Throwable) object; + else + task.value = (int) object; - /** - * Gets the profile photo link of the account associated with the username provided. - * @param username The username of the account. - * @return A {@link Task} holding profile picture of the user. - */ - public Task getProfilePicUrl(@NotNull String username) { - Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username),"dp"); - Task task = new Task<>(); + return task; + } + + + /** + * Gets the followings count of the account associated with the username provided. + * @return A {@link Task} holding number of followings of the user. + */ + @NotNull + public Task getFollowingsCount() { + Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username), "followings"); + Task task = new Task<>(); - if (object instanceof Throwable) - task.exception = (Throwable) object; - else - task.value = (String) object; + if (object instanceof Throwable) + task.exception = (Throwable) object; + else + task.value = (int) object; + + return task; + } + + + /** + * Gets the post count of the account associated with the username provided. + * @return A {@link Task} holding number of posts of the user. + */ + @NotNull + public Task getPostCount() { + Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username), "post"); + Task task = new Task<>(); + + if (object instanceof Throwable) + task.exception = (Throwable) object; + else + task.value = (int) object; - return task; + return task; + } } + + + /** - * Gets the follower count of the account associated with the username. - * @param username The username of the account. - * @return A {@link Task} holding number of followers of the user. + * This class includes all the methods related to your feed. */ - public Task getFollowersCount(@NotNull String username) { - Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username),"followers"); - Task task = new Task<>(); + public static final class Feed { + /** + * Post a new picture. + * + * @param photo The photo to post + * @param caption Caption for the post + * @return A {@link Task} indication success or failure of the request + */ + public Task postPhoto(@NotNull File photo, String caption) { + if (photo.getName().endsWith(".mp4")) + throw new InstagramException("Uploading or sending video is not currently supported", Reasons.UNSUPPORTED_FILE_FORMAT); + + Task task = new Task<>(); + try { + client.actions().timeline().uploadPhoto(photo, caption == null ? "Uploaded using EasyInsta library" : caption) + .exceptionally(new Function() { + @Override + public MediaResponse.MediaConfigureTimelineResponse apply(Throwable throwable) { + task.exception = throwable; + return null; + } + }).join(); + return task; + } catch (CompletionException e) { + return new Task<>(e); + } + } + - if (object instanceof Throwable) - task.exception = (Throwable) object; - else - task.value = (int) object; + /** + * Adds a photo to your story. + * + * @param photo The photo to add as story. + * @return A {@link Task} indication success or failure of the request + */ + public Task addStory(@NotNull File photo) { + if (photo.getName().endsWith(".mp4")) + throw new InstagramException("Uploading or sending video is not currently supported", Reasons.UNSUPPORTED_FILE_FORMAT); + + Task task = new Task<>(); + try { + client.actions().story().uploadPhoto(photo).exceptionally(new Function() { + @Override + public MediaResponse.MediaConfigureToStoryResponse apply(Throwable throwable) { + task.exception = throwable; + return null; + } + }).join(); + return task; + } catch (CancellationException e) { + return new Task<>(e); + } + } - return task; } /** - * Gets the followings count of the account associated with the username provided. - * @param username The username of the account. - * @return A {@link Task} holding number of followings of the user. + * This class includes all common action of your instagram, like following someone,accepting follow request,removing followers etc. */ - public Task getFollowingsCount(@NotNull String username) { - Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username),"followings"); - Task task = new Task<>(); + public static final class Actions { - if (object instanceof Throwable) - task.exception = (Throwable) object; - else - task.value = (int) object; + private Actions(){}; - return task; - } + /** + * Follows the user. + * @param username Username of the user to follow. + * @return A {@link Task} indication success or failure of the request + */ + public Task follow(@NotNull String username) { + return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.CREATE); + } - /** - * Gets the post count of the account associated with the username provided. - * @param username The username of the account. + /** + * Unfollows the user. + * + * @param username Username of the user to unfollow. + * @return A {@link Task} indication success or failure of the request + */ + public Task unfollow(@NotNull String username) { + return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.DESTROY); + } + + + /** + * Accept the pending follow request, if had any. + * + * @param username Username of the user who had requested. + * @return A {@link Task} indication success or failure of the request + */ + public Task accept(@NotNull String username) { + return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.APPROVE); + } - * @return A {@link Task} holding number of posts of the user. - */ - public Task getPostCount(@NotNull String username) { - Object object = utils.getProfileMetadata(client.actions().users().findByUsername(username),"post"); - Task task = new Task<>(); - if (object instanceof Throwable) - task.exception = (Throwable) object; - else - task.value = (int) object; + /** + * Ignores the pending follow request, if had any. + * + * @param username Username of the user who had requested. + * @return A {@link Task} indication success or failure of the request + */ + public Task ignore(@NotNull String username) { + return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.IGNORE); + } + + + /** + * Remove the user from your followers. + * + * @param username Username of the user to remove. + * @return A {@link Task} indication success or failure of the request + */ + public Task removeFollower(@NotNull String username) { + return utils.followAction(username, FriendshipsActionRequest.FriendshipsAction.REMOVE_FOLLOWER); + } + } - return task; + public static void main(String[] args) throws IGLoginException, IOException { + Instagram instagram = Instagram.loginOrCache(new File("C:\\Users\\Asus\\Desktop"),"",""); } -} +} \ No newline at end of file diff --git a/EasyInsta/src/main/java/com/xcoder/easyinsta/Task.java b/EasyInsta/src/main/java/com/xcoder/easyinsta/Task.java index 4454d67..7565373 100644 --- a/EasyInsta/src/main/java/com/xcoder/easyinsta/Task.java +++ b/EasyInsta/src/main/java/com/xcoder/easyinsta/Task.java @@ -1,10 +1,12 @@ package com.xcoder.easyinsta; +import org.jetbrains.annotations.NotNull; + public final class Task { protected T value; protected Throwable exception; - protected Task(Exception e) { + public Task(Exception e) { exception = e; } @@ -28,6 +30,7 @@ public void addOnCompleteListener(OnCompletionListener callback) { callback.onComplete(this); } + @NotNull public T getValue() { return value; } diff --git a/EasyInsta/src/main/java/com/xcoder/easyinsta/Utils.java b/EasyInsta/src/main/java/com/xcoder/easyinsta/Utils.java index 1b3382d..3f40aae 100644 --- a/EasyInsta/src/main/java/com/xcoder/easyinsta/Utils.java +++ b/EasyInsta/src/main/java/com/xcoder/easyinsta/Utils.java @@ -2,41 +2,58 @@ import com.github.instagram4j.instagram4j.IGClient; import com.github.instagram4j.instagram4j.actions.users.UserAction; +import com.github.instagram4j.instagram4j.models.direct.IGThread; +import com.github.instagram4j.instagram4j.models.direct.item.ThreadItem; +import com.github.instagram4j.instagram4j.models.direct.item.ThreadTextItem; +import com.github.instagram4j.instagram4j.models.media.timeline.TimelineMedia; import com.github.instagram4j.instagram4j.models.user.Profile; import com.github.instagram4j.instagram4j.models.user.User; import com.github.instagram4j.instagram4j.requests.IGRequest; +import com.github.instagram4j.instagram4j.requests.direct.DirectInboxRequest; +import com.github.instagram4j.instagram4j.requests.direct.DirectThreadsRequest; +import com.github.instagram4j.instagram4j.requests.feed.FeedTimelineRequest; import com.github.instagram4j.instagram4j.requests.friendships.FriendshipsActionRequest; +import com.github.instagram4j.instagram4j.requests.media.MediaInfoRequest; import com.github.instagram4j.instagram4j.responses.IGResponse; +import com.github.instagram4j.instagram4j.responses.feed.FeedTimelineResponse; import com.github.instagram4j.instagram4j.responses.feed.FeedUsersResponse; +import com.xcoder.easyinsta.exceptions.InstagramException; +import com.xcoder.easyinsta.exceptions.Reasons; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; class Utils { private static IGClient client; private Object meta; - protected Utils(IGClient client){ + + + protected Utils(IGClient client) { Utils.client = client; } - protected Task request(IGRequest request) throws CompletionException { - Task task = new Task<>(); - CompletableFuture response = client.sendRequest(request); - response.thenAccept(new Consumer() { + public Task request(IGRequest request) throws CompletionException { + Task task = new Task<>(); + client.sendRequest(request).exceptionally(new Function() { @Override - public void accept(IGResponse igResponse) { - task.value = igResponse.getMessage(); - } - }).exceptionally(new Function() { - @Override - public Void apply(Throwable throwable) { + public T apply(Throwable throwable) { task.exception = throwable; return null; } @@ -45,7 +62,7 @@ public Void apply(Throwable throwable) { } - protected byte[] readFile(File file) throws IOException { + byte[] readFile(File file) throws IOException { FileInputStream in = new FileInputStream(file); byte[] bytes = new byte[in.available()]; in.read(bytes); @@ -53,17 +70,17 @@ protected byte[] readFile(File file) throws IOException { } - protected Task followAction(String username, FriendshipsActionRequest.FriendshipsAction action){ + protected Task followAction(String username, FriendshipsActionRequest.FriendshipsAction action) { try { User user = client.actions().users().findByUsername(username).get().getUser(); - return request(new FriendshipsActionRequest(user.getPk(),action)); + return request(new FriendshipsActionRequest(user.getPk(), action)); } catch (ExecutionException | InterruptedException e) { return new Task<>(e); } } - protected Object getProfileMetadata(CompletableFuture response, String what){ + protected Object getProfileMetadata(CompletableFuture response, String what) { try { response.thenAccept(new Consumer() { @Override @@ -81,8 +98,9 @@ public void accept(UserAction userAction) { case "followings": meta = userAction.getUser().getFollowing_count(); break; - default: + case "posts": meta = userAction.getUser().getMedia_count(); + break; } } }).exceptionally(new Function() { @@ -93,12 +111,13 @@ public Void apply(Throwable throwable) { } }).join(); return meta; - } catch (CompletionException e){ + } catch (CompletionException e) { return e; } } - protected Task> getFeeds(CompletableFuture response,boolean isFollowersFeed){ + + protected Task> getFeeds(CompletableFuture response, boolean isFollowersFeed) { Task> task = new Task<>(); List list = new ArrayList<>(); try { @@ -120,8 +139,89 @@ public Void apply(Throwable throwable) { } }).join(); return task; - } catch (CompletionException e){ + } catch (CompletionException e) { return new Task<>(e); } } + + @NotNull + protected IGThread getThread(String username) throws ExecutionException, InterruptedException { + List threads = client.sendRequest(new DirectInboxRequest()).get().getInbox().getThreads(); + for (IGThread thread : threads) + for (Profile user : thread.getUsers()) { + if (user.getUsername().equals(username)) { + return thread; + } + } + throw new InstagramException("There is no user with username " + username, Reasons.INVALID_USERNAME); + } + + + protected List getThreadItem(String username, int count, boolean onlySent, @Nullable Instagram.OnProgressListener listener) throws ExecutionException, InterruptedException { + List list = new ArrayList<>(); + IGThread thread = getThread(username); + String cursor = thread.getOldest_cursor(); + list.add(thread.getItems().get(0)); + if (count > 20) { + int loop = (count/20) + (count%20 == 0 ? 0 : 1); + for (int i = 0; i < loop; i++){ + thread = client.sendRequest(new DirectThreadsRequest(thread.getThread_id(), cursor)).get().getThread(); + list.addAll(thread.getItems()); + cursor = thread.getOldest_cursor(); + if (listener != null) + listener.onProgress((i + 1)*100/loop); + if (cursor == null) + break; + } + } else if (count == 0) { + while (cursor != null) { + thread = client.sendRequest(new DirectThreadsRequest(thread.getThread_id(), cursor)).get().getThread(); + list.addAll(thread.getItems()); + cursor = thread.getOldest_cursor(); + } + } else { + while (list.size() < count) { + thread = client.sendRequest(new DirectThreadsRequest(thread.getThread_id(), cursor)).get().getThread(); + list.addAll(thread.getItems()); + cursor = thread.getOldest_cursor(); + if (cursor == null) + break; + } + } + list.removeIf(threadItem -> onlySent && !isMessageSent(threadItem)); + return list.stream().limit(count == 0 ? list.size() : count).collect(Collectors.toList()); + } + + + protected List getThreadItem(String username, String from, int frequency, boolean onlySent, @Nullable Instagram.OnProgressListener listener) throws IllegalArgumentException, ExecutionException, InterruptedException { + List items = getThreadItem(username, 0, onlySent,listener); + List messages = items + .stream() + .map(threadItem -> threadItem instanceof ThreadTextItem ? ((ThreadTextItem) threadItem).getText() : null) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + + if (frequency == 0){ + frequency = Collections.frequency(messages,from); + } else if (frequency < 0) + throw new IllegalArgumentException("Frequency can't be negative"); + + List threadItems = new ArrayList<>(); + for (ThreadItem item : items) { + threadItems.add(item); + if (item instanceof ThreadTextItem && ((ThreadTextItem) item).getText().equals(from)){ + if (frequency == 1) + return threadItems; + else + frequency--; + } + } + throw new IllegalArgumentException("There is no such message '" + from + "' in the chat"); + } + + + protected boolean isMessageSent(ThreadItem item) { + return client.getSelfProfile().getPk() == item.getUser_id(); + } } diff --git a/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/IGLoginException.java b/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/IGLoginException.java new file mode 100644 index 0000000..92270a2 --- /dev/null +++ b/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/IGLoginException.java @@ -0,0 +1,14 @@ +package com.xcoder.easyinsta.exceptions; + +public class IGLoginException extends Exception { + private final Reasons reason; + + public IGLoginException(String message, Reasons reason) { + super(message); + this.reason = reason; + } + + public Reasons getReason() { + return reason; + } +} diff --git a/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/InstagramException.java b/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/InstagramException.java new file mode 100644 index 0000000..5beffaa --- /dev/null +++ b/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/InstagramException.java @@ -0,0 +1,14 @@ +package com.xcoder.easyinsta.exceptions; + +public class InstagramException extends RuntimeException { + private final Reasons reason; + + public InstagramException(String message, Reasons reason) { + super(message); + this.reason = reason; + } + + public Reasons getReason() { + return reason; + } +} diff --git a/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/Reasons.java b/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/Reasons.java new file mode 100644 index 0000000..0befa50 --- /dev/null +++ b/EasyInsta/src/main/java/com/xcoder/easyinsta/exceptions/Reasons.java @@ -0,0 +1,18 @@ +package com.xcoder.easyinsta.exceptions; + +public enum Reasons { + REQUIRE_2_FACTOR_AUTHENTICATION, + LOGIN_ERROR_UNKNOWN, + BIO_LENGTH_EXCEEDED, + UNSUPPORTED_FILE_FORMAT, + INVALID_CREDENTIALS, + CHALLENGE_REQUIRED, + CACHING_ERROR, + PROXY_ERROR, + NO_SUCH_ADMIN, + INVALID_USERNAME, + LOGIN_TOO_FREQUENTLY, + API_RESPONSE_ERROR, + NO_SUCH_MESSAGE + +} diff --git a/build.gradle b/build.gradle index 9730203..6fded54 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,12 @@ buildscript { repositories { google() mavenCentral() + gradlePluginPortal() } dependencies { + classpath 'com.google.gms:google-services:4.3.10' classpath 'com.android.tools.build:gradle:4.2.2' + classpath 'gradle.plugin.com.onesignal:onesignal-gradle-plugin:0.14.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }