From bc10841ed93c9886cb11952e2d1b17e78c806097 Mon Sep 17 00:00:00 2001 From: antony Date: Sat, 4 Nov 2023 17:41:52 +0100 Subject: [PATCH] experimental --- .../muzei/pixiv/provider/BookmarksHelper.kt | 28 ++++- .../muzei/pixiv/provider/PixivArtWorker.kt | 56 +++++---- .../network/PixivAuthFeedJsonService.java | 10 +- .../muzei/pixiv/settings/MainActivity.kt | 70 +++++------ .../pixiv/settings/SectionsPagerAdapter.java | 3 +- .../fragments/BookmarkExportFragment.kt | 117 ++++++++++++++++++ .../main/res/xml/bookmark_export_layout.xml | 11 ++ 7 files changed, 229 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/com/antony/muzei/pixiv/settings/fragments/BookmarkExportFragment.kt create mode 100644 app/src/main/res/xml/bookmark_export_layout.xml diff --git a/app/src/main/java/com/antony/muzei/pixiv/provider/BookmarksHelper.kt b/app/src/main/java/com/antony/muzei/pixiv/provider/BookmarksHelper.kt index 72734077..09a16857 100644 --- a/app/src/main/java/com/antony/muzei/pixiv/provider/BookmarksHelper.kt +++ b/app/src/main/java/com/antony/muzei/pixiv/provider/BookmarksHelper.kt @@ -10,15 +10,35 @@ class BookmarksHelper(_userId: String) { .create(PixivAuthFeedJsonService::class.java) private val userId: String = _userId - fun getNewIllusts(maxBookmarkId: String): Illusts { - val call = service.getBookmarkOffsetJson(userId, maxBookmarkId) + fun getNewPublicBookmarks(maxBookmarkId: String): Illusts { + val call = service.getPublicBookmarkOffsetJson(userId, maxBookmarkId) illusts = call.execute().body()!! return illusts } - fun getNewIllusts(): Illusts { - val call = service.getBookmarkJson(userId) + fun getNewPrivateIllusts(maxBookmarkId: String): Illusts { + val call = service.getPrivateBookmarkOffsetJson(userId, maxBookmarkId) illusts = call.execute().body()!! return illusts } + + fun getNewPublicBookmarks(): Illusts { + val call = service.getPublicBookmarkJson(userId) + illusts = call.execute().body()!! + return illusts + } + + fun getNewPrivateIllusts(): Illusts { + val call = service.getPrivateBookmarkJson(userId) + illusts = call.execute().body()!! + return illusts + } + + fun getNextBookmarks(): Illusts { + val call = service.getNextUrl(illusts.next_url) + illusts = call.execute().body()!! + return illusts + } + + fun getBookmarks() = illusts } diff --git a/app/src/main/java/com/antony/muzei/pixiv/provider/PixivArtWorker.kt b/app/src/main/java/com/antony/muzei/pixiv/provider/PixivArtWorker.kt index 89df5737..0c48765a 100644 --- a/app/src/main/java/com/antony/muzei/pixiv/provider/PixivArtWorker.kt +++ b/app/src/main/java/com/antony/muzei/pixiv/provider/PixivArtWorker.kt @@ -107,40 +107,42 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : * * Example: * Say that the initial value is 100, and the target value is 67.5 - * The inital search at 100 is too high, so we go down by half the search space to 50 + * We perform an initial search at value 100 + * We find the initial value is too high, so we go down by half the search space to 50 * 50 is too low, go up by half the previous step (25 = 50 / 2) to 75 * 75 is too high, so we go down by half the previous step (12.5 = 25 / 2) to 67.5 * We have a match */ private fun findBookmarkStartTime(userId: String) { Log.d(LOG_TAG, "Looking for oldest bookmark id") - val service: PixivAuthFeedJsonService = RestClient.getRetrofitAuthInstance() - .create(PixivAuthFeedJsonService::class.java) - var call: Call = service.getBookmarkJson(userId) + val bookmarks = BookmarksHelper(userId) + bookmarks.getNewPublicBookmarks() + // setting initial values var counter = 0 var callingId = 0L - // setting initial value - var illusts = call.execute().body()!! - var step = illusts.next_url!!.substringAfter("max_bookmark_id=").toLong() + var step = bookmarks.getBookmarks().next_url!!.substringAfter("max_bookmark_id=").toLong() + while (true) { counter++ + step /= 2 //Halving the step size Log.d(LOG_TAG, "Iteration $counter") - if (illusts.next_url != null) { - // we are too high - val currentId = illusts.next_url!!.substringAfter("max_bookmark_id=").toLong() - step /= 2 + if (bookmarks.getBookmarks().next_url != null) { + // we are not looking far enough in the past + // we need to reduce the maxBookmarkId parameter to + val currentId = + bookmarks.getBookmarks().next_url!!.substringAfter("max_bookmark_id=").toLong() callingId = currentId - step - } else if (illusts.artworks.isEmpty()) { - // we are too low - step /= 2 + } else if (bookmarks.getBookmarks().artworks.isEmpty()) { + // we are looking too far in the past + // we need to increase the maxBookmarkId parameter to look closer to current time callingId += step } else { + // we have found the stop criteria Log.d(LOG_TAG, "Found at $callingId") break } - call = service.getBookmarkOffsetJson(userId, callingId.toString()) - illusts = call.execute().body()!! + bookmarks.getNewPublicBookmarks(callingId.toString()) } with(PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()) { putLong("oldestMaxBookmarkId", callingId) @@ -744,11 +746,13 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : val oldestBookmarkId = sharedPrefs.getLong("oldestMaxBookmarkId", 0) // Find the upper bound val currentBookmarkId: Long = - (bookmarksHelper.getNewIllusts().next_url?.substringAfter("max_bookmark_id=")!! + (bookmarksHelper.getNewPublicBookmarks().next_url?.substringAfter("max_bookmark_id=")!! .toLong() * 1.01).toLong() var bookmarkArtworks = - bookmarksHelper.getNewIllusts((oldestBookmarkId..currentBookmarkId).random().toString()).artworks + bookmarksHelper.getNewPublicBookmarks( + (oldestBookmarkId..currentBookmarkId).random().toString() + ).artworks val artworkList = mutableListOf() var counter = 0 while (counter < sharedPrefs.getInt("prefSlider_numToDownload", 2)) { @@ -758,7 +762,9 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : } catch (e: FilterMatchNotFoundException) { Log.i(LOG_TAG, "Fetching new bookmarks") bookmarkArtworks = - bookmarksHelper.getNewIllusts((oldestBookmarkId..currentBookmarkId).random().toString()).artworks + bookmarksHelper.getNewPublicBookmarks( + (oldestBookmarkId..currentBookmarkId).random().toString() + ).artworks continue } catch (e: CorruptFileException) { Log.i(LOG_TAG, "Corrupt artwork found") @@ -770,11 +776,12 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : return artworkList } + // Bookmarks artworks are handled in a separate function + // Part of the reason is that Pixiv itself has different API surface for bookmarks + // And must be handled accordingly private fun getArtworksAuth(updateMode: String): List { val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(applicationContext) // Determines if any extra information is needed, and passes it along - - // {"follow", "bookmark", "tag_search", "artist", "recommended"}; val illustsHelper = when (updateMode) { "follow" -> IllustsHelper(updateMode) "recommended" -> IllustsHelper(updateMode) @@ -784,6 +791,7 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : sharedPrefs.getString("pref_tagSearch", "") ?: "", sharedPrefs.getString("pref_tagLanguage", "") ?: "" ) + else -> IllustsHelper("follow") } var authArtworkList = illustsHelper.getNewIllusts().artworks @@ -847,9 +855,6 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : } } - // App has functionality to temporarily or permanently change the update mode if authentication fails - // i.e. update mode can change between the previous if block and this if block - // Thus two identical if statements are required Log.i(LOG_TAG, "Feed mode: $updateMode") val artworkList: List = when (updateMode) { "bookmark" -> getArtworksBookmark() @@ -875,6 +880,7 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : }) return "daily" } + "doNotChange_downDaily" -> { Log.i(LOG_TAG, "Downloading a single daily") PixivMuzeiSupervisor.post(Runnable { @@ -886,6 +892,7 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : }) return "daily" } + "doNotChange_doNotDown" -> { Log.i(LOG_TAG, "Retrying with no changes") PixivMuzeiSupervisor.post(Runnable { @@ -897,6 +904,7 @@ class PixivArtWorker(context: Context, workerParams: WorkerParameters) : }) return null } + else -> return null } } diff --git a/app/src/main/java/com/antony/muzei/pixiv/provider/network/PixivAuthFeedJsonService.java b/app/src/main/java/com/antony/muzei/pixiv/provider/network/PixivAuthFeedJsonService.java index 562e7153..833c68b3 100644 --- a/app/src/main/java/com/antony/muzei/pixiv/provider/network/PixivAuthFeedJsonService.java +++ b/app/src/main/java/com/antony/muzei/pixiv/provider/network/PixivAuthFeedJsonService.java @@ -32,10 +32,16 @@ public interface PixivAuthFeedJsonService { Call getFollowJson(); @GET("v1/user/bookmarks/illust?restrict=public") - Call getBookmarkJson(@Query("user_id") String userId); + Call getPublicBookmarkJson(@Query("user_id") String userId); + + @GET("v1/user/bookmarks/illust?restrict=private") + Call getPrivateBookmarkJson(@Query("user_id") String userId); @GET("v1/user/bookmarks/illust?restrict=public") - Call getBookmarkOffsetJson(@Query("user_id") String userId, @Query("max_bookmark_id") String maxBookmarkId); + Call getPublicBookmarkOffsetJson(@Query("user_id") String userId, @Query("max_bookmark_id") String maxBookmarkId); + + @GET("v1/user/bookmarks/illust?restrict=private") + Call getPrivateBookmarkOffsetJson(@Query("user_id") String userId, @Query("max_bookmark_id") String maxBookmarkId); @GET("v1/search/illust?search_target=partial_match_for_tags&sort=date_desc") Call getTagSearchJson(@Header("Accept-Language") String language, @Query("word") String tag); diff --git a/app/src/main/java/com/antony/muzei/pixiv/settings/MainActivity.kt b/app/src/main/java/com/antony/muzei/pixiv/settings/MainActivity.kt index c59c88c0..abde3b09 100644 --- a/app/src/main/java/com/antony/muzei/pixiv/settings/MainActivity.kt +++ b/app/src/main/java/com/antony/muzei/pixiv/settings/MainActivity.kt @@ -54,41 +54,41 @@ class MainActivity : PixivMuzeiActivity(), AdvOptionsPreferenceFragment.NightMod }.attach() // If Muzei is not installed, this will redirect the user to Muzei's Play Store listing - if (!isMuzeiInstalled) { - AlertDialog.Builder(this) - .setTitle(getString(R.string.dialogTitle_muzeiNotInstalled)) - .setMessage(getString(R.string.dialog_installMuzei)) - .setPositiveButton(R.string.dialog_yes) { dialog: DialogInterface?, which: Int -> - if (!IntentUtils.launchActivity( - this, - Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=net.nurik.roman.muzei")) - ) - ) { - val fallback = Intent( - Intent.ACTION_VIEW, - Uri.parse("https://play.google.com/store/apps/details?id=net.nurik.roman.muzei") - ) - IntentUtils.launchActivity(this, fallback) - } - } - .setNegativeButton(R.string.dialog_no) { dialog: DialogInterface, which: Int -> - // Do nothing - dialog.dismiss() - } - .show() - } else if (!isProviderSelected(this, BuildConfig.APPLICATION_ID + ".provider")) { - // If Pixiv for Muzei 3 is not the selected provider - AlertDialog.Builder(this) - .setTitle(applicationContext.getString(R.string.dialogTitle_muzeiNotActiveSource)) - .setMessage(applicationContext.getString(R.string.dialog_selectSource)) - .setNeutralButton(android.R.string.ok) { dialog: DialogInterface?, which: Int -> - val intent = createChooseProviderIntent(BuildConfig.APPLICATION_ID + ".provider") - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - finishAffinity() - IntentUtils.launchActivity(this, intent) - } - .show() - } +// if (!isMuzeiInstalled) { +// AlertDialog.Builder(this) +// .setTitle(getString(R.string.dialogTitle_muzeiNotInstalled)) +// .setMessage(getString(R.string.dialog_installMuzei)) +// .setPositiveButton(R.string.dialog_yes) { dialog: DialogInterface?, which: Int -> +// if (!IntentUtils.launchActivity( +// this, +// Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=net.nurik.roman.muzei")) +// ) +// ) { +// val fallback = Intent( +// Intent.ACTION_VIEW, +// Uri.parse("https://play.google.com/store/apps/details?id=net.nurik.roman.muzei") +// ) +// IntentUtils.launchActivity(this, fallback) +// } +// } +// .setNegativeButton(R.string.dialog_no) { dialog: DialogInterface, which: Int -> +// // Do nothing +// dialog.dismiss() +// } +// .show() +// } else if (!isProviderSelected(this, BuildConfig.APPLICATION_ID + ".provider")) { +// // If Pixiv for Muzei 3 is not the selected provider +// AlertDialog.Builder(this) +// .setTitle(applicationContext.getString(R.string.dialogTitle_muzeiNotActiveSource)) +// .setMessage(applicationContext.getString(R.string.dialog_selectSource)) +// .setNeutralButton(android.R.string.ok) { dialog: DialogInterface?, which: Int -> +// val intent = createChooseProviderIntent(BuildConfig.APPLICATION_ID + ".provider") +// intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK +// finishAffinity() +// IntentUtils.launchActivity(this, intent) +// } +// .show() +// } } // Checks if Muzei is installed diff --git a/app/src/main/java/com/antony/muzei/pixiv/settings/SectionsPagerAdapter.java b/app/src/main/java/com/antony/muzei/pixiv/settings/SectionsPagerAdapter.java index 8348f303..581f08c9 100644 --- a/app/src/main/java/com/antony/muzei/pixiv/settings/SectionsPagerAdapter.java +++ b/app/src/main/java/com/antony/muzei/pixiv/settings/SectionsPagerAdapter.java @@ -24,6 +24,7 @@ import com.antony.muzei.pixiv.settings.deleteArtwork.ArtworkDeletionFragment; import com.antony.muzei.pixiv.settings.fragments.AdvOptionsPreferenceFragment; +import com.antony.muzei.pixiv.settings.fragments.BookmarkExportFragment; import com.antony.muzei.pixiv.settings.fragments.CreditsPreferenceFragment; import com.antony.muzei.pixiv.settings.fragments.MainPreferenceFragment; import com.antony.muzei.pixiv.settings.fragments.RoadmapPreferenceFragment; @@ -50,7 +51,7 @@ public Fragment createFragment(int position) { default: return new CreditsPreferenceFragment(); case 4: - return new RoadmapPreferenceFragment(); + return new BookmarkExportFragment(); } } diff --git a/app/src/main/java/com/antony/muzei/pixiv/settings/fragments/BookmarkExportFragment.kt b/app/src/main/java/com/antony/muzei/pixiv/settings/fragments/BookmarkExportFragment.kt new file mode 100644 index 00000000..d9f5da18 --- /dev/null +++ b/app/src/main/java/com/antony/muzei/pixiv/settings/fragments/BookmarkExportFragment.kt @@ -0,0 +1,117 @@ +/* + * This file is part of PixivforMuzei3. + * + * PixivforMuzei3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.antony.muzei.pixiv.settings.fragments + +import android.os.Bundle +import android.os.Environment +import android.os.Handler +import android.util.Log +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager +import com.antony.muzei.pixiv.R +import com.antony.muzei.pixiv.provider.BookmarksHelper +import com.google.android.material.snackbar.Snackbar +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File +import java.io.IOException + + +class BookmarkExportFragment : PreferenceFragmentCompat() { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.bookmark_export_layout, rootKey) + // setting up some prereqs + val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(requireContext()) + val userId = sharedPrefs.getString("userId", "") + + // public bookmark + val getPublicBookmarkPreference = + findPreference("button_exportBookmarkPublic") ?: return + getPublicBookmarkPreference.onPreferenceClickListener = + Preference.OnPreferenceClickListener { + getBookmarks(true, userId!!, getPublicBookmarkPreference) + + Snackbar.make(requireView(), "public bookmarks exported", Snackbar.LENGTH_SHORT) + .show() + true + } + + // private BOOKMARK + val getPrivateBookmarkPreference = + findPreference("button_exportBookmarkPrivate") ?: return + getPrivateBookmarkPreference.onPreferenceClickListener = + Preference.OnPreferenceClickListener { + getBookmarks(false, userId!!, getPrivateBookmarkPreference) + + Snackbar.make(requireView(), "private bookmarks exported", Snackbar.LENGTH_SHORT) + .show() + true + } + } + + private fun getBookmarks(publicBookmark: Boolean, userId: String, preference: Preference) { + try { + // NetworkOnMainThread exception + CoroutineScope(Dispatchers.Main + SupervisorJob()).launch(Dispatchers.IO) { + val bookmarks = BookmarksHelper(userId) + + if (publicBookmark) { + bookmarks.getNewPublicBookmarks() + } else { + bookmarks.getNewPrivateIllusts() + } + + val filename = if (publicBookmark) { + "bookmarksPublic.txt" + } else { + "bookmarksPrivate.txt" + } + val textFile: File = File( + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), + filename + ).also { it.writeText("") } + + var iterationCounter = 1 + while (bookmarks.getBookmarks().artworks.isNotEmpty()) { + // Iterate through list of artworks and add id's to list + for (artwork in bookmarks.getBookmarks().artworks) { + //Log.d("BOOKMARK", artwork.id.toString()) + textFile.appendText("https://www.pixiv.net/en/artworks/${artwork.id}\n") + } + // Update the UI to show progress + withContext(Dispatchers.Main) { + preference.summary = "Saving page $iterationCounter" + } + iterationCounter++ + // Delay of 500 ms to avoid overloading Pixiv network + delay(500L) + bookmarks.getNextBookmarks() + } + withContext(Dispatchers.Main) { + preference.summary = "Completed saving artworks" + } + } + } catch (ex: IOException) { + ex.printStackTrace() + } + } +} diff --git a/app/src/main/res/xml/bookmark_export_layout.xml b/app/src/main/res/xml/bookmark_export_layout.xml new file mode 100644 index 00000000..3d05c18f --- /dev/null +++ b/app/src/main/res/xml/bookmark_export_layout.xml @@ -0,0 +1,11 @@ + + + + +