instagram is not returning most data in graphql anymore so mitigation has been implemented, but again they need to stop trampling on the rights of anonymous users
This commit is contained in:
parent
133abcca85
commit
f67d3a023c
@ -10,8 +10,8 @@ android {
|
|||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
|
|
||||||
versionCode 52
|
versionCode 53
|
||||||
versionName '19.0.0'
|
versionName '19.0.1'
|
||||||
|
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
binding.postImage.setAspectRatio(1);
|
binding.postImage.setAspectRatio(1);
|
||||||
}
|
}
|
||||||
if (layoutPreferences.isAvatarVisible()) {
|
if (layoutPreferences.isAvatarVisible()) {
|
||||||
binding.profilePic.setVisibility(View.VISIBLE);
|
binding.profilePic.setVisibility(TextUtils.isEmpty(feedModel.getProfileModel().getSdProfilePic()) ? View.GONE : View.VISIBLE);
|
||||||
binding.profilePic.setImageURI(feedModel.getProfileModel().getSdProfilePic());
|
binding.profilePic.setImageURI(feedModel.getProfileModel().getSdProfilePic());
|
||||||
final ViewGroup.LayoutParams layoutParams = binding.profilePic.getLayoutParams();
|
final ViewGroup.LayoutParams layoutParams = binding.profilePic.getLayoutParams();
|
||||||
@DimenRes final int dimenRes;
|
@DimenRes final int dimenRes;
|
||||||
@ -88,7 +88,7 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
binding.profilePic.setVisibility(View.GONE);
|
binding.profilePic.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
if (layoutPreferences.isNameVisible()) {
|
if (layoutPreferences.isNameVisible()) {
|
||||||
binding.name.setVisibility(View.VISIBLE);
|
binding.name.setVisibility(TextUtils.isEmpty(feedModel.getProfileModel().getUsername()) ? View.GONE : View.VISIBLE);
|
||||||
binding.name.setText(feedModel.getProfileModel().getUsername());
|
binding.name.setText(feedModel.getProfileModel().getUsername());
|
||||||
} else {
|
} else {
|
||||||
binding.name.setVisibility(View.GONE);
|
binding.name.setVisibility(View.GONE);
|
||||||
|
@ -14,16 +14,36 @@ public class HashtagPostFetchService implements PostFetcher.PostFetchService {
|
|||||||
private final TagsService tagsService;
|
private final TagsService tagsService;
|
||||||
private final HashtagModel hashtagModel;
|
private final HashtagModel hashtagModel;
|
||||||
private String nextMaxId;
|
private String nextMaxId;
|
||||||
private boolean moreAvailable;
|
private boolean moreAvailable, isLoggedIn;
|
||||||
|
|
||||||
public HashtagPostFetchService(final HashtagModel hashtagModel) {
|
public HashtagPostFetchService(final HashtagModel hashtagModel, final boolean isLoggedIn) {
|
||||||
this.hashtagModel = hashtagModel;
|
this.hashtagModel = hashtagModel;
|
||||||
|
this.isLoggedIn = isLoggedIn;
|
||||||
tagsService = TagsService.getInstance();
|
tagsService = TagsService.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetch(final FetchListener<List<FeedModel>> fetchListener) {
|
public void fetch(final FetchListener<List<FeedModel>> fetchListener) {
|
||||||
tagsService.fetchPosts(hashtagModel.getName().toLowerCase(), nextMaxId, new ServiceCallback<TagPostsFetchResponse>() {
|
if (isLoggedIn) tagsService.fetchPosts(hashtagModel.getName().toLowerCase(), nextMaxId, new ServiceCallback<TagPostsFetchResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final TagPostsFetchResponse result) {
|
||||||
|
if (result == null) return;
|
||||||
|
nextMaxId = result.getNextMaxId();
|
||||||
|
moreAvailable = result.isMoreAvailable();
|
||||||
|
if (fetchListener != null) {
|
||||||
|
fetchListener.onResult(result.getItems());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(final Throwable t) {
|
||||||
|
// Log.e(TAG, "onFailure: ", t);
|
||||||
|
if (fetchListener != null) {
|
||||||
|
fetchListener.onFailure(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
else tagsService.fetchGraphQLPosts(hashtagModel.getName().toLowerCase(), nextMaxId, new ServiceCallback<TagPostsFetchResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(final TagPostsFetchResponse result) {
|
public void onSuccess(final TagPostsFetchResponse result) {
|
||||||
if (result == null) return;
|
if (result == null) return;
|
||||||
|
@ -352,7 +352,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
private void setupPosts() {
|
private void setupPosts() {
|
||||||
binding.posts.setViewModelStoreOwner(this)
|
binding.posts.setViewModelStoreOwner(this)
|
||||||
.setLifeCycleOwner(this)
|
.setLifeCycleOwner(this)
|
||||||
.setPostFetchService(new HashtagPostFetchService(hashtagModel))
|
.setPostFetchService(new HashtagPostFetchService(hashtagModel, isLoggedIn))
|
||||||
.setLayoutPreferences(PostsLayoutPreferences.fromJson(settingsHelper.getString(Constants.PREF_HASHTAG_POSTS_LAYOUT)))
|
.setLayoutPreferences(PostsLayoutPreferences.fromJson(settingsHelper.getString(Constants.PREF_HASHTAG_POSTS_LAYOUT)))
|
||||||
.addFetchStatusChangeListener(fetching -> updateSwipeRefreshState())
|
.addFetchStatusChangeListener(fetching -> updateSwipeRefreshState())
|
||||||
.setFeedItemCallback(feedItemCallback)
|
.setFeedItemCallback(feedItemCallback)
|
||||||
|
@ -112,7 +112,7 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
private StoryModel currentStory;
|
private StoryModel currentStory;
|
||||||
private int slidePos;
|
private int slidePos;
|
||||||
private int lastSlidePos;
|
private int lastSlidePos;
|
||||||
private String url, username;
|
private String url;
|
||||||
private PollModel poll;
|
private PollModel poll;
|
||||||
private QuestionModel question;
|
private QuestionModel question;
|
||||||
private String[] mentions;
|
private String[] mentions;
|
||||||
@ -498,7 +498,7 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
} else if (!TextUtils.isEmpty(fragmentArgs.getProfileId()) && !TextUtils.isEmpty(fragmentArgs.getUsername())) {
|
} else if (!TextUtils.isEmpty(fragmentArgs.getProfileId()) && !TextUtils.isEmpty(fragmentArgs.getUsername())) {
|
||||||
currentStoryMediaId = fragmentArgs.getProfileId();
|
currentStoryMediaId = fragmentArgs.getProfileId();
|
||||||
username = fragmentArgs.getUsername();
|
currentStoryUsername = fragmentArgs.getUsername();
|
||||||
}
|
}
|
||||||
isHashtag = fragmentArgs.getIsHashtag();
|
isHashtag = fragmentArgs.getIsHashtag();
|
||||||
isLoc = fragmentArgs.getIsLoc();
|
isLoc = fragmentArgs.getIsLoc();
|
||||||
@ -534,7 +534,7 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
storiesService.getUserStory(currentStoryMediaId,
|
storiesService.getUserStory(currentStoryMediaId,
|
||||||
username,
|
currentStoryUsername,
|
||||||
isLoc,
|
isLoc,
|
||||||
isHashtag,
|
isHashtag,
|
||||||
isHighlight,
|
isHighlight,
|
||||||
|
@ -39,10 +39,10 @@ public class AboutFragment extends BasePreferencesFragment {
|
|||||||
//thirdPartyCategory.setSummary(R.string.about_category_3pt_summary);
|
//thirdPartyCategory.setSummary(R.string.about_category_3pt_summary);
|
||||||
thirdPartyCategory.setIconSpaceReserved(false);
|
thirdPartyCategory.setIconSpaceReserved(false);
|
||||||
// alphabetical order!!!
|
// alphabetical order!!!
|
||||||
|
thirdPartyCategory.addPreference(getACIPreference());
|
||||||
thirdPartyCategory.addPreference(getAutolinkPreference());
|
thirdPartyCategory.addPreference(getAutolinkPreference());
|
||||||
thirdPartyCategory.addPreference(getExoPlayerPreference());
|
thirdPartyCategory.addPreference(getExoPlayerPreference());
|
||||||
thirdPartyCategory.addPreference(getFrescoPreference());
|
thirdPartyCategory.addPreference(getFrescoPreference());
|
||||||
thirdPartyCategory.addPreference(getIcafePreference());
|
|
||||||
thirdPartyCategory.addPreference(getJsoupPreference());
|
thirdPartyCategory.addPreference(getJsoupPreference());
|
||||||
thirdPartyCategory.addPreference(getMDIPreference());
|
thirdPartyCategory.addPreference(getMDIPreference());
|
||||||
thirdPartyCategory.addPreference(getRetrofitPreference());
|
thirdPartyCategory.addPreference(getRetrofitPreference());
|
||||||
@ -101,7 +101,7 @@ public class AboutFragment extends BasePreferencesFragment {
|
|||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
final Preference preference = new Preference(context);
|
final Preference preference = new Preference(context);
|
||||||
preference.setTitle("Retrofit");
|
preference.setTitle("Retrofit");
|
||||||
preference.setSummary("Copyright 2013 Square, Inc. Apache Version 2.0.");
|
preference.setSummary("Copyright 2013 Square, Inc. Apache 2.0.");
|
||||||
preference.setIconSpaceReserved(false);
|
preference.setIconSpaceReserved(false);
|
||||||
preference.setOnPreferenceClickListener(p -> {
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
@ -149,7 +149,7 @@ public class AboutFragment extends BasePreferencesFragment {
|
|||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
final Preference preference = new Preference(context);
|
final Preference preference = new Preference(context);
|
||||||
preference.setTitle("ExoPlayer");
|
preference.setTitle("ExoPlayer");
|
||||||
preference.setSummary("Copyright (C) 2016 The Android Open Source Project. Apache Version 2.0.");
|
preference.setSummary("Copyright (C) 2016 The Android Open Source Project. Apache 2.0.");
|
||||||
preference.setIconSpaceReserved(false);
|
preference.setIconSpaceReserved(false);
|
||||||
preference.setOnPreferenceClickListener(p -> {
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
@ -165,7 +165,7 @@ public class AboutFragment extends BasePreferencesFragment {
|
|||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
final Preference preference = new Preference(context);
|
final Preference preference = new Preference(context);
|
||||||
preference.setTitle("Material Design Icons");
|
preference.setTitle("Material Design Icons");
|
||||||
preference.setSummary("Copyright (C) 2014 Austin Andrews & Google LLC. Apache Version 2.0.");
|
preference.setSummary("Copyright (C) 2014 Austin Andrews & Google LLC. Apache 2.0.");
|
||||||
preference.setIconSpaceReserved(false);
|
preference.setIconSpaceReserved(false);
|
||||||
preference.setOnPreferenceClickListener(p -> {
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
@ -181,7 +181,7 @@ public class AboutFragment extends BasePreferencesFragment {
|
|||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
final Preference preference = new Preference(context);
|
final Preference preference = new Preference(context);
|
||||||
preference.setTitle("AutoLinkTextViewV2");
|
preference.setTitle("AutoLinkTextViewV2");
|
||||||
preference.setSummary("Copyright (C) 2019 Arman Chatikyan. Apache Version 2.0.");
|
preference.setSummary("Copyright (C) 2019 Arman Chatikyan. Apache 2.0.");
|
||||||
preference.setIconSpaceReserved(false);
|
preference.setIconSpaceReserved(false);
|
||||||
preference.setOnPreferenceClickListener(p -> {
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
@ -192,16 +192,16 @@ public class AboutFragment extends BasePreferencesFragment {
|
|||||||
return preference;
|
return preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Preference getIcafePreference() {
|
private Preference getACIPreference() {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
final Preference preference = new Preference(context);
|
final Preference preference = new Preference(context);
|
||||||
preference.setTitle("ICAFE");
|
preference.setTitle("Apache Commons Imaging");
|
||||||
preference.setSummary("Copyright (C) 2014-2019 Wen Yu. Eclipse Version 2.0.");
|
preference.setSummary("Copyright 2007-2020 The Apache Software Foundation. Apache 2.0.");
|
||||||
preference.setIconSpaceReserved(false);
|
preference.setIconSpaceReserved(false);
|
||||||
preference.setOnPreferenceClickListener(p -> {
|
preference.setOnPreferenceClickListener(p -> {
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
intent.setData(Uri.parse("https://github.com/dragon66/icafe"));
|
intent.setData(Uri.parse("https://commons.apache.org/proper/commons-imaging/"));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -24,4 +24,7 @@ public interface TagsRepository {
|
|||||||
@GET("/api/v1/feed/tag/{tag}/")
|
@GET("/api/v1/feed/tag/{tag}/")
|
||||||
Call<String> fetchPosts(@Path("tag") final String tag,
|
Call<String> fetchPosts(@Path("tag") final String tag,
|
||||||
@QueryMap Map<String, String> queryParams);
|
@QueryMap Map<String, String> queryParams);
|
||||||
|
|
||||||
|
@GET("/graphql/query/")
|
||||||
|
Call<String> fetchGraphQLPosts(@QueryMap(encoded = true) Map<String, String> queryParams);
|
||||||
}
|
}
|
||||||
|
@ -665,6 +665,124 @@ public final class ResponseBodyUtils {
|
|||||||
return feedModelBuilder.build();
|
return feedModelBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FeedModel parseGraphQLItem(final JSONObject itemJson) throws JSONException {
|
||||||
|
if (itemJson == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final JSONObject feedItem = itemJson.getJSONObject("node");
|
||||||
|
final String mediaType = feedItem.optString("__typename");
|
||||||
|
if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
final boolean isVideo = feedItem.optBoolean("is_video");
|
||||||
|
final long videoViews = feedItem.optLong("video_view_count", 0);
|
||||||
|
|
||||||
|
final String displayUrl = feedItem.optString("display_url");
|
||||||
|
if (TextUtils.isEmpty(displayUrl)) return null;
|
||||||
|
final String resourceUrl;
|
||||||
|
if (isVideo && feedItem.has("video_url")) {
|
||||||
|
resourceUrl = feedItem.getString("video_url");
|
||||||
|
} else {
|
||||||
|
resourceUrl = feedItem.has("display_resources") ? ResponseBodyUtils.getHighQualityImage(feedItem) : displayUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfileModel profileModel = null;
|
||||||
|
if (feedItem.has("owner")) {
|
||||||
|
final JSONObject owner = feedItem.getJSONObject("owner");
|
||||||
|
profileModel = new ProfileModel(
|
||||||
|
owner.optBoolean("is_private"),
|
||||||
|
false, // if you can see it then you def follow
|
||||||
|
owner.optBoolean("is_verified"),
|
||||||
|
owner.getString(Constants.EXTRAS_ID),
|
||||||
|
owner.optString(Constants.EXTRAS_USERNAME),
|
||||||
|
owner.optString("full_name"),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
owner.optString("profile_pic_url"),
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
JSONObject tempJsonObject = feedItem.optJSONObject("edge_media_preview_comment");
|
||||||
|
final long commentsCount = tempJsonObject != null ? tempJsonObject.optLong("count") : 0;
|
||||||
|
tempJsonObject = feedItem.optJSONObject("edge_media_preview_like");
|
||||||
|
final long likesCount = tempJsonObject != null ? tempJsonObject.optLong("count") : 0;
|
||||||
|
tempJsonObject = feedItem.optJSONObject("edge_media_to_caption");
|
||||||
|
final JSONArray captions = tempJsonObject != null ? tempJsonObject.getJSONArray("edges") : null;
|
||||||
|
String captionText = null;
|
||||||
|
if (captions != null && captions.length() > 0) {
|
||||||
|
if ((tempJsonObject = captions.optJSONObject(0)) != null &&
|
||||||
|
(tempJsonObject = tempJsonObject.optJSONObject("node")) != null) {
|
||||||
|
captionText = tempJsonObject.getString("text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final JSONObject location = feedItem.optJSONObject("location");
|
||||||
|
// Log.d(TAG, "location: " + (location == null ? null : location.toString()));
|
||||||
|
String locationId = null;
|
||||||
|
String locationName = null;
|
||||||
|
if (location != null) {
|
||||||
|
locationName = location.optString("name");
|
||||||
|
if (location.has("id")) {
|
||||||
|
locationId = location.getString("id");
|
||||||
|
} else if (location.has("pk")) {
|
||||||
|
locationId = location.getString("pk");
|
||||||
|
}
|
||||||
|
// Log.d(TAG, "locationId: " + locationId);
|
||||||
|
}
|
||||||
|
int height = 0;
|
||||||
|
int width = 0;
|
||||||
|
final JSONObject dimensions = feedItem.optJSONObject("dimensions");
|
||||||
|
if (dimensions != null) {
|
||||||
|
height = dimensions.optInt("height");
|
||||||
|
width = dimensions.optInt("width");
|
||||||
|
}
|
||||||
|
String thumbnailUrl = null;
|
||||||
|
try {
|
||||||
|
thumbnailUrl = feedItem.getJSONArray("display_resources")
|
||||||
|
.getJSONObject(0)
|
||||||
|
.getString("src");
|
||||||
|
} catch (JSONException ignored) {}
|
||||||
|
final FeedModel.Builder feedModelBuilder = new FeedModel.Builder()
|
||||||
|
.setProfileModel(profileModel)
|
||||||
|
.setItemType(isVideo ? MediaItemType.MEDIA_TYPE_VIDEO
|
||||||
|
: MediaItemType.MEDIA_TYPE_IMAGE)
|
||||||
|
.setViewCount(videoViews)
|
||||||
|
.setPostId(feedItem.getString(Constants.EXTRAS_ID))
|
||||||
|
.setDisplayUrl(resourceUrl)
|
||||||
|
.setThumbnailUrl(thumbnailUrl != null ? thumbnailUrl : displayUrl)
|
||||||
|
.setShortCode(feedItem.getString(Constants.EXTRAS_SHORTCODE))
|
||||||
|
.setPostCaption(captionText)
|
||||||
|
.setCommentsCount(commentsCount)
|
||||||
|
.setTimestamp(feedItem.optLong("taken_at_timestamp", -1))
|
||||||
|
.setLiked(feedItem.optBoolean("viewer_has_liked"))
|
||||||
|
.setBookmarked(feedItem.optBoolean("viewer_has_saved"))
|
||||||
|
.setLikesCount(likesCount)
|
||||||
|
.setLocationName(locationName)
|
||||||
|
.setLocationId(locationId)
|
||||||
|
.setImageHeight(height)
|
||||||
|
.setImageWidth(width);
|
||||||
|
|
||||||
|
final boolean isSlider = "GraphSidecar".equals(mediaType) && feedItem.has("edge_sidecar_to_children");
|
||||||
|
|
||||||
|
if (isSlider) {
|
||||||
|
feedModelBuilder.setItemType(MediaItemType.MEDIA_TYPE_SLIDER);
|
||||||
|
final JSONObject sidecar = feedItem.optJSONObject("edge_sidecar_to_children");
|
||||||
|
if (sidecar != null) {
|
||||||
|
final JSONArray children = sidecar.optJSONArray("edges");
|
||||||
|
if (children != null) {
|
||||||
|
final List<PostChild> sliderItems = getSliderItems(children);
|
||||||
|
feedModelBuilder.setSliderItems(sliderItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return feedModelBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
private static List<PostChild> getChildPosts(final JSONObject mediaJson) throws JSONException {
|
private static List<PostChild> getChildPosts(final JSONObject mediaJson) throws JSONException {
|
||||||
if (mediaJson == null) {
|
if (mediaJson == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@ -708,4 +826,42 @@ public final class ResponseBodyUtils {
|
|||||||
.setWidth(childJson.optInt("original_width"))
|
.setWidth(childJson.optInt("original_width"))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is for graphql
|
||||||
|
@NonNull
|
||||||
|
private static List<PostChild> getSliderItems(final JSONArray children) throws JSONException {
|
||||||
|
final List<PostChild> sliderItems = new ArrayList<>();
|
||||||
|
for (int j = 0; j < children.length(); ++j) {
|
||||||
|
final JSONObject childNode = children.optJSONObject(j).getJSONObject("node");
|
||||||
|
final boolean isChildVideo = childNode.optBoolean("is_video");
|
||||||
|
int height = 0;
|
||||||
|
int width = 0;
|
||||||
|
final JSONObject dimensions = childNode.optJSONObject("dimensions");
|
||||||
|
if (dimensions != null) {
|
||||||
|
height = dimensions.optInt("height");
|
||||||
|
width = dimensions.optInt("width");
|
||||||
|
}
|
||||||
|
String thumbnailUrl = null;
|
||||||
|
try {
|
||||||
|
thumbnailUrl = childNode.getJSONArray("display_resources")
|
||||||
|
.getJSONObject(0)
|
||||||
|
.getString("src");
|
||||||
|
} catch (JSONException ignored) {}
|
||||||
|
final PostChild sliderItem = new PostChild.Builder()
|
||||||
|
.setItemType(isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO
|
||||||
|
: MediaItemType.MEDIA_TYPE_IMAGE)
|
||||||
|
.setPostId(childNode.getString(Constants.EXTRAS_ID))
|
||||||
|
.setDisplayUrl(isChildVideo ? childNode.getString("video_url")
|
||||||
|
: childNode.getString("display_url"))
|
||||||
|
.setThumbnailUrl(thumbnailUrl != null ? thumbnailUrl
|
||||||
|
: childNode.getString("display_url"))
|
||||||
|
.setVideoViews(childNode.optLong("video_view_count", 0))
|
||||||
|
.setHeight(height)
|
||||||
|
.setWidth(width)
|
||||||
|
.build();
|
||||||
|
// Log.d(TAG, "getSliderItems: sliderItem: " + sliderItem);
|
||||||
|
sliderItems.add(sliderItem);
|
||||||
|
}
|
||||||
|
return sliderItems;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,157 +150,13 @@ public class FeedService extends BaseService {
|
|||||||
final JSONArray feedItems = timelineFeed.getJSONArray("edges");
|
final JSONArray feedItems = timelineFeed.getJSONArray("edges");
|
||||||
|
|
||||||
for (int i = 0; i < feedItems.length(); ++i) {
|
for (int i = 0; i < feedItems.length(); ++i) {
|
||||||
final JSONObject feedItem = feedItems.getJSONObject(i).getJSONObject("node");
|
final JSONObject itemJson = feedItems.optJSONObject(i);
|
||||||
final String mediaType = feedItem.optString("__typename");
|
if (itemJson == null) {
|
||||||
if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
final boolean isVideo = feedItem.optBoolean("is_video");
|
|
||||||
final long videoViews = feedItem.optLong("video_view_count", 0);
|
|
||||||
|
|
||||||
final String displayUrl = feedItem.optString("display_url");
|
|
||||||
if (TextUtils.isEmpty(displayUrl)) continue;
|
|
||||||
final String resourceUrl;
|
|
||||||
if (isVideo) {
|
|
||||||
resourceUrl = feedItem.getString("video_url");
|
|
||||||
} else {
|
|
||||||
resourceUrl = feedItem.has("display_resources") ? ResponseBodyUtils.getHighQualityImage(feedItem) : displayUrl;
|
|
||||||
}
|
}
|
||||||
|
final FeedModel feedModel = ResponseBodyUtils.parseItem(itemJson);
|
||||||
ProfileModel profileModel = null;
|
|
||||||
if (feedItem.has("owner")) {
|
|
||||||
final JSONObject owner = feedItem.getJSONObject("owner");
|
|
||||||
profileModel = new ProfileModel(
|
|
||||||
owner.optBoolean("is_private"),
|
|
||||||
false, // if you can see it then you def follow
|
|
||||||
owner.optBoolean("is_verified"),
|
|
||||||
owner.getString(Constants.EXTRAS_ID),
|
|
||||||
owner.getString(Constants.EXTRAS_USERNAME),
|
|
||||||
owner.optString("full_name"),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
owner.getString("profile_pic_url"),
|
|
||||||
null,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
JSONObject tempJsonObject = feedItem.optJSONObject("edge_media_preview_comment");
|
|
||||||
final long commentsCount = tempJsonObject != null ? tempJsonObject.optLong("count") : 0;
|
|
||||||
tempJsonObject = feedItem.optJSONObject("edge_media_preview_like");
|
|
||||||
final long likesCount = tempJsonObject != null ? tempJsonObject.optLong("count") : 0;
|
|
||||||
tempJsonObject = feedItem.optJSONObject("edge_media_to_caption");
|
|
||||||
final JSONArray captions = tempJsonObject != null ? tempJsonObject.getJSONArray("edges") : null;
|
|
||||||
String captionText = null;
|
|
||||||
if (captions != null && captions.length() > 0) {
|
|
||||||
if ((tempJsonObject = captions.optJSONObject(0)) != null &&
|
|
||||||
(tempJsonObject = tempJsonObject.optJSONObject("node")) != null) {
|
|
||||||
captionText = tempJsonObject.getString("text");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final JSONObject location = feedItem.optJSONObject("location");
|
|
||||||
// Log.d(TAG, "location: " + (location == null ? null : location.toString()));
|
|
||||||
String locationId = null;
|
|
||||||
String locationName = null;
|
|
||||||
if (location != null) {
|
|
||||||
locationName = location.optString("name");
|
|
||||||
if (location.has("id")) {
|
|
||||||
locationId = location.getString("id");
|
|
||||||
} else if (location.has("pk")) {
|
|
||||||
locationId = location.getString("pk");
|
|
||||||
}
|
|
||||||
// Log.d(TAG, "locationId: " + locationId);
|
|
||||||
}
|
|
||||||
int height = 0;
|
|
||||||
int width = 0;
|
|
||||||
final JSONObject dimensions = feedItem.optJSONObject("dimensions");
|
|
||||||
if (dimensions != null) {
|
|
||||||
height = dimensions.optInt("height");
|
|
||||||
width = dimensions.optInt("width");
|
|
||||||
}
|
|
||||||
String thumbnailUrl = null;
|
|
||||||
try {
|
|
||||||
thumbnailUrl = feedItem.getJSONArray("display_resources")
|
|
||||||
.getJSONObject(0)
|
|
||||||
.getString("src");
|
|
||||||
} catch (JSONException ignored) {}
|
|
||||||
final FeedModel.Builder feedModelBuilder = new FeedModel.Builder()
|
|
||||||
.setProfileModel(profileModel)
|
|
||||||
.setItemType(isVideo ? MediaItemType.MEDIA_TYPE_VIDEO
|
|
||||||
: MediaItemType.MEDIA_TYPE_IMAGE)
|
|
||||||
.setViewCount(videoViews)
|
|
||||||
.setPostId(feedItem.getString(Constants.EXTRAS_ID))
|
|
||||||
.setDisplayUrl(resourceUrl)
|
|
||||||
.setThumbnailUrl(thumbnailUrl != null ? thumbnailUrl : displayUrl)
|
|
||||||
.setShortCode(feedItem.getString(Constants.EXTRAS_SHORTCODE))
|
|
||||||
.setPostCaption(captionText)
|
|
||||||
.setCommentsCount(commentsCount)
|
|
||||||
.setTimestamp(feedItem.optLong("taken_at_timestamp", -1))
|
|
||||||
.setLiked(feedItem.getBoolean("viewer_has_liked"))
|
|
||||||
.setBookmarked(feedItem.getBoolean("viewer_has_saved"))
|
|
||||||
.setLikesCount(likesCount)
|
|
||||||
.setLocationName(locationName)
|
|
||||||
.setLocationId(locationId)
|
|
||||||
.setImageHeight(height)
|
|
||||||
.setImageWidth(width);
|
|
||||||
|
|
||||||
final boolean isSlider = "GraphSidecar".equals(mediaType) && feedItem.has("edge_sidecar_to_children");
|
|
||||||
|
|
||||||
if (isSlider) {
|
|
||||||
feedModelBuilder.setItemType(MediaItemType.MEDIA_TYPE_SLIDER);
|
|
||||||
final JSONObject sidecar = feedItem.optJSONObject("edge_sidecar_to_children");
|
|
||||||
if (sidecar != null) {
|
|
||||||
final JSONArray children = sidecar.optJSONArray("edges");
|
|
||||||
if (children != null) {
|
|
||||||
final List<PostChild> sliderItems = getSliderItems(children);
|
|
||||||
feedModelBuilder.setSliderItems(sliderItems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final FeedModel feedModel = feedModelBuilder.build();
|
|
||||||
feedModels.add(feedModel);
|
feedModels.add(feedModel);
|
||||||
}
|
}
|
||||||
return new PostsFetchResponse(feedModels, hasNextPage, endCursor);
|
return new PostsFetchResponse(feedModels, hasNextPage, endCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private List<PostChild> getSliderItems(final JSONArray children) throws JSONException {
|
|
||||||
final List<PostChild> sliderItems = new ArrayList<>();
|
|
||||||
for (int j = 0; j < children.length(); ++j) {
|
|
||||||
final JSONObject childNode = children.optJSONObject(j).getJSONObject("node");
|
|
||||||
final boolean isChildVideo = childNode.optBoolean("is_video");
|
|
||||||
int height = 0;
|
|
||||||
int width = 0;
|
|
||||||
final JSONObject dimensions = childNode.optJSONObject("dimensions");
|
|
||||||
if (dimensions != null) {
|
|
||||||
height = dimensions.optInt("height");
|
|
||||||
width = dimensions.optInt("width");
|
|
||||||
}
|
|
||||||
String thumbnailUrl = null;
|
|
||||||
try {
|
|
||||||
thumbnailUrl = childNode.getJSONArray("display_resources")
|
|
||||||
.getJSONObject(0)
|
|
||||||
.getString("src");
|
|
||||||
} catch (JSONException ignored) {}
|
|
||||||
final PostChild sliderItem = new PostChild.Builder()
|
|
||||||
.setItemType(isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO
|
|
||||||
: MediaItemType.MEDIA_TYPE_IMAGE)
|
|
||||||
.setPostId(childNode.getString(Constants.EXTRAS_ID))
|
|
||||||
.setDisplayUrl(isChildVideo ? childNode.getString("video_url")
|
|
||||||
: childNode.getString("display_url"))
|
|
||||||
.setThumbnailUrl(thumbnailUrl != null ? thumbnailUrl
|
|
||||||
: childNode.getString("display_url"))
|
|
||||||
.setVideoViews(childNode.optLong("video_view_count", 0))
|
|
||||||
.setHeight(height)
|
|
||||||
.setWidth(width)
|
|
||||||
.build();
|
|
||||||
// Log.d(TAG, "getSliderItems: sliderItem: " + sliderItem);
|
|
||||||
sliderItems.add(sliderItem);
|
|
||||||
}
|
|
||||||
return sliderItems;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,9 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import awais.instagrabber.models.FeedModel;
|
import awais.instagrabber.models.FeedModel;
|
||||||
@ -186,6 +188,82 @@ public class TagsService extends BaseService {
|
|||||||
return feedModels;
|
return feedModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fetchGraphQLPosts(@NonNull final String tag,
|
||||||
|
final String maxId,
|
||||||
|
final ServiceCallback<TagPostsFetchResponse> callback) {
|
||||||
|
final Map<String, String> queryMap = new HashMap<>();
|
||||||
|
queryMap.put("query_hash", "9b498c08113f1e09617a1703c22b2f32");
|
||||||
|
queryMap.put("variables", "{" +
|
||||||
|
"\"tag_name\":\"" + tag + "\"," +
|
||||||
|
"\"first\":25," +
|
||||||
|
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"" +
|
||||||
|
"}");
|
||||||
|
final Call<String> request = webRepository.fetchGraphQLPosts(queryMap);
|
||||||
|
request.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||||
|
try {
|
||||||
|
if (callback == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String body = response.body();
|
||||||
|
if (TextUtils.isEmpty(body)) {
|
||||||
|
callback.onSuccess(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final TagPostsFetchResponse tagPostsFetchResponse = parseGraphQLResponse(body);
|
||||||
|
callback.onSuccess(tagPostsFetchResponse);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(TAG, "onResponse", e);
|
||||||
|
callback.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private TagPostsFetchResponse parseGraphQLResponse(@NonNull final String body) throws JSONException {
|
||||||
|
final JSONObject rootroot = new JSONObject(body);
|
||||||
|
final JSONObject root = rootroot.getJSONObject("data").getJSONObject("hashtag").getJSONObject("edge_hashtag_to_media");
|
||||||
|
final boolean moreAvailable = root.getJSONObject("page_info").optBoolean("has_next_page");
|
||||||
|
final String nextMaxId = root.getJSONObject("page_info").optString("end_cursor");
|
||||||
|
final int numResults = root.optInt("count");
|
||||||
|
final String status = rootroot.optString("status");
|
||||||
|
final JSONArray itemsJson = root.optJSONArray("edges");
|
||||||
|
final List<FeedModel> items = parseGraphQLItems(itemsJson);
|
||||||
|
return new TagPostsFetchResponse(
|
||||||
|
moreAvailable,
|
||||||
|
nextMaxId,
|
||||||
|
numResults,
|
||||||
|
status,
|
||||||
|
items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FeedModel> parseGraphQLItems(final JSONArray items) throws JSONException {
|
||||||
|
if (items == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
final List<FeedModel> feedModels = new ArrayList<>();
|
||||||
|
for (int i = 0; i < items.length(); i++) {
|
||||||
|
final JSONObject itemJson = items.optJSONObject(i);
|
||||||
|
if (itemJson == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson);
|
||||||
|
if (feedModel != null) {
|
||||||
|
feedModels.add(feedModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return feedModels;
|
||||||
|
}
|
||||||
|
|
||||||
public static class TagPostsFetchResponse {
|
public static class TagPostsFetchResponse {
|
||||||
private boolean moreAvailable;
|
private boolean moreAvailable;
|
||||||
private String nextMaxId;
|
private String nextMaxId;
|
||||||
|
Loading…
Reference in New Issue
Block a user