diff --git a/.gitignore b/.gitignore index d582af87..7ca3a2e2 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ /gh-pages #Private files -**/google-services.json \ No newline at end of file +**/google-services.json +**/credentials.json \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/BroadcastReciever.kt b/app/src/main/java/xyz/quaver/pupil/BroadcastReciever.kt index 9d21e062..2456da45 100644 --- a/app/src/main/java/xyz/quaver/pupil/BroadcastReciever.kt +++ b/app/src/main/java/xyz/quaver/pupil/BroadcastReciever.kt @@ -29,7 +29,6 @@ import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.content.FileProvider import androidx.preference.PreferenceManager -import xyz.quaver.pupil.util.cancelImport import java.io.File class BroadcastReciever : BroadcastReceiver() { @@ -93,9 +92,6 @@ class BroadcastReciever : BroadcastReceiver() { notificationManager.notify(R.id.notification_id_update, notification) } - ACTION_CANCEL_IMPORT -> { - cancelImport = true - } } } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt index 44ebc1b3..7d5e7909 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt @@ -156,43 +156,6 @@ class SettingsActivity : AppCompatActivity() { .apply() } } - R.id.request_import_old_galleries -> { - if (resultCode == Activity.RESULT_OK) { - data?.data?.also { uri -> - val takeFlags: Int = - intent.flags and (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) - contentResolver.takePersistableUriPermission(uri, takeFlags) - - val file = uri.toFile(this) - - if (file?.canRead() != true) - Snackbar.make( - settings, - resources.getText(R.string.import_old_galleries_folder_not_readable), - Snackbar.LENGTH_LONG - ).show() - else - importOldGalleries(this, file) - } - } - } - R.id.request_import_old_galleries_old -> { - if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { - val directory = data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!! - - if (!File(directory).canRead()) - Snackbar.make( - settings, - resources.getText(R.string.import_old_galleries_folder_not_readable), - Snackbar.LENGTH_LONG - ).show() - else { - importOldGalleries(this, File(directory)) - } - } - } else -> super.onActivityResult(requestCode, resultCode, data) } } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt index 43cc4362..ce2198e8 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt @@ -198,31 +198,6 @@ class SettingsFragment : activity?.startActivityForResult(intent, R.id.request_restore.normalizeID()) } - "old_import_galleries" -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - - if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) - ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), R.id.request_write_permission_and_saf.normalizeID()) - else { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { - putExtra("android.content.extra.SHOW_ADVANCED", true) - } - - activity?.startActivityForResult(intent, R.id.request_import_old_galleries.normalizeID()) - } - } else { // Can't use SAF on old Androids! - val config = DirectoryChooserConfig.builder() - .newDirectoryName("Pupil") - .allowNewDirectoryNameModification(true) - .build() - - val intent = Intent(requireContext(), DirectoryChooserActivity::class.java).apply { - putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config) - } - - activity?.startActivityForResult(intent, R.id.request_import_old_galleries_old.normalizeID()) - } - } "user_id" -> { (context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip( ClipData.newPlainText("user_id", sharedPreference.getString("user_id", "")) @@ -380,9 +355,6 @@ class SettingsFragment : "restore" -> { onPreferenceClickListener = this@SettingsFragment } - "old_import_galleries" -> { - onPreferenceClickListener = this@SettingsFragment - } "user_id" -> { summary = sharedPreference.getString("user_id", "") onPreferenceClickListener = this@SettingsFragment diff --git a/app/src/main/java/xyz/quaver/pupil/util/update.kt b/app/src/main/java/xyz/quaver/pupil/util/update.kt index 14a56d92..b2b64c05 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/update.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt @@ -184,149 +184,4 @@ fun checkUpdate(context: Context, force: Boolean = false) { dialog.show() } } -} - -var cancelImport = false -@SuppressLint("RestrictedApi") -fun importOldGalleries(context: Context, folder: File) = CoroutineScope(Dispatchers.IO).launch { - val client = OkHttpClient.Builder() - .connectTimeout(0, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.SECONDS) - .proxy(proxy) - .build() - - val cancelIntent = Intent(context, BroadcastReciever::class.java).apply { - action = BroadcastReciever.ACTION_CANCEL_IMPORT - putExtra(BroadcastReciever.EXTRA_IMPORT_NOTIFICATION_ID, 0) - } - val pendingIntent = PendingIntent.getBroadcast(context, 0, cancelIntent, 0) - - val notificationManager = NotificationManagerCompat.from(context) - val notificationBuilder = NotificationCompat.Builder(context, "import").apply { - setContentTitle(context.getText(R.string.import_old_galleries_notification)) - setProgress(0, 0, true) - setSmallIcon(R.drawable.ic_notification) - addAction(0, context.getText(android.R.string.cancel), pendingIntent) - setOngoing(true) - } - - notificationManager.notify(0, notificationBuilder.build()) - - if (!folder.isDirectory) - return@launch - - val galleryRegex = Regex("""[0-9]+$""") - val imageRegex = Regex("""^[0-9]+\..+$""") - var size = 0 - fun setProgress(progress: Int) { - notificationBuilder.apply { - setContentText( - context.getString( - R.string.import_old_galleries_notification_text, - progress, - size - ) - ) - setProgress(size, progress, false) - } - - notificationManager.notify(0, notificationBuilder.build()) - } - - folder.listFiles { _, name -> - galleryRegex.matches(name) - }?.also { - size = it.size - setProgress(0) - }?.forEachIndexed { index, gallery -> - if (cancelImport) - return@forEachIndexed - - setProgress(index) - - val galleryID = gallery.name.toIntOrNull() ?: return@forEachIndexed - - File(getDownloadDirectory(context), galleryID.toString()).mkdirs() - - val reader = async { - kotlin.runCatching { - Json.decodeFromString(File(gallery, "reader.json").readText()) - }.getOrElse { - getReader(galleryID) - } - } - val galleryBlock = async { - kotlin.runCatching { - Json.decodeFromString(File(gallery, "galleryBlock.json").readText()) - }.getOrElse { - getGalleryBlock(galleryID) - } - } - @Suppress("NAME_SHADOWING") - val thumbnail = async thumbnail@{ - val galleryBlock = galleryBlock.await() - - Base64.encodeToString(try { - File(gallery, "thumbnail.jpg").readBytes() - } catch (e: Exception) { - val url = galleryBlock?.thumbnails?.firstOrNull() - - if (url == null) - null - else { - val request = Request.Builder().url(url).build() - - var done = false - var result: ByteArray? = null - client.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call?, e: IOException?) { - done = true - } - - override fun onResponse(call: Call?, response: Response?) { - result = response?.body()?.use { - it.bytes() - } - done = true - } - }) - - if (!done) - yield() - - result - } - } ?: return@thumbnail null, Base64.DEFAULT) - } - - Cache(context).setCachedMetadata(galleryID, - Metadata( - thumbnail.await(), - galleryBlock.await(), - reader.await() - ) - ) - - File(gallery, "images").listFiles { _, name -> - imageRegex.matches(name) - }?.forEach { - if (cancelImport) - return@forEach - - @Suppress("NAME_SHADOWING") - val index = it.nameWithoutExtension.toIntOrNull() ?: return@forEach - - Cache(context).putImage(galleryID, index, it.extension, it.inputStream()) - } - } - - notificationBuilder.apply { - setContentText(context.getText(R.string.import_old_galleries_notification_done)) - setProgress(0, 0, false) - setOngoing(false) - mActions.clear() - } - notificationManager.notify(0, notificationBuilder.build()) - - cancelImport = false } \ No newline at end of file diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 4846bdad..63f01b71 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -108,10 +108,6 @@ app:key="restore" app:title="@string/settings_restore_title"/> - - diff --git a/libpupil/.gitignore b/libpupil/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/libpupil/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/libpupil/LICENSE b/libpupil/LICENSE deleted file mode 100644 index d6456956..00000000 --- a/libpupil/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/libpupil/build.gradle b/libpupil/build.gradle deleted file mode 100644 index f943ef77..00000000 --- a/libpupil/build.gradle +++ /dev/null @@ -1,36 +0,0 @@ -apply plugin: 'java-library' -apply plugin: 'kotlin' -apply plugin: 'kotlinx-serialization' - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0" - implementation 'org.jsoup:jsoup:1.13.1' - testImplementation 'junit:junit:4.13' -} - -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - } -} -repositories { - mavenCentral() -} -compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental' - } -} -compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} diff --git a/libpupil/src/main/java/xyz/quaver/Code.kt b/libpupil/src/main/java/xyz/quaver/Code.kt deleted file mode 100644 index 0251d817..00000000 --- a/libpupil/src/main/java/xyz/quaver/Code.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver - - -enum class Code { - HITOMI, - HIYOBI -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/Utils.kt b/libpupil/src/main/java/xyz/quaver/Utils.kt deleted file mode 100644 index 86fd5b9e..00000000 --- a/libpupil/src/main/java/xyz/quaver/Utils.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver - -import kotlinx.serialization.UnstableDefault -import kotlinx.serialization.json.Json -import java.net.Proxy - -var proxy : Proxy = Proxy.NO_PROXY - -@OptIn(UnstableDefault::class) -var json = Json { - isLenient = true - ignoreUnknownKeys = true - serializeSpecialFloatingPointValues = true - useArrayPolymorphism = true -} - -fun availableInHiyobi(galleryID: Int) : Boolean { - return try { - xyz.quaver.hiyobi.getReader(galleryID) - true - } catch (e: Exception) { - false - } -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/common.kt b/libpupil/src/main/java/xyz/quaver/hitomi/common.kt deleted file mode 100644 index bbbff1ac..00000000 --- a/libpupil/src/main/java/xyz/quaver/hitomi/common.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hitomi - -import xyz.quaver.json -import xyz.quaver.proxy -import java.net.URL - -const val protocol = "https:" - -@Suppress("EXPERIMENTAL_API_USAGE") -fun getGalleryInfo(galleryID: Int) = - json.parse( - GalleryInfo.serializer(), - URL("$protocol//$domain/galleries/$galleryID.js").openConnection(proxy).getInputStream().use { - it.reader().readText() - }.replace("var galleryinfo = ", "") - ) - -//common.js -var adapose = false -const val domain = "ltn.hitomi.la" -const val galleryblockdir = "galleryblock" -const val nozomiextension = ".nozomi" - -fun subdomainFromGalleryID(g: Int, numberOfFrontends: Int) : String { - if (adapose) - return "0" - - val o = g % numberOfFrontends - - return (97+o).toChar().toString() -} - -fun subdomainFromURL(url: String, base: String? = null) : String { - var retval = "a" - - if (!base.isNullOrBlank()) - retval = base - - var numberOfFrontends = 3 - val b = 16 - - val r = Regex("""/[0-9a-f]/([0-9a-f]{2})/""") - val m = r.find(url) ?: return retval - - var g = m.groupValues[1].toIntOrNull(b) - - if (g != null) { - if (g < 0x30) - numberOfFrontends = 2 - if (g < 0x09) - g = 1 - - retval = subdomainFromGalleryID(g, numberOfFrontends) + retval - } - - return retval -} - -fun urlFromURL(url: String, base: String? = null) : String { - return url.replace(Regex("""//..?\.hitomi\.la/"""), "//${subdomainFromURL(url, base)}.hitomi.la/") -} - - -fun fullPathFromHash(hash: String?) : String? { - return when { - (hash?.length ?: 0) < 3 -> hash - else -> hash!!.replace(Regex("^.*(..)(.)$"), "$2/$1/$hash") - } -} - -@Suppress("NAME_SHADOWING", "UNUSED_PARAMETER") -fun urlFromHash(galleryID: Int, image: GalleryFiles, dir: String? = null, ext: String? = null) : String { - val ext = ext ?: dir ?: image.name.split('.').last() - val dir = dir ?: "images" - return "$protocol//a.hitomi.la/$dir/${fullPathFromHash(image.hash)}.$ext" -} - -fun urlFromUrlFromHash(galleryID: Int, image: GalleryFiles, dir: String? = null, ext: String? = null, base: String? = null) = - urlFromURL(urlFromHash(galleryID, image, dir, ext), base) - -fun imageUrlFromImage(galleryID: Int, image: GalleryFiles, noWebp: Boolean) : String { - val webp = if (image.hash != null && image.haswebp != 0 && !noWebp) - "webp" - else - null - - return urlFromUrlFromHash(galleryID, image, webp) -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/galleries.kt b/libpupil/src/main/java/xyz/quaver/hitomi/galleries.kt deleted file mode 100644 index c9b1fae8..00000000 --- a/libpupil/src/main/java/xyz/quaver/hitomi/galleries.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hitomi - -import kotlinx.serialization.Serializable -import org.jsoup.Jsoup -import xyz.quaver.proxy -import java.net.URLDecoder - -@Serializable -data class Gallery( - val related: List, - val langList: List>, - val cover: String, - val title: String, - val artists: List, - val groups: List, - val type: String, - val language: String, - val series: List, - val characters: List, - val tags: List, - val thumbnails: List -) -fun getGallery(galleryID: Int) : Gallery { - val url = Jsoup.connect("https://hitomi.la/galleries/$galleryID.html").proxy(proxy).get() - .select("a").attr("href") - - val doc = Jsoup.connect(url).get() - - val related = Regex("\\d+") - .findAll(doc.select("script").first().html()) - .map { - it.value.toInt() - }.toList() - - val langList = doc.select("#lang-list a").map { - Pair(it.text(), "$protocol//hitomi.la${it.attr("href")}") - } - - val cover = protocol + doc.selectFirst(".cover img").attr("src") - val title = doc.selectFirst(".gallery h1 a").text() - val artists = doc.select(".gallery h2 a").map { it.text() } - val groups = doc.select(".gallery-info a[href~=^/group/]").map { it.text() } - val type = doc.selectFirst(".gallery-info a[href~=^/type/]").text() - - val language = { - val href = doc.select(".gallery-info a[href~=^/index-.+-1.html]").attr("href") - href.slice(7 until href.indexOf("-1")) - }.invoke() - - val series = doc.select(".gallery-info a[href~=^/series/]").map { it.text() } - val characters = doc.select(".gallery-info a[href~=^/character/]").map { it.text() } - - val tags = doc.select(".gallery-info a[href~=^/tag/]").map { - val href = URLDecoder.decode(it.attr("href"), "UTF-8") - href.slice(5 until href.indexOf('-')) - } - - val thumbnails = getGalleryInfo(galleryID).files.map { galleryInfo -> - urlFromUrlFromHash(galleryID, galleryInfo, "smalltn", "jpg", "tn") - } - - return Gallery(related, langList, cover, title, artists, groups, type, language, series, characters, tags, thumbnails) -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt b/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt deleted file mode 100644 index b783588c..00000000 --- a/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hitomi - -import kotlinx.serialization.Serializable -import org.jsoup.Jsoup -import xyz.quaver.Code -import xyz.quaver.proxy -import java.net.URL -import java.net.URLDecoder -import java.nio.ByteBuffer -import java.nio.ByteOrder -import java.util.* -import javax.net.ssl.HttpsURLConnection - -//galleryblock.js -fun fetchNozomi(area: String? = null, tag: String = "index", language: String = "all", start: Int = -1, count: Int = -1) : Pair, Int> { - val url = - when(area) { - null -> "$protocol//$domain/$tag-$language$nozomiextension" - else -> "$protocol//$domain/$area/$tag-$language$nozomiextension" - } - - with(URL(url).openConnection() as HttpsURLConnection) { - requestMethod = "GET" - - if (start != -1 && count != -1) { - val startByte = start*4 - val endByte = (start+count)*4-1 - - setRequestProperty("Range", "bytes=$startByte-$endByte") - } - - connect() - - val totalItems = getHeaderField("Content-Range") - .replace(Regex("^[Bb]ytes \\d+-\\d+/"), "").toInt() / 4 - - val nozomi = ArrayList() - - val arrayBuffer = ByteBuffer - .wrap(inputStream.readBytes()) - .order(ByteOrder.BIG_ENDIAN) - - while (arrayBuffer.hasRemaining()) - nozomi.add(arrayBuffer.int) - - return Pair(nozomi, totalItems) - } -} - -@Serializable -data class GalleryBlock( - val code: Code, - val id: Int, - val galleryUrl: String, - val thumbnails: List, - val title: String, - val artists: List, - val series: List, - val type: String, - val language: String, - val relatedTags: List -) -fun getGalleryBlock(galleryID: Int) : GalleryBlock? { - val url = "$protocol//$domain/$galleryblockdir/$galleryID$extension" - - val doc = Jsoup.connect(url).proxy(proxy).get() - - val galleryUrl = doc.selectFirst(".lillie").attr("href") - - val thumbnails = doc.select(".dj-img-cont img").map { protocol + it.attr("src") } - - val title = doc.selectFirst("h1.lillie > a").text() - val artists = doc.select("div.artist-list a").map{ it.text() } - val series = doc.select("a[href~=^/series/]").map { it.text() } - val type = doc.selectFirst("a[href~=^/type/]").text() - - val language = { - val href = doc.select("a[href~=^/index-.+-1.html]").attr("href") - href.slice(7 until href.indexOf("-1")) - }.invoke() - - val relatedTags = doc.select(".relatedtags a").map { - val href = URLDecoder.decode(it.attr("href"), "UTF-8") - href.slice(5 until href.indexOf("-all")) - } - - return GalleryBlock(Code.HITOMI, galleryID, galleryUrl, thumbnails, title, artists, series, type, language, relatedTags) -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/reader.kt b/libpupil/src/main/java/xyz/quaver/hitomi/reader.kt deleted file mode 100644 index 138a37a8..00000000 --- a/libpupil/src/main/java/xyz/quaver/hitomi/reader.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hitomi - -import kotlinx.serialization.Serializable -import xyz.quaver.Code - -fun getReferer(galleryID: Int) = "https://hitomi.la/reader/$galleryID.html" - -@Serializable -data class GalleryInfo( - val language_localname: String? = null, - val language: String? = null, - val date: String? = null, - val files: List, - val id: Int? = null, - val type: String? = null, - val title: String? = null -) - -@Serializable -data class GalleryFiles( - val width: Int, - val hash: String? = null, - val haswebp: Int = 0, - val name: String, - val height: Int, - val hasavif: Int = 0 -) - -@Serializable -data class Reader(val code: Code, val galleryInfo: GalleryInfo) - -//Set header `Referer` to reader url to avoid 403 error -fun getReader(galleryID: Int) : Reader { - return Reader(Code.HITOMI, getGalleryInfo(galleryID)) -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/results.kt b/libpupil/src/main/java/xyz/quaver/hitomi/results.kt deleted file mode 100644 index 9e200b70..00000000 --- a/libpupil/src/main/java/xyz/quaver/hitomi/results.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hitomi - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.runBlocking -import java.util.* - -fun doSearch(query: String, sortByPopularity: Boolean = false) : List { - val terms = query - .trim() - .replace(Regex("""^\?"""), "") - .toLowerCase(Locale.US) - .split(Regex("\\s+")) - .map { - it.replace('_', ' ') - } - - val positiveTerms = LinkedList() - val negativeTerms = LinkedList() - - for (term in terms) { - if (term.matches(Regex("^-.+"))) - negativeTerms.push(term.replace(Regex("^-"), "")) - else - positiveTerms.push(term) - } - - val positiveResults = positiveTerms.map { - CoroutineScope(Dispatchers.IO).async { - getGalleryIDsForQuery(it) - } - } - - val negativeResults = negativeTerms.map { - CoroutineScope(Dispatchers.IO).async { - getGalleryIDsForQuery(it) - } - } - - var results = when { - sortByPopularity -> getGalleryIDsFromNozomi(null, "popular", "all") - positiveTerms.isEmpty() -> getGalleryIDsFromNozomi(null, "index", "all") - else -> listOf() - } - - runBlocking { - @Synchronized fun filterPositive(newResults: List) { - results = when { - results.isEmpty() -> newResults - else -> newResults.sorted().let { sorted -> - results.filter { sorted.binarySearch(it) >= 0 } - } - } - } - - @Synchronized fun filterNegative(newResults: List) { - results = newResults.sorted().let { sorted -> - results.filter { sorted.binarySearch(it) < 0 } - } - } - - //positive results - positiveResults.forEach { - filterPositive(it.await()) - } - - //negative results - negativeResults.forEach { - filterNegative(it.await()) - } - } - - return results -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/search.kt b/libpupil/src/main/java/xyz/quaver/hitomi/search.kt deleted file mode 100644 index b3e65769..00000000 --- a/libpupil/src/main/java/xyz/quaver/hitomi/search.kt +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hitomi - -import xyz.quaver.proxy -import java.net.URL -import java.nio.ByteBuffer -import java.nio.ByteOrder -import java.security.MessageDigest -import javax.net.ssl.HttpsURLConnection - -//searchlib.js -const val separator = "-" -const val extension = ".html" -const val index_dir = "tagindex" -const val galleries_index_dir = "galleriesindex" -const val max_node_size = 464 -const val B = 16 -const val compressed_nozomi_prefix = "n" - -var tag_index_version = getIndexVersion("tagindex") -var galleries_index_version = getIndexVersion("galleriesindex") - -fun sha256(data: ByteArray) : ByteArray { - return MessageDigest.getInstance("SHA-256").digest(data) -} - -@OptIn(ExperimentalUnsignedTypes::class) -fun hashTerm(term: String) : UByteArray { - return sha256(term.toByteArray()).toUByteArray().sliceArray(0 until 4) -} - -fun sanitize(input: String) : String { - return input.replace(Regex("[/#]"), "") -} - -fun getIndexVersion(name: String) : String { - return try { - URL("$protocol//$domain/$name/version?_=${System.currentTimeMillis()}").openConnection(proxy).getInputStream().use { - it.reader().readText() - } - } catch (e: Exception) { - "" - } -} - -//search.js -fun getGalleryIDsForQuery(query: String) : List { - query.replace("_", " ").let { - if (it.indexOf(':') > -1) { - val sides = it.split(":") - val ns = sides[0] - var tag = sides[1] - - var area : String? = ns - var language = "all" - when (ns) { - "female", "male" -> { - area = "tag" - tag = it - } - "language" -> { - area = null - language = tag - tag = "index" - } - } - - return getGalleryIDsFromNozomi(area, tag, language) - } - - val key = hashTerm(it) - val field = "galleries" - - val node = getNodeAtAddress(field, 0) ?: return emptyList() - - val data = bSearch(field, key, node) - - if (data != null) - return getGalleryIDsFromData(data) - - return emptyList() - } -} - -fun getSuggestionsForQuery(query: String) : List { - query.replace('_', ' ').let { - var field = "global" - var term = it - - if (term.indexOf(':') > -1) { - val sides = it.split(':') - field = sides[0] - term = sides[1] - } - - val key = hashTerm(term) - val node = getNodeAtAddress(field, 0) ?: return emptyList() - val data = bSearch(field, key, node) - - if (data != null) - return getSuggestionsFromData(field, data) - - return emptyList() - } -} - -data class Suggestion(val s: String, val t: Int, val u: String, val n: String) -fun getSuggestionsFromData(field: String, data: Pair) : List { - if (tag_index_version.isEmpty()) - tag_index_version = getIndexVersion("tagindex") - - val url = "$protocol//$domain/$index_dir/$field.$tag_index_version.data" - val (offset, length) = data - if (length > 10000 || length <= 0) - throw Exception("length $length is too long") - - val inbuf = getURLAtRange(url, offset.until(offset+length)) ?: return emptyList() - - val suggestions = ArrayList() - - val buffer = ByteBuffer - .wrap(inbuf) - .order(ByteOrder.BIG_ENDIAN) - val numberOfSuggestions = buffer.int - - if (numberOfSuggestions > 100 || numberOfSuggestions <= 0) - throw Exception("number of suggestions $numberOfSuggestions is too long") - - for (i in 0.until(numberOfSuggestions)) { - var top = buffer.int - - val ns = inbuf.sliceArray(buffer.position().until(buffer.position()+top)).toString(charset("UTF-8")) - buffer.position(buffer.position()+top) - - top = buffer.int - - val tag = inbuf.sliceArray(buffer.position().until(buffer.position()+top)).toString(charset("UTF-8")) - buffer.position(buffer.position()+top) - - val count = buffer.int - - val tagname = sanitize(tag) - val u = - when(ns) { - "female", "male" -> "/tag/$ns:$tagname${separator}1$extension" - "language" -> "/index-$tagname${separator}1$extension" - else -> "/$ns/$tagname${separator}all${separator}1$extension" - } - - suggestions.add(Suggestion(tag, count, u, ns)) - } - - return suggestions -} - -fun getGalleryIDsFromNozomi(area: String?, tag: String, language: String) : List { - val nozomiAddress = - when(area) { - null -> "$protocol//$domain/$compressed_nozomi_prefix/$tag-$language$nozomiextension" - else -> "$protocol//$domain/$compressed_nozomi_prefix/$area/$tag-$language$nozomiextension" - } - - val bytes = try { - URL(nozomiAddress).openConnection(proxy).getInputStream().use { - it.readBytes() - } - } catch (e: Exception) { - return emptyList() - } - - val nozomi = ArrayList() - - val arrayBuffer = ByteBuffer - .wrap(bytes) - .order(ByteOrder.BIG_ENDIAN) - - while (arrayBuffer.hasRemaining()) - nozomi.add(arrayBuffer.int) - - return nozomi -} - -fun getGalleryIDsFromData(data: Pair) : List { - if (galleries_index_version.isEmpty()) - galleries_index_version = getIndexVersion("galleriesindex") - - val url = "$protocol//$domain/$galleries_index_dir/galleries.$galleries_index_version.data" - val (offset, length) = data - if (length > 100000000 || length <= 0) - throw Exception("length $length is too long") - - val inbuf = getURLAtRange(url, offset.until(offset+length)) ?: return emptyList() - - val galleryIDs = ArrayList() - - val buffer = ByteBuffer - .wrap(inbuf) - .order(ByteOrder.BIG_ENDIAN) - - val numberOfGalleryIDs = buffer.int - - val expectedLength = numberOfGalleryIDs*4+4 - - if (numberOfGalleryIDs > 10000000 || numberOfGalleryIDs <= 0) - throw Exception("number_of_galleryids $numberOfGalleryIDs is too long") - else if (inbuf.size != expectedLength) - throw Exception("inbuf.byteLength ${inbuf.size} != expected_length $expectedLength") - - for (i in 0.until(numberOfGalleryIDs)) - galleryIDs.add(buffer.int) - - return galleryIDs -} - -fun getNodeAtAddress(field: String, address: Long) : Node? { - if (tag_index_version.isEmpty()) - tag_index_version = getIndexVersion("tagindex") - if (galleries_index_version.isEmpty()) - galleries_index_version = getIndexVersion("galleriesindex") - - val url = - when(field) { - "galleries" -> "$protocol//$domain/$galleries_index_dir/galleries.$galleries_index_version.index" - else -> "$protocol//$domain/$index_dir/$field.$tag_index_version.index" - } - - val nodedata = getURLAtRange(url, address.until(address+max_node_size)) ?: return null - - return decodeNode(nodedata) -} - -fun getURLAtRange(url: String, range: LongRange) : ByteArray? { - try { - with (URL(url).openConnection(proxy) as HttpsURLConnection) { - requestMethod = "GET" - - setRequestProperty("Range", "bytes=${range.first}-${range.last}") - - return inputStream.readBytes() - } - } catch (e: Exception) { - return null - } -} - -@OptIn(ExperimentalUnsignedTypes::class) -data class Node(val keys: List, val datas: List>, val subNodeAddresses: List) -@OptIn(ExperimentalUnsignedTypes::class) -fun decodeNode(data: ByteArray) : Node { - val buffer = ByteBuffer - .wrap(data) - .order(ByteOrder.BIG_ENDIAN) - - val uData = data.toUByteArray() - - val numberOfKeys = buffer.int - val keys = ArrayList() - - for (i in 0.until(numberOfKeys)) { - val keySize = buffer.int - - if (keySize == 0 || keySize > 32) - throw Exception("fatal: !keySize || keySize > 32") - - keys.add(uData.sliceArray(buffer.position().until(buffer.position()+keySize))) - buffer.position(buffer.position()+keySize) - } - - val numberOfDatas = buffer.int - val datas = ArrayList>() - - for (i in 0.until(numberOfDatas)) { - val offset = buffer.long - val length = buffer.int - - datas.add(Pair(offset, length)) - } - - val numberOfSubNodeAddresses = B+1 - val subNodeAddresses = ArrayList() - - for (i in 0.until(numberOfSubNodeAddresses)) { - val subNodeAddress = buffer.long - subNodeAddresses.add(subNodeAddress) - } - - return Node(keys, datas, subNodeAddresses) -} - -@OptIn(ExperimentalUnsignedTypes::class) -fun bSearch(field: String, key: UByteArray, node: Node) : Pair? { - fun compareArrayBuffers(dv1: UByteArray, dv2: UByteArray) : Int { - val top = Math.min(dv1.size, dv2.size) - - for (i in 0.until(top)) { - if (dv1[i] < dv2[i]) - return -1 - else if (dv1[i] > dv2[i]) - return 1 - } - - return 0 - } - - fun locateKey(key: UByteArray, node: Node) : Pair { - for (i in 0 until node.keys.size) { - val cmpResult = compareArrayBuffers(key, node.keys[i]) - - if (cmpResult <= 0) - return Pair(cmpResult==0, i) - } - - return Pair(false, node.keys.size) - } - - fun isLeaf(node: Node) : Boolean { - for (subnode in node.subNodeAddresses) - if (subnode != 0L) - return false - - return true - } - - if (node.keys.isEmpty()) - return null - - val (there, where) = locateKey(key, node) - if (there) - return node.datas[where] - else if (isLeaf(node)) - return null - - val nextNode = getNodeAtAddress(field, node.subNodeAddresses[where]) ?: return null - return bSearch(field, key, nextNode) -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt b/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt deleted file mode 100644 index 72e4cf48..00000000 --- a/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2020 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hiyobi - -import kotlinx.serialization.json.contentOrNull -import kotlinx.serialization.json.intOrNull -import xyz.quaver.Code -import xyz.quaver.hitomi.GalleryBlock -import xyz.quaver.hitomi.protocol -import xyz.quaver.json -import xyz.quaver.proxy -import java.net.URL -import javax.net.ssl.HttpsURLConnection - -fun getGalleryBlock(galleryID: Int) : GalleryBlock? { - val url = "$protocol//api.$hiyobi/gallery/$galleryID" - - val galleryBlock = with (URL(url).openConnection(proxy) as HttpsURLConnection) { - setRequestProperty("User-Agent", user_agent) - setRequestProperty("Cookie", cookie) - connectTimeout = 1000 - connect() - - inputStream.bufferedReader().use { it.readText() } - }.let { - json.parseJson(it).jsonObject - } - - val galleryUrl = "reader/$galleryID" - - val thumbnails = listOf("$protocol//cdn.$hiyobi/tn/$galleryID.jpg") - - val title = galleryBlock["title"]?.contentOrNull ?: "" - val artists = galleryBlock["artists"]?.jsonArray?.mapNotNull { - it.jsonObject["value"]?.contentOrNull - } ?: listOf() - val series = galleryBlock["parodys"]?.jsonArray?.mapNotNull { - it.jsonObject["value"]?.contentOrNull - } ?: listOf() - val type = when (galleryBlock["type"]?.intOrNull) { - 1 -> "doujinshi" - 2 -> "manga" - 3 -> "artistcg" - 4 -> "gamecg" - else -> "" - } - - val language = "korean" - - val relatedTags = galleryBlock["tags"]?.jsonArray?.mapNotNull { - it.jsonObject["value"]?.contentOrNull - } ?: listOf() - - return GalleryBlock(Code.HIYOBI, galleryID, galleryUrl, thumbnails, title, artists, series, type, language, relatedTags) -} \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt b/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt deleted file mode 100644 index 5ed65661..00000000 --- a/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package xyz.quaver.hiyobi - -import kotlinx.serialization.UnstableDefault -import kotlinx.serialization.builtins.list -import kotlinx.serialization.json.contentOrNull -import xyz.quaver.Code -import xyz.quaver.hitomi.GalleryFiles -import xyz.quaver.hitomi.GalleryInfo -import xyz.quaver.hitomi.Reader -import xyz.quaver.hitomi.protocol -import xyz.quaver.json -import xyz.quaver.proxy -import java.net.URL -import javax.net.ssl.HttpsURLConnection - -const val hiyobi = "hiyobi.me" -const val primary_img_domain = "cdn.hiyobi.me" -const val user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36" - -var cookie: String = "" - get() { - if (field.isEmpty()) - field = renewCookie() - - return field - } - -data class Images( - val path: String, - val no: Int, - val name: String -) - -fun renewCookie() : String { - val url = "https://$hiyobi/" - - try { - with(URL(url).openConnection(proxy) as HttpsURLConnection) { - setRequestProperty("User-Agent", user_agent) - connectTimeout = 2000 - connect() - return headerFields["Set-Cookie"]!![0] - } - } catch (e: Exception) { - return "" - } -} - -@OptIn(UnstableDefault::class) -fun getReader(galleryID: Int) : Reader { - val data = "https://cdn.$hiyobi/data/json/$galleryID.json" - val list = "https://cdn.$hiyobi/data/json/${galleryID}_list.json" - - val title = with(URL(data).openConnection(proxy) as HttpsURLConnection) { - setRequestProperty("User-Agent", user_agent) - setRequestProperty("Cookie", cookie) - connectTimeout = 1000 - connect() - - inputStream.bufferedReader().use { it.readText() } - }.let { - json.parseJson(it).jsonObject["n"]?.contentOrNull - } - - val galleryFiles = json.parse( - GalleryFiles.serializer().list, - with(URL(list).openConnection(proxy) as HttpsURLConnection) { - setRequestProperty("User-Agent", user_agent) - setRequestProperty("Cookie", cookie) - connectTimeout = 1000 - connect() - - inputStream.bufferedReader().use { it.readText() } - } - ) - - return Reader(Code.HIYOBI, GalleryInfo(title = title, files = galleryFiles)) -} - -fun createImgList(galleryID: Int, reader: Reader, lowQuality: Boolean = false) = - if (lowQuality) - reader.galleryInfo.files.map { - val name = it.name.replace(Regex("""\.[^/.]+$"""), "") - Images("$protocol//$primary_img_domain/data_r/$galleryID/$name.jpg", galleryID, it.name) - } - else - reader.galleryInfo.files.map { Images("$protocol//$primary_img_domain/data/$galleryID/${it.name}", galleryID, it.name) } \ No newline at end of file diff --git a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt deleted file mode 100644 index f282cd6b..00000000 --- a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2019 tom5079 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("UNUSED_VARIABLE") - -package xyz.quaver.hitomi - -import org.junit.Assert.assertEquals -import org.junit.Test -import xyz.quaver.availableInHiyobi - -class UnitTest { - @Test - fun test() { - assertEquals( - "6/2d/c26014fc6153ef717932d85f4d26c75195560fb2ce1da60b431ef376501642d6", - fullPathFromHash("c26014fc6153ef717932d85f4d26c75195560fb2ce1da60b431ef376501642d6") - ) - } - - @Test - fun test_nozomi() { - val nozomi = getGalleryIDsFromNozomi(null, "popular", "all") - - print(nozomi.size) - } - - @Test - fun test_search() { - val ids = getGalleryIDsForQuery("language:korean").reversed() - - print(ids.size) - } - - @Test - fun test_suggestions() { - val suggestions = getSuggestionsForQuery("language:g") - - print(suggestions) - } - - @Test - fun test_doSearch() { - val r = doSearch("female:loli female:bondage language:korean -male:yaoi -male:guro -female:guro", true) - - print(r.size) - } - - @Test - fun test_getBlock() { - val galleryBlock = getGalleryBlock(1428250) - - print(galleryBlock) - } - - @Test - fun test_getGallery() { - val gallery = getGallery(1552751) - - print(gallery) - } - - @Test - fun test_getReader() { - val reader = getReader(1574736) - - print(reader) - } - - @Test - fun test_getImages() { - val reader = getReader(1702001) - - print(urlFromUrlFromHash(1702001, reader.galleryInfo.files[15], "webp")) - } - - @Test - fun test_hiyobi() { - val reader = xyz.quaver.hiyobi.getReader(1664762) - - print(reader) - } - - @Test - fun test_urlFromUrlFromHash() { - val url = urlFromUrlFromHash(1531795, GalleryFiles( - 212, "719d46a7556be0d0021c5105878507129b5b3308b02cf67f18901b69dbb3b5ef", 1, "00.jpg", 300 - ), "webp") - - print(url) - } - - @Test - fun test_availableInHiyobi() { - val result = availableInHiyobi(1272781) - - print(result) - } - - @Test - fun test_hiyobi_galleryBlock() { - val galleryBlock = xyz.quaver.hiyobi.getGalleryBlock(10000027) - - print(galleryBlock) - } -} \ No newline at end of file