Browse Source
Add Kotlin and convert some model classes to kotlin
renovate/org.robolectric-robolectric-4.x
Add Kotlin and convert some model classes to kotlin
renovate/org.robolectric-robolectric-4.x
54 changed files with 589 additions and 1297 deletions
-
1app/build.gradle
-
2app/src/main/java/awais/instagrabber/activities/MainActivity.java
-
9app/src/main/java/awais/instagrabber/adapters/FeedStoriesAdapter.java
-
2app/src/main/java/awais/instagrabber/adapters/FeedStoriesListAdapter.java
-
6app/src/main/java/awais/instagrabber/adapters/viewholder/FilterViewHolder.java
-
8app/src/main/java/awais/instagrabber/customviews/Tooltip.java
-
6app/src/main/java/awais/instagrabber/customviews/emoji/EmojiGridAdapter.java
-
4app/src/main/java/awais/instagrabber/customviews/emoji/EmojiVariantManager.java
-
2app/src/main/java/awais/instagrabber/customviews/emoji/EmojiVariantPopup.java
-
3app/src/main/java/awais/instagrabber/customviews/emoji/ReactionsManager.java
-
26app/src/main/java/awais/instagrabber/db/repositories/AccountRepository.java
-
26app/src/main/java/awais/instagrabber/db/repositories/DMLastNotifiedRepository.java
-
18app/src/main/java/awais/instagrabber/db/repositories/FavoriteRepository.java
-
22app/src/main/java/awais/instagrabber/db/repositories/RecentSearchRepository.java
-
2app/src/main/java/awais/instagrabber/dialogs/AccountSwitcherDialogFragment.java
-
8app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java
-
10app/src/main/java/awais/instagrabber/fragments/imageedit/FiltersFragment.java
-
2app/src/main/java/awais/instagrabber/fragments/imageedit/ImageEditFragment.java
-
7app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java
-
117app/src/main/java/awais/instagrabber/models/Comment.java
-
69app/src/main/java/awais/instagrabber/models/Comment.kt
-
78app/src/main/java/awais/instagrabber/models/FeedStoryModel.java
-
20app/src/main/java/awais/instagrabber/models/FeedStoryModel.kt
-
68app/src/main/java/awais/instagrabber/models/FollowModel.java
-
49app/src/main/java/awais/instagrabber/models/FollowModel.kt
-
52app/src/main/java/awais/instagrabber/models/HighlightModel.java
-
15app/src/main/java/awais/instagrabber/models/HighlightModel.kt
-
21app/src/main/java/awais/instagrabber/models/IntentModel.java
-
5app/src/main/java/awais/instagrabber/models/IntentModel.kt
-
64app/src/main/java/awais/instagrabber/models/Resource.java
-
36app/src/main/java/awais/instagrabber/models/Resource.kt
-
66app/src/main/java/awais/instagrabber/models/SavedImageEditState.java
-
13app/src/main/java/awais/instagrabber/models/SavedImageEditState.kt
-
110app/src/main/java/awais/instagrabber/models/Tab.java
-
36app/src/main/java/awais/instagrabber/models/Tab.kt
-
97app/src/main/java/awais/instagrabber/models/UploadPhotoOptions.java
-
9app/src/main/java/awais/instagrabber/models/UploadPhotoOptions.kt
-
217app/src/main/java/awais/instagrabber/models/UploadVideoOptions.java
-
22app/src/main/java/awais/instagrabber/models/UploadVideoOptions.kt
-
106app/src/main/java/awais/instagrabber/utils/AppExecutors.java
-
52app/src/main/java/awais/instagrabber/utils/AppExecutors.kt
-
14app/src/main/java/awais/instagrabber/utils/BitmapUtils.java
-
20app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
-
4app/src/main/java/awais/instagrabber/utils/FlavorTown.java
-
6app/src/main/java/awais/instagrabber/utils/MediaController.java
-
173app/src/main/java/awais/instagrabber/utils/MediaUploadHelper.java
-
154app/src/main/java/awais/instagrabber/utils/MediaUploadHelper.kt
-
10app/src/main/java/awais/instagrabber/utils/MediaUploader.java
-
4app/src/main/java/awais/instagrabber/utils/MediaUtils.java
-
2app/src/main/java/awais/instagrabber/utils/UpdateCheckCommon.java
-
2app/src/main/java/awais/instagrabber/viewmodels/ImageEditViewModel.java
-
2app/src/main/java/awais/instagrabber/viewmodels/SearchFragmentViewModel.java
-
6app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
-
3build.gradle
@ -1,117 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
import java.util.Objects; |
|||
|
|||
import awais.instagrabber.repositories.responses.User; |
|||
import awais.instagrabber.utils.Utils; |
|||
|
|||
public class Comment implements Serializable, Cloneable { |
|||
private final User user; |
|||
private final String id; |
|||
private final String text; |
|||
private long likes; |
|||
private final long timestamp; |
|||
private boolean liked; |
|||
private final int replyCount; |
|||
private final boolean isChild; |
|||
|
|||
public Comment(final String id, |
|||
final String text, |
|||
final long timestamp, |
|||
final long likes, |
|||
final boolean liked, |
|||
final User user, |
|||
final int replyCount, final boolean isChild) { |
|||
this.id = id; |
|||
this.text = text; |
|||
this.likes = likes; |
|||
this.liked = liked; |
|||
this.timestamp = timestamp; |
|||
this.user = user; |
|||
this.replyCount = replyCount; |
|||
this.isChild = isChild; |
|||
} |
|||
|
|||
public String getId() { |
|||
return id; |
|||
} |
|||
|
|||
public String getText() { |
|||
return text; |
|||
} |
|||
|
|||
@NonNull |
|||
public String getDateTime() { |
|||
return Utils.datetimeParser.format(new Date(timestamp * 1000L)); |
|||
} |
|||
|
|||
public long getLikes() { |
|||
return likes; |
|||
} |
|||
|
|||
public boolean getLiked() { |
|||
return liked; |
|||
} |
|||
|
|||
public void setLiked(boolean liked) { |
|||
this.likes = liked ? likes + 1 : likes - 1; |
|||
this.liked = liked; |
|||
} |
|||
|
|||
public User getUser() { |
|||
return user; |
|||
} |
|||
|
|||
public int getReplyCount() { |
|||
return replyCount; |
|||
} |
|||
|
|||
public boolean isChild() { |
|||
return isChild; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public Object clone() throws CloneNotSupportedException { |
|||
return super.clone(); |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(final Object o) { |
|||
if (this == o) return true; |
|||
if (o == null || getClass() != o.getClass()) return false; |
|||
final Comment comment = (Comment) o; |
|||
return likes == comment.likes && |
|||
timestamp == comment.timestamp && |
|||
liked == comment.liked && |
|||
replyCount == comment.replyCount && |
|||
Objects.equals(user, comment.user) && |
|||
Objects.equals(id, comment.id) && |
|||
Objects.equals(text, comment.text) && |
|||
isChild == comment.isChild; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(user, id, text, likes, timestamp, liked, replyCount, isChild); |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public String toString() { |
|||
return "Comment{" + |
|||
"user=" + user + |
|||
", id='" + id + '\'' + |
|||
", text='" + text + '\'' + |
|||
", likes=" + likes + |
|||
", timestamp=" + timestamp + |
|||
", liked=" + liked + |
|||
", replyCount" + replyCount + |
|||
", isChild" + isChild + |
|||
'}'; |
|||
} |
|||
} |
@ -0,0 +1,69 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import awais.instagrabber.repositories.responses.User |
|||
import awais.instagrabber.utils.Utils |
|||
import java.io.Serializable |
|||
import java.util.* |
|||
|
|||
class Comment( |
|||
val id: String, |
|||
val text: String, |
|||
val timestamp: Long, |
|||
var likes: Long, |
|||
private var liked: Boolean, |
|||
val user: User, |
|||
val replyCount: Int, |
|||
val isChild: Boolean, |
|||
) : Serializable, Cloneable { |
|||
val dateTime: String |
|||
get() = Utils.datetimeParser.format(Date(timestamp * 1000L)) |
|||
|
|||
fun getLiked(): Boolean { |
|||
return liked |
|||
} |
|||
|
|||
fun setLiked(liked: Boolean) { |
|||
likes = if (liked) likes + 1 else likes - 1 |
|||
this.liked = liked |
|||
} |
|||
|
|||
@Throws(CloneNotSupportedException::class) |
|||
public override fun clone(): Any { |
|||
return super.clone() |
|||
} |
|||
|
|||
|
|||
override fun equals(other: Any?): Boolean { |
|||
if (this === other) return true |
|||
if (javaClass != other?.javaClass) return false |
|||
|
|||
other as Comment |
|||
|
|||
if (id != other.id) return false |
|||
if (text != other.text) return false |
|||
if (timestamp != other.timestamp) return false |
|||
if (likes != other.likes) return false |
|||
if (liked != other.liked) return false |
|||
if (user != other.user) return false |
|||
if (replyCount != other.replyCount) return false |
|||
if (isChild != other.isChild) return false |
|||
|
|||
return true |
|||
} |
|||
|
|||
override fun hashCode(): Int { |
|||
var result = id.hashCode() |
|||
result = 31 * result + text.hashCode() |
|||
result = 31 * result + timestamp.hashCode() |
|||
result = 31 * result + likes.hashCode() |
|||
result = 31 * result + liked.hashCode() |
|||
result = 31 * result + user.hashCode() |
|||
result = 31 * result + replyCount |
|||
result = 31 * result + isChild.hashCode() |
|||
return result |
|||
} |
|||
|
|||
override fun toString(): String { |
|||
return "Comment(id='$id', text='$text', timestamp=$timestamp, likes=$likes, liked=$liked, user=$user, replyCount=$replyCount, isChild=$isChild)" |
|||
} |
|||
} |
@ -1,78 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
import awais.instagrabber.repositories.responses.User; |
|||
import awais.instagrabber.utils.Utils; |
|||
|
|||
public final class FeedStoryModel implements Serializable { |
|||
private final String storyMediaId; |
|||
private final User profileModel; |
|||
private final StoryModel firstStoryModel; |
|||
private Boolean fullyRead; |
|||
private final boolean isLive, isBestie; |
|||
private final long timestamp; |
|||
private final int mediaCount; |
|||
|
|||
public FeedStoryModel(final String storyMediaId, |
|||
final User profileModel, |
|||
final boolean fullyRead, |
|||
final long timestamp, |
|||
final StoryModel firstStoryModel, |
|||
final int mediaCount, |
|||
final boolean isLive, |
|||
final boolean isBestie) { |
|||
this.storyMediaId = storyMediaId; |
|||
this.profileModel = profileModel; |
|||
this.fullyRead = fullyRead; |
|||
this.timestamp = timestamp; |
|||
this.firstStoryModel = firstStoryModel; |
|||
this.mediaCount = mediaCount; |
|||
this.isLive = isLive; |
|||
this.isBestie = isBestie; |
|||
} |
|||
|
|||
public String getStoryMediaId() { |
|||
return storyMediaId; |
|||
} |
|||
|
|||
public long getTimestamp() { |
|||
return timestamp; |
|||
} |
|||
|
|||
@NonNull |
|||
public String getDateTime() { |
|||
return Utils.datetimeParser.format(new Date(timestamp * 1000L)); |
|||
} |
|||
|
|||
public int getMediaCount() { |
|||
return mediaCount; |
|||
} |
|||
|
|||
public User getProfileModel() { |
|||
return profileModel; |
|||
} |
|||
|
|||
public StoryModel getFirstStoryModel() { |
|||
return firstStoryModel; |
|||
} |
|||
|
|||
public Boolean isFullyRead() { |
|||
return fullyRead; |
|||
} |
|||
|
|||
public void setFullyRead(final boolean fullyRead) { |
|||
this.fullyRead = fullyRead; |
|||
} |
|||
|
|||
public boolean isLive() { |
|||
return isLive; |
|||
} |
|||
|
|||
public boolean isBestie() { |
|||
return isBestie; |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import awais.instagrabber.repositories.responses.User |
|||
import awais.instagrabber.utils.Utils |
|||
import java.io.Serializable |
|||
import java.util.* |
|||
|
|||
data class FeedStoryModel( |
|||
val storyMediaId: String, |
|||
val profileModel: User, |
|||
var isFullyRead: Boolean, |
|||
val timestamp: Long, |
|||
val firstStoryModel: StoryModel, |
|||
val mediaCount: Int, |
|||
val isLive: Boolean, |
|||
val isBestie: Boolean |
|||
) : Serializable { |
|||
val dateTime: String |
|||
get() = Utils.datetimeParser.format(Date(timestamp * 1000L)) |
|||
} |
@ -1,68 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import androidx.annotation.Nullable; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
public final class FollowModel implements Serializable { |
|||
private final String id; |
|||
private final String username; |
|||
private final String fullName; |
|||
private final String profilePicUrl; |
|||
private String endCursor; |
|||
private boolean hasNextPage; |
|||
private boolean isShown = true; |
|||
|
|||
public FollowModel(final String id, final String username, final String fullName, final String profilePicUrl) { |
|||
this.id = id; |
|||
this.username = username; |
|||
this.fullName = fullName; |
|||
this.profilePicUrl = profilePicUrl; |
|||
} |
|||
|
|||
public String getId() { |
|||
return id; |
|||
} |
|||
|
|||
public String getUsername() { |
|||
return username; |
|||
} |
|||
|
|||
public String getFullName() { |
|||
return fullName; |
|||
} |
|||
|
|||
public String getProfilePicUrl() { |
|||
return profilePicUrl; |
|||
} |
|||
|
|||
public boolean isShown() { |
|||
return isShown; |
|||
} |
|||
|
|||
public void setShown(final boolean shown) { |
|||
isShown = shown; |
|||
} |
|||
|
|||
public void setPageCursor(final boolean hasNextPage, final String endCursor) { |
|||
this.endCursor = endCursor; |
|||
this.hasNextPage = hasNextPage; |
|||
} |
|||
|
|||
public boolean hasNextPage() { |
|||
return endCursor != null && hasNextPage; |
|||
} |
|||
|
|||
public String getEndCursor() { |
|||
return endCursor; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(@Nullable final Object obj) { |
|||
if (obj instanceof FollowModel) { |
|||
final FollowModel model = (FollowModel) obj; |
|||
if (model.getId().equals(id) && model.getUsername().equals(username)) return true; |
|||
} |
|||
return super.equals(obj); |
|||
} |
|||
} |
@ -0,0 +1,49 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import java.io.Serializable |
|||
|
|||
class FollowModel( |
|||
val id: String, |
|||
val username: String, |
|||
val fullName: String, |
|||
val profilePicUrl: String |
|||
) : Serializable { |
|||
private var hasNextPage = false |
|||
get() = endCursor != null && field |
|||
|
|||
var isShown = true |
|||
|
|||
var endCursor: String? = null |
|||
private set |
|||
|
|||
fun setPageCursor(hasNextPage: Boolean, endCursor: String?) { |
|||
this.endCursor = endCursor |
|||
this.hasNextPage = hasNextPage |
|||
} |
|||
|
|||
override fun equals(other: Any?): Boolean { |
|||
if (this === other) return true |
|||
if (javaClass != other?.javaClass) return false |
|||
|
|||
other as FollowModel |
|||
|
|||
if (id != other.id) return false |
|||
if (username != other.username) return false |
|||
if (fullName != other.fullName) return false |
|||
if (profilePicUrl != other.profilePicUrl) return false |
|||
if (isShown != other.isShown) return false |
|||
if (endCursor != other.endCursor) return false |
|||
|
|||
return true |
|||
} |
|||
|
|||
override fun hashCode(): Int { |
|||
var result = id.hashCode() |
|||
result = 31 * result + username.hashCode() |
|||
result = 31 * result + fullName.hashCode() |
|||
result = 31 * result + profilePicUrl.hashCode() |
|||
result = 31 * result + isShown.hashCode() |
|||
result = 31 * result + (endCursor?.hashCode() ?: 0) |
|||
return result |
|||
} |
|||
} |
@ -1,52 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import java.util.Date; |
|||
|
|||
import awais.instagrabber.utils.Utils; |
|||
|
|||
public final class HighlightModel { |
|||
private final String title; |
|||
private final String id; |
|||
private final String thumbnailUrl; |
|||
private final long timestamp; |
|||
private final int mediaCount; |
|||
|
|||
public HighlightModel(final String title, |
|||
final String id, |
|||
final String thumbnailUrl, |
|||
final long timestamp, |
|||
final int mediaCount) { |
|||
this.title = title; |
|||
this.id = id; |
|||
this.thumbnailUrl = thumbnailUrl; |
|||
this.timestamp = timestamp; |
|||
this.mediaCount = mediaCount; |
|||
} |
|||
|
|||
public String getTitle() { |
|||
return title; |
|||
} |
|||
|
|||
public String getId() { |
|||
return id; |
|||
} |
|||
|
|||
public String getThumbnailUrl() { |
|||
return thumbnailUrl; |
|||
} |
|||
|
|||
public long getTimestamp() { |
|||
return timestamp; |
|||
} |
|||
|
|||
@NonNull |
|||
public String getDateTime() { |
|||
return Utils.datetimeParser.format(new Date(timestamp * 1000L)); |
|||
} |
|||
|
|||
public int getMediaCount() { |
|||
return mediaCount; |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import awais.instagrabber.utils.Utils |
|||
import java.util.* |
|||
|
|||
data class HighlightModel( |
|||
val title: String, |
|||
val id: String, |
|||
val thumbnailUrl: String, |
|||
val timestamp: Long, |
|||
val mediaCount: Int |
|||
) { |
|||
val dateTime: String |
|||
get() = Utils.datetimeParser.format(Date(timestamp * 1000L)) |
|||
} |
@ -1,21 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import awais.instagrabber.models.enums.IntentModelType; |
|||
|
|||
public final class IntentModel { |
|||
private final IntentModelType type; |
|||
private final String text; |
|||
|
|||
public IntentModel(final IntentModelType type, final String text) { |
|||
this.type = type; |
|||
this.text = text; |
|||
} |
|||
|
|||
public IntentModelType getType() { |
|||
return type; |
|||
} |
|||
|
|||
public String getText() { |
|||
return text; |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import awais.instagrabber.models.enums.IntentModelType |
|||
|
|||
data class IntentModel(val type: IntentModelType, val text: String) |
@ -1,64 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
|
|||
import java.util.Objects; |
|||
|
|||
public class Resource<T> { |
|||
public final Status status; |
|||
public final T data; |
|||
public final String message; |
|||
public final int resId; |
|||
|
|||
private Resource(@NonNull Status status, |
|||
@Nullable T data, |
|||
@Nullable String message, |
|||
int resId) { |
|||
this.status = status; |
|||
this.data = data; |
|||
this.message = message; |
|||
this.resId = resId; |
|||
} |
|||
|
|||
@NonNull |
|||
public static <T> Resource<T> success(@NonNull T data) { |
|||
return new Resource<>(Status.SUCCESS, data, null, 0); |
|||
} |
|||
|
|||
@NonNull |
|||
public static <T> Resource<T> error(String msg, @Nullable T data) { |
|||
return new Resource<>(Status.ERROR, data, msg, 0); |
|||
} |
|||
|
|||
@NonNull |
|||
public static <T> Resource<T> error(int resId, @Nullable T data) { |
|||
return new Resource<>(Status.ERROR, data, null, resId); |
|||
} |
|||
|
|||
@NonNull |
|||
public static <T> Resource<T> loading(@Nullable T data) { |
|||
return new Resource<>(Status.LOADING, data, null, 0); |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(final Object o) { |
|||
if (this == o) return true; |
|||
if (o == null || getClass() != o.getClass()) return false; |
|||
final Resource<?> resource = (Resource<?>) o; |
|||
return status == resource.status && |
|||
Objects.equals(data, resource.data) && |
|||
Objects.equals(message, resource.message); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(status, data, message); |
|||
} |
|||
|
|||
public enum Status { |
|||
SUCCESS, |
|||
ERROR, |
|||
LOADING |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import androidx.annotation.StringRes |
|||
|
|||
data class Resource<T>( |
|||
@JvmField val status: Status, |
|||
@JvmField val data: T? = null, |
|||
@JvmField val message: String? = null, |
|||
@JvmField @StringRes val resId: Int = 0, |
|||
) { |
|||
enum class Status { |
|||
SUCCESS, ERROR, LOADING |
|||
} |
|||
|
|||
companion object { |
|||
@JvmStatic |
|||
fun <T> success(data: T): Resource<T> { |
|||
return Resource(Status.SUCCESS, data, null, 0) |
|||
} |
|||
|
|||
@JvmStatic |
|||
fun <T> error(msg: String?, data: T?): Resource<T?> { |
|||
return Resource(Status.ERROR, data, msg, 0) |
|||
} |
|||
|
|||
@JvmStatic |
|||
fun <T> error(resId: Int, data: T?): Resource<T?> { |
|||
return Resource(Status.ERROR, data, null, resId) |
|||
} |
|||
|
|||
@JvmStatic |
|||
fun <T> loading(data: T?): Resource<T?> { |
|||
return Resource(Status.LOADING, data, null, 0) |
|||
} |
|||
} |
|||
} |
@ -1,66 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import android.graphics.RectF; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
import awais.instagrabber.fragments.imageedit.filters.FiltersHelper; |
|||
import awais.instagrabber.utils.SerializablePair; |
|||
|
|||
public class SavedImageEditState { |
|||
|
|||
private final String sessionId; |
|||
private final String originalPath; |
|||
|
|||
private float[] cropImageMatrixValues; // 9 values of matrix |
|||
private RectF cropRect; |
|||
private HashMap<FiltersHelper.FilterType, Map<Integer, Object>> appliedTuningFilters; |
|||
private SerializablePair<FiltersHelper.FilterType, Map<Integer, Object>> appliedFilter; |
|||
|
|||
public SavedImageEditState(final String sessionId, String originalPath) { |
|||
this.sessionId = sessionId; |
|||
this.originalPath = originalPath; |
|||
} |
|||
|
|||
public String getSessionId() { |
|||
return sessionId; |
|||
} |
|||
|
|||
public String getOriginalPath() { |
|||
return originalPath; |
|||
} |
|||
|
|||
public float[] getCropImageMatrixValues() { |
|||
return cropImageMatrixValues; |
|||
} |
|||
|
|||
public void setCropImageMatrixValues(float[] cropImageMatrixValues) { |
|||
this.cropImageMatrixValues = cropImageMatrixValues; |
|||
} |
|||
|
|||
public RectF getCropRect() { |
|||
return cropRect; |
|||
} |
|||
|
|||
public void setCropRect(RectF cropRect) { |
|||
this.cropRect = cropRect; |
|||
} |
|||
|
|||
public HashMap<FiltersHelper.FilterType, Map<Integer, Object>> getAppliedTuningFilters() { |
|||
return appliedTuningFilters; |
|||
} |
|||
|
|||
public void setAppliedTuningFilters(final HashMap<FiltersHelper.FilterType, Map<Integer, Object>> appliedTuningFilters) { |
|||
this.appliedTuningFilters = appliedTuningFilters; |
|||
} |
|||
|
|||
public SerializablePair<FiltersHelper.FilterType, Map<Integer, Object>> getAppliedFilter() { |
|||
return appliedFilter; |
|||
} |
|||
|
|||
public void setAppliedFilter(final SerializablePair<FiltersHelper.FilterType, Map<Integer, Object>> appliedFilter) { |
|||
this.appliedFilter = appliedFilter; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,13 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import android.graphics.RectF |
|||
import awais.instagrabber.fragments.imageedit.filters.FiltersHelper |
|||
import awais.instagrabber.utils.SerializablePair |
|||
import java.util.* |
|||
|
|||
data class SavedImageEditState(val sessionId: String, val originalPath: String) { |
|||
var cropImageMatrixValues: FloatArray? = null // 9 values of matrix |
|||
var cropRect: RectF? = null |
|||
var appliedTuningFilters: HashMap<FiltersHelper.FilterType, Map<Int, Any>>? = null |
|||
var appliedFilter: SerializablePair<FiltersHelper.FilterType, Map<Int, Any>>? = null |
|||
} |
@ -1,110 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import androidx.annotation.DrawableRes; |
|||
import androidx.annotation.IdRes; |
|||
import androidx.annotation.NavigationRes; |
|||
import androidx.annotation.NonNull; |
|||
|
|||
import java.util.Objects; |
|||
|
|||
public class Tab { |
|||
private final int iconResId; |
|||
private final String title; |
|||
private final boolean removable; |
|||
|
|||
/** |
|||
* This is name part of the navigation resource |
|||
* eg: @navigation/<b>graphName</b> |
|||
*/ |
|||
private final String graphName; |
|||
|
|||
/** |
|||
* This is the actual resource id of the navigation resource (R.navigation.graphName = navigationResId) |
|||
*/ |
|||
private final int navigationResId; |
|||
|
|||
/** |
|||
* This is the resource id of the root navigation tag of the navigation resource. |
|||
* <p>eg: inside R.navigation.direct_messages_nav_graph, the id of the root tag is R.id.direct_messages_nav_graph. |
|||
* <p>So this field would equal to the value of R.id.direct_messages_nav_graph |
|||
*/ |
|||
private final int navigationRootId; |
|||
|
|||
/** |
|||
* This is the start destination of the nav graph |
|||
*/ |
|||
private final int startDestinationFragmentId; |
|||
|
|||
public Tab(@DrawableRes final int iconResId, |
|||
@NonNull final String title, |
|||
final boolean removable, |
|||
@NonNull final String graphName, |
|||
@NavigationRes final int navigationResId, |
|||
@IdRes final int navigationRootId, |
|||
@IdRes final int startDestinationFragmentId) { |
|||
this.iconResId = iconResId; |
|||
this.title = title; |
|||
this.removable = removable; |
|||
this.graphName = graphName; |
|||
this.navigationResId = navigationResId; |
|||
this.navigationRootId = navigationRootId; |
|||
this.startDestinationFragmentId = startDestinationFragmentId; |
|||
} |
|||
|
|||
public int getIconResId() { |
|||
return iconResId; |
|||
} |
|||
|
|||
public String getTitle() { |
|||
return title; |
|||
} |
|||
|
|||
public boolean isRemovable() { |
|||
return removable; |
|||
} |
|||
|
|||
public String getGraphName() { |
|||
return graphName; |
|||
} |
|||
|
|||
public int getNavigationResId() { |
|||
return navigationResId; |
|||
} |
|||
|
|||
public int getNavigationRootId() { |
|||
return navigationRootId; |
|||
} |
|||
|
|||
public int getStartDestinationFragmentId() { |
|||
return startDestinationFragmentId; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(final Object o) { |
|||
if (this == o) return true; |
|||
if (o == null || getClass() != o.getClass()) return false; |
|||
final Tab tab = (Tab) o; |
|||
return iconResId == tab.iconResId && |
|||
removable == tab.removable && |
|||
navigationResId == tab.navigationResId && |
|||
navigationRootId == tab.navigationRootId && |
|||
startDestinationFragmentId == tab.startDestinationFragmentId && |
|||
Objects.equals(title, tab.title) && |
|||
Objects.equals(graphName, tab.graphName); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(iconResId, title, removable, graphName, navigationResId, navigationRootId, startDestinationFragmentId); |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public String toString() { |
|||
return "Tab{" + |
|||
"title='" + title + '\'' + |
|||
", removable=" + removable + |
|||
", graphName='" + graphName + '\'' + |
|||
'}'; |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import androidx.annotation.DrawableRes |
|||
import androidx.annotation.IdRes |
|||
import androidx.annotation.NavigationRes |
|||
|
|||
data class Tab( |
|||
@param:DrawableRes val iconResId: Int, |
|||
val title: String, |
|||
val isRemovable: Boolean, |
|||
|
|||
/** |
|||
* This is name part of the navigation resource |
|||
* eg: @navigation/ **graphName** |
|||
*/ |
|||
val graphName: String, |
|||
|
|||
/** |
|||
* This is the actual resource id of the navigation resource (R.navigation.graphName = navigationResId) |
|||
*/ |
|||
@param:NavigationRes val navigationResId: Int, |
|||
|
|||
/** |
|||
* This is the resource id of the root navigation tag of the navigation resource. |
|||
* |
|||
* eg: inside R.navigation.direct_messages_nav_graph, the id of the root tag is R.id.direct_messages_nav_graph. |
|||
* |
|||
* So this field would equal to the value of R.id.direct_messages_nav_graph |
|||
*/ |
|||
@param:IdRes val navigationRootId: Int, |
|||
|
|||
/** |
|||
* This is the start destination of the nav graph |
|||
*/ |
|||
@param:IdRes val startDestinationFragmentId: Int, |
|||
) |
@ -1,97 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
public class UploadPhotoOptions { |
|||
private final String uploadId; |
|||
private final String name; |
|||
// private final Uri uri; |
|||
private final long byteLength; |
|||
private final boolean isSideCar; |
|||
private final String waterfallId; |
|||
|
|||
public static class Builder { |
|||
private String uploadId; |
|||
private String name; |
|||
// private Uri uri; |
|||
private boolean isSideCar; |
|||
private String waterfallId; |
|||
private long byteLength; |
|||
|
|||
private Builder() {} |
|||
|
|||
public Builder setUploadId(final String uploadId) { |
|||
this.uploadId = uploadId; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setName(final String name) { |
|||
this.name = name; |
|||
return this; |
|||
} |
|||
|
|||
// public Builder setUri(final Uri uri) { |
|||
// this.uri = uri; |
|||
// return this; |
|||
// } |
|||
|
|||
public Builder setByteLength(final long byteLength) { |
|||
this.byteLength = byteLength; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setIsSideCar(final boolean isSideCar) { |
|||
this.isSideCar = isSideCar; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setWaterfallId(final String waterfallId) { |
|||
this.waterfallId = waterfallId; |
|||
return this; |
|||
} |
|||
|
|||
public UploadPhotoOptions build() { |
|||
return new UploadPhotoOptions(uploadId, name, /*uri,*/ byteLength, isSideCar, waterfallId); |
|||
} |
|||
} |
|||
|
|||
public static Builder builder() { |
|||
return new Builder(); |
|||
} |
|||
|
|||
public UploadPhotoOptions(final String uploadId, |
|||
final String name, |
|||
// final Uri uri, |
|||
final long byteLength, |
|||
final boolean isSideCar, |
|||
final String waterfallId) { |
|||
this.uploadId = uploadId; |
|||
this.name = name; |
|||
// this.uri = uri; |
|||
this.byteLength = byteLength; |
|||
this.isSideCar = isSideCar; |
|||
this.waterfallId = waterfallId; |
|||
} |
|||
|
|||
public String getUploadId() { |
|||
return uploadId; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
// public Uri getUri() { |
|||
// return uri; |
|||
// } |
|||
|
|||
public long getByteLength() { |
|||
return byteLength; |
|||
} |
|||
|
|||
public boolean isSideCar() { |
|||
return isSideCar; |
|||
} |
|||
|
|||
public String getWaterfallId() { |
|||
return waterfallId; |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
data class UploadPhotoOptions( |
|||
val uploadId: String? = null, |
|||
val name: String, |
|||
val byteLength: Long = 0, |
|||
val isSideCar: Boolean = false, |
|||
val waterfallId: String? = null, |
|||
) |
@ -1,217 +0,0 @@ |
|||
package awais.instagrabber.models; |
|||
|
|||
import awais.instagrabber.models.enums.MediaItemType; |
|||
|
|||
public class UploadVideoOptions { |
|||
private final String uploadId; |
|||
private final String name; |
|||
private final long byteLength; |
|||
private final long duration; |
|||
private final int width; |
|||
private final int height; |
|||
private final boolean isSideCar; |
|||
private final boolean forAlbum; // Stories |
|||
private final boolean isDirect; |
|||
private final boolean isDirectVoice; |
|||
private final boolean forDirectStory; |
|||
private final boolean isIgtvVideo; |
|||
private final String waterfallId; |
|||
private final long offset; |
|||
private final MediaItemType mediaType; |
|||
|
|||
public static class Builder { |
|||
private String uploadId; |
|||
private String name; |
|||
private long byteLength; |
|||
private long duration; |
|||
private int width; |
|||
private int height; |
|||
private boolean isSideCar; |
|||
private boolean forAlbum; // Stories |
|||
private boolean isDirect; |
|||
private boolean isDirectVoice; |
|||
private boolean forDirectStory; |
|||
private boolean isIgtvVideo; |
|||
private String waterfallId; |
|||
private long offset; |
|||
private MediaItemType mediaType; |
|||
|
|||
private Builder() {} |
|||
|
|||
public Builder setUploadId(final String uploadId) { |
|||
this.uploadId = uploadId; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setName(final String name) { |
|||
this.name = name; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setByteLength(final long byteLength) { |
|||
this.byteLength = byteLength; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setDuration(final long duration) { |
|||
this.duration = duration; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setWidth(final int width) { |
|||
this.width = width; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setHeight(final int height) { |
|||
this.height = height; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setIsSideCar(final boolean isSideCar) { |
|||
this.isSideCar = isSideCar; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setForAlbum(final boolean forAlbum) { |
|||
this.forAlbum = forAlbum; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setIsDirect(final boolean isDirect) { |
|||
this.isDirect = isDirect; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setIsDirectVoice(final boolean isDirectVoice) { |
|||
this.isDirectVoice = isDirectVoice; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setForDirectStory(final boolean forDirectStory) { |
|||
this.forDirectStory = forDirectStory; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setIsIgtvVideo(final boolean isIgtvVideo) { |
|||
this.isIgtvVideo = isIgtvVideo; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setWaterfallId(final String waterfallId) { |
|||
this.waterfallId = waterfallId; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setOffset(final long offset) { |
|||
this.offset = offset; |
|||
return this; |
|||
} |
|||
|
|||
public Builder setMediaType(final MediaItemType mediaType) { |
|||
this.mediaType = mediaType; |
|||
return this; |
|||
} |
|||
|
|||
public UploadVideoOptions build() { |
|||
return new UploadVideoOptions(uploadId, name, byteLength, duration, width, height, isSideCar, forAlbum, isDirect, isDirectVoice, |
|||
forDirectStory, isIgtvVideo, waterfallId, offset, mediaType); |
|||
} |
|||
} |
|||
|
|||
public static Builder builder() { |
|||
return new Builder(); |
|||
} |
|||
|
|||
private UploadVideoOptions(final String uploadId, |
|||
final String name, |
|||
final long byteLength, |
|||
final long duration, |
|||
final int width, |
|||
final int height, |
|||
final boolean isSideCar, |
|||
final boolean forAlbum, |
|||
final boolean isDirect, |
|||
final boolean isDirectVoice, |
|||
final boolean forDirectStory, |
|||
final boolean isIgtvVideo, |
|||
final String waterfallId, |
|||
final long offset, |
|||
final MediaItemType mediaType) { |
|||
this.uploadId = uploadId; |
|||
this.name = name; |
|||
this.byteLength = byteLength; |
|||
this.duration = duration; |
|||
this.width = width; |
|||
this.height = height; |
|||
this.isSideCar = isSideCar; |
|||
this.forAlbum = forAlbum; |
|||
this.isDirect = isDirect; |
|||
this.isDirectVoice = isDirectVoice; |
|||
this.forDirectStory = forDirectStory; |
|||
this.isIgtvVideo = isIgtvVideo; |
|||
this.waterfallId = waterfallId; |
|||
this.offset = offset; |
|||
this.mediaType = mediaType; |
|||
} |
|||
|
|||
public String getUploadId() { |
|||
return uploadId; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public long getByteLength() { |
|||
return byteLength; |
|||
} |
|||
|
|||
public long getDuration() { |
|||
return duration; |
|||
} |
|||
|
|||
public int getWidth() { |
|||
return width; |
|||
} |
|||
|
|||
public int getHeight() { |
|||
return height; |
|||
} |
|||
|
|||
public boolean isSideCar() { |
|||
return isSideCar; |
|||
} |
|||
|
|||
public boolean isForAlbum() { |
|||
return forAlbum; |
|||
} |
|||
|
|||
public boolean isDirect() { |
|||
return isDirect; |
|||
} |
|||
|
|||
public boolean isDirectVoice() { |
|||
return isDirectVoice; |
|||
} |
|||
|
|||
public boolean isForDirectStory() { |
|||
return forDirectStory; |
|||
} |
|||
|
|||
public boolean isIgtvVideo() { |
|||
return isIgtvVideo; |
|||
} |
|||
|
|||
public String getWaterfallId() { |
|||
return waterfallId; |
|||
} |
|||
|
|||
public long getOffset() { |
|||
return offset; |
|||
} |
|||
|
|||
public MediaItemType getMediaType() { |
|||
return mediaType; |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
package awais.instagrabber.models |
|||
|
|||
import awais.instagrabber.models.enums.MediaItemType |
|||
|
|||
data class UploadVideoOptions( |
|||
val uploadId: String, |
|||
val name: String, |
|||
val byteLength: Long = 0, |
|||
val duration: Long = 0, |
|||
val width: Int = 0, |
|||
val height: Int = 0, |
|||
val isSideCar: Boolean = false, |
|||
// Stories |
|||
val isForAlbum: Boolean = false, |
|||
val isDirect: Boolean = false, |
|||
val isDirectVoice: Boolean = false, |
|||
val isForDirectStory: Boolean = false, |
|||
val isIgtvVideo: Boolean = false, |
|||
val waterfallId: String? = null, |
|||
val offset: Long = 0, |
|||
val mediaType: MediaItemType? = null, |
|||
) |
@ -1,106 +0,0 @@ |
|||
/* |
|||
* Copyright (C) 2017 The Android Open Source Project |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
|
|||
package awais.instagrabber.utils; |
|||
|
|||
import android.os.Handler; |
|||
import android.os.Looper; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import com.google.common.util.concurrent.ListeningExecutorService; |
|||
import com.google.common.util.concurrent.MoreExecutors; |
|||
|
|||
import java.util.concurrent.Executor; |
|||
import java.util.concurrent.Executors; |
|||
|
|||
/** |
|||
* Global executor pools for the whole application. |
|||
* <p> |
|||
* Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind |
|||
* webservice requests). |
|||
*/ |
|||
public class AppExecutors { |
|||
|
|||
private static final int THREAD_COUNT = 3; |
|||
private static final Object LOCK = new Object(); |
|||
|
|||
private static AppExecutors instance; |
|||
|
|||
private final Executor diskIO; |
|||
private final Executor networkIO; |
|||
private final MainThreadExecutor mainThread; |
|||
private final ListeningExecutorService tasksThread; |
|||
|
|||
private AppExecutors(Executor diskIO, |
|||
Executor networkIO, |
|||
MainThreadExecutor mainThread, |
|||
ListeningExecutorService tasksThread) { |
|||
this.diskIO = diskIO; |
|||
this.networkIO = networkIO; |
|||
this.mainThread = mainThread; |
|||
this.tasksThread = tasksThread; |
|||
} |
|||
|
|||
public static AppExecutors getInstance() { |
|||
if (instance == null) { |
|||
synchronized (LOCK) { |
|||
if (instance == null) { |
|||
instance = new AppExecutors(Executors.newSingleThreadExecutor(), |
|||
Executors.newFixedThreadPool(THREAD_COUNT), |
|||
new MainThreadExecutor(), |
|||
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10))); |
|||
} |
|||
} |
|||
} |
|||
return instance; |
|||
} |
|||
|
|||
|
|||
public Executor diskIO() { |
|||
return diskIO; |
|||
} |
|||
|
|||
public Executor networkIO() { |
|||
return networkIO; |
|||
} |
|||
|
|||
|
|||
public ListeningExecutorService tasksThread() { |
|||
return tasksThread; |
|||
} |
|||
|
|||
public MainThreadExecutor mainThread() { |
|||
return mainThread; |
|||
} |
|||
|
|||
public static class MainThreadExecutor implements Executor { |
|||
private final Handler mainThreadHandler = new Handler(Looper.getMainLooper()); |
|||
|
|||
@Override |
|||
public void execute(@NonNull Runnable command) { |
|||
mainThreadHandler.post(command); |
|||
} |
|||
|
|||
public void execute(final Runnable command, final int delay) { |
|||
mainThreadHandler.postDelayed(command, delay); |
|||
} |
|||
|
|||
public void cancel(@NonNull Runnable command) { |
|||
mainThreadHandler.removeCallbacks(command); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
/* |
|||
* Copyright (C) 2017 The Android Open Source Project |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package awais.instagrabber.utils |
|||
|
|||
import android.os.Handler |
|||
import android.os.Looper |
|||
import com.google.common.util.concurrent.ListeningExecutorService |
|||
import com.google.common.util.concurrent.MoreExecutors |
|||
import java.util.concurrent.Executor |
|||
import java.util.concurrent.Executors |
|||
|
|||
/** |
|||
* Global executor pools for the whole application. |
|||
* |
|||
* |
|||
* Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind |
|||
* webservice requests). |
|||
*/ |
|||
object AppExecutors { |
|||
val diskIO: Executor = Executors.newSingleThreadExecutor() |
|||
val networkIO: Executor = Executors.newFixedThreadPool(3) |
|||
val mainThread: MainThreadExecutor = MainThreadExecutor() |
|||
val tasksThread: ListeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)) |
|||
|
|||
class MainThreadExecutor : Executor { |
|||
private val mainThreadHandler = Handler(Looper.getMainLooper()) |
|||
override fun execute(command: Runnable) { |
|||
mainThreadHandler.post(command) |
|||
} |
|||
|
|||
fun execute(command: Runnable?, delay: Int) { |
|||
mainThreadHandler.postDelayed(command!!, delay.toLong()) |
|||
} |
|||
|
|||
fun cancel(command: Runnable) { |
|||
mainThreadHandler.removeCallbacks(command) |
|||
} |
|||
} |
|||
} |
@ -1,173 +0,0 @@ |
|||
package awais.instagrabber.utils; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import com.google.common.collect.ImmutableMap; |
|||
|
|||
import org.json.JSONObject; |
|||
|
|||
import java.util.Date; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
|
|||
import awais.instagrabber.models.UploadPhotoOptions; |
|||
import awais.instagrabber.models.UploadVideoOptions; |
|||
import awais.instagrabber.models.enums.MediaItemType; |
|||
|
|||
public final class MediaUploadHelper { |
|||
private static final long LOWER = 1000000000L; |
|||
private static final long UPPER = 9999999999L; |
|||
|
|||
private static Map<String, String> createPhotoRuploadParams(final UploadPhotoOptions options) { |
|||
final String retryContextString = getRetryContextString(); |
|||
final Map<String, String> params = new HashMap<>(); |
|||
params.put("retry_context", retryContextString); |
|||
params.put("media_type", "1"); |
|||
params.put("upload_id", options.getUploadId()); |
|||
params.put("xsharing_user_ids", "[]"); |
|||
final Map<String, String> imageCompression = new HashMap<>(); |
|||
imageCompression.put("lib_name", "moz"); |
|||
imageCompression.put("lib_version", "3.1.m"); |
|||
imageCompression.put("quality", "80"); |
|||
params.put("image_compression", new JSONObject(imageCompression).toString()); |
|||
if (options.isSideCar()) { |
|||
params.put("is_sidecar", "1"); |
|||
} |
|||
return params; |
|||
} |
|||
|
|||
private static Map<String, String> createVideoRuploadParams(final UploadVideoOptions options) { |
|||
final String retryContextString = getRetryContextString(); |
|||
final Map<String, String> ruploadParams = new HashMap<>(); |
|||
ruploadParams.put("retry_context", retryContextString); |
|||
ruploadParams.put("media_type", "2"); |
|||
ruploadParams.put("xsharing_user_ids", "[]"); |
|||
ruploadParams.put("upload_id", options.getUploadId()); |
|||
ruploadParams.put("upload_media_width", String.valueOf(options.getWidth())); |
|||
ruploadParams.put("upload_media_height", String.valueOf(options.getHeight())); |
|||
ruploadParams.put("upload_media_duration_ms", String.valueOf(options.getDuration())); |
|||
if (options.isSideCar()) { |
|||
ruploadParams.put("is_sidecar", "1"); |
|||
} |
|||
if (options.isForAlbum()) { |
|||
ruploadParams.put("for_album", "1"); |
|||
} |
|||
if (options.isDirect()) { |
|||
ruploadParams.put("direct_v2", "1"); |
|||
} |
|||
if (options.isForDirectStory()) { |
|||
ruploadParams.put("for_direct_story", "1"); |
|||
ruploadParams.put("content_tags", ""); |
|||
} |
|||
if (options.isIgtvVideo()) { |
|||
ruploadParams.put("is_igtv_video", "1"); |
|||
} |
|||
if (options.isDirectVoice()) { |
|||
ruploadParams.put("is_direct_voice", "1"); |
|||
} |
|||
return ruploadParams; |
|||
} |
|||
|
|||
@NonNull |
|||
public static String getRetryContextString() { |
|||
final Map<String, Integer> retryContext = new HashMap<>(); |
|||
retryContext.put("num_step_auto_retry", 0); |
|||
retryContext.put("num_reupload", 0); |
|||
retryContext.put("num_step_manual_retry", 0); |
|||
return new JSONObject(retryContext).toString(); |
|||
} |
|||
|
|||
public static UploadPhotoOptions createUploadPhotoOptions(final long byteLength) { |
|||
final String uploadId = generateUploadId(); |
|||
return UploadPhotoOptions.builder() |
|||
.setUploadId(uploadId) |
|||
.setName(generateName(uploadId)) |
|||
.setByteLength(byteLength) |
|||
.build(); |
|||
} |
|||
|
|||
public static UploadVideoOptions createUploadDmVideoOptions(final long byteLength, |
|||
final long duration, |
|||
final int width, |
|||
final int height) { |
|||
final String uploadId = generateUploadId(); |
|||
return UploadVideoOptions.builder() |
|||
.setUploadId(uploadId) |
|||
.setName(generateName(uploadId)) |
|||
.setByteLength(byteLength) |
|||
.setDuration(duration) |
|||
.setWidth(width) |
|||
.setHeight(height) |
|||
.setIsDirect(true) |
|||
.setMediaType(MediaItemType.MEDIA_TYPE_VIDEO) |
|||
.build(); |
|||
} |
|||
|
|||
public static UploadVideoOptions createUploadDmVoiceOptions(final long byteLength, |
|||
final long duration) { |
|||
final String uploadId = generateUploadId(); |
|||
return UploadVideoOptions.builder() |
|||
.setUploadId(uploadId) |
|||
.setName(generateName(uploadId)) |
|||
.setDuration(duration) |
|||
.setIsDirectVoice(true) |
|||
.setByteLength(byteLength) |
|||
.setMediaType(MediaItemType.MEDIA_TYPE_VOICE) |
|||
.build(); |
|||
} |
|||
|
|||
@NonNull |
|||
public static String generateUploadId() { |
|||
return String.valueOf(new Date().getTime() / 1000); |
|||
} |
|||
|
|||
@NonNull |
|||
public static String generateName(final String uploadId) { |
|||
final long random = NumberUtils.random(LOWER, UPPER + 1); |
|||
return String.format("%s_0_%s", uploadId, random); |
|||
} |
|||
|
|||
@NonNull |
|||
public static Map<String, String> getUploadPhotoHeaders(@NonNull final UploadPhotoOptions options) { |
|||
final String waterfallId = TextUtils.isEmpty(options.getWaterfallId()) ? UUID.randomUUID().toString() : options.getWaterfallId(); |
|||
final String contentLength = String.valueOf(options.getByteLength()); |
|||
final Map<String, String> headers = new HashMap<>(); |
|||
headers.put("X_FB_PHOTO_WATERFALL_ID", waterfallId); |
|||
headers.put("X-Entity-Type", "image/jpeg"); |
|||
headers.put("Offset", "0"); |
|||
headers.put("X-Instagram-Rupload-Params", new JSONObject(createPhotoRuploadParams(options)).toString()); |
|||
headers.put("X-Entity-Name", options.getName()); |
|||
headers.put("X-Entity-Length", contentLength); |
|||
headers.put("Content-Type", "application/octet-stream"); |
|||
headers.put("Content-Length", contentLength); |
|||
headers.put("Accept-Encoding", "gzip"); |
|||
return headers; |
|||
} |
|||
|
|||
@NonNull |
|||
public static Map<String, String> getUploadVideoHeaders(@NonNull final UploadVideoOptions options) { |
|||
final Map<String, String> ruploadParams = createVideoRuploadParams(options); |
|||
final String waterfallId = TextUtils.isEmpty(options.getWaterfallId()) ? UUID.randomUUID().toString() : options.getWaterfallId(); |
|||
final String contentLength = String.valueOf(options.getByteLength()); |
|||
return ImmutableMap.<String, String>builder() |
|||
.putAll(getBaseUploadVideoHeaders(ruploadParams)) |
|||
.put("X_FB_PHOTO_WATERFALL_ID", waterfallId) |
|||
.put("X-Entity-Type", "video/mp4") |
|||
.put("Offset", String.valueOf(options.getOffset() > 0 ? options.getOffset() : 0)) |
|||
.put("X-Entity-Name", options.getName()) |
|||
.put("X-Entity-Length", contentLength) |
|||
.put("Content-Type", "application/octet-stream") |
|||
.put("Content-Length", contentLength) |
|||
.build(); |
|||
} |
|||
|
|||
private static Map<String, String> getBaseUploadVideoHeaders(@NonNull final Map<String, String> ruploadParams) { |
|||
return ImmutableMap.of( |
|||
"X-IG-Connection-Type", "WIFI", |
|||
"X-IG-Capabilities", "3brTvwE=", |
|||
"Accept-Encoding", "gzip", |
|||
"X-Instagram-Rupload-Params", new JSONObject(ruploadParams).toString() |
|||
); |
|||
} |
|||
} |
@ -0,0 +1,154 @@ |
|||
@file:JvmName("MediaUploadHelper") |
|||
|
|||
package awais.instagrabber.utils |
|||
|
|||
import awais.instagrabber.models.UploadPhotoOptions |
|||
import awais.instagrabber.models.UploadVideoOptions |
|||
import awais.instagrabber.models.enums.MediaItemType |
|||
import org.json.JSONObject |
|||
import java.util.* |
|||
|
|||
|
|||
private const val LOWER = 1000000000L |
|||
private const val UPPER = 9999999999L |
|||
|
|||
private fun createPhotoRuploadParams(options: UploadPhotoOptions): Map<String, String> { |
|||
val imageCompression = mapOf( |
|||
"lib_name" to "moz", |
|||
"lib_version" to "3.1.m", |
|||
"quality" to "80", |
|||
) |
|||
return listOfNotNull( |
|||
"retry_context" to retryContextString, |
|||
"media_type" to "1", |
|||
"upload_id" to (options.uploadId ?: ""), |
|||
"xsharing_user_ids" to "[]", |
|||
"image_compression" to JSONObject(imageCompression).toString(), |
|||
if (options.isSideCar) "is_sidecar" to "1" else null, |
|||
).toMap() |
|||
} |
|||
|
|||
private fun createVideoRuploadParams(options: UploadVideoOptions): Map<String, String> { |
|||
val retryContextString = retryContextString |
|||
return listOfNotNull( |
|||
"retry_context" to retryContextString, |
|||
"media_type" to "2", |
|||
"xsharing_user_ids" to "[]", |
|||
"upload_id" to options.uploadId, |
|||
"upload_media_width" to options.width.toString(), |
|||
"upload_media_height" to options.height.toString(), |
|||
"upload_media_duration_ms" to options.duration.toString(), |
|||
if (options.isSideCar) "is_sidecar" to "1" else null, |
|||
if (options.isForAlbum) "for_album" to "1" else null, |
|||
if (options.isDirect) "direct_v2" to "1" else null, |
|||
*(if (options.isForDirectStory) arrayOf( |
|||
"for_direct_story" to "1", |
|||
"content_tags" to "" |
|||
) else emptyArray()), |
|||
if (options.isIgtvVideo) "is_igtv_video" to "1" else null, |
|||
if (options.isDirectVoice) "is_direct_voice" to "1" else null, |
|||
).toMap() |
|||
} |
|||
|
|||
val retryContextString: String |
|||
get() { |
|||
return JSONObject( |
|||
mapOf( |
|||
"num_step_auto_retry" to 0, |
|||
"num_reupload" to 0, |
|||
"num_step_manual_retry" to 0, |
|||
) |
|||
).toString() |
|||
} |
|||
|
|||
fun createUploadPhotoOptions(byteLength: Long): UploadPhotoOptions { |
|||
val uploadId = generateUploadId() |
|||
return UploadPhotoOptions( |
|||
uploadId, |
|||
generateName(uploadId), |
|||
byteLength, |
|||
) |
|||
} |
|||
|
|||
fun createUploadDmVideoOptions( |
|||
byteLength: Long, |
|||
duration: Long, |
|||
width: Int, |
|||
height: Int |
|||
): UploadVideoOptions { |
|||
val uploadId = generateUploadId() |
|||
return UploadVideoOptions( |
|||
uploadId, |
|||
generateName(uploadId), |
|||
byteLength, |
|||
duration, |
|||
width, |
|||
height, |
|||
true, |
|||
mediaType = MediaItemType.MEDIA_TYPE_VIDEO, |
|||
) |
|||
} |
|||
|
|||
fun createUploadDmVoiceOptions( |
|||
byteLength: Long, |
|||
duration: Long |
|||
): UploadVideoOptions { |
|||
val uploadId = generateUploadId() |
|||
return UploadVideoOptions( |
|||
uploadId, |
|||
generateName(uploadId), |
|||
byteLength, |
|||
duration, |
|||
isDirectVoice = true, |
|||
mediaType = MediaItemType.MEDIA_TYPE_VOICE, |
|||
) |
|||
} |
|||
|
|||
fun generateUploadId(): String { |
|||
return (Date().time / 1000).toString() |
|||
} |
|||
|
|||
fun generateName(uploadId: String): String { |
|||
val random = NumberUtils.random(LOWER, UPPER + 1) |
|||
return "${uploadId}_0_$random" |
|||
} |
|||
|
|||
fun getUploadPhotoHeaders(options: UploadPhotoOptions): Map<String, String> { |
|||
val waterfallId = options.waterfallId ?: UUID.randomUUID().toString() |
|||
val contentLength = options.byteLength.toString() |
|||
return mapOf( |
|||
"X_FB_PHOTO_WATERFALL_ID" to waterfallId, |
|||
"X-Entity-Type" to "image/jpeg", |
|||
"Offset" to "0", |
|||
"X-Instagram-Rupload-Params" to JSONObject(createPhotoRuploadParams(options)).toString(), |
|||
"X-Entity-Name" to options.name, |
|||
"X-Entity-Length" to contentLength, |
|||
"Content-Type" to "application/octet-stream", |
|||
"Content-Length" to contentLength, |
|||
"Accept-Encoding" to "gzip", |
|||
) |
|||
} |
|||
|
|||
fun getUploadVideoHeaders(options: UploadVideoOptions): Map<String, String> { |
|||
val ruploadParams = createVideoRuploadParams(options) |
|||
val waterfallId = options.waterfallId ?: UUID.randomUUID().toString() |
|||
val contentLength = options.byteLength.toString() |
|||
return getBaseUploadVideoHeaders(ruploadParams) + mapOf( |
|||
"X_FB_PHOTO_WATERFALL_ID" to waterfallId, |
|||
"X-Entity-Type" to "video/mp4", |
|||
"Offset" to (if (options.offset > 0) options.offset else 0).toString(), |
|||
"X-Entity-Name" to options.name, |
|||
"X-Entity-Length" to contentLength, |
|||
"Content-Type" to "application/octet-stream", |
|||
"Content-Length" to contentLength, |
|||
) |
|||
} |
|||
|
|||
private fun getBaseUploadVideoHeaders(ruploadParams: Map<String, String>): Map<String, String> { |
|||
return mapOf( |
|||
"X-IG-Connection-Type" to "WIFI", |
|||
"X-IG-Capabilities" to "3brTvwE=", |
|||
"Accept-Encoding" to "gzip", |
|||
"X-Instagram-Rupload-Params" to JSONObject(ruploadParams).toString() |
|||
) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue