mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 06:37:30 +00:00
Convert MediaRepository and MediaService to kotlin.
This commit is contained in:
parent
708e0fda5b
commit
b997504602
@ -31,6 +31,7 @@ import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavController.OnDestinationChangedListener
|
||||
import androidx.navigation.NavDestination
|
||||
@ -68,6 +69,8 @@ import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.Iterators
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import java.util.stream.Collectors
|
||||
|
||||
@ -81,11 +84,14 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
||||
private var isActivityCheckerServiceBound = false
|
||||
private var isBackStackEmpty = false
|
||||
private var isLoggedIn = false
|
||||
private var deviceUuid: String? = null
|
||||
private var csrfToken: String? = null
|
||||
private var userId: Long = 0
|
||||
|
||||
// private var behavior: HideBottomViewOnScrollBehavior<BottomNavigationView>? = null
|
||||
var currentTabs: List<Tab> = emptyList()
|
||||
private set
|
||||
private var showBottomViewDestinations: List<Int> = emptyList<Int>()
|
||||
private var showBottomViewDestinations: List<Int> = emptyList()
|
||||
private var graphQLService: GraphQLService? = null
|
||||
private var mediaService: MediaService? = null
|
||||
|
||||
@ -157,17 +163,17 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
||||
|
||||
private fun setupCookie() {
|
||||
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
|
||||
var userId: Long = 0
|
||||
var csrfToken: String? = null
|
||||
if (!isEmpty(cookie)) {
|
||||
userId = 0
|
||||
csrfToken = null
|
||||
if (cookie.isNotBlank()) {
|
||||
userId = getUserIdFromCookie(cookie)
|
||||
csrfToken = getCsrfTokenFromCookie(cookie)
|
||||
}
|
||||
if (isEmpty(cookie) || userId == 0L || isEmpty(csrfToken)) {
|
||||
if (cookie.isBlank() || userId == 0L || csrfToken.isNullOrBlank()) {
|
||||
isLoggedIn = false
|
||||
return
|
||||
}
|
||||
val deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
|
||||
if (isEmpty(deviceUuid)) {
|
||||
Utils.settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString())
|
||||
}
|
||||
@ -175,6 +181,7 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
||||
isLoggedIn = true
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private fun initDmService() {
|
||||
if (!isLoggedIn) return
|
||||
val enabled = Utils.settingsHelper.getBoolean(PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH)
|
||||
@ -628,7 +635,9 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
||||
.setView(R.layout.dialog_opening_post)
|
||||
.create()
|
||||
if (graphQLService == null) graphQLService = GraphQLService.getInstance()
|
||||
if (mediaService == null) mediaService = MediaService.getInstance(null, null, 0L)
|
||||
if (mediaService == null) {
|
||||
mediaService = deviceUuid?.let { csrfToken?.let { it1 -> MediaService.getInstance(it, it1, userId) } }
|
||||
}
|
||||
val postCb: ServiceCallback<Media> = object : ServiceCallback<Media> {
|
||||
override fun onSuccess(feedModel: Media?) {
|
||||
if (feedModel != null) {
|
||||
@ -650,7 +659,18 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
||||
}
|
||||
}
|
||||
alertDialog.show()
|
||||
if (isLoggedIn) mediaService?.fetch(shortcodeToId(shortCode), postCb) else graphQLService?.fetchPost(shortCode, postCb)
|
||||
if (isLoggedIn) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val media = mediaService?.fetch(shortcodeToId(shortCode))
|
||||
postCb.onSuccess(media)
|
||||
} catch (e: Exception) {
|
||||
postCb.onFailure(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
graphQLService?.fetchPost(shortCode, postCb)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLocationView(intentModel: IntentModel) {
|
||||
|
@ -25,12 +25,15 @@ import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
|
||||
import awais.instagrabber.databinding.FragmentLikesBinding;
|
||||
import awais.instagrabber.repositories.responses.GraphQLUserListFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.webservices.GraphQLService;
|
||||
import awais.instagrabber.webservices.MediaService;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
import kotlinx.coroutines.Dispatchers;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
@ -104,9 +107,12 @@ public final class LikesViewerFragment extends BottomSheetDialogFragment impleme
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
||||
// final AppCompatActivity fragmentActivity = (AppCompatActivity) getActivity();
|
||||
mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
|
||||
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||
isLoggedIn = !TextUtils.isEmpty(cookie) && userId != 0;
|
||||
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||
if (csrfToken == null) return;
|
||||
mediaService = isLoggedIn ? MediaService.getInstance(deviceUuid, csrfToken, userId) : null;
|
||||
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
||||
// setHasOptionsMenu(true);
|
||||
}
|
||||
@ -130,7 +136,20 @@ public final class LikesViewerFragment extends BottomSheetDialogFragment impleme
|
||||
if (isComment && !isLoggedIn) {
|
||||
lazyLoader.resetState();
|
||||
graphQLService.fetchCommentLikers(postId, null, anonCb);
|
||||
} else mediaService.fetchLikes(postId, isComment, cb);
|
||||
} else {
|
||||
mediaService.fetchLikes(
|
||||
postId,
|
||||
isComment,
|
||||
CoroutineUtilsKt.getContinuation((users, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
cb.onFailure(throwable);
|
||||
return;
|
||||
}
|
||||
//noinspection unchecked
|
||||
cb.onSuccess((List<User>) users);
|
||||
}), Dispatchers.getIO())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
@ -35,12 +35,13 @@ import awais.instagrabber.databinding.FragmentNotificationsViewerBinding;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationImage;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.viewmodels.NotificationViewModel;
|
||||
@ -48,6 +49,7 @@ import awais.instagrabber.webservices.FriendshipService;
|
||||
import awais.instagrabber.webservices.MediaService;
|
||||
import awais.instagrabber.webservices.NewsService;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
import kotlinx.coroutines.Dispatchers;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
@ -106,26 +108,25 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
||||
.setView(R.layout.dialog_opening_post)
|
||||
.create();
|
||||
alertDialog.show();
|
||||
mediaService.fetch(mediaId, new ServiceCallback<Media>() {
|
||||
@Override
|
||||
public void onSuccess(final Media feedModel) {
|
||||
mediaService.fetch(
|
||||
mediaId,
|
||||
CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
alertDialog.dismiss();
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
final NavController navController = NavHostFragment.findNavController(NotificationsViewerFragment.this);
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
|
||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
|
||||
try {
|
||||
navController.navigate(R.id.action_global_post_view, bundle);
|
||||
alertDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onSuccess: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
alertDialog.dismiss();
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}), Dispatchers.getIO())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,11 +219,11 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
|
||||
if (TextUtils.isEmpty(cookie)) {
|
||||
Toast.makeText(context, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
mediaService = MediaService.getInstance(null, null, 0);
|
||||
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||
deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
|
||||
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
|
||||
mediaService = MediaService.getInstance(deviceUuid, csrfToken, userId);
|
||||
newsService = NewsService.getInstance();
|
||||
}
|
||||
|
||||
|
@ -85,8 +85,8 @@ import awais.instagrabber.models.stickers.SwipeUpModel;
|
||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||
import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
|
||||
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.StoryStickerResponse;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||
@ -159,7 +159,7 @@ public class StoryViewerFragment extends Fragment {
|
||||
final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||
fragmentActivity = (AppCompatActivity) requireActivity();
|
||||
storiesService = StoriesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
||||
mediaService = MediaService.getInstance(null, null, 0);
|
||||
mediaService = MediaService.getInstance(deviceId, csrfToken, userIdFromCookie);
|
||||
directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
@ -220,7 +220,7 @@ public class StoryViewerFragment extends Fragment {
|
||||
.setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread(
|
||||
Collections.singletonList(currentStory.getUserId()),
|
||||
null,
|
||||
CoroutineUtilsKt.getContinuation((thread, throwable) -> {
|
||||
CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
Log.e(TAG, "onOptionsItemSelected: ", throwable);
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
@ -231,17 +231,19 @@ public class StoryViewerFragment extends Fragment {
|
||||
input.getText().toString(),
|
||||
currentStory.getStoryMediaId(),
|
||||
String.valueOf(currentStory.getUserId()),
|
||||
CoroutineUtilsKt.getContinuation((directThreadBroadcastResponse, throwable1) -> {
|
||||
CoroutineUtilsKt.getContinuation(
|
||||
(directThreadBroadcastResponse, throwable1) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable1 != null) {
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "onFailure: ", throwable1);
|
||||
return;
|
||||
}
|
||||
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||
}, Dispatchers.getIO())
|
||||
}), Dispatchers.getIO()
|
||||
)
|
||||
|
||||
);
|
||||
}, Dispatchers.getIO())
|
||||
}), Dispatchers.getIO())
|
||||
))
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
@ -451,26 +453,25 @@ public class StoryViewerFragment extends Fragment {
|
||||
.setView(R.layout.dialog_opening_post)
|
||||
.create();
|
||||
alertDialog.show();
|
||||
mediaService.fetch(Long.parseLong(mediaId), new ServiceCallback<Media>() {
|
||||
@Override
|
||||
public void onSuccess(final Media feedModel) {
|
||||
mediaService.fetch(
|
||||
Long.parseLong(mediaId),
|
||||
CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
alertDialog.dismiss();
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
final NavController navController = NavHostFragment.findNavController(StoryViewerFragment.this);
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
|
||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
|
||||
try {
|
||||
navController.navigate(R.id.action_global_post_view, bundle);
|
||||
alertDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "openPostDialog: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
alertDialog.dismiss();
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}), Dispatchers.getIO())
|
||||
);
|
||||
});
|
||||
final View.OnClickListener storyActionListener = v -> {
|
||||
final Object tag = v.getTag();
|
||||
|
@ -55,6 +55,7 @@ import awais.instagrabber.viewmodels.ImageEditViewModel;
|
||||
import jp.co.cyberagent.android.gpuimage.GPUImage;
|
||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
|
||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilterGroup;
|
||||
import kotlinx.coroutines.Dispatchers;
|
||||
|
||||
public class FiltersFragment extends Fragment {
|
||||
private static final String TAG = FiltersFragment.class.getSimpleName();
|
||||
@ -461,7 +462,10 @@ public class FiltersFragment extends Fragment {
|
||||
filtersAdapter.setSelected(position);
|
||||
appliedFilter = filter;
|
||||
};
|
||||
BitmapUtils.getThumbnail(context, sourceUri, CoroutineUtilsKt.getContinuation((bitmapResult, throwable) -> {
|
||||
BitmapUtils.getThumbnail(
|
||||
context,
|
||||
sourceUri,
|
||||
CoroutineUtilsKt.getContinuation((bitmapResult, throwable) -> appExecutors.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
Log.e(TAG, "setupFilters: ", throwable);
|
||||
return;
|
||||
@ -478,14 +482,13 @@ public class FiltersFragment extends Fragment {
|
||||
bitmapResult.getBitmap(),
|
||||
onFilterClickListener
|
||||
);
|
||||
appExecutors.getMainThread().execute(() -> {
|
||||
binding.filters.setAdapter(filtersAdapter);
|
||||
filtersAdapter.submitList(FiltersHelper.getFilters(), () -> {
|
||||
if (appliedFilter == null) return;
|
||||
filtersAdapter.setSelectedFilter(appliedFilter.getInstance());
|
||||
});
|
||||
});
|
||||
}));
|
||||
}), Dispatchers.getIO())
|
||||
);
|
||||
addInitialFilter();
|
||||
binding.preview.setFilter(filterGroup);
|
||||
}
|
||||
|
@ -30,11 +30,16 @@ import awais.instagrabber.fragments.PostViewV2Fragment;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicCluster;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.viewmodels.TopicClusterViewModel;
|
||||
import awais.instagrabber.webservices.DiscoverService;
|
||||
import awais.instagrabber.webservices.MediaService;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
import kotlinx.coroutines.Dispatchers;
|
||||
|
||||
public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
||||
private static final String TAG = "DiscoverFragment";
|
||||
@ -52,7 +57,11 @@ public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
super.onCreate(savedInstanceState);
|
||||
fragmentActivity = (MainActivity) requireActivity();
|
||||
discoverService = DiscoverService.getInstance();
|
||||
mediaService = MediaService.getInstance(null, null, 0);
|
||||
final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
|
||||
final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
||||
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||
mediaService = MediaService.getInstance(deviceUuid, csrfToken, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,29 +113,29 @@ public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
.setView(R.layout.dialog_opening_post)
|
||||
.create();
|
||||
alertDialog.show();
|
||||
mediaService.fetch(Long.valueOf(coverMedia.getPk()), new ServiceCallback<Media>() {
|
||||
@Override
|
||||
public void onSuccess(final Media feedModel) {
|
||||
final String pk = coverMedia.getPk();
|
||||
if (pk == null) return;
|
||||
mediaService.fetch(
|
||||
Long.parseLong(pk),
|
||||
CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
alertDialog.dismiss();
|
||||
try {
|
||||
Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
} catch (Throwable ignored) {}
|
||||
return;
|
||||
}
|
||||
final NavController navController = NavHostFragment.findNavController(DiscoverFragment.this);
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
|
||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
|
||||
try {
|
||||
navController.navigate(R.id.action_global_post_view, bundle);
|
||||
alertDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onSuccess: ", e);
|
||||
Log.e(TAG, "onTopicLongClick: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
alertDialog.dismiss();
|
||||
try {
|
||||
Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
catch (Throwable e) {}
|
||||
}
|
||||
});
|
||||
}), Dispatchers.getIO())
|
||||
);
|
||||
}
|
||||
};
|
||||
final DiscoverTopicsAdapter adapter = new DiscoverTopicsAdapter(otcl);
|
||||
|
@ -84,6 +84,7 @@ import awais.instagrabber.repositories.responses.FriendshipStatus;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.UserProfileContextLink;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||
@ -335,7 +336,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
friendshipService = isLoggedIn ? FriendshipService.getInstance(deviceUuid, csrfToken, myId) : null;
|
||||
directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null;
|
||||
storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null;
|
||||
mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
|
||||
mediaService = isLoggedIn ? MediaService.getInstance(deviceUuid, csrfToken, myId) : null;
|
||||
userService = isLoggedIn ? UserService.getInstance() : null;
|
||||
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
||||
final Context context = getContext();
|
||||
@ -821,11 +822,16 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
Utils.copyText(context, biography);
|
||||
break;
|
||||
case 1:
|
||||
mediaService.translate(String.valueOf(profileModel.getPk()), "3", new ServiceCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(final String result) {
|
||||
mediaService.translate(String.valueOf(profileModel.getPk()), "3", CoroutineUtilsKt.getContinuation(
|
||||
(result, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
Log.e(TAG, "Error translating bio", throwable);
|
||||
Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (TextUtils.isEmpty(result)) {
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
new AlertDialog.Builder(context)
|
||||
@ -833,14 +839,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
.setMessage(result)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
Log.e(TAG, "Error translating bio", t);
|
||||
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}),
|
||||
Dispatchers.getIO()
|
||||
));
|
||||
break;
|
||||
}
|
||||
})
|
||||
@ -1079,7 +1080,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
directMessagesService.createThread(
|
||||
Collections.singletonList(profileModel.getPk()),
|
||||
null,
|
||||
CoroutineUtilsKt.getContinuation((thread, throwable) -> {
|
||||
CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||
if (throwable != null) {
|
||||
Log.e(TAG, "setupCommonListeners: ", throwable);
|
||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
@ -1092,7 +1093,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
inboxManager.addThread(thread, 0);
|
||||
}
|
||||
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
|
||||
}, Dispatchers.getIO())
|
||||
}), Dispatchers.getIO())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -41,8 +41,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
@ -457,40 +455,15 @@ class ThreadManager private constructor(
|
||||
"4",
|
||||
null
|
||||
)
|
||||
val uploadFinishRequest = mediaService.uploadFinish(uploadFinishOptions)
|
||||
uploadFinishRequest.enqueue(object : Callback<String?> {
|
||||
override fun onResponse(call: Call<String?>, response: Response<String?>) {
|
||||
if (response.isSuccessful) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val request = service.broadcastVoice(
|
||||
mediaService.uploadFinish(uploadFinishOptions)
|
||||
val broadcastResponse = service.broadcastVoice(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
uploadDmVoiceOptions.uploadId,
|
||||
waveform,
|
||||
samplingFreq
|
||||
)
|
||||
parseResponse(request, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, directItem))
|
||||
Log.e(TAG, "sendVoice: ", e)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if (response.errorBody() != null) {
|
||||
handleErrorBody(call, response, data)
|
||||
return
|
||||
}
|
||||
data.postValue(error("uploadFinishRequest was not successful and response error body was null", directItem))
|
||||
Log.e(TAG, "uploadFinishRequest was not successful and response error body was null")
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<String?>, t: Throwable) {
|
||||
data.postValue(error(t.message, directItem))
|
||||
Log.e(TAG, "sendVoice: ", t)
|
||||
}
|
||||
})
|
||||
parseResponse(broadcastResponse, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, directItem))
|
||||
Log.e(TAG, "sendVoice: ", e)
|
||||
@ -806,39 +779,15 @@ class ThreadManager private constructor(
|
||||
"2",
|
||||
VideoOptions(duration / 1000f, emptyList(), 0, false)
|
||||
)
|
||||
val uploadFinishRequest = mediaService.uploadFinish(uploadFinishOptions)
|
||||
uploadFinishRequest.enqueue(object : Callback<String?> {
|
||||
override fun onResponse(call: Call<String?>, response: Response<String?>) {
|
||||
if (response.isSuccessful) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val response1 = service.broadcastVideo(
|
||||
mediaService.uploadFinish(uploadFinishOptions)
|
||||
val broadcastResponse = service.broadcastVideo(
|
||||
clientContext,
|
||||
threadIdOrUserIds,
|
||||
uploadDmVideoOptions.uploadId,
|
||||
"",
|
||||
true
|
||||
)
|
||||
parseResponse(response1, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
Log.e(TAG, "sendVideo: ", e)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if (response.errorBody() != null) {
|
||||
handleErrorBody(call, response, data)
|
||||
return
|
||||
}
|
||||
data.postValue(error("uploadFinishRequest was not successful and response error body was null", directItem))
|
||||
Log.e(TAG, "uploadFinishRequest was not successful and response error body was null")
|
||||
}
|
||||
override fun onFailure(call: Call<String?>, t: Throwable) {
|
||||
data.postValue(error(t.message, directItem))
|
||||
Log.e(TAG, "sendVideo: ", t)
|
||||
}
|
||||
})
|
||||
parseResponse(broadcastResponse, data, directItem)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, directItem))
|
||||
Log.e(TAG, "sendVideo: ", e)
|
||||
@ -900,26 +849,6 @@ class ThreadManager private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleErrorBody(
|
||||
call: Call<*>,
|
||||
response: Response<*>,
|
||||
data: MutableLiveData<Resource<Any?>>?,
|
||||
) {
|
||||
try {
|
||||
val string = response.errorBody()?.string() ?: ""
|
||||
val msg = String.format(Locale.US,
|
||||
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
||||
call.request().url().toString(),
|
||||
response.code(),
|
||||
string)
|
||||
data?.postValue(error(msg, null))
|
||||
Log.e(TAG, msg)
|
||||
} catch (e: IOException) {
|
||||
data?.postValue(error(e.message, null))
|
||||
Log.e(TAG, "onResponse: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleInvalidResponse(
|
||||
data: MutableLiveData<Resource<Any?>>,
|
||||
response: MediaUploadResponse,
|
||||
|
@ -1,55 +0,0 @@
|
||||
package awais.instagrabber.repositories;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import awais.instagrabber.repositories.responses.LikersResponse;
|
||||
import awais.instagrabber.repositories.responses.MediaInfoResponse;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.FieldMap;
|
||||
import retrofit2.http.FormUrlEncoded;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Header;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
import retrofit2.http.QueryMap;
|
||||
|
||||
public interface MediaRepository {
|
||||
@GET("/api/v1/media/{mediaId}/info/")
|
||||
Call<MediaInfoResponse> fetch(@Path("mediaId") final long mediaId);
|
||||
|
||||
@GET("/api/v1/media/{mediaId}/{action}/")
|
||||
Call<LikersResponse> fetchLikes(@Path("mediaId") final String mediaId,
|
||||
@Path("action") final String action); // one of "likers" or "comment_likers"
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/{action}/")
|
||||
Call<String> action(@Path("action") final String action,
|
||||
@Path("mediaId") final String mediaId,
|
||||
@FieldMap final Map<String, String> signedForm);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/edit_media/")
|
||||
Call<String> editCaption(@Path("mediaId") final String mediaId,
|
||||
@FieldMap final Map<String, String> signedForm);
|
||||
|
||||
@GET("/api/v1/language/translate/")
|
||||
Call<String> translate(@QueryMap final Map<String, String> form);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/upload_finish/")
|
||||
Call<String> uploadFinish(@Header("retry_context") final String retryContext,
|
||||
@QueryMap Map<String, String> queryParams,
|
||||
@FieldMap final Map<String, String> signedForm);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/delete/")
|
||||
Call<String> delete(@Path("mediaId") final String mediaId,
|
||||
@Query("media_type") final String mediaType,
|
||||
@FieldMap final Map<String, String> signedForm);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/archive/")
|
||||
Call<String> archive(@Path("mediaId") final String mediaId,
|
||||
@FieldMap final Map<String, String> signedForm);
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package awais.instagrabber.repositories
|
||||
|
||||
import awais.instagrabber.repositories.responses.LikersResponse
|
||||
import awais.instagrabber.repositories.responses.MediaInfoResponse
|
||||
import retrofit2.http.*
|
||||
|
||||
interface MediaRepository {
|
||||
@GET("/api/v1/media/{mediaId}/info/")
|
||||
suspend fun fetch(@Path("mediaId") mediaId: Long): MediaInfoResponse
|
||||
|
||||
@GET("/api/v1/media/{mediaId}/{action}/")
|
||||
suspend fun fetchLikes(
|
||||
@Path("mediaId") mediaId: String, // one of "likers" or "comment_likers"
|
||||
@Path("action") action: String,
|
||||
): LikersResponse
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/{action}/")
|
||||
suspend fun action(
|
||||
@Path("action") action: String,
|
||||
@Path("mediaId") mediaId: String,
|
||||
@FieldMap signedForm: Map<String, String>,
|
||||
): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/edit_media/")
|
||||
suspend fun editCaption(
|
||||
@Path("mediaId") mediaId: String,
|
||||
@FieldMap signedForm: Map<String, String>,
|
||||
): String
|
||||
|
||||
@GET("/api/v1/language/translate/")
|
||||
suspend fun translate(@QueryMap form: Map<String, String>): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/upload_finish/")
|
||||
suspend fun uploadFinish(
|
||||
@Header("retry_context") retryContext: String,
|
||||
@QueryMap queryParams: Map<String, String>,
|
||||
@FieldMap signedForm: Map<String, String>,
|
||||
): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/delete/")
|
||||
suspend fun delete(
|
||||
@Path("mediaId") mediaId: String,
|
||||
@Query("media_type") mediaType: String,
|
||||
@FieldMap signedForm: Map<String, String>,
|
||||
): String
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/api/v1/media/{mediaId}/archive/")
|
||||
suspend fun archive(
|
||||
@Path("mediaId") mediaId: String,
|
||||
@FieldMap signedForm: Map<String, String>,
|
||||
): String
|
||||
}
|
@ -26,13 +26,11 @@ object MediaUploader {
|
||||
suspend fun uploadPhoto(
|
||||
uri: Uri,
|
||||
contentResolver: ContentResolver,
|
||||
): MediaUploadResponse {
|
||||
return withContext(Dispatchers.IO) {
|
||||
): MediaUploadResponse = withContext(Dispatchers.IO) {
|
||||
val bitmapResult = BitmapUtils.loadBitmap(contentResolver, uri, 1000f, false)
|
||||
val bitmap = bitmapResult?.bitmap ?: throw IOException("bitmap is null")
|
||||
uploadPhoto(bitmap)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
private suspend fun uploadPhoto(
|
||||
@ -98,8 +96,7 @@ object MediaUploader {
|
||||
}
|
||||
}
|
||||
|
||||
private fun create(mediaType: MediaType, inputStream: InputStream): RequestBody {
|
||||
return object : RequestBody() {
|
||||
private fun create(mediaType: MediaType, inputStream: InputStream): RequestBody = object : RequestBody() {
|
||||
override fun contentType(): MediaType {
|
||||
return mediaType
|
||||
}
|
||||
@ -118,7 +115,6 @@ object MediaUploader {
|
||||
Okio.source(inputStream).use { sink.writeAll(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class MediaUploadResponse(val responseCode: Int, val response: JSONObject?)
|
||||
}
|
@ -23,11 +23,9 @@ import awais.instagrabber.utils.extensions.TAG
|
||||
import awais.instagrabber.utils.getCsrfTokenFromCookie
|
||||
import awais.instagrabber.utils.getUserIdFromCookie
|
||||
import awais.instagrabber.webservices.MediaService
|
||||
import awais.instagrabber.webservices.ServiceCallback
|
||||
import com.google.common.collect.ImmutableList
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
class PostViewV2ViewModel : ViewModel() {
|
||||
@ -127,21 +125,35 @@ class PostViewV2ViewModel : ViewModel() {
|
||||
fun like(): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
data.postValue(loading(null))
|
||||
mediaService?.like(media.pk, getLikeUnlikeCallback(data))
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val mediaId = media.pk ?: return@launch
|
||||
val liked = mediaService?.like(mediaId)
|
||||
updateMediaLikeUnlike(data, liked ?: false)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun unlike(): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
data.postValue(loading(null))
|
||||
mediaService?.unlike(media.pk, getLikeUnlikeCallback(data))
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val mediaId = media.pk ?: return@launch
|
||||
val unliked = mediaService?.unlike(mediaId)
|
||||
updateMediaLikeUnlike(data, unliked ?: false)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
private fun getLikeUnlikeCallback(data: MutableLiveData<Resource<Any?>>): ServiceCallback<Boolean?> {
|
||||
return object : ServiceCallback<Boolean?> {
|
||||
override fun onSuccess(result: Boolean?) {
|
||||
if (result != null && !result) {
|
||||
private fun updateMediaLikeUnlike(data: MutableLiveData<Resource<Any?>>, result: Boolean) {
|
||||
if (!result) {
|
||||
data.postValue(error("", null))
|
||||
return
|
||||
}
|
||||
@ -160,13 +172,6 @@ class PostViewV2ViewModel : ViewModel() {
|
||||
liked.postValue(media.hasLiked)
|
||||
}
|
||||
|
||||
override fun onFailure(t: Throwable) {
|
||||
data.postValue(error(t.message, null))
|
||||
Log.e(TAG, "Error during like/unlike", t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleSave(): LiveData<Resource<Any?>> {
|
||||
return if (!media.hasViewerSaved) {
|
||||
save(null, false)
|
||||
@ -180,24 +185,35 @@ class PostViewV2ViewModel : ViewModel() {
|
||||
fun save(collection: String?, ignoreSaveState: Boolean): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
data.postValue(loading(null))
|
||||
mediaService?.save(media.pk, collection, getSaveUnsaveCallback(data, ignoreSaveState))
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val mediaId = media.pk ?: return@launch
|
||||
val saved = mediaService?.save(mediaId, collection)
|
||||
getSaveUnsaveCallback(data, saved ?: false, ignoreSaveState)
|
||||
} catch (e: Exception) {
|
||||
data.postValue(error(e.message, null))
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun unsave(): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
data.postValue(loading(null))
|
||||
mediaService?.unsave(media.pk, getSaveUnsaveCallback(data, false))
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val mediaId = media.pk ?: return@launch
|
||||
val unsaved = mediaService?.unsave(mediaId)
|
||||
getSaveUnsaveCallback(data, unsaved ?: false, false)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
private fun getSaveUnsaveCallback(
|
||||
data: MutableLiveData<Resource<Any?>>,
|
||||
result: Boolean,
|
||||
ignoreSaveState: Boolean,
|
||||
): ServiceCallback<Boolean?> {
|
||||
return object : ServiceCallback<Boolean?> {
|
||||
override fun onSuccess(result: Boolean?) {
|
||||
if (result != null && !result) {
|
||||
) {
|
||||
if (!result) {
|
||||
data.postValue(error("", null))
|
||||
return
|
||||
}
|
||||
@ -206,53 +222,50 @@ class PostViewV2ViewModel : ViewModel() {
|
||||
saved.postValue(media.hasViewerSaved)
|
||||
}
|
||||
|
||||
override fun onFailure(t: Throwable) {
|
||||
data.postValue(error(t.message, null))
|
||||
Log.e(TAG, "Error during save/unsave", t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCaption(caption: String): LiveData<Resource<Any?>> {
|
||||
val data = MutableLiveData<Resource<Any?>>()
|
||||
data.postValue(loading(null))
|
||||
mediaService?.editCaption(media.pk, caption, object : ServiceCallback<Boolean?> {
|
||||
override fun onSuccess(result: Boolean?) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val postId = media.pk ?: return@launch
|
||||
val result = mediaService?.editCaption(postId, caption)
|
||||
if (result != null && result) {
|
||||
data.postValue(success(""))
|
||||
media.setPostCaption(caption)
|
||||
this@PostViewV2ViewModel.caption.postValue(media.caption)
|
||||
return
|
||||
return@launch
|
||||
}
|
||||
data.postValue(error("", null))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error editing caption", e)
|
||||
data.postValue(error(e.message, null))
|
||||
}
|
||||
|
||||
override fun onFailure(t: Throwable) {
|
||||
Log.e(TAG, "Error editing caption", t)
|
||||
data.postValue(error(t.message, null))
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
fun translateCaption(): LiveData<Resource<String?>> {
|
||||
val data = MutableLiveData<Resource<String?>>()
|
||||
data.postValue(loading(null))
|
||||
val value = caption.value ?: return data
|
||||
mediaService?.translate(value.pk, "1", object : ServiceCallback<String?> {
|
||||
override fun onSuccess(result: String?) {
|
||||
val value = caption.value
|
||||
val pk = value?.pk
|
||||
if (pk == null) {
|
||||
data.postValue(error("caption is null", null))
|
||||
return data
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val result = mediaService?.translate(pk, "1")
|
||||
if (result.isNullOrBlank()) {
|
||||
data.postValue(error("", null))
|
||||
return
|
||||
return@launch
|
||||
}
|
||||
data.postValue(success(result))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error translating comment", e)
|
||||
data.postValue(error(e.message, null))
|
||||
}
|
||||
|
||||
override fun onFailure(t: Throwable) {
|
||||
Log.e(TAG, "Error translating comment", t)
|
||||
data.postValue(error(t.message, null))
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
@ -273,30 +286,19 @@ class PostViewV2ViewModel : ViewModel() {
|
||||
data.postValue(error("media id or type is null", null))
|
||||
return data
|
||||
}
|
||||
val request = mediaService?.delete(mediaId, mediaType)
|
||||
if (request == null) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val response = mediaService?.delete(mediaId, mediaType)
|
||||
if (response == null) {
|
||||
data.postValue(success(Any()))
|
||||
return data
|
||||
}
|
||||
request.enqueue(object : Callback<String?> {
|
||||
override fun onResponse(call: Call<String?>, response: Response<String?>) {
|
||||
if (!response.isSuccessful) {
|
||||
data.postValue(error(R.string.generic_null_response, null))
|
||||
return
|
||||
}
|
||||
val body = response.body()
|
||||
if (body == null) {
|
||||
data.postValue(error(R.string.generic_null_response, null))
|
||||
return
|
||||
return@launch
|
||||
}
|
||||
data.postValue(success(Any()))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "delete: ", e)
|
||||
data.postValue(error(e.message, null))
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<String?>, t: Throwable) {
|
||||
Log.e(TAG, "onFailure: ", t)
|
||||
data.postValue(error(t.message, null))
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
|
@ -1,317 +0,0 @@
|
||||
package awais.instagrabber.webservices;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.MediaRepository;
|
||||
import awais.instagrabber.repositories.requests.Clip;
|
||||
import awais.instagrabber.repositories.requests.UploadFinishOptions;
|
||||
import awais.instagrabber.repositories.requests.VideoOptions;
|
||||
import awais.instagrabber.repositories.responses.LikersResponse;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.MediaInfoResponse;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.DateUtils;
|
||||
import awais.instagrabber.utils.MediaUploadHelper;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class MediaService extends BaseService {
|
||||
private static final String TAG = "MediaService";
|
||||
private static final List<MediaItemType> DELETABLE_ITEMS_TYPES = ImmutableList.of(MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
MediaItemType.MEDIA_TYPE_VIDEO,
|
||||
MediaItemType.MEDIA_TYPE_SLIDER);
|
||||
|
||||
private final MediaRepository repository;
|
||||
private final String deviceUuid, csrfToken;
|
||||
private final long userId;
|
||||
|
||||
private static MediaService instance;
|
||||
|
||||
private MediaService(final String deviceUuid,
|
||||
final String csrfToken,
|
||||
final long userId) {
|
||||
this.deviceUuid = deviceUuid;
|
||||
this.csrfToken = csrfToken;
|
||||
this.userId = userId;
|
||||
repository = RetrofitFactory.INSTANCE
|
||||
.getRetrofit()
|
||||
.create(MediaRepository.class);
|
||||
}
|
||||
|
||||
public String getCsrfToken() {
|
||||
return csrfToken;
|
||||
}
|
||||
|
||||
public String getDeviceUuid() {
|
||||
return deviceUuid;
|
||||
}
|
||||
|
||||
public long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public static MediaService getInstance(final String deviceUuid, final String csrfToken, final long userId) {
|
||||
if (instance == null
|
||||
|| !Objects.equals(instance.getCsrfToken(), csrfToken)
|
||||
|| !Objects.equals(instance.getDeviceUuid(), deviceUuid)
|
||||
|| !Objects.equals(instance.getUserId(), userId)) {
|
||||
instance = new MediaService(deviceUuid, csrfToken, userId);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void fetch(final long mediaId,
|
||||
final ServiceCallback<Media> callback) {
|
||||
final Call<MediaInfoResponse> request = repository.fetch(mediaId);
|
||||
request.enqueue(new Callback<MediaInfoResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<MediaInfoResponse> call,
|
||||
@NonNull final Response<MediaInfoResponse> response) {
|
||||
if (callback == null) return;
|
||||
final MediaInfoResponse mediaInfoResponse = response.body();
|
||||
if (mediaInfoResponse == null || mediaInfoResponse.getItems() == null || mediaInfoResponse.getItems().isEmpty()) {
|
||||
callback.onSuccess(null);
|
||||
return;
|
||||
}
|
||||
callback.onSuccess(mediaInfoResponse.getItems().get(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<MediaInfoResponse> call,
|
||||
@NonNull final Throwable t) {
|
||||
if (callback != null) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void like(final String mediaId,
|
||||
final ServiceCallback<Boolean> callback) {
|
||||
action(mediaId, "like", null, callback);
|
||||
}
|
||||
|
||||
public void unlike(final String mediaId,
|
||||
final ServiceCallback<Boolean> callback) {
|
||||
action(mediaId, "unlike", null, callback);
|
||||
}
|
||||
|
||||
public void save(final String mediaId,
|
||||
final String collection,
|
||||
final ServiceCallback<Boolean> callback) {
|
||||
action(mediaId, "save", collection, callback);
|
||||
}
|
||||
|
||||
public void unsave(final String mediaId,
|
||||
final ServiceCallback<Boolean> callback) {
|
||||
action(mediaId, "unsave", null, callback);
|
||||
}
|
||||
|
||||
private void action(final String mediaId,
|
||||
final String action,
|
||||
final String collection,
|
||||
final ServiceCallback<Boolean> callback) {
|
||||
final Map<String, Object> form = new HashMap<>();
|
||||
form.put("media_id", mediaId);
|
||||
form.put("_csrftoken", csrfToken);
|
||||
form.put("_uid", userId);
|
||||
form.put("_uuid", deviceUuid);
|
||||
// form.put("radio_type", "wifi-none");
|
||||
if (action.equals("save") && !TextUtils.isEmpty(collection)) form.put("added_collection_ids", "[" + collection + "]");
|
||||
// there also exists "removed_collection_ids" which can be used with "save" and "unsave"
|
||||
final Map<String, String> signedForm = Utils.sign(form);
|
||||
final Call<String> request = repository.action(action, mediaId, signedForm);
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call,
|
||||
@NonNull final Response<String> response) {
|
||||
if (callback == null) return;
|
||||
final String body = response.body();
|
||||
if (body == null) {
|
||||
callback.onFailure(new RuntimeException("Returned body is null"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final JSONObject jsonObject = new JSONObject(body);
|
||||
final String status = jsonObject.optString("status");
|
||||
callback.onSuccess(status.equals("ok"));
|
||||
} catch (JSONException e) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<String> call,
|
||||
@NonNull final Throwable t) {
|
||||
if (callback != null) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void editCaption(final String postId,
|
||||
final String newCaption,
|
||||
@NonNull final ServiceCallback<Boolean> callback) {
|
||||
final Map<String, Object> form = new HashMap<>();
|
||||
form.put("_csrftoken", csrfToken);
|
||||
form.put("_uid", userId);
|
||||
form.put("_uuid", deviceUuid);
|
||||
form.put("igtv_feed_preview", "false");
|
||||
form.put("media_id", postId);
|
||||
form.put("caption_text", newCaption);
|
||||
final Map<String, String> signedForm = Utils.sign(form);
|
||||
final Call<String> request = repository.editCaption(postId, signedForm);
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
final String body = response.body();
|
||||
if (body == null) {
|
||||
Log.e(TAG, "Error occurred while editing caption");
|
||||
callback.onSuccess(false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final JSONObject jsonObject = new JSONObject(body);
|
||||
final String status = jsonObject.optString("status");
|
||||
callback.onSuccess(status.equals("ok"));
|
||||
} catch (JSONException e) {
|
||||
// Log.e(TAG, "Error parsing body", e);
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "Error editing caption", t);
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void fetchLikes(final String mediaId,
|
||||
final boolean isComment,
|
||||
@NonNull final ServiceCallback<List<User>> callback) {
|
||||
final Call<LikersResponse> likesRequest = repository.fetchLikes(mediaId, isComment ? "comment_likers" : "likers");
|
||||
likesRequest.enqueue(new Callback<LikersResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<LikersResponse> call, @NonNull final Response<LikersResponse> response) {
|
||||
final LikersResponse likersResponse = response.body();
|
||||
if (likersResponse == null) {
|
||||
Log.e(TAG, "Error occurred while fetching likes of " + mediaId);
|
||||
callback.onSuccess(null);
|
||||
return;
|
||||
}
|
||||
callback.onSuccess(likersResponse.getUsers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<LikersResponse> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "Error getting likes", t);
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void translate(final String id,
|
||||
final String type, // 1 caption 2 comment 3 bio
|
||||
@NonNull final ServiceCallback<String> callback) {
|
||||
final Map<String, String> form = new HashMap<>();
|
||||
form.put("id", String.valueOf(id));
|
||||
form.put("type", type);
|
||||
final Call<String> request = repository.translate(form);
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
final String body = response.body();
|
||||
if (body == null) {
|
||||
Log.e(TAG, "Error occurred while translating");
|
||||
callback.onSuccess(null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final JSONObject jsonObject = new JSONObject(body);
|
||||
final String translation = jsonObject.optString("translation");
|
||||
callback.onSuccess(translation);
|
||||
} catch (JSONException e) {
|
||||
// Log.e(TAG, "Error parsing body", e);
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||
Log.e(TAG, "Error translating", t);
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Call<String> uploadFinish(@NonNull final UploadFinishOptions options) {
|
||||
if (options.getVideoOptions() != null) {
|
||||
final VideoOptions videoOptions = options.getVideoOptions();
|
||||
if (videoOptions.getClips().isEmpty()) {
|
||||
videoOptions.setClips(Collections.singletonList(new Clip(videoOptions.getLength(), options.getSourceType())));
|
||||
}
|
||||
}
|
||||
final String timezoneOffset = String.valueOf(DateUtils.getTimezoneOffset());
|
||||
final ImmutableMap.Builder<String, Object> formBuilder = ImmutableMap.<String, Object>builder()
|
||||
.put("timezone_offset", timezoneOffset)
|
||||
.put("_csrftoken", csrfToken)
|
||||
.put("source_type", options.getSourceType())
|
||||
.put("_uid", String.valueOf(userId))
|
||||
.put("_uuid", deviceUuid)
|
||||
.put("upload_id", options.getUploadId());
|
||||
if (options.getVideoOptions() != null) {
|
||||
formBuilder.putAll(options.getVideoOptions().getMap());
|
||||
}
|
||||
final Map<String, String> queryMap = options.getVideoOptions() != null ? ImmutableMap.of("video", "1") : Collections.emptyMap();
|
||||
final Map<String, String> signedForm = Utils.sign(formBuilder.build());
|
||||
return repository.uploadFinish(MediaUploadHelper.getRetryContextString(), queryMap, signedForm);
|
||||
}
|
||||
|
||||
public Call<String> delete(@NonNull final String postId,
|
||||
@NonNull final MediaItemType type) {
|
||||
if (!DELETABLE_ITEMS_TYPES.contains(type)) return null;
|
||||
final Map<String, Object> form = new HashMap<>();
|
||||
form.put("_csrftoken", csrfToken);
|
||||
form.put("_uid", userId);
|
||||
form.put("_uuid", deviceUuid);
|
||||
form.put("igtv_feed_preview", "false");
|
||||
form.put("media_id", postId);
|
||||
final Map<String, String> signedForm = Utils.sign(form);
|
||||
final String mediaType;
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
mediaType = "PHOTO";
|
||||
break;
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
mediaType = "VIDEO";
|
||||
break;
|
||||
case MEDIA_TYPE_SLIDER:
|
||||
mediaType = "CAROUSEL";
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return repository.delete(postId, mediaType, signedForm);
|
||||
}
|
||||
}
|
169
app/src/main/java/awais/instagrabber/webservices/MediaService.kt
Normal file
169
app/src/main/java/awais/instagrabber/webservices/MediaService.kt
Normal file
@ -0,0 +1,169 @@
|
||||
package awais.instagrabber.webservices
|
||||
|
||||
import awais.instagrabber.models.enums.MediaItemType
|
||||
import awais.instagrabber.repositories.MediaRepository
|
||||
import awais.instagrabber.repositories.requests.Clip
|
||||
import awais.instagrabber.repositories.requests.UploadFinishOptions
|
||||
import awais.instagrabber.repositories.responses.Media
|
||||
import awais.instagrabber.repositories.responses.User
|
||||
import awais.instagrabber.utils.DateUtils
|
||||
import awais.instagrabber.utils.Utils
|
||||
import awais.instagrabber.utils.retryContextString
|
||||
import awais.instagrabber.webservices.RetrofitFactory.retrofit
|
||||
import org.json.JSONObject
|
||||
|
||||
class MediaService private constructor(
|
||||
val deviceUuid: String,
|
||||
val csrfToken: String,
|
||||
val userId: Long,
|
||||
) : BaseService() {
|
||||
private val repository: MediaRepository = retrofit.create(MediaRepository::class.java)
|
||||
|
||||
suspend fun fetch(
|
||||
mediaId: Long,
|
||||
): Media? {
|
||||
val response = repository.fetch(mediaId)
|
||||
return if (response.items.isNullOrEmpty()) {
|
||||
null
|
||||
} else response.items[0]
|
||||
}
|
||||
|
||||
suspend fun like(mediaId: String): Boolean = action(mediaId, "like", null)
|
||||
|
||||
suspend fun unlike(mediaId: String): Boolean = action(mediaId, "unlike", null)
|
||||
|
||||
suspend fun save(mediaId: String, collection: String?): Boolean = action(mediaId, "save", collection)
|
||||
|
||||
suspend fun unsave(mediaId: String): Boolean = action(mediaId, "unsave", null)
|
||||
|
||||
private suspend fun action(
|
||||
mediaId: String,
|
||||
action: String,
|
||||
collection: String?,
|
||||
): Boolean {
|
||||
val form: MutableMap<String, Any> = mutableMapOf(
|
||||
"media_id" to mediaId,
|
||||
"_csrftoken" to csrfToken,
|
||||
"_uid" to userId,
|
||||
"_uuid" to deviceUuid,
|
||||
)
|
||||
// form.put("radio_type", "wifi-none");
|
||||
if (action == "save" && !collection.isNullOrBlank()) {
|
||||
form["added_collection_ids"] = "[$collection]"
|
||||
}
|
||||
// there also exists "removed_collection_ids" which can be used with "save" and "unsave"
|
||||
val signedForm = Utils.sign(form)
|
||||
val response = repository.action(action, mediaId, signedForm)
|
||||
val jsonObject = JSONObject(response)
|
||||
val status = jsonObject.optString("status")
|
||||
return status == "ok"
|
||||
}
|
||||
|
||||
suspend fun editCaption(
|
||||
postId: String,
|
||||
newCaption: String,
|
||||
): Boolean {
|
||||
val form = mapOf(
|
||||
"_csrftoken" to csrfToken,
|
||||
"_uid" to userId,
|
||||
"_uuid" to deviceUuid,
|
||||
"igtv_feed_preview" to "false",
|
||||
"media_id" to postId,
|
||||
"caption_text" to newCaption,
|
||||
)
|
||||
val signedForm = Utils.sign(form)
|
||||
val response = repository.editCaption(postId, signedForm)
|
||||
val jsonObject = JSONObject(response)
|
||||
val status = jsonObject.optString("status")
|
||||
return status == "ok"
|
||||
}
|
||||
|
||||
suspend fun fetchLikes(
|
||||
mediaId: String,
|
||||
isComment: Boolean,
|
||||
): List<User> {
|
||||
val response = repository.fetchLikes(mediaId, if (isComment) "comment_likers" else "likers")
|
||||
return response.users
|
||||
}
|
||||
|
||||
suspend fun translate(
|
||||
id: String,
|
||||
type: String, // 1 caption 2 comment 3 bio
|
||||
): String {
|
||||
val form = mapOf(
|
||||
"id" to id,
|
||||
"type" to type,
|
||||
)
|
||||
val response = repository.translate(form)
|
||||
val jsonObject = JSONObject(response)
|
||||
return jsonObject.optString("translation")
|
||||
}
|
||||
|
||||
suspend fun uploadFinish(options: UploadFinishOptions): String {
|
||||
if (options.videoOptions != null) {
|
||||
val videoOptions = options.videoOptions
|
||||
if (videoOptions.clips.isEmpty()) {
|
||||
videoOptions.clips = listOf(Clip(videoOptions.length, options.sourceType))
|
||||
}
|
||||
}
|
||||
val timezoneOffset = DateUtils.getTimezoneOffset().toString()
|
||||
val form = mutableMapOf<String, Any>(
|
||||
"timezone_offset" to timezoneOffset,
|
||||
"_csrftoken" to csrfToken,
|
||||
"source_type" to options.sourceType,
|
||||
"_uid" to userId.toString(),
|
||||
"_uuid" to deviceUuid,
|
||||
"upload_id" to options.uploadId,
|
||||
)
|
||||
if (options.videoOptions != null) {
|
||||
form.putAll(options.videoOptions.map)
|
||||
}
|
||||
val queryMap = if (options.videoOptions != null) mapOf("video" to "1") else emptyMap()
|
||||
val signedForm = Utils.sign(form)
|
||||
return repository.uploadFinish(retryContextString, queryMap, signedForm)
|
||||
}
|
||||
|
||||
suspend fun delete(
|
||||
postId: String,
|
||||
type: MediaItemType,
|
||||
): String? {
|
||||
if (!DELETABLE_ITEMS_TYPES.contains(type)) return null
|
||||
val form = mapOf(
|
||||
"_csrftoken" to csrfToken,
|
||||
"_uid" to userId,
|
||||
"_uuid" to deviceUuid,
|
||||
"igtv_feed_preview" to "false",
|
||||
"media_id" to postId,
|
||||
)
|
||||
val signedForm = Utils.sign(form)
|
||||
val mediaType: String = when (type) {
|
||||
MediaItemType.MEDIA_TYPE_IMAGE -> "PHOTO"
|
||||
MediaItemType.MEDIA_TYPE_VIDEO -> "VIDEO"
|
||||
MediaItemType.MEDIA_TYPE_SLIDER -> "CAROUSEL"
|
||||
else -> return null
|
||||
}
|
||||
return repository.delete(postId, mediaType, signedForm)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DELETABLE_ITEMS_TYPES = listOf(
|
||||
MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
MediaItemType.MEDIA_TYPE_VIDEO,
|
||||
MediaItemType.MEDIA_TYPE_SLIDER
|
||||
)
|
||||
private lateinit var instance: MediaService
|
||||
|
||||
@JvmStatic
|
||||
fun getInstance(deviceUuid: String, csrfToken: String, userId: Long): MediaService {
|
||||
if (!this::instance.isInitialized
|
||||
|| instance.csrfToken != csrfToken
|
||||
|| instance.deviceUuid != deviceUuid
|
||||
|| instance.userId != userId
|
||||
) {
|
||||
instance = MediaService(deviceUuid, csrfToken, userId)
|
||||
}
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user