mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-14 10:47: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.LiveData
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavController.OnDestinationChangedListener
|
import androidx.navigation.NavController.OnDestinationChangedListener
|
||||||
import androidx.navigation.NavDestination
|
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.android.material.textfield.TextInputLayout
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.common.collect.Iterators
|
import com.google.common.collect.Iterators
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
@ -81,11 +84,14 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
|||||||
private var isActivityCheckerServiceBound = false
|
private var isActivityCheckerServiceBound = false
|
||||||
private var isBackStackEmpty = false
|
private var isBackStackEmpty = false
|
||||||
private var isLoggedIn = 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
|
// private var behavior: HideBottomViewOnScrollBehavior<BottomNavigationView>? = null
|
||||||
var currentTabs: List<Tab> = emptyList()
|
var currentTabs: List<Tab> = emptyList()
|
||||||
private set
|
private set
|
||||||
private var showBottomViewDestinations: List<Int> = emptyList<Int>()
|
private var showBottomViewDestinations: List<Int> = emptyList()
|
||||||
private var graphQLService: GraphQLService? = null
|
private var graphQLService: GraphQLService? = null
|
||||||
private var mediaService: MediaService? = null
|
private var mediaService: MediaService? = null
|
||||||
|
|
||||||
@ -157,17 +163,17 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
|||||||
|
|
||||||
private fun setupCookie() {
|
private fun setupCookie() {
|
||||||
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
|
val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
|
||||||
var userId: Long = 0
|
userId = 0
|
||||||
var csrfToken: String? = null
|
csrfToken = null
|
||||||
if (!isEmpty(cookie)) {
|
if (cookie.isNotBlank()) {
|
||||||
userId = getUserIdFromCookie(cookie)
|
userId = getUserIdFromCookie(cookie)
|
||||||
csrfToken = getCsrfTokenFromCookie(cookie)
|
csrfToken = getCsrfTokenFromCookie(cookie)
|
||||||
}
|
}
|
||||||
if (isEmpty(cookie) || userId == 0L || isEmpty(csrfToken)) {
|
if (cookie.isBlank() || userId == 0L || csrfToken.isNullOrBlank()) {
|
||||||
isLoggedIn = false
|
isLoggedIn = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
|
deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID)
|
||||||
if (isEmpty(deviceUuid)) {
|
if (isEmpty(deviceUuid)) {
|
||||||
Utils.settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString())
|
Utils.settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString())
|
||||||
}
|
}
|
||||||
@ -175,6 +181,7 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
|||||||
isLoggedIn = true
|
isLoggedIn = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
private fun initDmService() {
|
private fun initDmService() {
|
||||||
if (!isLoggedIn) return
|
if (!isLoggedIn) return
|
||||||
val enabled = Utils.settingsHelper.getBoolean(PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH)
|
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)
|
.setView(R.layout.dialog_opening_post)
|
||||||
.create()
|
.create()
|
||||||
if (graphQLService == null) graphQLService = GraphQLService.getInstance()
|
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> {
|
val postCb: ServiceCallback<Media> = object : ServiceCallback<Media> {
|
||||||
override fun onSuccess(feedModel: Media?) {
|
override fun onSuccess(feedModel: Media?) {
|
||||||
if (feedModel != null) {
|
if (feedModel != null) {
|
||||||
@ -650,7 +659,18 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
alertDialog.show()
|
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) {
|
private fun showLocationView(intentModel: IntentModel) {
|
||||||
|
@ -25,12 +25,15 @@ import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
|
|||||||
import awais.instagrabber.databinding.FragmentLikesBinding;
|
import awais.instagrabber.databinding.FragmentLikesBinding;
|
||||||
import awais.instagrabber.repositories.responses.GraphQLUserListFetchResponse;
|
import awais.instagrabber.repositories.responses.GraphQLUserListFetchResponse;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
|
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.webservices.GraphQLService;
|
import awais.instagrabber.webservices.GraphQLService;
|
||||||
import awais.instagrabber.webservices.MediaService;
|
import awais.instagrabber.webservices.MediaService;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
|
import kotlinx.coroutines.Dispatchers;
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
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) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||||
// final AppCompatActivity fragmentActivity = (AppCompatActivity) getActivity();
|
isLoggedIn = !TextUtils.isEmpty(cookie) && userId != 0;
|
||||||
mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
|
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();
|
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
||||||
// setHasOptionsMenu(true);
|
// setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
@ -130,7 +136,20 @@ public final class LikesViewerFragment extends BottomSheetDialogFragment impleme
|
|||||||
if (isComment && !isLoggedIn) {
|
if (isComment && !isLoggedIn) {
|
||||||
lazyLoader.resetState();
|
lazyLoader.resetState();
|
||||||
graphQLService.fetchCommentLikers(postId, null, anonCb);
|
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() {
|
private void init() {
|
||||||
|
@ -35,12 +35,13 @@ import awais.instagrabber.databinding.FragmentNotificationsViewerBinding;
|
|||||||
import awais.instagrabber.models.enums.NotificationType;
|
import awais.instagrabber.models.enums.NotificationType;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
|
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.Notification;
|
||||||
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
||||||
import awais.instagrabber.repositories.responses.notification.NotificationImage;
|
import awais.instagrabber.repositories.responses.notification.NotificationImage;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
|
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import awais.instagrabber.viewmodels.NotificationViewModel;
|
import awais.instagrabber.viewmodels.NotificationViewModel;
|
||||||
@ -48,6 +49,7 @@ import awais.instagrabber.webservices.FriendshipService;
|
|||||||
import awais.instagrabber.webservices.MediaService;
|
import awais.instagrabber.webservices.MediaService;
|
||||||
import awais.instagrabber.webservices.NewsService;
|
import awais.instagrabber.webservices.NewsService;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
|
import kotlinx.coroutines.Dispatchers;
|
||||||
|
|
||||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
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)
|
.setView(R.layout.dialog_opening_post)
|
||||||
.create();
|
.create();
|
||||||
alertDialog.show();
|
alertDialog.show();
|
||||||
mediaService.fetch(mediaId, new ServiceCallback<Media>() {
|
mediaService.fetch(
|
||||||
@Override
|
mediaId,
|
||||||
public void onSuccess(final Media feedModel) {
|
CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
final NavController navController = NavHostFragment.findNavController(NotificationsViewerFragment.this);
|
if (throwable != null) {
|
||||||
final Bundle bundle = new Bundle();
|
alertDialog.dismiss();
|
||||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
try {
|
return;
|
||||||
navController.navigate(R.id.action_global_post_view, bundle);
|
}
|
||||||
alertDialog.dismiss();
|
final NavController navController = NavHostFragment.findNavController(NotificationsViewerFragment.this);
|
||||||
} catch (Exception e) {
|
final Bundle bundle = new Bundle();
|
||||||
Log.e(TAG, "onSuccess: ", e);
|
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
|
||||||
}
|
try {
|
||||||
}
|
navController.navigate(R.id.action_global_post_view, bundle);
|
||||||
|
alertDialog.dismiss();
|
||||||
@Override
|
} catch (Exception e) {
|
||||||
public void onFailure(final Throwable t) {
|
Log.e(TAG, "onSuccess: ", e);
|
||||||
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)) {
|
if (TextUtils.isEmpty(cookie)) {
|
||||||
Toast.makeText(context, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
mediaService = MediaService.getInstance(null, null, 0);
|
|
||||||
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
||||||
deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
|
deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
|
||||||
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||||
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
|
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
|
||||||
|
mediaService = MediaService.getInstance(deviceUuid, csrfToken, userId);
|
||||||
newsService = NewsService.getInstance();
|
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;
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions.Type;
|
||||||
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds;
|
import awais.instagrabber.repositories.requests.directmessages.ThreadIdOrUserIds;
|
||||||
import awais.instagrabber.repositories.responses.Media;
|
|
||||||
import awais.instagrabber.repositories.responses.StoryStickerResponse;
|
import awais.instagrabber.repositories.responses.StoryStickerResponse;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||||
@ -159,7 +159,7 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
|
final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||||
fragmentActivity = (AppCompatActivity) requireActivity();
|
fragmentActivity = (AppCompatActivity) requireActivity();
|
||||||
storiesService = StoriesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
storiesService = StoriesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
||||||
mediaService = MediaService.getInstance(null, null, 0);
|
mediaService = MediaService.getInstance(deviceId, csrfToken, userIdFromCookie);
|
||||||
directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
.setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread(
|
.setPositiveButton(R.string.confirm, (d, w) -> directMessagesService.createThread(
|
||||||
Collections.singletonList(currentStory.getUserId()),
|
Collections.singletonList(currentStory.getUserId()),
|
||||||
null,
|
null,
|
||||||
CoroutineUtilsKt.getContinuation((thread, throwable) -> {
|
CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
Log.e(TAG, "onOptionsItemSelected: ", throwable);
|
Log.e(TAG, "onOptionsItemSelected: ", throwable);
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
@ -231,17 +231,19 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
input.getText().toString(),
|
input.getText().toString(),
|
||||||
currentStory.getStoryMediaId(),
|
currentStory.getStoryMediaId(),
|
||||||
String.valueOf(currentStory.getUserId()),
|
String.valueOf(currentStory.getUserId()),
|
||||||
CoroutineUtilsKt.getContinuation((directThreadBroadcastResponse, throwable1) -> {
|
CoroutineUtilsKt.getContinuation(
|
||||||
if (throwable1 != null) {
|
(directThreadBroadcastResponse, throwable1) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
if (throwable1 != null) {
|
||||||
Log.e(TAG, "onFailure: ", throwable1);
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
Log.e(TAG, "onFailure: ", throwable1);
|
||||||
}
|
return;
|
||||||
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
}
|
||||||
}, Dispatchers.getIO())
|
Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show();
|
||||||
|
}), Dispatchers.getIO()
|
||||||
|
)
|
||||||
|
|
||||||
);
|
);
|
||||||
}, Dispatchers.getIO())
|
}), Dispatchers.getIO())
|
||||||
))
|
))
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show();
|
.show();
|
||||||
@ -451,26 +453,25 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
.setView(R.layout.dialog_opening_post)
|
.setView(R.layout.dialog_opening_post)
|
||||||
.create();
|
.create();
|
||||||
alertDialog.show();
|
alertDialog.show();
|
||||||
mediaService.fetch(Long.parseLong(mediaId), new ServiceCallback<Media>() {
|
mediaService.fetch(
|
||||||
@Override
|
Long.parseLong(mediaId),
|
||||||
public void onSuccess(final Media feedModel) {
|
CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
final NavController navController = NavHostFragment.findNavController(StoryViewerFragment.this);
|
if (throwable != null) {
|
||||||
final Bundle bundle = new Bundle();
|
alertDialog.dismiss();
|
||||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
try {
|
return;
|
||||||
navController.navigate(R.id.action_global_post_view, bundle);
|
}
|
||||||
alertDialog.dismiss();
|
final NavController navController = NavHostFragment.findNavController(StoryViewerFragment.this);
|
||||||
} catch (Exception e) {
|
final Bundle bundle = new Bundle();
|
||||||
Log.e(TAG, "openPostDialog: ", e);
|
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
|
||||||
}
|
try {
|
||||||
}
|
navController.navigate(R.id.action_global_post_view, bundle);
|
||||||
|
alertDialog.dismiss();
|
||||||
@Override
|
} catch (Exception e) {
|
||||||
public void onFailure(final Throwable t) {
|
Log.e(TAG, "openPostDialog: ", e);
|
||||||
alertDialog.dismiss();
|
}
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
}), Dispatchers.getIO())
|
||||||
}
|
);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
final View.OnClickListener storyActionListener = v -> {
|
final View.OnClickListener storyActionListener = v -> {
|
||||||
final Object tag = v.getTag();
|
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.GPUImage;
|
||||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
|
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
|
||||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilterGroup;
|
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilterGroup;
|
||||||
|
import kotlinx.coroutines.Dispatchers;
|
||||||
|
|
||||||
public class FiltersFragment extends Fragment {
|
public class FiltersFragment extends Fragment {
|
||||||
private static final String TAG = FiltersFragment.class.getSimpleName();
|
private static final String TAG = FiltersFragment.class.getSimpleName();
|
||||||
@ -461,31 +462,33 @@ public class FiltersFragment extends Fragment {
|
|||||||
filtersAdapter.setSelected(position);
|
filtersAdapter.setSelected(position);
|
||||||
appliedFilter = filter;
|
appliedFilter = filter;
|
||||||
};
|
};
|
||||||
BitmapUtils.getThumbnail(context, sourceUri, CoroutineUtilsKt.getContinuation((bitmapResult, throwable) -> {
|
BitmapUtils.getThumbnail(
|
||||||
if (throwable != null) {
|
context,
|
||||||
Log.e(TAG, "setupFilters: ", throwable);
|
sourceUri,
|
||||||
return;
|
CoroutineUtilsKt.getContinuation((bitmapResult, throwable) -> appExecutors.getMainThread().execute(() -> {
|
||||||
}
|
if (throwable != null) {
|
||||||
if (bitmapResult == null || bitmapResult.getBitmap() == null) {
|
Log.e(TAG, "setupFilters: ", throwable);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
filtersAdapter = new FiltersAdapter(
|
if (bitmapResult == null || bitmapResult.getBitmap() == null) {
|
||||||
tuningFilters.values()
|
return;
|
||||||
.stream()
|
}
|
||||||
.map(Filter::getInstance)
|
filtersAdapter = new FiltersAdapter(
|
||||||
.collect(Collectors.toList()),
|
tuningFilters.values()
|
||||||
sourceUri.toString(),
|
.stream()
|
||||||
bitmapResult.getBitmap(),
|
.map(Filter::getInstance)
|
||||||
onFilterClickListener
|
.collect(Collectors.toList()),
|
||||||
);
|
sourceUri.toString(),
|
||||||
appExecutors.getMainThread().execute(() -> {
|
bitmapResult.getBitmap(),
|
||||||
binding.filters.setAdapter(filtersAdapter);
|
onFilterClickListener
|
||||||
filtersAdapter.submitList(FiltersHelper.getFilters(), () -> {
|
);
|
||||||
if (appliedFilter == null) return;
|
binding.filters.setAdapter(filtersAdapter);
|
||||||
filtersAdapter.setSelectedFilter(appliedFilter.getInstance());
|
filtersAdapter.submitList(FiltersHelper.getFilters(), () -> {
|
||||||
});
|
if (appliedFilter == null) return;
|
||||||
});
|
filtersAdapter.setSelectedFilter(appliedFilter.getInstance());
|
||||||
}));
|
});
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
addInitialFilter();
|
addInitialFilter();
|
||||||
binding.preview.setFilter(filterGroup);
|
binding.preview.setFilter(filterGroup);
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,16 @@ import awais.instagrabber.fragments.PostViewV2Fragment;
|
|||||||
import awais.instagrabber.repositories.responses.Media;
|
import awais.instagrabber.repositories.responses.Media;
|
||||||
import awais.instagrabber.repositories.responses.discover.TopicCluster;
|
import awais.instagrabber.repositories.responses.discover.TopicCluster;
|
||||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse;
|
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.utils.Utils;
|
||||||
import awais.instagrabber.viewmodels.TopicClusterViewModel;
|
import awais.instagrabber.viewmodels.TopicClusterViewModel;
|
||||||
import awais.instagrabber.webservices.DiscoverService;
|
import awais.instagrabber.webservices.DiscoverService;
|
||||||
import awais.instagrabber.webservices.MediaService;
|
import awais.instagrabber.webservices.MediaService;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
|
import kotlinx.coroutines.Dispatchers;
|
||||||
|
|
||||||
public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
||||||
private static final String TAG = "DiscoverFragment";
|
private static final String TAG = "DiscoverFragment";
|
||||||
@ -52,7 +57,11 @@ public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
fragmentActivity = (MainActivity) requireActivity();
|
fragmentActivity = (MainActivity) requireActivity();
|
||||||
discoverService = DiscoverService.getInstance();
|
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
|
@Override
|
||||||
@ -104,29 +113,29 @@ public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||||||
.setView(R.layout.dialog_opening_post)
|
.setView(R.layout.dialog_opening_post)
|
||||||
.create();
|
.create();
|
||||||
alertDialog.show();
|
alertDialog.show();
|
||||||
mediaService.fetch(Long.valueOf(coverMedia.getPk()), new ServiceCallback<Media>() {
|
final String pk = coverMedia.getPk();
|
||||||
@Override
|
if (pk == null) return;
|
||||||
public void onSuccess(final Media feedModel) {
|
mediaService.fetch(
|
||||||
final NavController navController = NavHostFragment.findNavController(DiscoverFragment.this);
|
Long.parseLong(pk),
|
||||||
final Bundle bundle = new Bundle();
|
CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
|
if (throwable != null) {
|
||||||
try {
|
alertDialog.dismiss();
|
||||||
navController.navigate(R.id.action_global_post_view, bundle);
|
try {
|
||||||
alertDialog.dismiss();
|
Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
} catch (Exception e) {
|
} catch (Throwable ignored) {}
|
||||||
Log.e(TAG, "onSuccess: ", e);
|
return;
|
||||||
}
|
}
|
||||||
}
|
final NavController navController = NavHostFragment.findNavController(DiscoverFragment.this);
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
@Override
|
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media);
|
||||||
public void onFailure(final Throwable t) {
|
try {
|
||||||
alertDialog.dismiss();
|
navController.navigate(R.id.action_global_post_view, bundle);
|
||||||
try {
|
alertDialog.dismiss();
|
||||||
Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
} catch (Exception e) {
|
||||||
}
|
Log.e(TAG, "onTopicLongClick: ", e);
|
||||||
catch (Throwable e) {}
|
}
|
||||||
}
|
}), Dispatchers.getIO())
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final DiscoverTopicsAdapter adapter = new DiscoverTopicsAdapter(otcl);
|
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.Media;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
import awais.instagrabber.repositories.responses.UserProfileContextLink;
|
import awais.instagrabber.repositories.responses.UserProfileContextLink;
|
||||||
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.CookieUtils;
|
import awais.instagrabber.utils.CookieUtils;
|
||||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
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;
|
friendshipService = isLoggedIn ? FriendshipService.getInstance(deviceUuid, csrfToken, myId) : null;
|
||||||
directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null;
|
directMessagesService = isLoggedIn ? DirectMessagesService.getInstance(csrfToken, myId, deviceUuid) : null;
|
||||||
storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : 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;
|
userService = isLoggedIn ? UserService.getInstance() : null;
|
||||||
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
@ -821,26 +822,26 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
Utils.copyText(context, biography);
|
Utils.copyText(context, biography);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mediaService.translate(String.valueOf(profileModel.getPk()), "3", new ServiceCallback<String>() {
|
mediaService.translate(String.valueOf(profileModel.getPk()), "3", CoroutineUtilsKt.getContinuation(
|
||||||
@Override
|
(result, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final String result) {
|
if (throwable != null) {
|
||||||
if (TextUtils.isEmpty(result)) {
|
Log.e(TAG, "Error translating bio", throwable);
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new AlertDialog.Builder(context)
|
if (TextUtils.isEmpty(result)) {
|
||||||
.setTitle(profileModel.getUsername())
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT)
|
||||||
.setMessage(result)
|
.show();
|
||||||
.setPositiveButton(R.string.ok, null)
|
return;
|
||||||
.show();
|
}
|
||||||
}
|
new AlertDialog.Builder(context)
|
||||||
|
.setTitle(profileModel.getUsername())
|
||||||
@Override
|
.setMessage(result)
|
||||||
public void onFailure(final Throwable t) {
|
.setPositiveButton(R.string.ok, null)
|
||||||
Log.e(TAG, "Error translating bio", t);
|
.show();
|
||||||
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
|
}),
|
||||||
}
|
Dispatchers.getIO()
|
||||||
});
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1079,7 +1080,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
|||||||
directMessagesService.createThread(
|
directMessagesService.createThread(
|
||||||
Collections.singletonList(profileModel.getPk()),
|
Collections.singletonList(profileModel.getPk()),
|
||||||
null,
|
null,
|
||||||
CoroutineUtilsKt.getContinuation((thread, throwable) -> {
|
CoroutineUtilsKt.getContinuation((thread, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
Log.e(TAG, "setupCommonListeners: ", throwable);
|
Log.e(TAG, "setupCommonListeners: ", throwable);
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
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);
|
inboxManager.addThread(thread, 0);
|
||||||
}
|
}
|
||||||
fragmentActivity.navigateToThread(thread.getThreadId(), profileModel.getUsername());
|
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.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
|
||||||
import retrofit2.Response
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
@ -457,40 +455,15 @@ class ThreadManager private constructor(
|
|||||||
"4",
|
"4",
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
val uploadFinishRequest = mediaService.uploadFinish(uploadFinishOptions)
|
mediaService.uploadFinish(uploadFinishOptions)
|
||||||
uploadFinishRequest.enqueue(object : Callback<String?> {
|
val broadcastResponse = service.broadcastVoice(
|
||||||
override fun onResponse(call: Call<String?>, response: Response<String?>) {
|
clientContext,
|
||||||
if (response.isSuccessful) {
|
threadIdOrUserIds,
|
||||||
scope.launch(Dispatchers.IO) {
|
uploadDmVoiceOptions.uploadId,
|
||||||
try {
|
waveform,
|
||||||
val request = service.broadcastVoice(
|
samplingFreq
|
||||||
clientContext,
|
)
|
||||||
threadIdOrUserIds,
|
parseResponse(broadcastResponse, data, directItem)
|
||||||
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
data.postValue(error(e.message, directItem))
|
data.postValue(error(e.message, directItem))
|
||||||
Log.e(TAG, "sendVoice: ", e)
|
Log.e(TAG, "sendVoice: ", e)
|
||||||
@ -806,39 +779,15 @@ class ThreadManager private constructor(
|
|||||||
"2",
|
"2",
|
||||||
VideoOptions(duration / 1000f, emptyList(), 0, false)
|
VideoOptions(duration / 1000f, emptyList(), 0, false)
|
||||||
)
|
)
|
||||||
val uploadFinishRequest = mediaService.uploadFinish(uploadFinishOptions)
|
mediaService.uploadFinish(uploadFinishOptions)
|
||||||
uploadFinishRequest.enqueue(object : Callback<String?> {
|
val broadcastResponse = service.broadcastVideo(
|
||||||
override fun onResponse(call: Call<String?>, response: Response<String?>) {
|
clientContext,
|
||||||
if (response.isSuccessful) {
|
threadIdOrUserIds,
|
||||||
scope.launch(Dispatchers.IO) {
|
uploadDmVideoOptions.uploadId,
|
||||||
try {
|
"",
|
||||||
val response1 = service.broadcastVideo(
|
true
|
||||||
clientContext,
|
)
|
||||||
threadIdOrUserIds,
|
parseResponse(broadcastResponse, data, directItem)
|
||||||
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
data.postValue(error(e.message, directItem))
|
data.postValue(error(e.message, directItem))
|
||||||
Log.e(TAG, "sendVideo: ", e)
|
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(
|
private fun handleInvalidResponse(
|
||||||
data: MutableLiveData<Resource<Any?>>,
|
data: MutableLiveData<Resource<Any?>>,
|
||||||
response: MediaUploadResponse,
|
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,12 +26,10 @@ object MediaUploader {
|
|||||||
suspend fun uploadPhoto(
|
suspend fun uploadPhoto(
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
contentResolver: ContentResolver,
|
contentResolver: ContentResolver,
|
||||||
): MediaUploadResponse {
|
): MediaUploadResponse = withContext(Dispatchers.IO) {
|
||||||
return withContext(Dispatchers.IO) {
|
val bitmapResult = BitmapUtils.loadBitmap(contentResolver, uri, 1000f, false)
|
||||||
val bitmapResult = BitmapUtils.loadBitmap(contentResolver, uri, 1000f, false)
|
val bitmap = bitmapResult?.bitmap ?: throw IOException("bitmap is null")
|
||||||
val bitmap = bitmapResult?.bitmap ?: throw IOException("bitmap is null")
|
uploadPhoto(bitmap)
|
||||||
uploadPhoto(bitmap)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
@ -98,25 +96,23 @@ object MediaUploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun create(mediaType: MediaType, inputStream: InputStream): RequestBody {
|
private fun create(mediaType: MediaType, inputStream: InputStream): RequestBody = object : RequestBody() {
|
||||||
return object : RequestBody() {
|
override fun contentType(): MediaType {
|
||||||
override fun contentType(): MediaType {
|
return mediaType
|
||||||
return mediaType
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun contentLength(): Long {
|
override fun contentLength(): Long {
|
||||||
return try {
|
return try {
|
||||||
inputStream.available().toLong()
|
inputStream.available().toLong()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
0
|
0
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@Suppress("DEPRECATION_ERROR")
|
@Suppress("DEPRECATION_ERROR")
|
||||||
override fun writeTo(sink: BufferedSink) {
|
override fun writeTo(sink: BufferedSink) {
|
||||||
Okio.source(inputStream).use { sink.writeAll(it) }
|
Okio.source(inputStream).use { sink.writeAll(it) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,11 +23,9 @@ import awais.instagrabber.utils.extensions.TAG
|
|||||||
import awais.instagrabber.utils.getCsrfTokenFromCookie
|
import awais.instagrabber.utils.getCsrfTokenFromCookie
|
||||||
import awais.instagrabber.utils.getUserIdFromCookie
|
import awais.instagrabber.utils.getUserIdFromCookie
|
||||||
import awais.instagrabber.webservices.MediaService
|
import awais.instagrabber.webservices.MediaService
|
||||||
import awais.instagrabber.webservices.ServiceCallback
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import retrofit2.Call
|
import kotlinx.coroutines.Dispatchers
|
||||||
import retrofit2.Callback
|
import kotlinx.coroutines.launch
|
||||||
import retrofit2.Response
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PostViewV2ViewModel : ViewModel() {
|
class PostViewV2ViewModel : ViewModel() {
|
||||||
@ -127,44 +125,51 @@ class PostViewV2ViewModel : ViewModel() {
|
|||||||
fun like(): LiveData<Resource<Any?>> {
|
fun like(): LiveData<Resource<Any?>> {
|
||||||
val data = MutableLiveData<Resource<Any?>>()
|
val data = MutableLiveData<Resource<Any?>>()
|
||||||
data.postValue(loading(null))
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unlike(): LiveData<Resource<Any?>> {
|
fun unlike(): LiveData<Resource<Any?>> {
|
||||||
val data = MutableLiveData<Resource<Any?>>()
|
val data = MutableLiveData<Resource<Any?>>()
|
||||||
data.postValue(loading(null))
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLikeUnlikeCallback(data: MutableLiveData<Resource<Any?>>): ServiceCallback<Boolean?> {
|
private fun updateMediaLikeUnlike(data: MutableLiveData<Resource<Any?>>, result: Boolean) {
|
||||||
return object : ServiceCallback<Boolean?> {
|
if (!result) {
|
||||||
override fun onSuccess(result: Boolean?) {
|
data.postValue(error("", null))
|
||||||
if (result != null && !result) {
|
return
|
||||||
data.postValue(error("", null))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data.postValue(success(true))
|
|
||||||
val currentLikesCount = media.likeCount
|
|
||||||
val updatedCount: Long
|
|
||||||
if (!media.hasLiked) {
|
|
||||||
updatedCount = currentLikesCount + 1
|
|
||||||
media.hasLiked = true
|
|
||||||
} else {
|
|
||||||
updatedCount = currentLikesCount - 1
|
|
||||||
media.hasLiked = false
|
|
||||||
}
|
|
||||||
media.likeCount = updatedCount
|
|
||||||
likeCount.postValue(updatedCount)
|
|
||||||
liked.postValue(media.hasLiked)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(t: Throwable) {
|
|
||||||
data.postValue(error(t.message, null))
|
|
||||||
Log.e(TAG, "Error during like/unlike", t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
data.postValue(success(true))
|
||||||
|
val currentLikesCount = media.likeCount
|
||||||
|
val updatedCount: Long
|
||||||
|
if (!media.hasLiked) {
|
||||||
|
updatedCount = currentLikesCount + 1
|
||||||
|
media.hasLiked = true
|
||||||
|
} else {
|
||||||
|
updatedCount = currentLikesCount - 1
|
||||||
|
media.hasLiked = false
|
||||||
|
}
|
||||||
|
media.likeCount = updatedCount
|
||||||
|
likeCount.postValue(updatedCount)
|
||||||
|
liked.postValue(media.hasLiked)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleSave(): LiveData<Resource<Any?>> {
|
fun toggleSave(): LiveData<Resource<Any?>> {
|
||||||
@ -180,79 +185,87 @@ class PostViewV2ViewModel : ViewModel() {
|
|||||||
fun save(collection: String?, ignoreSaveState: Boolean): LiveData<Resource<Any?>> {
|
fun save(collection: String?, ignoreSaveState: Boolean): LiveData<Resource<Any?>> {
|
||||||
val data = MutableLiveData<Resource<Any?>>()
|
val data = MutableLiveData<Resource<Any?>>()
|
||||||
data.postValue(loading(null))
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unsave(): LiveData<Resource<Any?>> {
|
fun unsave(): LiveData<Resource<Any?>> {
|
||||||
val data = MutableLiveData<Resource<Any?>>()
|
val data = MutableLiveData<Resource<Any?>>()
|
||||||
data.postValue(loading(null))
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSaveUnsaveCallback(
|
private fun getSaveUnsaveCallback(
|
||||||
data: MutableLiveData<Resource<Any?>>,
|
data: MutableLiveData<Resource<Any?>>,
|
||||||
|
result: Boolean,
|
||||||
ignoreSaveState: Boolean,
|
ignoreSaveState: Boolean,
|
||||||
): ServiceCallback<Boolean?> {
|
) {
|
||||||
return object : ServiceCallback<Boolean?> {
|
if (!result) {
|
||||||
override fun onSuccess(result: Boolean?) {
|
data.postValue(error("", null))
|
||||||
if (result != null && !result) {
|
return
|
||||||
data.postValue(error("", null))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data.postValue(success(true))
|
|
||||||
if (!ignoreSaveState) media.hasViewerSaved = !media.hasViewerSaved
|
|
||||||
saved.postValue(media.hasViewerSaved)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(t: Throwable) {
|
|
||||||
data.postValue(error(t.message, null))
|
|
||||||
Log.e(TAG, "Error during save/unsave", t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
data.postValue(success(true))
|
||||||
|
if (!ignoreSaveState) media.hasViewerSaved = !media.hasViewerSaved
|
||||||
|
saved.postValue(media.hasViewerSaved)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateCaption(caption: String): LiveData<Resource<Any?>> {
|
fun updateCaption(caption: String): LiveData<Resource<Any?>> {
|
||||||
val data = MutableLiveData<Resource<Any?>>()
|
val data = MutableLiveData<Resource<Any?>>()
|
||||||
data.postValue(loading(null))
|
data.postValue(loading(null))
|
||||||
mediaService?.editCaption(media.pk, caption, object : ServiceCallback<Boolean?> {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
override fun onSuccess(result: Boolean?) {
|
try {
|
||||||
|
val postId = media.pk ?: return@launch
|
||||||
|
val result = mediaService?.editCaption(postId, caption)
|
||||||
if (result != null && result) {
|
if (result != null && result) {
|
||||||
data.postValue(success(""))
|
data.postValue(success(""))
|
||||||
media.setPostCaption(caption)
|
media.setPostCaption(caption)
|
||||||
this@PostViewV2ViewModel.caption.postValue(media.caption)
|
this@PostViewV2ViewModel.caption.postValue(media.caption)
|
||||||
return
|
return@launch
|
||||||
}
|
}
|
||||||
data.postValue(error("", null))
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translateCaption(): LiveData<Resource<String?>> {
|
fun translateCaption(): LiveData<Resource<String?>> {
|
||||||
val data = MutableLiveData<Resource<String?>>()
|
val data = MutableLiveData<Resource<String?>>()
|
||||||
data.postValue(loading(null))
|
data.postValue(loading(null))
|
||||||
val value = caption.value ?: return data
|
val value = caption.value
|
||||||
mediaService?.translate(value.pk, "1", object : ServiceCallback<String?> {
|
val pk = value?.pk
|
||||||
override fun onSuccess(result: String?) {
|
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()) {
|
if (result.isNullOrBlank()) {
|
||||||
data.postValue(error("", null))
|
data.postValue(error("", null))
|
||||||
return
|
return@launch
|
||||||
}
|
}
|
||||||
data.postValue(success(result))
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,30 +286,19 @@ class PostViewV2ViewModel : ViewModel() {
|
|||||||
data.postValue(error("media id or type is null", null))
|
data.postValue(error("media id or type is null", null))
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
val request = mediaService?.delete(mediaId, mediaType)
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
if (request == null) {
|
try {
|
||||||
data.postValue(success(Any()))
|
val response = mediaService?.delete(mediaId, mediaType)
|
||||||
return data
|
if (response == null) {
|
||||||
}
|
data.postValue(success(Any()))
|
||||||
request.enqueue(object : Callback<String?> {
|
return@launch
|
||||||
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
|
|
||||||
}
|
}
|
||||||
data.postValue(success(Any()))
|
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
|
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