公告内容="" 最新版本="1.1" 更新内容="支持抖音、快手、最右、皮皮虾、小红书等平台分享的短视频无水印解析。" 更新地址="https://www.lanzoux.com/b00wngw77e#密码:hie8" --是否开启远程代码加载功能 【开关】开【开关】 --获取远程代码 【远程代码】--[[ Video Parser Tool Supports Douyin, Kuaishou, Xiaohongshu and other short video platforms. Features: Parse video links, Play, Copy link, Download. Version: 1.0.0 (Refactored) --]] -- ########################## 1. Imports & Initialization ########################## require "import" import "android.app.*" import "android.os.*" import "android.widget.*" import "android.view.*" import "android.support.*" import 'android.webkit.WebView' import "android.net.Uri" import "android.text.format.Formatter" import "android.provider.Settings$Secure" import "android.graphics.PorterDuffColorFilter" import "android.graphics.PorterDuff" import "android.widget.ScrollView" import "android.webkit.WebViewClient" import "android.animation.LayoutTransition" import "android.view.WindowManager" import "android.widget.VideoView" import "android.os.Build" import "java.io.File" import "android.media.MediaPlayer" import "android.graphics.Typeface" import "android.graphics.drawable.GradientDrawable" import "android.content.Intent" import "android.content.Context" import "android.content.ClipboardManager" import "android.content.ClipData" import "android.app.DownloadManager" import "java.net.URL" -- Prevent screen from sleeping activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) -- ########################## 2. Constants & Global Variables ########################## local TAG = "VideoParser" -- For logging (if any) local STATE_IDLE = 0 local STATE_PARSING = 1 local STATE_PLAYING = 2 local webView = LuaWebView(activity) local videoUrl = "" -- Stores the parsed video URL local imageUrl = "" -- Stores the parsed image URL local isPlaying = false -- Video playback state local exitParam = 0 -- Parameter for double-click back to exit -- Platform identifiers (used for routing logic) local PLATFORM_DOUYIN = "douyin" local PLATFORM_KUAISHOU = "kuaishou" local PLATFORM_XIAOHONGSHU = "xiaohongshu" local PLATFORM_PIPIXIA = "pipixia" local PLATFORM_ZUIYOU = "zuiyou" local PLATFORM_DOUBAO = "doubao" -- Network Configuration local USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36" local UPDATE_CONFIG_URL = "https://kdjiexi.pages.dev/" -- ########################## 3. Utility / Helper Functions ########################## --- Displays a custom styled Toast message. --- @param message string The content to display. --- @param duration number Optional. Toast duration (Toast.LENGTH_SHORT or Toast.LENGTH_LONG). Defaults to LENGTH_SHORT. local function showCustomToast(message, duration) duration = duration or Toast.LENGTH_SHORT local toastLayout = { LinearLayout; orientation = 'horizontal'; layout_width = 'fill'; layout_height = 'wrap'; BackgroundColor = '0x00000000'; { CardView; layout_width = 'wrap'; layout_height = 'wrap'; CardBackgroundColor = '0xffffffff'; layout_margin = '5dp'; layout_gravity = 'center'; CardElevation = "5dp"; elevation = '10'; radius = '1%w'; { TextView; layout_margin = '3%w'; layout_width = 'fill'; layout_height = 'fill'; gravity = 'center'; textColor = '0xFF000000'; textSize = '15'; id = "toast_text"; } } } local toast = Toast.makeText(activity, "", duration) toast.setView(loadlayout(toastLayout)) toast.setGravity(Gravity.BOTTOM, 0, 100) toast_text.Text = tostring(message) toast.show() end -- Override global print to use custom Toast. function print(message) showCustomToast(message) end --- Hides the soft input keyboard. local function hideSoftKeyboard() import "android.view.inputmethod.InputMethodManager" local imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) local currentFocus = activity.getCurrentFocus() if currentFocus then imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0) end end --- Generates a random string of specified length. --- @param len number The length of the string. --- @return string Random string. local function generateRandomString(len) local characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" local result = "" for _ = 1, len do local randomIndex = math.random(1, #characters) result = result .. string.sub(characters, randomIndex, randomIndex) end return result end --- Extracts the first HTTP/HTTPS URL from a string. --- @param str string Input string. --- @return string|nil Extracted URL or nil. local function extractUrlFromString(str) local pattern = "https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]" return string.match(str, pattern) end --- Downloads a file using Android's DownloadManager. --- @param fileName string The name to save the file as. --- @param downloadUrl string The URL of the file to download. --- @param mimeType string Optional. MIME type. Defaults to "video/mp4". local function downloadFile(fileName, downloadUrl, mimeType) mimeType = mimeType or "video/mp4" local downloadManager = activity.getSystemService(Context.DOWNLOAD_SERVICE) local url = Uri.parse(downloadUrl) local request = DownloadManager.Request(url) request.setTitle(fileName) request.setDescription("Downloading...") request.setMimeType(mimeType) request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI) request.setDestinationInExternalPublicDir("Download", fileName) request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) downloadManager.enqueue(request) print("Download started: " .. fileName) end --- Prompts user to confirm download, then initiates it. local function promptAndDownloadVideo(fileName, downloadUrl) 对话框() .设置标题("Confirm Download") .设置消息("Do you want to download this video?") .设置积极按钮("Yes", function() downloadFile(fileName, downloadUrl, "video/mp4") end) .设置消极按钮("No") .显示() end --- Prompts user to confirm download, then initiates it for an image. local function promptAndDownloadImage(fileName, downloadUrl) 对话框() .设置标题("Confirm Download") .设置消息("Do you want to download this image?") .设置积极按钮("Yes", function() downloadFile(fileName, downloadUrl, "image/png") end) .设置消极按钮("No") .显示() end -- ########################## 4. String Processing Functions (HTML/Unicode/URL) ########################## --- Decodes common HTML entities to their character equivalents. --- @param content string The HTML string to decode. --- @return string Decoded string. local function decodeHtmlEntities(content) local replacements = { -- Common HTML entities ["'"] = "'", [" "] = " ", [" "] = " ", [" "] = " ", ["¢"] = "¢", ["£"] = "£", ["¥"] = "¥", ["€"] = "€", ["®"] = "®", ["™"] = "™", ["±"] = "±", ["×"] = "×", ["÷"] = "÷", ["≠"] = "≠", ["≤"] = "≤", ["≥"] = "≥", ["“"] = '"', ["”"] = '"', ["‘"] = "'", ["’"] = "'", ["←"] = "←", ["↑"] = "↑", ["→"] = "→", ["↓"] = "↓", ["°"] = "°", ["¶"] = "¶", ["§"] = "§", ["•"] = "•", ["…"] = "…", ["—"] = "—", ["–"] = "–", -- Hexadecimal numeric entities ["""] = '"', ["&"] = "&", ["<"] = "<", [">"] = ">", ["/"] = "/", ["`"] = "`", ["'"] = "'", [":"] = ":", [";"] = ";", ["="] = "=", ["?"] = "?", ["@"] = "@", ["["] = "[", ["\"] = "\\", ["]"] = "]", ["^"] = "^", ["_"] = "_", ["{"] = "{", ["|"] = "|", ["}"] = "}", ["~"] = "~", -- Decimal numeric entities ["""] = '"', ["&"] = "&", ["<"] = "<", [">"] = ">", ["/"] = "/", ["`"] = "`", [":"] = ":", [";"] = ";", ["="] = "=", ["?"] = "?", ["@"] = "@", ["["] = "[", ["\"] = "\\", ["]"] = "]", ["^"] = "^", ["_"] = "_", ["{"] = "{", ["|"] = "|", ["}"] = "}", ["~"] = "~", -- Unicode escape sequences ["u003C"] = "<", ["u003A"] = ":", ["u002F"] = "/", ["u0022"] = '"', ["u0026"] = "&", ["u0027"] = "'", ["u003E"] = ">", ["u003F"] = "?", ["u0040"] = "@", ["u005B"] = "[", ["u005C"] = "\\", ["u005D"] = "]", ["u0060"] = "`", ["u007B"] = "{", ["u007C"] = "|", ["u007D"] = "}", -- URL encoded sequences ["%%3A"] = ":", ["%%2F"] = "/", ["%%22"] = '"', ["%%26"] = "&", ["%%27"] = "'", ["%%3C"] = "<", ["%%3E"] = ">", ["%%3F"] = "?", ["%%40"] = "@", ["%%5B"] = "[", ["%%5C"] = "\\", ["%%5D"] = "]", ["%%60"] = "`", ["%%7B"] = "{", ["%%7C"] = "|", ["%%7D"] = "}", -- Base rules ["amp;"] = "", [" "] = " ", ["<"] = "<", [">"] = ">", ["&"] = "&", ["""] = '"', ["'"] = "'", ["/"] = "/", ["#x27"] = "\\", ["`"] = "`", ["©"] = "©", ["\\"] = "", ['""'] = "html>", } for k, v in pairs(replacements) do content = content:gsub(k, v) end content = content:gsub('^"', '') content = content:gsub("&", "&") -- Ensure & is fully resolved last return content end --- Decodes Unicode escape sequences (\uXXXX). --- @param s string Input string. --- @return string Decoded string. local function decodeUnicodeEscapes(s) return string.gsub(s, '\\u(%x%x%x%x)', function(h) return string.char(tonumber(h, 16)) end) end --- Decodes URL-encoded strings. --- @param s string Input string. --- @return string Decoded string. local function urlDecode(s) if not s then return nil end s = string.gsub(s, '%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end) s = string.gsub(s, '\\+', ' ') return s end --- A comprehensive string cleaner combining HTML, Unicode, and URL decoding. --- @param content string Raw string from network/JS. --- @return string Cleaned string. local function cleanRawString(content) if not content then return "" end local cleaned = decodeHtmlEntities(content) cleaned = decodeUnicodeEscapes(cleaned) return cleaned end -- ########################## 7. Application Lifecycle & Security ########################## -- VPN Detection Thread thread(function() while true do import "java.net.NetworkInterface" import "java.util.Collections" local networkInterfaces = NetworkInterface.getNetworkInterfaces() if networkInterfaces then local iterator = Collections.list(networkInterfaces).iterator() while iterator.hasNext() do local intf = iterator.next() if intf.isUp() and intf.getInterfaceAddresses().size() ~= 0 then local name = intf.getName() if name == "tun0" or name == "ppp0" then activity.finish() os.exit() end end end end Thread.sleep(500) end end) -- Back Button Handler function onKeyDown(keyCode, event) if string.find(tostring(event), "KEYCODE_BACK") ~= nil then if exitParam + 2 > tonumber(os.time()) then activity.finish() os.exit() return true else if keyCode == 4 then if webView and webView.canGoBack() then webView.goBack() return true else print("Press again to exit.") exitParam = tonumber(os.time()) end end end return true end end --检测更新代码 function checkForUpdates(configUrl) -- 获取当前版本名 (推荐) function getAppVersion() local packName = activity.getPackageName() local packManager = activity.getPackageManager() local versionName = packManager.getPackageInfo(packName, 0).versionName return versionName or "0.0" end Http.get(configUrl, function(code, content) if code == 200 and content then local cleaned = cleanRawString(content) local announcement = cleaned:match('公告内容="(.-)"') local latestVersion = cleaned:match('最新版本="(.-)"') local updateContent = cleaned:match('更新内容="(.-)"') local updateUrl = cleaned:match('更新地址="(.-)"') -- 1. 显示公告 if announcement and announcement ~= "" then 对话框() .设置标题("公告") .设置消息(announcement) .设置积极按钮("知道了", function() end) .显示() end -- 2. 检测版本更新 local currentVersion = getAppVersion() -- 改用新的获取方式 if latestVersion and latestVersion ~= "" and latestVersion ~= currentVersion and updateUrl and updateUrl ~= "" then local message = updateContent and updateContent ~= "" and ("更新内容:\n" .. updateContent) or ("最新版本:" .. latestVersion) 对话框() .设置标题("发现新版本") .设置消息(message) .设置积极按钮("立即更新", function() activity.finish() local viewIntent = Intent("android.intent.action.VIEW", Uri.parse(updateUrl)) activity.startActivity(viewIntent) end) .设置消极按钮("退出", function() activity.finish() os.exit() end) .setCancelable(false) .显示() else print("当前版本 " .. currentVersion .. " 已是最新") end else print("检查更新失败:" .. tostring(code)) end end) end checkForUpdates(UPDATE_CONFIG_URL) -- ########################## 5. Platform-Specific Parsing Logic ########################## --- Handles video sniffing for platforms that require WebView resource interception. --- @param targetUrl string The URL to load in the WebView. local function sniffVideoViaWebView(targetUrl) local extractedUrl = extractUrlFromString(targetUrl) if not extractedUrl then print("Invalid URL for sniffing") return end print("Sniffing for video stream...") local webView = LuaWebView(activity) webView.setWebViewClient({ shouldOverrideUrlLoading = function(view, url) -- Block intent:// schemes to prevent opening external apps if not url:find("^https?://") then return true end return false end }) webView.getSettings().setUserAgentString(USER_AGENT) webView.setWebViewClient{ onLoadResource = function(view, url) local lowerUrl = url:lower() if (lowerUrl:find("%.m3u8") or lowerUrl:find("%.mp4") or lowerUrl:find("%.mp3") or lowerUrl:find("%.m4v") or lowerUrl:find("%.m4a") or lowerUrl:find("%.wma") or lowerUrl:find("%.douyinvod.com") or lowerUrl:find("%.ppxvod.com") or lowerUrl:find("web(.-)v(.-)izuiyou") or lowerUrl:find("xgwap.ixigua.com/(.-)/video/") or lowerUrl:find("mime_type=video_mp4") or lowerUrl:find("mime_type=audio_mp3")) and (webView.getUrl() ~= "about:blank") then videoUrl = cleanRawString(url) webView.loadUrl("about:blank") webView.stopLoading() containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") end end } webView.loadUrl(extractedUrl) webView.setDownloadListener{ onDownloadStart = function(url) end } end --- Parser for Douyin (TikTok) links. --- @param targetUrl string Douyin share URL. local function parseDouyin(targetUrl) Http.get(targetUrl, function(code, content) if code ~= 200 or not content then print("Network request failed: " .. tostring(code)) return end local cleanedContent = cleanRawString(content) local videoId = cleanedContent:match([[video_id=(.-)&ratio]]) if videoId and videoId ~= "" then videoUrl = "https://www.iesdouyin.com/aweme/v1/play/?video_id=" .. videoId .. "&ratio=1080p&line=0" videoUrl = cleanRawString(videoUrl) containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") else -- Fallback to JS evaluation in WebView if pcall(function() local webView = LuaWebView(activity) webView.setWebViewClient({ shouldOverrideUrlLoading = function(view, url) if not url:find("^https?://") then return true end return false end }) webView.loadUrl(targetUrl) webView.getSettings().setMediaPlaybackRequiresUserGesture(true) webView.setDownloadListener{ onDownloadStart = function(url) end } task(5000, function() local js = "document.documentElement.outerHTML" webView.evaluateJavascript(js, { onReceiveValue = function(jsContent) local cleanedJsContent = cleanRawString(jsContent) cleanedJsContent = cleanedJsContent:match('"play_addr":{(.-)},') if cleanedJsContent then cleanedJsContent = cleanedJsContent:match('"url_list":%["(.-)"%]') if cleanedJsContent then videoUrl = cleanedJsContent:gsub('/playwm/', '/play/') videoUrl = cleanRawString(videoUrl) if videoUrl and (videoUrl:find("video_id=") or videoUrl:find("%.snssdk.com")) then containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") else print("Fallback failed, attempting sniff...") sniffVideoViaWebView(targetUrl) end end else print("Fallback failed, attempting sniff...") sniffVideoViaWebView(targetUrl) end end }) end) end) then end end end) end --- Parser for Kuaishou links. --- @param targetUrl string Kuaishou share URL. local function parseKuaishou(targetUrl) Http.get(targetUrl, function(code, content) if code ~= 200 or not content then print("Network request failed: " .. tostring(code)) return end local cleanedContent = cleanRawString(content) local videoSection = cleanedContent:match('mainMvUrls"(.-)%]') if videoSection then local extractedUrl = videoSection:match('"url":"(.-)"}') if extractedUrl and (extractedUrl:find("%.mp4") or extractedUrl:find("%.m3u8")) then videoUrl = cleanRawString(extractedUrl) containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") else print("URL not found in Kuaishou meta, attempting sniff...") sniffVideoViaWebView(targetUrl) end else print("Meta section not found, attempting sniff...") sniffVideoViaWebView(targetUrl) end end) end --- Parser for Xiaohongshu links. --- @param targetUrl string Xiaohongshu share URL. local function parseXiaohongshu(targetUrl) -- Case 1: Short link that needs to be expanded via WebView if targetUrl:find("xhslink.com") then local webView = LuaWebView(activity) webView.setWebViewClient({ shouldOverrideUrlLoading = function(view, url) if not url:find("^https?://") then return true end return false end }) webView.getSettings().setMediaPlaybackRequiresUserGesture(true) webView.loadUrl(targetUrl) webView.setWebViewClient{ onLoadResource = function(view, url) if url:find("xhsdiscover://") then local decodedUrl = urlDecode(url) local preloadInfo = string.match(decodedUrl, "h5VideoPreloadInfo=(.+)") if preloadInfo then local h265Section = preloadInfo:match('"h265":%[(.-)%}%]}}}}') if h265Section then local masterUrl = h265Section:match('"master_url":"([^"]*)"') if masterUrl and (masterUrl:find("%.mp4") or masterUrl:find("%.m3u8")) then videoUrl = cleanRawString(masterUrl) containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") else sniffVideoViaWebView(targetUrl) end end end end end } webView.setDownloadListener{ onDownloadStart = function(url) end } -- Case 2: Direct .xiaohongshu.com link elseif targetUrl:find("%.xiaohongshu.com") then Http.get(targetUrl, function(code, content) if code ~= 200 or not content then print("Network request failed: " .. tostring(code)) return end local cleanedContent = cleanRawString(content) local h265Section = string.match(cleanedContent, '"h265":%[([^&]+)%]') if h265Section then local backupUrl = h265Section:match('"backupUrls":%["(.-)"') if backupUrl and (backupUrl:find("%.mp4") or backupUrl:find("%.m3u8")) then videoUrl = cleanRawString(backupUrl) containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") return end end local videoTagUrl = cleanedContent:match('"videoUrl":"(.-)"') if videoTagUrl then videoUrl = cleanRawString(videoTagUrl:gsub("\\/", "/")) containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") else print("URL not found in Xiaohongshu meta, attempting sniff...") sniffVideoViaWebView(targetUrl) end end) end end --- Parser for Pipixia links. --- @param targetUrl string Pipixia share URL. local function parsePipixia(targetUrl) if pcall(function() local webView = LuaWebView(activity) webView.setWebViewClient({ shouldOverrideUrlLoading = function(view, url) if not url:find("^https?://") then return true end return false end }) webView.loadUrl(targetUrl) webView.getSettings().setMediaPlaybackRequiresUserGesture(true) webView.setDownloadListener{ onDownloadStart = function(url) end } task(5000, function() local js = "document.documentElement.outerHTML" webView.evaluateJavascript(js, { onReceiveValue = function(content) local content = urlDecode(content) local cleanedContent = cleanRawString(content) cleanedContent = cleanedContent:match("p2p_type(.+)") if cleanedContent then cleanedContent = cleanedContent:match([[video_model(.-)expires]]) if cleanedContent then videoUrl = cleanedContent:match([["url_list":%[{"url":"(.-)",]]) if videoUrl and (videoUrl:find("mime_type=video_mp4") or videoUrl:find("%.ppxvod.com")) then videoUrl = cleanRawString(videoUrl) containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") else sniffVideoViaWebView(targetUrl) end end end end }) end) end) then end end --- Parser for Zuiyou links. local function parseZuiyou(targetUrl) local headers = {["User-Agent"] = USER_AGENT} Http.get(targetUrl, nil, "UTF-8", headers, function(code, content) if code ~= 200 or not content then print("Network request failed: " .. tostring(code)) return end local cleanedContent = cleanRawString(content) local videoSection = cleanedContent:match('') if videoSection then local srcUrl = videoSection:match('src="(.-)"') if srcUrl then videoUrl = cleanRawString(srcUrl) containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") else sniffVideoViaWebView(targetUrl) end else sniffVideoViaWebView(targetUrl) end end) end --- Parser for Doubao (Image/Video) links. local function parseDoubao(targetUrl) local webView = LuaWebView(activity) webView.setWebViewClient({ shouldOverrideUrlLoading = function(view, url) if not url:find("^https?://") then return true end return false end }) webView.loadUrl(targetUrl) webView.getSettings().setMediaPlaybackRequiresUserGesture(true) webView.setDownloadListener{ onDownloadStart = function(url) end } -- Handle Doubao Images (Threads) if targetUrl:find("%.doubao.com/thread/") then task(5000, function() local js = "document.documentElement.outerHTML" webView.evaluateJavascript(js, { onReceiveValue = function(content) if content and content ~= "" then local cleanedContent = cleanRawString(content) local rawMatch = cleanedContent:match([[image_ori_raw"?:%s*{(.-)}]]) if rawMatch then imageUrl = rawMatch:match([["url"%s*:%s*"([^"]+)"]]) end if not imageUrl then imageUrl = cleanedContent:match([["url"%s*:%s*"([^"]*%.byteimg%.[^"]+)"]]) end if not imageUrl then imageUrl = cleanedContent:match([["url"%s*:%s*"([^"]+%.(jpg|png|jpeg|webp)[^"]*)"]]) end if imageUrl and imageUrl:find("%.byteimg.com") then imageUrl = cleanRawString(imageUrl) local bitmap = loadbitmap(imageUrl) if bitmap and imageViewDisplay then imageViewDisplay.setImageBitmap(bitmap) containerImageViewer.setVisibility(View.VISIBLE) print("Loading image...") else print("Failed to load image bitmap.") end else print("No image URL found.") end end end }) end) -- Handle Doubao Videos elseif targetUrl:find("%.doubao.com/video%-sharing") then webView.getSettings().setUserAgentString(USER_AGENT) webView.setWebViewClient{ onLoadResource = function(view, url) if (url:find("%.m3u8") or url:find("%.mp4") or url:find("%.videoweb.doubao.com") or url:find("mime_type=video_mp4")) and (webView.getUrl() ~= "about:blank") then videoUrl = cleanRawString(url) webView.loadUrl("about:blank") webView.stopLoading() containerVideoPlayer.setVisibility(View.VISIBLE) videoViewPlayer.setVideoURI(Uri.parse(videoUrl)) videoViewPlayer.start() print("Playing video...") end end } webView.loadUrl(targetUrl) end end -- ########################## 6. Core Business Logic ########################## --- Main router for parsing based on URL patterns. --- @param inputUrl string The URL entered by the user. local function routeParser(inputUrl) local targetUrl = extractUrlFromString(inputUrl) if not targetUrl then print("Invalid URL.") return end print("Parsing, please wait...") hideSoftKeyboard() containerVideoPlayer.setVisibility(View.GONE) containerImageViewer.setVisibility(View.GONE) videoUrl = "" imageUrl = "" -- Determine platform and call corresponding parser if targetUrl:find("%.douyin.com") or targetUrl:find("%.iesdouyin.com") then parseDouyin(targetUrl) elseif targetUrl:find("%.kuaishou.com") or targetUrl:find("%.chenzhongtech.com") then parseKuaishou(targetUrl) elseif targetUrl:find("xhslink.com") or targetUrl:find("%.xiaohongshu.com") then parseXiaohongshu(targetUrl) elseif targetUrl:find("%.pipix.com") then parsePipixia(targetUrl) elseif targetUrl:find("%.xiaochuankeji.cn") then parseZuiyou(targetUrl) elseif targetUrl:find("%.doubao.com/thread/") or targetUrl:find("%.doubao.com/video%-sharing") then parseDoubao(targetUrl) else -- Fallback for unknown platforms: use generic WebView sniffing sniffVideoViaWebView(targetUrl) end end -- ########################## 8. UI Layout Definition ########################## local gradientDrawable = GradientDrawable() gradientDrawable.setOrientation(GradientDrawable.Orientation.TL_BR) gradientDrawable.setColors({0xFF667eea, 0xFF764ba2}) local editBackground = GradientDrawable() editBackground.setShape(GradientDrawable.RECTANGLE) editBackground.setColor(0xFFF5F5F5) editBackground.setCornerRadius(16) local mainLayout = { ScrollView; layout_width = 'fill'; layout_height = 'fill'; background = gradientDrawable; { LinearLayout; orientation = 'vertical'; layout_width = 'fill'; layout_height = 'wrap'; gravity = 'center_horizontal'; padding = '24dp'; { View; layout_width = 'match_parent'; layout_height = '40dp'; BackgroundColor = '0x00000000'; }; -- Input Card { CardView; CardBackgroundColor = '0xFFFFFFFF'; layout_margin = '0dp'; elevation = '8'; layout_width = 'fill'; layout_height = 'wrap'; radius = '24dp'; { LinearLayout; orientation = 'vertical'; layout_width = 'fill'; layout_height = 'wrap'; padding = '20dp'; { TextView; textSize = "14sp"; TextColor = "#FF666666"; layout_marginBottom = "8dp"; layout_width = "fill"; text = "Share Link"; }; { EditText; TextColor = "#FF333333"; hint = "Paste Douyin/Kuaishou share link..."; hintTextColor = "#FFCCCCCC"; layout_marginBottom = "20dp"; layout_width = "fill"; layout_height = "wrap"; id = "editTextShareLink"; background = editBackground; padding = '14dp'; textSize = '14'; onClick = function() editTextShareLink.setText("") end; }; }; }; -- Button Row { LinearLayout; orientation = 'horizontal'; layout_width = 'fill'; layout_height = 'wrap'; gravity = 'center'; layout_marginBottom = '24dp'; -- Parse Button { CardView; layout_margin = '6dp'; layout_gravity = 'center'; elevation = '4'; layout_width = '0dp'; layout_weight = '1'; CardBackgroundColor = '#FFFFFFFF'; layout_height = 'wrap'; radius = '40dp'; { TextView; layout_width = 'fill'; layout_height = '48dp'; gravity = 'center'; textColor = '#FF667eea'; text = "Parse"; textSize = '15'; id = "buttonParse"; onClick = function() routeParser(editTextShareLink.text) end; }; }; -- Copy Button { CardView; layout_margin = '6dp'; layout_gravity = 'center'; elevation = '4'; layout_width = '0dp'; layout_weight = '1'; CardBackgroundColor = '#FFFFFFFF'; layout_height = 'wrap'; radius = '40dp'; { TextView; layout_width = 'fill'; layout_height = '48dp'; gravity = 'center'; textColor = '#FF667eea'; text = "Copy"; textSize = '15'; id = "buttonCopy"; onClick = function() local urlToCopy = (videoUrl:find("https?://") and videoUrl) or (imageUrl:find("https?://") and imageUrl) if urlToCopy then local clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) local clip = ClipData.newPlainText("parsed_url", urlToCopy) clipboard.setPrimaryClip(clip) print("Copied to clipboard") else print("No resource to copy") end end; }; }; -- Download Button { CardView; layout_margin = '6dp'; layout_gravity = 'center'; elevation = '4'; layout_width = '0dp'; layout_weight = '1'; CardBackgroundColor = '#FFFFFFFF'; layout_height = 'wrap'; radius = '40dp'; { TextView; layout_width = 'fill'; layout_height = '48dp'; gravity = 'center'; textColor = '#FF667eea'; text = "Download"; textSize = '15'; id = "buttonDownload"; onClick = function() if videoUrl:find("https?://") then promptAndDownloadVideo("Video_" .. generateRandomString(10) .. ".mp4", videoUrl) elseif imageUrl:find("https?://") then promptAndDownloadImage("Image_" .. generateRandomString(10) .. ".png", imageUrl) else print("No resource to download") end end; }; }; }; -- Image Viewer Container { LinearLayout; orientation = 'vertical'; layout_width = 'wrap'; layout_height = 'wrap'; BackgroundColor = "0x00000000"; gravity = 'center'; layout_gravity = "center"; padding = '0dp'; id = "containerImageViewer"; Visibility = "gone"; { LinearLayout; orientation = 'horizontal'; layout_width = "wrap"; layout_height = "60%h"; BackgroundColor = "0x00000000"; gravity = 'center'; layout_gravity = "center"; layout_margin = '0dp'; { CardView; layout_width = "fill"; layout_height = "200dp"; layout_margin = "0dp"; cardElevation = "0dp"; cardBackgroundColor = "0x00000000"; radius = "0dp"; { ImageView; layout_width = "match_parent"; layout_height = "match_parent"; scaleType = "fitCenter"; src = ""; id = "imageViewDisplay"; }; }; }; }; -- Video Player Container { LinearLayout; orientation = 'vertical'; layout_width = 'wrap'; layout_height = 'wrap'; BackgroundColor = "0x00000000"; gravity = 'center'; layout_gravity = "center"; padding = '0dp'; id = "containerVideoPlayer"; Visibility = "gone"; { LinearLayout; orientation = 'horizontal'; layout_width = "wrap"; layout_height = "60%h"; BackgroundColor = "0x00000000"; gravity = 'center'; layout_gravity = "center"; layout_margin = '0dp'; onClick = function() if videoViewPlayer.isPlaying() then videoViewPlayer.pause() print("Video paused") else videoViewPlayer.start() print("Video playing") end end; { VideoView; layout_gravity = "center"; layout_width = "wrap"; layout_height = "wrap"; BackgroundColor = "0x00000000"; id = "videoViewPlayer"; }; }; }; -- Footer Hint { TextView; text = "Supports Douyin, Kuaishou and more."; textSize = '12'; textColor = '0xCCFFFFFF'; gravity = 'center'; layout_marginTop = '6dp'; }; }; }; -- Set the main content view activity.setContentView(loadlayout(mainLayout)) 【远程代码】