mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-23 07:07:30 +00:00
merge discover and feed api's and convert them to kotlin
This commit is contained in:
parent
2099aa8676
commit
32fe0edb55
@ -10,52 +10,49 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse;
|
||||
import awais.instagrabber.repositories.responses.WrappedMedia;
|
||||
import awais.instagrabber.webservices.DiscoverService;
|
||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||
import awais.instagrabber.webservices.FeedRepository;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
|
||||
public class DiscoverPostFetchService implements PostFetcher.PostFetchService {
|
||||
private static final String TAG = "DiscoverPostFetchService";
|
||||
private final DiscoverService discoverService;
|
||||
private final FeedRepository feedRepository;
|
||||
private String maxId;
|
||||
private boolean moreAvailable = false;
|
||||
|
||||
public DiscoverPostFetchService() {
|
||||
discoverService = DiscoverService.getInstance();
|
||||
feedRepository = FeedRepository.Companion.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(final FetchListener<List<Media>> fetchListener) {
|
||||
discoverService.topicalExplore(maxId, new ServiceCallback<TopicalExploreFeedResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final TopicalExploreFeedResponse result) {
|
||||
if (result == null) {
|
||||
onFailure(new RuntimeException("result is null"));
|
||||
return;
|
||||
}
|
||||
moreAvailable = result.getMoreAvailable();
|
||||
maxId = result.getNextMaxId();
|
||||
final List<WrappedMedia> items = result.getItems();
|
||||
final List<Media> posts;
|
||||
if (items == null) {
|
||||
posts = Collections.emptyList();
|
||||
} else {
|
||||
posts = items.stream()
|
||||
.map(WrappedMedia::getMedia)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
if (fetchListener != null) {
|
||||
fetchListener.onResult(posts);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
feedRepository.topicalExplore(maxId, CoroutineUtilsKt.getContinuation((result, t) -> {
|
||||
if (t != null) {
|
||||
if (fetchListener != null) {
|
||||
fetchListener.onFailure(t);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (result == null) {
|
||||
fetchListener.onFailure(new RuntimeException("result is null"));
|
||||
return;
|
||||
}
|
||||
moreAvailable = result.getMoreAvailable();
|
||||
maxId = result.getNextMaxId();
|
||||
final List<WrappedMedia> items = result.getItems();
|
||||
final List<Media> posts;
|
||||
if (items == null) {
|
||||
posts = Collections.emptyList();
|
||||
} else {
|
||||
posts = items.stream()
|
||||
.map(WrappedMedia::getMedia)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
if (fetchListener != null) {
|
||||
fetchListener.onResult(posts);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,19 +9,20 @@ import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.webservices.FeedService;
|
||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||
import awais.instagrabber.webservices.FeedRepository;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class FeedPostFetchService implements PostFetcher.PostFetchService {
|
||||
private static final String TAG = "FeedPostFetchService";
|
||||
private final FeedService feedService;
|
||||
private final FeedRepository feedRepository;
|
||||
private String nextCursor;
|
||||
private boolean hasNextPage;
|
||||
|
||||
public FeedPostFetchService() {
|
||||
feedService = FeedService.getInstance();
|
||||
feedRepository = FeedRepository.Companion.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -31,35 +32,27 @@ public class FeedPostFetchService implements PostFetcher.PostFetchService {
|
||||
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||
feedModels.clear();
|
||||
feedService.fetch(csrfToken, deviceUuid, nextCursor, new ServiceCallback<PostsFetchResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final PostsFetchResponse result) {
|
||||
if (result == null && feedModels.size() > 0) {
|
||||
fetchListener.onResult(feedModels);
|
||||
return;
|
||||
} else if (result == null) return;
|
||||
nextCursor = result.getNextCursor();
|
||||
hasNextPage = result.getHasNextPage();
|
||||
|
||||
final List<Media> mediaResults = result.getFeedModels();
|
||||
feedModels.addAll(mediaResults);
|
||||
|
||||
if (fetchListener != null) {
|
||||
// if (feedModels.size() < 15 && hasNextPage) {
|
||||
// feedService.fetch(csrfToken, nextCursor, this);
|
||||
// } else {
|
||||
fetchListener.onResult(feedModels);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
feedRepository.fetchFeed(csrfToken, deviceUuid, nextCursor, CoroutineUtilsKt.getContinuation((result, t) -> {
|
||||
if (t != null) {
|
||||
if (fetchListener != null) {
|
||||
fetchListener.onFailure(t);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (result == null && feedModels.size() > 0) {
|
||||
fetchListener.onResult(feedModels);
|
||||
return;
|
||||
} else if (result == null) return;
|
||||
nextCursor = result.getNextCursor();
|
||||
hasNextPage = result.getHasNextPage();
|
||||
|
||||
final List<Media> mediaResults = result.getFeedModels();
|
||||
feedModels.addAll(mediaResults);
|
||||
|
||||
if (fetchListener != null) {
|
||||
fetchListener.onResult(feedModels);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,7 +16,6 @@ import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.activity.OnBackPressedDispatcher;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavDirections;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
@ -34,7 +33,6 @@ import awais.instagrabber.customviews.PrimaryActionModeCallback;
|
||||
import awais.instagrabber.databinding.FragmentDiscoverBinding;
|
||||
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||
import awais.instagrabber.models.enums.PostItemType;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
@ -44,7 +42,6 @@ import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.webservices.DiscoverService;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
package awais.instagrabber.repositories;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.FieldMap;
|
||||
import retrofit2.http.FormUrlEncoded;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface FeedRepository {
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/feed/timeline/")
|
||||
Call<FeedFetchResponse> fetch(@FieldMap final Map<String, String> signedForm);
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
package awais.instagrabber.repositories;
|
||||
package awais.instagrabber.repositories
|
||||
|
||||
import java.util.Map;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse
|
||||
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.*
|
||||
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.QueryMap;
|
||||
|
||||
public interface DiscoverRepository {
|
||||
interface FeedService {
|
||||
@GET("/api/v1/discover/topical_explore/")
|
||||
Call<TopicalExploreFeedResponse> topicalExplore(@QueryMap Map<String, String> queryParams);
|
||||
suspend fun topicalExplore(@QueryMap queryParams: Map<String?, String?>?): TopicalExploreFeedResponse?
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/feed/timeline/")
|
||||
suspend fun fetchFeed(@FieldMap signedForm: Map<String?, String?>?): FeedFetchResponse
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package awais.instagrabber.webservices
|
||||
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse
|
||||
import awais.instagrabber.utils.TextUtils.isEmpty
|
||||
import awais.instagrabber.repositories.FeedService
|
||||
import com.google.common.collect.ImmutableMap
|
||||
|
||||
open class DiscoverRepository(private val repository: FeedService) {
|
||||
|
||||
|
||||
companion object {
|
||||
@Volatile
|
||||
private var INSTANCE: DiscoverRepository? = null
|
||||
|
||||
fun getInstance(): DiscoverRepository {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
val service = RetrofitFactory.retrofit.create(FeedService::class.java)
|
||||
DiscoverRepository(service).also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package awais.instagrabber.webservices;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.DiscoverRepository;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class DiscoverService {
|
||||
|
||||
private static final String TAG = "DiscoverService";
|
||||
|
||||
private final DiscoverRepository repository;
|
||||
|
||||
private static DiscoverService instance;
|
||||
|
||||
private DiscoverService() {
|
||||
repository = RetrofitFactory.INSTANCE
|
||||
.getRetrofit()
|
||||
.create(DiscoverRepository.class);
|
||||
}
|
||||
|
||||
public static DiscoverService getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new DiscoverService();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void topicalExplore(final String maxId,
|
||||
final ServiceCallback<TopicalExploreFeedResponse> callback) {
|
||||
final ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder()
|
||||
.put("module", "explore_popular");
|
||||
if (!TextUtils.isEmpty(maxId)) {
|
||||
builder.put("max_id", maxId);
|
||||
}
|
||||
final Call<TopicalExploreFeedResponse> req = repository.topicalExplore(builder.build());
|
||||
req.enqueue(new Callback<TopicalExploreFeedResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<TopicalExploreFeedResponse> call,
|
||||
@NonNull final Response<TopicalExploreFeedResponse> response) {
|
||||
if (callback == null) return;
|
||||
final TopicalExploreFeedResponse feedResponse = response.body();
|
||||
if (feedResponse == null) {
|
||||
callback.onSuccess(null);
|
||||
return;
|
||||
}
|
||||
callback.onSuccess(feedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<TopicalExploreFeedResponse> call, @NonNull final Throwable t) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package awais.instagrabber.webservices
|
||||
|
||||
import android.util.Log
|
||||
import awais.instagrabber.repositories.FeedService
|
||||
import awais.instagrabber.repositories.responses.Media
|
||||
import awais.instagrabber.repositories.responses.PostsFetchResponse
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse
|
||||
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse
|
||||
import awais.instagrabber.utils.TextUtils.isEmpty
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import java.util.*
|
||||
|
||||
open class FeedRepository(private val repository: FeedService) {
|
||||
suspend fun fetchFeed(
|
||||
csrfToken: String,
|
||||
deviceUuid: String,
|
||||
cursor: String
|
||||
): PostsFetchResponse {
|
||||
val form: MutableMap<String, String> = HashMap()
|
||||
form["_uuid"] = deviceUuid
|
||||
form["_csrftoken"] = csrfToken
|
||||
form["phone_id"] = UUID.randomUUID().toString()
|
||||
form["device_id"] = UUID.randomUUID().toString()
|
||||
form["client_session_id"] = UUID.randomUUID().toString()
|
||||
form["is_prefetch"] = "0"
|
||||
if (!isEmpty(cursor)) {
|
||||
form["max_id"] = cursor
|
||||
form["reason"] = "pagination"
|
||||
} else {
|
||||
form["is_pull_to_refresh"] = "1"
|
||||
form["reason"] = "pull_to_refresh"
|
||||
}
|
||||
return parseResponse(repository.fetchFeed(form.toMap()))
|
||||
}
|
||||
|
||||
suspend fun topicalExplore(maxId: String): TopicalExploreFeedResponse? {
|
||||
val builder = ImmutableMap.builder<String, String>().put("module", "explore_popular")
|
||||
if (!isEmpty(maxId)) {
|
||||
builder.put("max_id", maxId)
|
||||
}
|
||||
return repository.topicalExplore(builder.build())
|
||||
}
|
||||
|
||||
private fun parseResponse(feedFetchResponse: FeedFetchResponse): PostsFetchResponse {
|
||||
val moreAvailable = feedFetchResponse.isMoreAvailable
|
||||
var nextMaxId = feedFetchResponse.nextMaxId
|
||||
val needNewMaxId = nextMaxId == "feed_recs_head_load"
|
||||
val allPosts: MutableList<Media> = ArrayList()
|
||||
val items = feedFetchResponse.items
|
||||
for (media in items) {
|
||||
if (needNewMaxId && media!!.endOfFeedDemarcator != null) {
|
||||
val endOfFeedDemarcator = media.endOfFeedDemarcator
|
||||
val groupSet = endOfFeedDemarcator!!.groupSet ?: continue
|
||||
val groups = groupSet.groups ?: continue
|
||||
for (group in groups) {
|
||||
val id = group.id
|
||||
if (id == null || id != "past_posts") continue
|
||||
nextMaxId = group.nextMaxId
|
||||
val feedItems = group.feedItems
|
||||
for (feedItem in feedItems) {
|
||||
if (feedItem == null || feedItem.isInjected() || feedItem.type == null) continue
|
||||
allPosts.add(feedItem)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (media == null || media.isInjected() || media.type == null) continue
|
||||
allPosts.add(media)
|
||||
}
|
||||
return PostsFetchResponse(allPosts, moreAvailable, nextMaxId)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Volatile
|
||||
private var INSTANCE: FeedRepository? = null
|
||||
|
||||
fun getInstance(): FeedRepository {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
val service = RetrofitFactory.retrofit.create(FeedService::class.java)
|
||||
FeedRepository(service).also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
package awais.instagrabber.webservices;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import awais.instagrabber.repositories.FeedRepository;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator;
|
||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroup;
|
||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroupSet;
|
||||
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class FeedService {
|
||||
private static final String TAG = "FeedService";
|
||||
|
||||
private final FeedRepository repository;
|
||||
|
||||
private static FeedService instance;
|
||||
|
||||
private FeedService() {
|
||||
repository = RetrofitFactory.INSTANCE
|
||||
.getRetrofit()
|
||||
.create(FeedRepository.class);
|
||||
}
|
||||
|
||||
public static FeedService getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new FeedService();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void fetch(final String csrfToken,
|
||||
final String deviceUuid,
|
||||
final String cursor,
|
||||
final ServiceCallback<PostsFetchResponse> callback) {
|
||||
final Map<String, String> form = new HashMap<>();
|
||||
form.put("_uuid", deviceUuid);
|
||||
form.put("_csrftoken", csrfToken);
|
||||
form.put("phone_id", UUID.randomUUID().toString());
|
||||
form.put("device_id", UUID.randomUUID().toString());
|
||||
form.put("client_session_id", UUID.randomUUID().toString());
|
||||
form.put("is_prefetch", "0");
|
||||
if (!TextUtils.isEmpty(cursor)) {
|
||||
form.put("max_id", cursor);
|
||||
form.put("reason", "pagination");
|
||||
} else {
|
||||
form.put("is_pull_to_refresh", "1");
|
||||
form.put("reason", "pull_to_refresh");
|
||||
}
|
||||
final Call<FeedFetchResponse> request = repository.fetch(form);
|
||||
request.enqueue(new Callback<FeedFetchResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<FeedFetchResponse> call, @NonNull final Response<FeedFetchResponse> response) {
|
||||
try {
|
||||
// Log.d(TAG, "onResponse: body: " + response.body());
|
||||
final PostsFetchResponse postsFetchResponse = parseResponse(response);
|
||||
if (callback != null) {
|
||||
callback.onSuccess(postsFetchResponse);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onResponse", e);
|
||||
if (callback != null) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<FeedFetchResponse> call, @NonNull final Throwable t) {
|
||||
if (callback != null) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PostsFetchResponse parseResponse(@NonNull final Response<FeedFetchResponse> response) {
|
||||
final FeedFetchResponse feedFetchResponse = response.body();
|
||||
if (feedFetchResponse == null) {
|
||||
Log.e(TAG, "parseResponse: feed response body is empty with status code: " + response.code());
|
||||
return new PostsFetchResponse(Collections.emptyList(), false, null);
|
||||
}
|
||||
return parseResponseBody(feedFetchResponse);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PostsFetchResponse parseResponseBody(@NonNull final FeedFetchResponse feedFetchResponse) {
|
||||
final boolean moreAvailable = feedFetchResponse.isMoreAvailable();
|
||||
String nextMaxId = feedFetchResponse.getNextMaxId();
|
||||
final boolean needNewMaxId = nextMaxId.equals("feed_recs_head_load");
|
||||
final List<Media> allPosts = new ArrayList<>();
|
||||
final List<Media> items = feedFetchResponse.getItems();
|
||||
for (final Media media : items) {
|
||||
if (needNewMaxId && media.getEndOfFeedDemarcator() != null) {
|
||||
final EndOfFeedDemarcator endOfFeedDemarcator = media.getEndOfFeedDemarcator();
|
||||
final EndOfFeedGroupSet groupSet = endOfFeedDemarcator.getGroupSet();
|
||||
if (groupSet == null) continue;
|
||||
final List<EndOfFeedGroup> groups = groupSet.getGroups();
|
||||
if (groups == null) continue;
|
||||
for (final EndOfFeedGroup group : groups) {
|
||||
final String id = group.getId();
|
||||
if (id == null || !id.equals("past_posts")) continue;
|
||||
nextMaxId = group.getNextMaxId();
|
||||
final List<Media> feedItems = group.getFeedItems();
|
||||
for (final Media feedItem : feedItems) {
|
||||
if (feedItem == null || feedItem.isInjected() || feedItem.getType() == null) continue;
|
||||
allPosts.add(feedItem);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (media == null || media.isInjected() || media.getType() == null) continue;
|
||||
allPosts.add(media);
|
||||
}
|
||||
return new PostsFetchResponse(allPosts, moreAvailable, nextMaxId);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user