Răsfoiți Sursa

Squashed commit of the following:

commit 574fba87ab733332efa17733a6602a1649e62379
Author: Steve Johnson <stevejohnson1438@proton.me>
Date:   Sun Oct 29 21:31:23 2023 +0800

    support importing local geofile

commit ec410293f3abe29835645233349d026d3a55acc0
Author: Steve Johnson <stevejohnson1438@proton.me>
Date:   Sun Oct 29 17:18:52 2023 +0800

    release assets at runtime

commit 2dfb95bab98ba661a28efe255e2965c35c6580c4
Author: Steve Johnson <stevejohnson1438@proton.me>
Date:   Sun Oct 29 16:43:41 2023 +0800

    remove embedded country.mmdb

commit fb245ed4a3c257284685f3b1bee5d9f7333833ce
Author: Steve Johnson <stevejohnson1438@proton.me>
Date:   Sun Oct 29 16:35:14 2023 +0800

    simplity gradle

commit 2fb75c87a13dea7e5c8f8f4126cc53d2d6926b99
Author: Steve Johnson <stevejohnson1438@proton.me>
Date:   Sun Oct 29 16:06:17 2023 +0800

    add geofiles download
Steve Johnson 2 ani în urmă
părinte
comite
ecf03507e6

+ 3 - 0
.gitignore

