diff --git a/lib-multisrc/machinetranslations/AndroidManifest.xml b/lib-multisrc/machinetranslations/AndroidManifest.xml deleted file mode 100644 index dac6d158a..000000000 --- a/lib-multisrc/machinetranslations/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lib-multisrc/machinetranslations/assets/fonts/LICENSE_ANIMEACE.txt b/lib-multisrc/machinetranslations/assets/fonts/LICENSE_ANIMEACE.txt deleted file mode 100644 index 5ba98714a..000000000 --- a/lib-multisrc/machinetranslations/assets/fonts/LICENSE_ANIMEACE.txt +++ /dev/null @@ -1,25 +0,0 @@ -This font is © 2006 Nate Piekos. All Rights Reserved. -Created for Blambot Fonts - -This font is freeware for independent comic book creation and -non-profit use ONLY. ( This excludes use by "mainstream" publishers, -(Marvel, DC, Dark Horse, Oni, Image, SLG, Top Cow, Crossgen and their -subsidiaries) without a license fee. Use by a "mainstream" publisher -(or it's employee), and use for commercial non-comic book production -(eg. magazine ads, merchandise lables etc.) incurs a license fee -be paid to the designer, Nate Piekos. -This font may not be redistributed without the author's permission and -never with this text file missing from the .zip, .sit or .hqx. - -Blambot/Nate Piekos makes no guarantees about these font files, - the completeness of character sets, or safety of these files on your -computer. By installing these fonts on your system, you prove that -you have read and understand the above. - -If you have any questions, visit http://www.blambot.com/license.shtml - -For more free and original fonts visit Blambot. -www.blambot.com - -Nate Piekos -studio@blambot.com diff --git a/lib-multisrc/machinetranslations/assets/fonts/LICENSE_COMIC_NEUE.txt b/lib-multisrc/machinetranslations/assets/fonts/LICENSE_COMIC_NEUE.txt deleted file mode 100644 index 80062cfab..000000000 --- a/lib-multisrc/machinetranslations/assets/fonts/LICENSE_COMIC_NEUE.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2014 The Comic Neue Project Authors (https://github.com/crozynski/comicneue) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -https://openfontlicense.org - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/lib-multisrc/machinetranslations/assets/fonts/LICENSE_COMING_SOON.txt b/lib-multisrc/machinetranslations/assets/fonts/LICENSE_COMING_SOON.txt deleted file mode 100644 index 75b52484e..000000000 --- a/lib-multisrc/machinetranslations/assets/fonts/LICENSE_COMING_SOON.txt +++ /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/lib-multisrc/machinetranslations/assets/fonts/animeace2_regular.ttf b/lib-multisrc/machinetranslations/assets/fonts/animeace2_regular.ttf deleted file mode 100644 index 6521ab5b5..000000000 Binary files a/lib-multisrc/machinetranslations/assets/fonts/animeace2_regular.ttf and /dev/null differ diff --git a/lib-multisrc/machinetranslations/assets/fonts/comic_neue_bold.ttf b/lib-multisrc/machinetranslations/assets/fonts/comic_neue_bold.ttf deleted file mode 100644 index dc9a6d552..000000000 Binary files a/lib-multisrc/machinetranslations/assets/fonts/comic_neue_bold.ttf and /dev/null differ diff --git a/lib-multisrc/machinetranslations/assets/fonts/comic_neue_regular.ttf b/lib-multisrc/machinetranslations/assets/fonts/comic_neue_regular.ttf deleted file mode 100644 index d454f4693..000000000 Binary files a/lib-multisrc/machinetranslations/assets/fonts/comic_neue_regular.ttf and /dev/null differ diff --git a/lib-multisrc/machinetranslations/assets/fonts/coming_soon_regular.ttf b/lib-multisrc/machinetranslations/assets/fonts/coming_soon_regular.ttf deleted file mode 100644 index b0f6908dc..000000000 Binary files a/lib-multisrc/machinetranslations/assets/fonts/coming_soon_regular.ttf and /dev/null differ diff --git a/lib-multisrc/machinetranslations/assets/i18n/messages_en.properties b/lib-multisrc/machinetranslations/assets/i18n/messages_en.properties deleted file mode 100644 index 855d54ff1..000000000 --- a/lib-multisrc/machinetranslations/assets/i18n/messages_en.properties +++ /dev/null @@ -1,19 +0,0 @@ -font_name_title=Font name -font_name_summary=Customize dialogues by choosing your preferred font. To apply the change to chapters that have already been read, you will need to clear the chapter cache in "More > Data and storage > Clear chapter cache". Font changes will not affect downloaded chapters -font_name_message=Font name changed to %s -font_name_device_title=Device -font_size_title=Font size -font_size_summary=Font changes will not be applied to downloaded or cached chapters. The font size will be adjusted according to the size of the dialog box. -font_size_message=Font size changed to %s -default_font_size=Default -default_font_name=Default -default_font_name_title=Web site -disable_word_break_title=Disable word break -disable_word_break_summary=This feature prevents words from being automatically broken in the middle of a line. -disable_translator_title=Disable translator -disable_translator_summary=Disable auto translation and enable source translation. This does not mean that a translation is available. Make sure a translation is available before enabling this option. -translate_dialog_box_title=Translator -translate_dialog_box_summary=Engine used to translate dialog boxes -translate_dialog_box_toast=The translator has been changed to -enable_manga_details_translation_title=Enable translation of manga details -enable_manga_details_translation_summary=This option will slow down the loading of manga details diff --git a/lib-multisrc/machinetranslations/assets/i18n/messages_es.properties b/lib-multisrc/machinetranslations/assets/i18n/messages_es.properties deleted file mode 100644 index 48bc523f9..000000000 --- a/lib-multisrc/machinetranslations/assets/i18n/messages_es.properties +++ /dev/null @@ -1 +0,0 @@ -font_size_title=Tamaño de letra diff --git a/lib-multisrc/machinetranslations/assets/i18n/messages_fr.properties b/lib-multisrc/machinetranslations/assets/i18n/messages_fr.properties deleted file mode 100644 index 1beb3574f..000000000 --- a/lib-multisrc/machinetranslations/assets/i18n/messages_fr.properties +++ /dev/null @@ -1 +0,0 @@ -font_size_title=Taille de la police diff --git a/lib-multisrc/machinetranslations/assets/i18n/messages_id.properties b/lib-multisrc/machinetranslations/assets/i18n/messages_id.properties deleted file mode 100644 index b129b31a4..000000000 --- a/lib-multisrc/machinetranslations/assets/i18n/messages_id.properties +++ /dev/null @@ -1 +0,0 @@ -font_size_title=Ukuran font diff --git a/lib-multisrc/machinetranslations/assets/i18n/messages_it.properties b/lib-multisrc/machinetranslations/assets/i18n/messages_it.properties deleted file mode 100644 index 917acd0f9..000000000 --- a/lib-multisrc/machinetranslations/assets/i18n/messages_it.properties +++ /dev/null @@ -1 +0,0 @@ -font_size_title=Dimensione del carattere diff --git a/lib-multisrc/machinetranslations/assets/i18n/messages_pt_br.properties b/lib-multisrc/machinetranslations/assets/i18n/messages_pt_br.properties deleted file mode 100644 index b6852c993..000000000 --- a/lib-multisrc/machinetranslations/assets/i18n/messages_pt_br.properties +++ /dev/null @@ -1,19 +0,0 @@ -font_name_title=Fonte -font_name_summary=Personalize os diálogos escolhendo a fonte de sua preferência. Para aplicar a alteração em capitulos lidos será necessário limpar o cache de capitulos em "Mais > Dados e armazenamento > Limpar cache de capítulos". As alterações de fonte não serão aplicadas aos capítulos baixados. -font_name_message=Fonte alterada para %s -font_name_device_title=Dispositivo -font_size_title=Tamanho da fonte -font_size_summary=As alterações de fonte não serão aplicadas aos capítulos baixados ou armazenados em cache. O tamanho da fonte será ajustado de acordo com o tamanho da caixa de diálogo. -font_size_message=Tamanho da fonte foi alterada para %s -default_font_size=Padrão -default_font_name=Padrão -default_font_name_title=Site -disable_word_break_title=Desativar quebra de palavras -disable_word_break_summary=Esse recurso impede que palavras sejam quebradas automaticamente no meio da linha. -disable_translator_title=Desativar tradutor -disable_translator_summary=Desativar tradução automática e ativar tradução da fonte. Isso não significa que há uma tradução disponivel. Certifique-se de que exista uma tradução antes de ativar esta opção no site. -translate_dialog_box_title=Tradutor -translate_dialog_box_summary=Motor utilizado para traduzir caixas de diálogo -translate_dialog_box_toast=O tradutor foi alterado para -enable_manga_details_translation_title=Habilitar tradução dos detalhes do manga -enable_manga_details_translation_summary=Esta opção tornará o carregamento dos detalhes do mangá mais lento diff --git a/lib-multisrc/machinetranslations/build.gradle.kts b/lib-multisrc/machinetranslations/build.gradle.kts deleted file mode 100644 index 1c041fa3e..000000000 --- a/lib-multisrc/machinetranslations/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - id("lib-multisrc") -} - -baseVersionCode = 9 - -dependencies { - api(project(":lib:i18n")) -} diff --git a/lib-multisrc/machinetranslations/res/mipmap-hdpi/ic_launcher.png b/lib-multisrc/machinetranslations/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index c61c9328c..000000000 Binary files a/lib-multisrc/machinetranslations/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/lib-multisrc/machinetranslations/res/mipmap-mdpi/ic_launcher.png b/lib-multisrc/machinetranslations/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 68cb9f512..000000000 Binary files a/lib-multisrc/machinetranslations/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/lib-multisrc/machinetranslations/res/mipmap-xhdpi/ic_launcher.png b/lib-multisrc/machinetranslations/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 15d3ccdf9..000000000 Binary files a/lib-multisrc/machinetranslations/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/lib-multisrc/machinetranslations/res/mipmap-xxhdpi/ic_launcher.png b/lib-multisrc/machinetranslations/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index c7f54aaf0..000000000 Binary files a/lib-multisrc/machinetranslations/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/lib-multisrc/machinetranslations/res/mipmap-xxxhdpi/ic_launcher.png b/lib-multisrc/machinetranslations/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index ba00c8a5e..000000000 Binary files a/lib-multisrc/machinetranslations/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslations.kt b/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslations.kt deleted file mode 100644 index 16c9e640b..000000000 --- a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslations.kt +++ /dev/null @@ -1,501 +0,0 @@ -package eu.kanade.tachiyomi.multisrc.machinetranslations - -import android.content.SharedPreferences -import android.os.Build -import android.widget.Toast -import androidx.annotation.RequiresApi -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceScreen -import androidx.preference.SwitchPreferenceCompat -import eu.kanade.tachiyomi.lib.i18n.Intl -import eu.kanade.tachiyomi.multisrc.machinetranslations.interceptors.ComposedImageInterceptor -import eu.kanade.tachiyomi.multisrc.machinetranslations.interceptors.TranslationInterceptor -import eu.kanade.tachiyomi.multisrc.machinetranslations.translator.TranslatorEngine -import eu.kanade.tachiyomi.multisrc.machinetranslations.translator.bing.BingTranslator -import eu.kanade.tachiyomi.multisrc.machinetranslations.translator.google.GoogleTranslator -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.interceptor.rateLimit -import eu.kanade.tachiyomi.source.ConfigurableSource -import eu.kanade.tachiyomi.source.model.Filter -import eu.kanade.tachiyomi.source.model.FilterList -import eu.kanade.tachiyomi.source.model.MangasPage -import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.model.SChapter -import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import keiyoushi.utils.getPreferencesLazy -import keiyoushi.utils.parseAs -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.Interceptor -import okhttp3.OkHttpClient -import okhttp3.Request -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import rx.Observable -import uy.kohesive.injekt.injectLazy -import java.text.SimpleDateFormat -import java.util.Calendar -import java.util.Locale -import java.util.concurrent.TimeUnit - -@RequiresApi(Build.VERSION_CODES.O) -abstract class MachineTranslations( - override val name: String, - override val baseUrl: String, - private val language: Language, -) : ParsedHttpSource(), ConfigurableSource { - - override val supportsLatest = true - - private val json: Json by injectLazy() - - override val lang = language.lang - - protected val preferences: SharedPreferences by getPreferencesLazy() - - /** - * A flag that tracks whether the settings have been changed. It is used to indicate if - * any configuration change has occurred. Once the value is accessed, it resets to `false`. - * This is useful for tracking whether a preference has been modified, and ensures that - * the change status is cleared after it has been accessed, to prevent multiple triggers. - */ - private var isSettingsChanged: Boolean = false - get() { - val current = field - field = false - return current - } - - protected var fontSize: Int - get() = preferences.getString(FONT_SIZE_PREF, DEFAULT_FONT_SIZE)!!.toInt() - set(value) = preferences.edit().putString(FONT_SIZE_PREF, value.toString()).apply() - - protected var fontName: String - get() = preferences.getString(FONT_NAME_PREF, language.fontName)!! - set(value) = preferences.edit().putString(FONT_NAME_PREF, value).apply() - - protected var disableWordBreak: Boolean - get() = preferences.getBoolean(DISABLE_WORD_BREAK_PREF, language.disableWordBreak) - set(value) = preferences.edit().putBoolean(DISABLE_WORD_BREAK_PREF, value).apply() - - protected var disableTranslator: Boolean - get() = preferences.getBoolean(DISABLE_TRANSLATOR_PREF, language.disableTranslator) - set(value) = preferences.edit().putBoolean(DISABLE_TRANSLATOR_PREF, value).apply() - - protected var enableMangaDetailsTranslation: Boolean - get() = preferences.getBoolean(ENABLE_MANGA_DETAILS_TRANSLATION_PREF, false) - set(value) = preferences.edit().putBoolean(ENABLE_MANGA_DETAILS_TRANSLATION_PREF, value).apply() - - private val intl = Intl( - language = language.lang, - baseLanguage = "en", - availableLanguages = setOf("en", "es", "fr", "id", "it", "pt-BR"), - classLoader = this::class.java.classLoader!!, - ) - - private val settings get() = language.copy( - fontSize = this@MachineTranslations.fontSize, - fontName = this@MachineTranslations.fontName, - disableWordBreak = this@MachineTranslations.disableWordBreak, - disableTranslator = this@MachineTranslations.disableTranslator, - disableFontSettings = this@MachineTranslations.fontName == DEVICE_FONT, - ) - - override val client: OkHttpClient get() = clientInstance!! - - private val translators = arrayOf( - "Bing", - "Google", - ) - - private val provider: String get() = - preferences.getString(TRANSLATOR_PROVIDER_PREF, translators.first())!! - - /** - * This ensures that the `OkHttpClient` instance is only created when required, and it is rebuilt - * when there are configuration changes to ensure that the client uses the most up-to-date settings. - */ - private var clientInstance: OkHttpClient? = null - get() { - if (field == null || isSettingsChanged) { - field = clientBuilder().build() - } - return field - } - - private val clientUtils = network.cloudflareClient.newBuilder() - .rateLimit(3, 2, TimeUnit.SECONDS) - .build() - - private lateinit var translator: TranslatorEngine - - protected fun clientBuilder(): OkHttpClient.Builder { - translator = when (provider) { - "Google" -> GoogleTranslator(clientUtils, headers) - else -> BingTranslator(clientUtils, headers) - } - - return network.cloudflareClient.newBuilder() - .connectTimeout(1, TimeUnit.MINUTES) - .readTimeout(2, TimeUnit.MINUTES) - .rateLimit(3) - .addInterceptorIf(!disableTranslator && language.lang != language.origin, TranslationInterceptor(settings, translator)) - .addInterceptor(ComposedImageInterceptor(baseUrl, settings)) - } - - private fun OkHttpClient.Builder.addInterceptorIf(condition: Boolean, interceptor: Interceptor): OkHttpClient.Builder { - return this.takeIf { condition.not() } ?: this.addInterceptor(interceptor) - } - - // ============================== Popular =============================== - - private val popularFilter = FilterList(SelectionList("", listOf(Option(value = "views", query = "sort_by")))) - - override fun popularMangaRequest(page: Int) = searchMangaRequest(page, "", popularFilter) - - override fun popularMangaSelector() = searchMangaSelector() - - override fun popularMangaFromElement(element: Element) = searchMangaFromElement(element) - - override fun popularMangaNextPageSelector() = searchMangaNextPageSelector() - - // =============================== Latest =============================== - - private val latestFilter = FilterList(SelectionList("", listOf(Option(value = "recent", query = "sort_by")))) - - override fun latestUpdatesRequest(page: Int) = searchMangaRequest(page, "", latestFilter) - - override fun latestUpdatesSelector() = searchMangaSelector() - - override fun latestUpdatesFromElement(element: Element) = searchMangaFromElement(element) - - override fun latestUpdatesNextPageSelector() = searchMangaNextPageSelector() - - // =========================== Search ============================ - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = "$baseUrl/search".toHttpUrl().newBuilder() - .addQueryParameter("page", page.toString()) - - if (query.isNotBlank()) { - url.addQueryParameter("query", query) - } - - filters.forEach { filter -> - when (filter) { - is SelectionList -> { - val selected = filter.selected() - if (selected.value.isBlank()) { - return@forEach - } - url.addQueryParameter(selected.query, selected.value) - } - is GenreList -> { - filter.state.filter(GenreCheckBox::state).forEach { genre -> - url.addQueryParameter("genres", genre.id) - } - } - else -> {} - } - } - - return GET(url.build(), headers) - } - - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { - if (query.startsWith(PREFIX_SEARCH)) { - val slug = query.removePrefix(PREFIX_SEARCH) - return fetchMangaDetails(SManga.create().apply { url = "/comics/$slug" }).map { manga -> - MangasPage(listOf(manga), false) - } - } - - return super.fetchSearchManga(page, query, filters) - } - - override fun searchMangaSelector() = "section h2 + div > div" - - override fun searchMangaFromElement(element: Element) = SManga.create().apply { - title = element.selectFirst("h3")!!.text() - thumbnail_url = element.selectFirst("img")?.absUrl("src") - setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href")) - } - - override fun searchMangaNextPageSelector() = "a[href*=search]:contains(Next)" - - // =========================== Manga Details ============================ - override fun mangaDetailsParse(document: Document) = SManga.create().apply { - title = document.selectFirst("h1")!!.text().i18n() - description = document.selectFirst("p:has(span:contains(Synopsis))")?.ownText()?.i18n() - author = document.selectFirst("p:has(span:contains(Author))")?.ownText() - genre = document.select("h2:contains(Genres) + div span").joinToString { it.text() }.i18n() - thumbnail_url = document.selectFirst("img.object-cover")?.absUrl("src") - document.selectFirst("p:has(span:contains(Status))")?.ownText()?.let { - status = when (it.lowercase()) { - "ongoing" -> SManga.ONGOING - "complete" -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - } - setUrlWithoutDomain(document.location()) - } - - // ============================== Chapters ============================== - override fun chapterListSelector() = "section li" - - override fun chapterFromElement(element: Element) = SChapter.create().apply { - element.selectFirst("a")!!.let { - name = it.ownText() - setUrlWithoutDomain(it.absUrl("href")) - } - date_upload = parseChapterDate(element.selectFirst("span")?.text()) - } - - // =============================== Pages ================================ - - override fun pageListParse(document: Document): List { - val pages = document.selectFirst("div#json-data") - ?.ownText()?.parseAs>() - ?: throw Exception("Pages not found") - - return pages.mapIndexed { index, dto -> - val imageUrl = when { - dto.imageUrl.startsWith("http") -> dto.imageUrl - else -> "https://${dto.imageUrl}" - } - val fragment = json.encodeToString>( - dto.dialogues.filter { it.getTextBy(language).isNotBlank() }, - ) - Page(index, imageUrl = "$imageUrl${fragment.toFragment()}") - } - } - - override fun imageUrlParse(document: Document): String = "" - - // ============================= Utilities ============================== - - private fun parseChapterDate(date: String?): Long { - date ?: return 0 - return try { dateFormat.parse(date)!!.time } catch (_: Exception) { parseRelativeDate(date) } - } - - private fun parseRelativeDate(date: String): Long { - val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0 - val cal = Calendar.getInstance() - - return when { - date.contains("day", true) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis - date.contains("hour", true) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis - date.contains("minute", true) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis - date.contains("second", true) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis - date.contains("week", true) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number * 7) }.timeInMillis - else -> 0 - } - } - - // Prevent bad fragments - fun String.toFragment(): String = "#${this.replace("#", "*")}" - - private fun String.i18n(): String = when { - enableMangaDetailsTranslation -> translator.translate(language.origin, language.target, this) - else -> this - } - - // =============================== Filters ================================ - - override fun getFilterList(): FilterList { - val filters = mutableListOf>( - SelectionList("Sort", sortByList), - Filter.Separator(), - GenreList(title = "Genres", genres = genreList), - ) - - return FilterList(filters) - } - - override fun setupPreferenceScreen(screen: PreferenceScreen) { - // Some libreoffice font sizes - val sizes = arrayOf( - "12", "13", "14", - "15", "16", "18", - "20", "21", "22", - "24", "26", "28", - "32", "36", "40", - "42", "44", "48", - "54", "60", "72", - "80", "88", "96", - ) - - val fonts = arrayOf( - intl["default_font_name_title"] to "", - intl["font_name_device_title"] to DEVICE_FONT, - "Anime Ace" to "animeace2_regular", - "Comic Neue" to "comic_neue_bold", - "Coming Soon" to "coming_soon_regular", - ) - - ListPreference(screen.context).apply { - key = FONT_SIZE_PREF - title = intl["font_size_title"] - entries = sizes.map { - "${it}pt" + if (it == DEFAULT_FONT_SIZE) " - ${intl["default_font_size"]}" else "" - }.toTypedArray() - entryValues = sizes - - summary = buildString { - appendLine(intl["font_size_summary"]) - append("\t* %s") - } - - setDefaultValue(fontSize.toString()) - - setOnPreferenceChange { _, newValue -> - val selected = newValue as String - val index = this.findIndexOfValue(selected) - val entry = entries[index] as String - - fontSize = selected.toInt() - - Toast.makeText( - screen.context, - intl["font_size_message"].format(entry), - Toast.LENGTH_LONG, - ).show() - - true // It's necessary to update the user interface - } - }.also(screen::addPreference) - - if (!language.disableFontSettings) { - ListPreference(screen.context).apply { - key = FONT_NAME_PREF - title = intl["font_name_title"] - entries = fonts.map { - it.first + if (it.second.isBlank()) " - ${intl["default_font_name"]}" else "" - }.toTypedArray() - entryValues = fonts.map { it.second }.toTypedArray() - summary = buildString { - appendLine(intl["font_name_summary"]) - append("\t* %s") - } - - setDefaultValue(fontName) - - setOnPreferenceChange { _, newValue -> - val selected = newValue as String - val index = this.findIndexOfValue(selected) - val entry = entries[index] as String - - fontName = selected - - Toast.makeText( - screen.context, - intl["font_name_message"].format(entry), - Toast.LENGTH_LONG, - ).show() - - true // It's necessary to update the user interface - } - }.also(screen::addPreference) - } - - SwitchPreferenceCompat(screen.context).apply { - key = DISABLE_WORD_BREAK_PREF - title = "⚠ ${intl["disable_word_break_title"]}" - summary = intl["disable_word_break_summary"] - setDefaultValue(language.disableWordBreak) - setOnPreferenceChange { _, newValue -> - disableWordBreak = newValue as Boolean - true - } - }.also(screen::addPreference) - - if (language.target == language.origin) { - return - } - - SwitchPreferenceCompat(screen.context).apply { - key = ENABLE_MANGA_DETAILS_TRANSLATION_PREF - title = "⚠ ${intl["enable_manga_details_translation_title"]}" - summary = intl["enable_manga_details_translation_summary"] - setDefaultValue(enableMangaDetailsTranslation) - setOnPreferenceChange { _, newValue -> - enableMangaDetailsTranslation = newValue as Boolean - true - } - }.also(screen::addPreference) - - if (language.supportNativeTranslation) { - SwitchPreferenceCompat(screen.context).apply { - key = DISABLE_TRANSLATOR_PREF - title = "⚠ ${intl["disable_translator_title"]}" - summary = intl["disable_translator_summary"] - setDefaultValue(language.disableTranslator) - setOnPreferenceChange { _, newValue -> - disableTranslator = newValue as Boolean - true - } - }.also(screen::addPreference) - } - - if (!disableTranslator) { - ListPreference(screen.context).apply { - key = TRANSLATOR_PROVIDER_PREF - title = intl["translate_dialog_box_title"] - entries = translators - entryValues = translators - summary = buildString { - appendLine(intl["translate_dialog_box_summary"]) - append("\t* %s") - } - - setDefaultValue(translators.first()) - - setOnPreferenceChange { _, newValue -> - val selected = newValue as String - val index = this.findIndexOfValue(selected) - val entry = entries[index] as String - - Toast.makeText( - screen.context, - "${intl["translate_dialog_box_toast"]} '$entry'", - Toast.LENGTH_LONG, - ).show() - - true - } - }.also(screen::addPreference) - } - } - - /** - * Sets an `OnPreferenceChangeListener` for the preference, and before triggering the original listener, - * marks that the configuration has changed by setting `isSettingsChanged` to `true`. - * This behavior is useful for applying runtime configurations in the HTTP client, - * ensuring that the preference change is registered before invoking the original listener. - */ - protected fun Preference.setOnPreferenceChange(onPreferenceChangeListener: Preference.OnPreferenceChangeListener) { - setOnPreferenceChangeListener { preference, newValue -> - isSettingsChanged = true - onPreferenceChangeListener.onPreferenceChange(preference, newValue) - } - } - - companion object { - val PAGE_REGEX = Regex(".*?\\.(webp|png|jpg|jpeg)#\\[.*?]", RegexOption.IGNORE_CASE) - const val DEVICE_FONT = "device:" - const val PREFIX_SEARCH = "id:" - private const val FONT_SIZE_PREF = "fontSizePref" - private const val FONT_NAME_PREF = "fontNamePref" - private const val DISABLE_WORD_BREAK_PREF = "disableWordBreakPref" - private const val DISABLE_TRANSLATOR_PREF = "disableTranslatorPref" - private const val ENABLE_MANGA_DETAILS_TRANSLATION_PREF = "enableMangaDetailsTranslationPref" - private const val TRANSLATOR_PROVIDER_PREF = "translatorProviderPref" - private const val DEFAULT_FONT_SIZE = "24" - - private val dateFormat: SimpleDateFormat = SimpleDateFormat("dd MMMM yyyy", Locale.US) - } -} diff --git a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsDto.kt b/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsDto.kt deleted file mode 100644 index 6104d3a16..000000000 --- a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsDto.kt +++ /dev/null @@ -1,124 +0,0 @@ -package eu.kanade.tachiyomi.multisrc.machinetranslations - -import android.graphics.Color -import android.os.Build -import androidx.annotation.RequiresApi -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.json.JsonArray -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonTransformingSerializer -import kotlinx.serialization.json.buildJsonObject -import kotlinx.serialization.json.jsonArray -import kotlinx.serialization.json.jsonObject -import kotlinx.serialization.json.jsonPrimitive -import kotlinx.serialization.json.put -import java.io.IOException - -@Serializable -class PageDto( - @SerialName("img_url") - val imageUrl: String, - - @SerialName("translations") - @Serializable(with = DialogListSerializer::class) - val dialogues: List = emptyList(), -) - -@Serializable -@RequiresApi(Build.VERSION_CODES.O) -data class Dialog( - val x1: Float, - val y1: Float, - val x2: Float, - val y2: Float, - val angle: Float = 0f, - val isBold: Boolean = false, - val isNewApi: Boolean = false, - val textByLanguage: Map = emptyMap(), - val type: String = "normal", - private val fbColor: List = emptyList(), - private val bgColor: List = emptyList(), -) { - val text: String get() = textByLanguage["text"] ?: throw Exception("Dialog not found") - fun getTextBy(language: Language) = when { - !language.disableTranslator -> textByLanguage[language.origin] - else -> textByLanguage[language.target] - } ?: text - - val width get() = x2 - x1 - val height get() = y2 - y1 - val centerY get() = (y2 + y1) / 2f - val centerX get() = (x2 + x1) / 2f - - val foregroundColor: Int get() { - val color = fbColor.takeIf { it.isNotEmpty() } - ?: return Color.BLACK - return Color.rgb(color[0], color[1], color[2]) - } - - val backgroundColor: Int get() { - val color = bgColor.takeIf { it.isNotEmpty() } - ?: return Color.WHITE - return Color.rgb(color[0], color[1], color[2]) - } -} - -private object DialogListSerializer : - JsonTransformingSerializer>(ListSerializer(Dialog.serializer())) { - override fun transformDeserialize(element: JsonElement): JsonElement { - return JsonArray( - element.jsonArray.map { jsonElement -> - val coordinates = getCoordinates(jsonElement) - val textByLanguage = getDialogs(jsonElement) - - buildJsonObject { - put("x1", coordinates[0]) - put("y1", coordinates[1]) - put("x2", coordinates[2]) - put("y2", coordinates[3]) - put("textByLanguage", textByLanguage) - - if (jsonElement.isArray) { - return@buildJsonObject - } - - jsonElement.jsonObject.let { obj -> - obj["fg_color"]?.let { put("fbColor", it) } - obj["bg_color"]?.let { put("bgColor", it) } - obj["angle"]?.let { put("angle", it) } - obj["type"]?.let { put("type", it) } - obj["is_bold"]?.let { put("isBold", it) } - put("isNewApi", true) - } - } - }, - ) - } - - private fun getCoordinates(element: JsonElement): JsonArray { - return when (element) { - is JsonArray -> element.jsonArray[0].jsonArray - else -> element.jsonObject["bbox"]?.jsonArray - ?: throw IOException("Dialog box position not found") - } - } - private fun getDialogs(element: JsonElement): JsonObject { - return buildJsonObject { - when (element) { - is JsonArray -> put("text", element.jsonArray[1]) - else -> { - element.jsonObject.entries - .filter { it.value.isString } - .forEach { put(it.key, it.value) } - } - } - } - } - - private val JsonElement.isArray get() = this is JsonArray - private val JsonElement.isObject get() = this is JsonObject - private val JsonElement.isString get() = this.isObject.not() && this.isArray.not() && this.jsonPrimitive.isString -} diff --git a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsFactoryUtils.kt b/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsFactoryUtils.kt deleted file mode 100644 index f24b095e0..000000000 --- a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsFactoryUtils.kt +++ /dev/null @@ -1,15 +0,0 @@ -package eu.kanade.tachiyomi.multisrc.machinetranslations - -class MachineTranslationsFactoryUtils - -data class Language( - val lang: String, - val target: String = lang, - val origin: String = "en", - val fontSize: Int = 24, - val disableFontSettings: Boolean = false, - val disableWordBreak: Boolean = false, - val disableTranslator: Boolean = false, - val supportNativeTranslation: Boolean = false, - val fontName: String = "", -) diff --git a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsFilters.kt b/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsFilters.kt deleted file mode 100644 index a9624d1f7..000000000 --- a/lib-multisrc/machinetranslations/src/eu/kanade/tachiyomi/multisrc/machinetranslations/MachineTranslationsFilters.kt +++ /dev/null @@ -1,59 +0,0 @@ -package eu.kanade.tachiyomi.multisrc.machinetranslations - -import eu.kanade.tachiyomi.source.model.Filter - -class SelectionList(displayName: String, private val vals: List