mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Add migration ability.
Various bug fixes and code cleanup.
This commit is contained in:
		@@ -159,6 +159,8 @@ class PreferencesHelper(val context: Context) {
 | 
			
		||||
 | 
			
		||||
    fun thumbnailRows() = rxPrefs.getString("ex_thumb_rows", "tr_2")
 | 
			
		||||
 | 
			
		||||
    fun migrateLibraryAsked() = rxPrefs.getBoolean("ex_migrate_library", false)
 | 
			
		||||
 | 
			
		||||
    //EH Cookies
 | 
			
		||||
    fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null)
 | 
			
		||||
    fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.library
 | 
			
		||||
 | 
			
		||||
import android.os.Handler
 | 
			
		||||
import android.os.Looper
 | 
			
		||||
import android.view.Gravity
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 | 
			
		||||
@@ -17,6 +19,7 @@ import exh.search.SearchEngine
 | 
			
		||||
import kotlinx.android.synthetic.main.item_catalogue_grid.view.*
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.util.*
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adapter storing a list of manga in a certain category.
 | 
			
		||||
@@ -36,6 +39,8 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
 | 
			
		||||
    private val searchEngine = SearchEngine()
 | 
			
		||||
    private val metadataHelper = MetadataHelper()
 | 
			
		||||
 | 
			
		||||
    var asyncSearchText: String? = null
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        setHasStableIds(true)
 | 
			
		||||
    }
 | 
			
		||||
@@ -69,8 +74,17 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
 | 
			
		||||
     * @param param the filter. Not used.
 | 
			
		||||
     */
 | 
			
		||||
    override fun updateDataSet(param: String?) {
 | 
			
		||||
        filterItems(mangas)
 | 
			
		||||
        notifyDataSetChanged()
 | 
			
		||||
        //Async search filter (EH)
 | 
			
		||||
        val filtered = asyncSearchText?.let { search ->
 | 
			
		||||
            mangas.filter {
 | 
			
		||||
                filterObject(it, search)
 | 
			
		||||
            }
 | 
			
		||||
        } ?: mangas
 | 
			
		||||
        //The rest of the filters run on the main loop
 | 
			
		||||
        Handler(Looper.getMainLooper()).post {
 | 
			
		||||
            filterItems(filtered)
 | 
			
		||||
            notifyDataSetChanged()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -100,7 +114,7 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
 | 
			
		||||
                val metadata = metadataHelper.fetchMetadata(manga.url, exh)
 | 
			
		||||
                metadata?.let {
 | 
			
		||||
                    searchEngine.matches(metadata, searchEngine.parseQuery(query))
 | 
			
		||||
                } ?: title.toLowerCase().contains(query) //Use regular searching when the metadata is not set up for this gallery
 | 
			
		||||
                } ?: title.contains(query, ignoreCase = true) //Use regular searching when the metadata is not set up for this gallery
 | 
			
		||||
            } ?: false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,9 @@ import eu.kanade.tachiyomi.util.toast
 | 
			
		||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
 | 
			
		||||
import kotlinx.android.synthetic.main.item_library_category.view.*
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.util.concurrent.TimeUnit
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fragment containing the library manga for a certain category.
 | 
			
		||||