@@ -27,6 +27,9 @@ gradle-app.setting
 /core/src/premium/golang/.idea/*
 !/core/src/premium/golang/.idea/codeStyles
 
+# Ignore builtin geofiles
+app/src/main/assets
+
 # KeyStore
 signing.properties
 *.keystore

+ 41 - 0
app/build.gradle.kts

@@ -1,3 +1,7 @@
+import java.net.URL
+import java.nio.file.Files
+import java.nio.file.StandardCopyOption
+
 plugins {
     kotlin("android")
     kotlin("kapt")
@@ -25,3 +29,40 @@ dependencies {
 tasks.getByName("clean", type = Delete::class) {
     delete(file("release"))
 }
+
+val geoFilesDownloadDir = "src/main/assets"
+
+task("downloadGeoFiles") {
+
+    val geoFilesUrls = mapOf(
+        "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb" to "geoip.metadb",
+        "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat" to "geosite.dat",
+        // "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb" to "country.mmdb",
+    )
+
+    doLast {
+        geoFilesUrls.forEach { (downloadUrl, outputFileName) ->
+            val url = URL(downloadUrl)
+            val outputPath = file("$geoFilesDownloadDir/$outputFileName")
+            outputPath.parentFile.mkdirs()
+            url.openStream().use { input ->
+                Files.copy(input, outputPath.toPath(), StandardCopyOption.REPLACE_EXISTING)
+                println("$outputFileName downloaded to $outputPath")
+            }
+        }
+    }
+}
+
+afterEvaluate {
+    val downloadGeoFilesTask = tasks["downloadGeoFiles"]
+
+    tasks.forEach {
+        if (it.name.startsWith("assemble")) {
+            it.dependsOn(downloadGeoFilesTask)
+        }
+    }
+}
+
+tasks.getByName("clean", type = Delete::class) {
+    delete(file(geoFilesDownloadDir))
+}

+ 23 - 0
app/src/main/java/com/github/kr328/clash/MainApplication.kt

@@ -7,6 +7,12 @@ import com.github.kr328.clash.common.compat.currentProcessName
 import com.github.kr328.clash.common.log.Log
 import com.github.kr328.clash.remote.Remote
 import com.github.kr328.clash.service.util.sendServiceRecreated
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.InputStream
+import java.io.OutputStream
+
 
 @Suppress("unused")
 class MainApplication : Application() {
@@ -20,6 +26,7 @@ class MainApplication : Application() {
         super.onCreate()
 
         val processName = currentProcessName
+        extractGeoFiles()
 
         Log.d("Process $processName started")
 
@@ -30,6 +37,22 @@ class MainApplication : Application() {
         }
     }
 
+    private fun extractGeoFiles() {
+        val geoipFile = File(filesDir, "clash/geoip.metadb")
+        if(!geoipFile.exists()) {
+            FileOutputStream(geoipFile).use {
+                assets.open("geoip.metadb").copyTo(it);
+            }
+        }
+
+        val geositeFile = File(filesDir, "clash/geosite.dat")
+        if(!geositeFile.exists()) {
+            FileOutputStream(geositeFile).use {
+                assets.open("geosite.dat").copyTo(it);
+            }
+        }
+    }
+
     fun finalize() {
         Global.destroy()
     }

+ 94 - 0
app/src/main/java/com/github/kr328/clash/MetaFeatureSettingsActivity.kt

@@ -1,10 +1,23 @@
 package com.github.kr328.clash
 
+import android.R
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.database.Cursor
+import android.provider.OpenableColumns
+import android.widget.Toast
 import com.github.kr328.clash.core.Clash
 import com.github.kr328.clash.design.MetaFeatureSettingsDesign
 import com.github.kr328.clash.util.withClash
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.selects.select
+import java.io.File
+import java.io.FileOutputStream
+import kotlin.coroutines.resume
+
 
 class MetaFeatureSettingsActivity : BaseActivity<MetaFeatureSettingsDesign>() {
     override suspend fun main() {
@@ -41,9 +54,90 @@ class MetaFeatureSettingsActivity : BaseActivity<MetaFeatureSettingsDesign>() {
                                 finish()
                             }
                         }
+                        MetaFeatureSettingsDesign.Request.ImportGeoIp -> {
+                            val intent = Intent(Intent.ACTION_GET_CONTENT)
+                            intent.type = "*/*"
+                            intent.addCategory(Intent.CATEGORY_OPENABLE)
+                            startActivityForResult(
+                                intent,
+                                MetaFeatureSettingsDesign.Request.ImportGeoIp.ordinal
+                            )
+                        }
+                        MetaFeatureSettingsDesign.Request.ImportGeoSite -> {
+                            val intent = Intent(Intent.ACTION_GET_CONTENT)
+                            intent.type = "*/*"
+                            intent.addCategory(Intent.CATEGORY_OPENABLE)
+                            startActivityForResult(
+                                intent,
+                                MetaFeatureSettingsDesign.Request.ImportGeoSite.ordinal
+                            )
+                        }
+                        MetaFeatureSettingsDesign.Request.ImportCountry -> {
+                            val intent = Intent(Intent.ACTION_GET_CONTENT)
+                            intent.type = "*/*"
+                            intent.addCategory(Intent.CATEGORY_OPENABLE)
+                            startActivityForResult(
+                                intent,
+                                MetaFeatureSettingsDesign.Request.ImportCountry.ordinal
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public val validDatabaseExtensions = listOf(
+        ".metadb", ".db", ".dat", ".mmdb"
+    )
+    @SuppressLint("Range")
+    override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
+        super.onActivityResult(requestCode, resultCode, resultData)
+        if(resultCode == RESULT_OK) {
+            val uri = resultData?.data
+            val cursor: Cursor? = uri?.let {
+                contentResolver.query(it, null, null, null, null, null)
+            }
+            cursor?.use {
+                if (it.moveToFirst()) {
+                    val displayName: String =
+                        it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
+                    val ext = "." + displayName.substringAfterLast(".")
+                    if(!validDatabaseExtensions.contains(ext))
+                    {
+                        val dialog = MaterialAlertDialogBuilder(this)
+                            .setTitle("Unknown Database Format")
+                            .setMessage("Only ${validDatabaseExtensions.joinToString("/")} are supported")
+                            .setPositiveButton("OK"){ _, _ -> }
+                            .show()
+                        return
+                    }
+                    val outputFileName = when (requestCode) {
+                        MetaFeatureSettingsDesign.Request.ImportGeoIp.ordinal ->
+                            "geoip$ext"
+                        MetaFeatureSettingsDesign.Request.ImportGeoSite.ordinal ->
+                            "geosite$ext"
+                        MetaFeatureSettingsDesign.Request.ImportCountry.ordinal ->
+                            "country$ext"
+                        else -> ""
+                    }
+                    if(outputFileName.isEmpty())
+                    {
+                        Toast.makeText(this, "Bad request", Toast.LENGTH_LONG).show()
+                        return
+                    }
+
+                    val outputFile = File(File(filesDir, "clash"), outputFileName);
+                    contentResolver.openInputStream(uri).use { ins->
+                        FileOutputStream(outputFile).use { outs->
+                            ins?.copyTo(outs)
+                        }
                     }
+                    Toast.makeText(this, "$displayName imported", Toast.LENGTH_LONG).show()
+                    return
                 }
             }
         }
+        Toast.makeText(this, "Import failed", Toast.LENGTH_LONG).show()
     }
 }

+ 31 - 1
design/src/main/java/com/github/kr328/clash/design/MetaFeatureSettingsDesign.kt

