diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 13d2bbef..b01b39e6 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -3,7 +3,8 @@ "v6.7.0": { "released_date": "2025/06/10", "feature": [ - "zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))" + "zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))", + "mediainfo 模块, 用于查看媒体文件的详细信息 (参阅 项目文档 > [媒体信息](https://docs.autojs6.com/#/mediainfo))" ], "fix": [ "使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题", diff --git a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt index 051b4828..85d1ade9 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt @@ -63,6 +63,7 @@ import org.autojs.autojs.runtime.api.augment.jsox.Jsox import org.autojs.autojs.runtime.api.augment.jsox.Mathx import org.autojs.autojs.runtime.api.augment.jsox.Numberx import org.autojs.autojs.runtime.api.augment.media.Media +import org.autojs.autojs.runtime.api.augment.mediainfo.Mediainfo import org.autojs.autojs.runtime.api.augment.mime.Mime import org.autojs.autojs.runtime.api.augment.nanoid.NanoID import org.autojs.autojs.runtime.api.augment.notice.Notice @@ -109,6 +110,7 @@ import org.autojs.autojs.util.SdkVersionUtils import org.autojs.autojs.util.StringUtils import org.autojs.autojs.util.ViewUtils import org.autojs.autojs6.R +import org.mediainfo.android.MediaInfo import org.mozilla.javascript.BaseFunction import org.mozilla.javascript.ContextFactory import org.mozilla.javascript.RhinoException @@ -366,6 +368,10 @@ class ScriptRuntime private constructor(builder: Builder) { } } + @JvmField + @ScriptInterface + val mediaInfo = MediaInfo() + private lateinit var augmentedApp: ScriptableObject private lateinit var augmentedAutojs: ScriptableObject @@ -769,6 +775,7 @@ class ScriptRuntime private constructor(builder: Builder) { NanoID.augment(target, true) Pinyin.augment(target, true) Pinyin4j.augment(target, true) + Mediainfo(this).augment(target, true) augmentedApp.defineProp(Autojs::class.java.simpleName.lowercase(), augmentedAutojs) } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/mediainfo/Mediainfo.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/mediainfo/Mediainfo.kt new file mode 100644 index 00000000..8c40b714 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/mediainfo/Mediainfo.kt @@ -0,0 +1,30 @@ +package org.autojs.autojs.runtime.api.augment.mediainfo + +import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface +import org.autojs.autojs.runtime.ScriptRuntime +import org.autojs.autojs.runtime.api.augment.Augmentable +import org.autojs.autojs.runtime.api.augment.Invokable +import org.mozilla.javascript.NativeObject + +@Suppress("unused", "UNUSED_PARAMETER") +class Mediainfo(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable { + + override val selfAssignmentFunctions = listOf( + ::read.name, + ) + + override fun invoke(vararg args: Any?): NativeObject = ensureArgumentsOnlyOne(args) { path -> + read(scriptRuntime, arrayOf(path)) + } + + companion object { + + @JvmStatic + @RhinoRuntimeFunctionInterface + fun read(scriptRuntime: ScriptRuntime, args: Array): NativeObject = ensureArgumentsOnlyOne(args) { path -> + MediainfoNativeObject(scriptRuntime, path) + } + + } + +} diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/mediainfo/MediainfoNativeObject.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/mediainfo/MediainfoNativeObject.kt new file mode 100644 index 00000000..8de3fd58 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/mediainfo/MediainfoNativeObject.kt @@ -0,0 +1,122 @@ +package org.autojs.autojs.runtime.api.augment.mediainfo + +import org.autojs.autojs.annotation.RhinoFunctionBody +import org.autojs.autojs.annotation.RhinoStandardFunctionInterface +import org.autojs.autojs.extension.AnyExtensions.isJsNullish +import org.autojs.autojs.extension.AnyExtensions.jsBrief +import org.autojs.autojs.extension.FlexibleArray.Companion.ensureArgumentsIsEmpty +import org.autojs.autojs.extension.ScriptableExtensions.defineProp +import org.autojs.autojs.extension.ScriptableExtensions.getProp +import org.autojs.autojs.runtime.ScriptRuntime +import org.autojs.autojs.runtime.api.StringReadable +import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException +import org.autojs.autojs.util.RhinoUtils +import org.autojs.autojs.util.RhinoUtils.NOT_CONSTRUCTABLE +import org.autojs.autojs.util.RhinoUtils.coerceString +import org.autojs.autojs.util.RhinoUtils.newBaseFunction +import org.autojs.autojs.util.RhinoUtils.newNativeObject +import org.mediainfo.android.MediaInfo +import org.mozilla.javascript.Context +import org.mozilla.javascript.Function +import org.mozilla.javascript.NativeObject +import org.mozilla.javascript.Scriptable + +@Suppress("unused", "UNUSED_PARAMETER") +class MediainfoNativeObject( + private val scriptRuntime: ScriptRuntime, + rawPath: Any?, +) : NativeObject(), StringReadable { + + @JvmField + val path: String = when { + rawPath.isJsNullish() -> throw WrappedIllegalArgumentException("Argument path ${rawPath.jsBrief()} is invalid for mediainfo") + else -> { + val pathString = coerceString(rawPath) + require(pathString.isNotBlank()) { + "Argument \"path\" ${pathString.jsBrief()} for mediainfo cannot be empty" + } + scriptRuntime.files.nonNullPath(pathString) + } + } + + private var informToPrint: String = "" + + init { + RhinoUtils.initNativeObjectPrototype(this) + defineProperty(StringReadable.KEY, newBaseFunction(StringReadable.KEY, { toStringReadable() }, NOT_CONSTRUCTABLE), READONLY or DONTENUM or PERMANENT) + defineProperty("path", path, READONLY or PERMANENT) + initProperties() + } + + private fun initProperties() { + val inform = scriptRuntime.mediaInfo.getMI(path) + defineProperty("inform", inform, READONLY or PERMANENT) + MediaInfo.StreamKind.entries.forEach { streamKind -> + val funcName = streamKind.name.lowercase() + defineProperty(funcName, newBaseFunction(funcName, { argList -> + val parameter = argList.takeUnless { it.isEmpty() }?.get(0)?.let { coerceString(it) } ?: "" + scriptRuntime.mediaInfo.get(path, streamKind, 0, parameter) + }, NOT_CONSTRUCTABLE), READONLY or PERMANENT) + } + applyInform(inform) + } + + private fun applyInform(inform: String) { + var currentObj: Scriptable? = null + var currentSectionName: String? + + inform.lineSequence().forEach { raw -> + val line = raw.trimEnd() + if (line.isBlank()) return@forEach + when { + !line.contains(':') -> { + currentSectionName = line.lowercase() + currentObj = this.getProp(currentSectionName) as? Scriptable + ?: newNativeObject().also { defineProperty(currentSectionName, it, READONLY or PERMANENT) } + if (informToPrint.isNotBlank()) informToPrint += " },\n" + informToPrint += " $currentSectionName: {\n" + } + currentObj != null -> { + val idx = line.indexOf(':') + val key = line.substring(0, idx).trim().toCamel() + val value = line.substring(idx + 1).trim() + currentObj.defineProp(key, value, READONLY or PERMANENT) + informToPrint += " $key: \"$value\",\n" + } + } + } + if (informToPrint.isNotBlank()) informToPrint += " }," + } + + private fun String.toCamel(): String = this + .replace(Regex("\\((s|es|ies)\\)"), "$1") + .split(Regex("[^A-Za-z0-9]+")) + .filter { it.isNotEmpty() } + .joinToString("") { part -> + part.lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() } + }.replaceFirstChar { it.lowercase() } + + override fun toStringReadable() = toStringRhino(this) + + companion object { + + @JvmStatic + @RhinoStandardFunctionInterface + fun toString(cx: Context, thisObj: Scriptable, args: Array, funObj: Function): String = ensureArgumentsIsEmpty(args) { + toStringRhino(thisObj as MediainfoNativeObject) + } + + @JvmStatic + @RhinoFunctionBody + fun toStringRhino(thisObj: MediainfoNativeObject): String { + val objectName = MediainfoNativeObject::class.java.simpleName + val inform = thisObj.informToPrint + return when { + inform.isBlank() -> "$objectName {}" + else -> "$objectName {\n$inform\n}" + } + } + + } + +} diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/notice/Notice.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/notice/Notice.kt index 89a03e89..ce3f0229 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/notice/Notice.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/notice/Notice.kt @@ -32,15 +32,6 @@ import java.util.function.Supplier import kotlin.math.roundToInt import kotlin.reflect.KMutableProperty1 -// @Caution by SuperMonster003 on May 6, 2023. -// ! On device running with Android 7.x, importing NotificationManagerCompat will cause an exception: -// ! java.lang.ClassNotFoundException: Didn't find class "android.app.NotificationChannel" on path: DexPathList ... -// ! zh-CN: -// ! 在安卓 7.x 设备上, 导入 NotificationManagerCompat 类将导致异常: -// ! java.lang.ClassNotFoundException: 无法找到 "android.app.NotificationChannel" 类在此路径: DexPathList ... -// ! -// # import androidx.core.app.NotificationManagerCompat - @Suppress("unused", "UNUSED_PARAMETER") class Notice(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable { diff --git a/version.properties b/version.properties index 37e07fa6..1802d613 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Tue Jun 10 18:30:41 CST 2025 -BUILD_TIME=1749551441206 +#Wed Jun 11 18:10:41 CST 2025 +BUILD_TIME=1749636641459 COMPILE_SDK_VERSION=35 IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_NDK_VERSION=26.1.10909125 @@ -19,6 +19,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 TARGET_SDK_VERSION=35 TARGET_SDK_VERSION_INRT=29 -VERSION_BUILD=3289 +VERSION_BUILD=3292 VERSION_NAME=6.7.0 Alpha VSCODE_EXT_REQUIRED_VERSION=1.0.8