@@ -114,8 +116,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
 | 
			
		||||
 | 
			
		||||
        val presenter = fragment.presenter
 | 
			
		||||
 | 
			
		||||
        searchSubscription = presenter.searchSubject.subscribe { text ->
 | 
			
		||||
            adapter.searchText = text
 | 
			
		||||
        searchSubscription = presenter
 | 
			
		||||
                .searchSubject
 | 
			
		||||
                .debounce(100L, TimeUnit.MILLISECONDS)
 | 
			
		||||
                .subscribe { text -> //Debounce search (EH)
 | 
			
		||||
            adapter.asyncSearchText = text.trim().toLowerCase()
 | 
			
		||||
            adapter.updateDataSet()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import android.support.v4.app.TaskStackBuilder
 | 
			
		||||
import android.support.v4.view.GravityCompat
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.ui.backup.BackupFragment
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
 | 
			
		||||
@@ -17,9 +18,12 @@ import eu.kanade.tachiyomi.ui.library.LibraryFragment
 | 
			
		||||
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersFragment
 | 
			
		||||
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadFragment
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
 | 
			
		||||
import exh.ui.MetadataFetchDialog
 | 
			
		||||
import exh.ui.batchadd.BatchAddFragment
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_main.*
 | 
			
		||||
import kotlinx.android.synthetic.main.toolbar.*
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class MainActivity : BaseActivity() {
 | 
			
		||||
@@ -82,6 +86,14 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
 | 
			
		||||
            // Show changelog if needed
 | 
			
		||||
            ChangelogDialogFragment.show(this, preferences, supportFragmentManager)
 | 
			
		||||
 | 
			
		||||
            // Migrate library if needed
 | 
			
		||||
            Injekt.get<DatabaseHelper>().getLibraryMangas().asRxSingle().subscribe {
 | 
			
		||||
                if(it.size > 0)
 | 
			
		||||
                    runOnUiThread {
 | 
			
		||||
                        MetadataFetchDialog().tryAskMigration(this)
 | 
			
		||||
                    }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,9 @@ import android.support.v7.preference.XpPreferenceFragment
 | 
			
		||||
import android.view.View
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.util.plusAssign
 | 
			
		||||
import exh.ui.MetadataFetchDialog
 | 
			
		||||
import exh.ui.login.LoginActivity
 | 
			
		||||
import net.xpece.android.support.preference.Preference
 | 
			
		||||
import net.xpece.android.support.preference.SwitchPreference
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +31,10 @@ class SettingsEhFragment : SettingsFragment() {
 | 
			
		||||
        findPreference("enable_exhentai") as SwitchPreference
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val migrateLibraryPref by lazy {
 | 
			
		||||
        findPreference("ex_migrate_library") as Preference
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedState)
 | 
			
		||||
 | 
			
		||||
@@ -48,5 +54,10 @@ class SettingsEhFragment : SettingsFragment() {
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        migrateLibraryPref.setOnPreferenceClickListener {
 | 
			
		||||
            MetadataFetchDialog().askMigration(activity)
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,15 +9,22 @@ class MetadataHelper {
 | 
			
		||||
            = exGalleryBook().write(galleryMetadata.galleryUniqueIdentifier(), galleryMetadata)
 | 
			
		||||
 | 
			
		||||
    fun fetchMetadata(url: String, exh: Boolean): ExGalleryMetadata?
 | 
			
		||||
            = ExGalleryMetadata().apply {
 | 
			
		||||
        this.url = url
 | 
			
		||||
        this.exh = exh
 | 
			
		||||
        return exGalleryBook().read<ExGalleryMetadata>(galleryUniqueIdentifier())
 | 
			
		||||
            = ExGalleryMetadata().let {
 | 
			
		||||
        it.url = url
 | 
			
		||||
        it.exh = exh
 | 
			
		||||
        return exGalleryBook().read<ExGalleryMetadata>(it.galleryUniqueIdentifier())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getAllGalleries() = exGalleryBook().allKeys.map {
 | 
			
		||||
        exGalleryBook().read<ExGalleryMetadata>(it)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun hasMetadata(url: String, exh: Boolean): Boolean
 | 
			
		||||
            = ExGalleryMetadata().let {
 | 
			
		||||
        it.url = url
 | 
			
		||||
        it.exh = exh
 | 
			
		||||
        return exGalleryBook().exist(it.galleryUniqueIdentifier())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun exGalleryBook() = Paper.book("gallery-ex")!!
 | 
			
		||||
}
 | 
			
		||||
@@ -9,7 +9,7 @@ class SearchEngine {
 | 
			
		||||
 | 
			
		||||
    fun matches(metadata: ExGalleryMetadata, query: List<QueryComponent>): Boolean {
 | 
			
		||||
 | 
			
		||||
        fun matchTagList(tags: List<Tag>,
 | 
			
		||||
        fun matchTagList(tags: Sequence<Tag>,
 | 
			
		||||
                         component: Text): Boolean {
 | 
			
		||||
            //Match tags
 | 
			
		||||
            val tagMatcher = if(!component.exact)
 | 
			
		||||
@@ -28,15 +28,18 @@ class SearchEngine {
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val cachedLowercaseTitle = metadata.title?.toLowerCase()
 | 
			
		||||
        val cachedLowercaseAltTitle = metadata.altTitle?.toLowerCase()
 | 
			
		||||
 | 
			
		||||
        for(component in query) {
 | 
			
		||||
            if(component is Text) {
 | 
			
		||||
                //Match title
 | 
			
		||||
                if (component.asRegex().test(metadata.title?.toLowerCase())
 | 
			
		||||
                        || component.asRegex().test(metadata.altTitle?.toLowerCase())) {
 | 
			
		||||
                if (component.asRegex().test(cachedLowercaseTitle)
 | 
			
		||||
                        || component.asRegex().test(cachedLowercaseAltTitle)) {
 | 
			
		||||
                    continue
 | 
			
		||||
                }
 | 
			
		||||
                //Match tags
 | 
			
		||||
                if(!matchTagList(metadata.tags.entries.flatMap { it.value },
 | 
			
		||||
                if(!matchTagList(metadata.tags.entries.asSequence().flatMap { it.value.asSequence() },
 | 
			
		||||
                        component)) return false
 | 
			
		||||
            } else if(component is Namespace) {
 | 
			
		||||
                if(component.namespace == "uploader") {
 | 
			
		||||
@@ -47,9 +50,9 @@ class SearchEngine {
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    //Match namespace
 | 
			
		||||
                    val ns = metadata.tags.entries.filter {
 | 
			
		||||
                    val ns = metadata.tags.entries.asSequence().filter {
 | 
			
		||||
                        it.key == component.namespace
 | 
			
		||||
                    }.flatMap { it.value }
 | 
			
		||||
                    }.flatMap { it.value.asSequence() }
 | 
			
		||||
                    //Match tags
 | 
			
		||||
                    if (!matchTagList(ns, component.tag!!))
 | 
			
		||||
                        return false
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										139
									
								
								app/src/main/java/exh/ui/MetadataFetchDialog.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								app/src/main/java/exh/ui/MetadataFetchDialog.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
package exh.ui
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.content.pm.ActivityInfo
 | 
			
		||||
import com.afollestad.materialdialogs.MaterialDialog
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
 | 
			
		||||
import eu.kanade.tachiyomi.data.source.SourceManager
 | 
			
		||||
import eu.kanade.tachiyomi.data.source.online.all.EHentai
 | 
			
		||||
import exh.metadata.MetadataHelper
 | 
			
		||||
import exh.metadata.copyTo
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
class MetadataFetchDialog {
 | 
			
		||||
 | 
			
		||||
    val metadataHelper by lazy { MetadataHelper() }
 | 
			
		||||
 | 
			
		||||
    val db: DatabaseHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    val sourceManager: SourceManager by injectLazy()
 | 
			
		||||
 | 
			
		||||
    val preferenceHelper: PreferencesHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    fun show(context: Activity) {
 | 
			
		||||
        //Too lazy to actually deal with orientation changes
 | 
			
		||||
        context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
 | 
			
		||||
 | 
			
		||||
        val progressDialog = MaterialDialog.Builder(context)
 | 
			
		||||
                .title("Migrating library")
 | 
			
		||||
                .content("Preparing library")
 | 
			
		||||
                .progress(false, 0, true)
 | 
			
		||||
                .cancelable(false)
 | 
			
		||||
                .canceledOnTouchOutside(false)
 | 
			
		||||
                .show()
 | 
			
		||||
 | 
			
		||||
        thread {
 | 
			
		||||
            db.deleteMangasNotInLibrary().executeAsBlocking()
 | 
			
		||||
 | 
			
		||||
            val libraryMangas = db.getLibraryMangas()
 | 
			
		||||
                    .executeAsBlocking()
 | 
			
		||||
                    .filter {
 | 
			
		||||
                        it.source <= 2
 | 
			
		||||
                        && !metadataHelper.hasMetadata(it.url, it.source == 2)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
            context.runOnUiThread {
 | 
			
		||||
                progressDialog.maxProgress = libraryMangas.size
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Actual metadata fetch code
 | 
			
		||||
            libraryMangas.forEachIndexed { i, manga ->
 | 
			
		||||
                context.runOnUiThread {
 | 
			
		||||
                    progressDialog.setContent("Processing: ${manga.title}")
 | 
			
		||||
                    progressDialog.setProgress(i + 1)
 | 
			
		||||
                }
 | 
			
		||||
                try {
 | 
			
		||||
                    val source = sourceManager.get(manga.source)
 | 
			
		||||
                    source?.let {
 | 
			
		||||
                        it as EHentai
 | 
			
		||||
                        manga.copyFrom(it.fetchMangaDetails(manga).toBlocking().first())
 | 
			
		||||
                        metadataHelper.fetchMetadata(manga.url, it.exh)?.copyTo(manga)
 | 
			
		||||
                    }
 | 
			
		||||
                } catch(t: Throwable) {
 | 
			
		||||
                    Timber.e(t, "Could not migrate manga!")
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            context.runOnUiThread {
 | 
			
		||||
                progressDialog.dismiss()
 | 
			
		||||
 | 
			
		||||
                //Enable orientation changes again
 | 
			
		||||
                context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
 | 
			
		||||
 | 
			
		||||
                displayMigrationComplete(context)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun tryAskMigration(activity: Activity) {
 | 
			
		||||
        if(preferenceHelper.migrateLibraryAsked().getOrDefault()) return
 | 
			
		||||
 | 
			
		||||
        MaterialDialog.Builder(activity)
 | 
			
		||||
                .title("Migrate library")
 | 
			
		||||
                .content("You need to migrate your library before tag searching in the library will function.\n\n" +
 | 
			
		||||
                        "This migration may take a long time depending on your library size and will also use up a significant amount of internet bandwidth.\n\n" +
 | 
			
		||||
                        "This process can be done later if required.")
 | 
			
		||||
                .positiveText("Migrate")
 | 
			
		||||
                .negativeText("Later")
 | 
			
		||||
                .onPositive { materialDialog, dialogAction -> show(activity) }
 | 
			
		||||
                .onNegative { materialDialog, dialogAction -> adviseMigrationLater(activity) }
 | 
			
		||||
                .cancelable(false)
 | 
			
		||||
                .canceledOnTouchOutside(false)
 | 
			
		||||
                .dismissListener {
 | 
			
		||||
                    preferenceHelper.migrateLibraryAsked().set(true)
 | 
			
		||||
                }.show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun askMigration(activity: Activity) {
 | 
			
		||||
        MaterialDialog.Builder(activity)
 | 
			
		||||
                .title("Migrate library")
 | 
			
		||||
                .content("You need to migrate your library before tag searching in the library will function.\n\n" +
 | 
			
		||||
                        "This migration may take a long time depending on your library size and will also use up a significant amount of internet bandwidth.\n\n" +
 | 
			
		||||
                        "This process can be done later if required.")
 | 
			
		||||
                .positiveText("Migrate")
 | 
			
		||||
                .negativeText("Later")
 | 
			
		||||
                .onPositive { materialDialog, dialogAction -> show(activity) }
 | 
			
		||||
                .onNegative { materialDialog, dialogAction -> adviseMigrationLater(activity) }
 | 
			
		||||
                .cancelable(false)
 | 
			
		||||
                .canceledOnTouchOutside(false)
 | 
			
		||||
                .dismissListener {
 | 
			
		||||
                    preferenceHelper.migrateLibraryAsked().set(true)
 | 
			
		||||
                }.show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun adviseMigrationLater(activity: Activity) {
 | 
			
		||||
        MaterialDialog.Builder(activity)
 | 
			
		||||
                .title("Migration canceled")
 | 
			
		||||
                .content("Library migration has been canceled.\n\n" +
 | 
			
		||||
                        "You can run this operation later by going to: Settings > EHentai > Migrate Library")
 | 
			
		||||
                .positiveText("Ok")
 | 
			
		||||
                .cancelable(true)
 | 
			
		||||
                .canceledOnTouchOutside(true)
 | 
			
		||||
                .show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun displayMigrationComplete(activity: Activity) {
 | 
			
		||||
        MaterialDialog.Builder(activity)
 | 
			
		||||
                .title("Migration complete")
 | 
			
		||||
                .content("${activity.getString(R.string.app_name)} is now ready for use!")
 | 
			
		||||
                .positiveText("Ok")
 | 
			
		||||
                .cancelable(true)
 | 
			
		||||
                .canceledOnTouchOutside(true)
 | 
			
		||||
                .show()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -63,6 +63,16 @@
 | 
			
		||||
            android:entries="@array/ehentai_thumbnail_rows"
 | 
			
		||||
            android:entryValues="@array/ehentai_thumbnail_rows_values" />
 | 
			
		||||
 | 
			
		||||
        <PreferenceCategory
 | 
			
		||||
            android:title="Advanced"
 | 
			
		||||
            android:persistent="false">
 | 
			
		||||
            <Preference
 | 
			
		||||
                android:title="Migrate library"
 | 
			
		||||
                android:persistent="false"
 | 
			
		||||
                android:key="ex_migrate_library"
 | 
			
		||||
                android:summary="Migrate your library to enable tag searching in the library. This button will be visible even if you have already migrated your library" />
 | 
			
		||||
        </PreferenceCategory>
 | 
			
		||||
 | 
			
		||||
    </PreferenceScreen>
 | 
			
		||||
 | 
			
		||||
</PreferenceScreen>
 | 
			
		||||
		Reference in New Issue
	
	Block a user