@@ -15,7 +15,7 @@ class MetaFeatureSettingsDesign(
     configuration: ConfigurationOverride
 ) : Design<MetaFeatureSettingsDesign.Request>(context) {
     enum class Request {
-        ResetOverride
+        ResetOverride, ImportGeoIp, ImportGeoSite, ImportCountry
     }
 
     private val binding = DesignSettingsMetaFeatureBinding
@@ -198,6 +198,36 @@ class MetaFeatureSettingsDesign(
             )
 
             sniffer.listener?.onChanged()
+
+            category(R.string.geox_files)
+
+            clickable (
+                title = R.string.import_geoip_file,
+                summary = R.string.press_to_import,
+            ){
+                clicked {
+                    requests.trySend(Request.ImportGeoIp)
+                }
+            }
+
+            clickable (
+                title = R.string.import_geosite_file,
+                summary = R.string.press_to_import,
+            ){
+                clicked {
+                    requests.trySend(Request.ImportGeoSite)
+                }
+            }
+
+            clickable (
+                title = R.string.import_country_file,
+                summary = R.string.press_to_import,
+            ){
+                clicked {
+                    requests.trySend(Request.ImportCountry)
+                }
+            }
+
             /*
             category(R.string.geox_url_setting)
 

+ 5 - 0
design/src/main/res/values-ja-rJP/strings.xml

@@ -234,4 +234,9 @@
     <string name="geox_geoip">GeoIP URL</string>
     <string name="geox_mmdb">MMDB URL</string>
     <string name="geox_geosite">Geosite URL</string>
+    <string name="geox_files" >Geo Files</string>
+    <string name="import_geoip_file">Import GeoIP Database</string>
+    <string name="press_to_import">Press to import...</string>
+    <string name="import_geosite_file">Import GeoSite Database</string>
+    <string name="import_country_file">Import Country Database</string>
 </resources>

+ 5 - 0
design/src/main/res/values-ko-rKR/strings.xml

@@ -234,4 +234,9 @@
     <string name="geox_geoip">GeoIP Url</string>
     <string name="geox_mmdb">MMDB Url</string>
     <string name="geox_geosite">Geosite Url</string>
+    <string name="geox_files" >Geo Files</string>
+    <string name="import_geoip_file">Import GeoIP Database</string>
+    <string name="press_to_import">Press to import...</string>
+    <string name="import_geosite_file">Import GeoSite Database</string>
+    <string name="import_country_file">Import Country Database</string>
 </resources>

+ 5 - 0
design/src/main/res/values-ru/strings.xml

@@ -299,4 +299,9 @@
     <string name="geoip_url" translatable="false">https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat</string>
     <string name="mmdb_url" translatable="false">https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb</string>
     <string name="geosite_url" translatable="false">https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat</string>
+    <string name="geox_files" >Geo Files</string>
+    <string name="import_geoip_file">Import GeoIP Database</string>
+    <string name="press_to_import">Press to import...</string>
+    <string name="import_geosite_file">Import GeoSite Database</string>
+    <string name="import_country_file">Import Country Database</string>
 </resources>

+ 5 - 0
design/src/main/res/values-zh-rHK/strings.xml

@@ -231,4 +231,9 @@
     <string name="geox_geosite">Geosite Url</string>
     <string name="prefer_h3">Prefer h3</string>
     <string name="port_whitelist">Port Whitelist</string>
+    <string name="geox_files" >Geo Files</string>
+    <string name="import_geoip_file">Import GeoIP Database</string>
+    <string name="press_to_import">Press to import...</string>
+    <string name="import_geosite_file">Import GeoSite Database</string>
+    <string name="import_country_file">Import Country Database</string>
 </resources>

+ 5 - 0
design/src/main/res/values-zh-rTW/strings.xml

@@ -231,4 +231,9 @@
     <string name="geox_geosite">Geosite Url</string>
     <string name="prefer_h3">Prefer h3</string>
     <string name="port_whitelist">Port Whitelist</string>
+    <string name="geox_files" >Geo Files</string>
+    <string name="import_geoip_file">Import GeoIP Database</string>
+    <string name="press_to_import">Press to import...</string>
+    <string name="import_geosite_file">Import GeoSite Database</string>
+    <string name="import_country_file">Import Country Database</string>
 </resources>

+ 5 - 0
design/src/main/res/values-zh/strings.xml

@@ -234,4 +234,9 @@
     <string name="geox_geosite">Geosite Url</string>
     <string name="prefer_h3">Prefer h3</string>
     <string name="port_whitelist">Port Whitelist</string>
+    <string name="geox_files" >Geo Files</string>
+    <string name="import_geoip_file">导入 GeoIP 数据库</string>
+    <string name="press_to_import">Press to import...</string>
+    <string name="import_geosite_file">导入 GeoSite 数据库</string>
+    <string name="import_country_file">导入 Country 数据库</string>
 </resources>

+ 5 - 0
design/src/main/res/values/strings.xml

@@ -299,4 +299,9 @@
     <string name="geoip_url" translatable="false">https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/release/geoip.dat</string>
     <string name="mmdb_url" translatable="false">https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/release/country.mmdb</string>
     <string name="geosite_url" translatable="false">https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/release/geosite.dat</string>
+    <string name="geox_files" >Geo Files</string>
+    <string name="import_geoip_file">Import GeoIP Database</string>
+    <string name="press_to_import">Press to import...</string>
+    <string name="import_geosite_file">Import GeoSite Database</string>
+    <string name="import_country_file">Import Country Database</string>
 </resources>