Easy Android Installer 简易安装器
介绍
最近总有需求表示需要通过电脑给一些支持网络调试的设备安装软件
虽然每次我都建议直接使用platform-tools里面的ADB工具,但显然并不是所有人都有类似的能力来操作命令行。
所以快速的使用批处理脚本写了个小型安装器,只需要简单的输入和拖拽即可安装APK。
当前版本基于Platform-Tools r34
截图
版权
Platform-Tools来自Google,Inc
下载
下载解压后打开eai.bat即可使用
下载
Nothing Here...
最近总有需求表示需要通过电脑给一些支持网络调试的设备安装软件
虽然每次我都建议直接使用platform-tools里面的ADB工具,但显然并不是所有人都有类似的能力来操作命令行。
所以快速的使用批处理脚本写了个小型安装器,只需要简单的输入和拖拽即可安装APK。
当前版本基于Platform-Tools r34
Platform-Tools来自Google,Inc
下载解压后打开eai.bat即可使用
下载
最近有迁移个人存储内容到DSM的需求,本来服务器上使用的是CloudReve。
其文件夹结构和文件名都与上传时候的版本有诸多差异。
写了这个小工具来帮助解决,敬请使用。
#!/bin/bash
CLEAN_EMPTY=0
CLEAN_THUMB=0
CLEAN_FILENAME=0
while [ "$#" -gt 0 ]; do
case $1 in
--clsempty) CLEAN_EMPTY=1 ;;
--clsthumb) CLEAN_THUMB=1 ;;
--clsfilename) CLEAN_FILENAME=1 ;;
*) break ;;
esac
shift
done
if [ "$#" -ne 1 ]; then
echo "Cloudreve Cleaner 1.0"
echo "Usage: ./clscrve.sh [--clsempty] [--clsthumb] [--clsfilename] <directory>"
exit 1
fi
DIR=$1
if [ ! -d "$DIR" ]; then
echo "Directory not found: $DIR"
exit 1
fi
if [ "$CLEAN_FILENAME" -eq 1 ]; then
echo "Cleaning filenames..."
find "$DIR" -type f | while read -r file; do
dir=$(dirname "$file")
base=$(basename "$file")
originname=$(echo "$base" | awk -F'_' '{ $1=$2=""; sub(/^ /,""); print }')
if [ "$base" == "$originname" ]; then
continue
fi
mv -n "$file" "$dir/$originname"
echo "${base} -> ${originname}"
done
fi
if [ "$CLEAN_EMPTY" -eq 1 ]; then
echo "Cleaning empty directories..."
find "$DIR" -type d -empty -delete
fi
if [ "$CLEAN_THUMB" -eq 1 ]; then
echo "Cleaning thumbnail files..."
find "$DIR" -type f -name '*. thumb' -delete
fi
echo "SUCCESS IN $(date '+%Y-%m-%d %H:%M:%S')"
朋友的网站DemoDB近来被刷评分的问题所困扰,导致其排行榜内容失真。在一天的无聊讨论之中,我突然想到可以基于网站本身的特色来制作一个特别的验证码——音高验证码,即符合了网站本身的主题,又达到了防护的效果,无障碍的标准也得到了满足。
利用了硬编码的频率值,使得可以使用JavaScript的AudioContext来基于随机Challenge产生音频并且保存Challenge的值,而后基于Challenge值使用HTML Canvas图形来绘制五线谱和音符,再基于前面保存的Challenge与前台用户输入的Challenge作比较来判断用户状态。
可在线体验
Tone CAPTCHA Demo
DemoDB的示范曲评分功能
1.5
Jan.05-2024
添加ADSR包络支持以优化听感
1.4
Jan.04-2024
合入来自dgy18787的音符显示错误修复补丁
修改调试日志展示
添加标准音播放功能
1.3
Dec.17-2023
优化Demo界面UI
1.2
Dec.10-2023
添加加线功能
添加简谱输入转换器功能
修复音符漂移问题
1.1
Dec.09-2023
首次发布
最近在一个Discord群里跟一群大佬们折腾老的日系传统平台手机,有群友发现SH-03E这个MOAP(Symbian)设备使用的是eMMC,并且成功进行了Dump,历经一些研究,我和另一位群友一起研究了ROFS相关内容,成功解压了它的Z分区,Z分区中很多图符资源都是使用MBM(MultiBitmap/多重位图)格式打包并压缩的,需要使用塞班SDK里面的bmconv小工具来解压,但是其使用逻辑很奇怪,所以这次尝试写了一个图形界面。又由于群内很多人使用的是Linux,所以这个小软件支持Windows/Linux双平台使用。
请使用ARCHIVE.ORG取得塞班SDK,安装之后在<安装目录>\epoc32\bin下找到bmconv的Windows和Linux可执行文件
Windows下
Linux下
import tkinter as tk
from tkinter import filedialog, messagebox, Toplevel, Text, Scrollbar
from tkinter.ttk import Progressbar
from subprocess import Popen, PIPE
from PIL import Image, ImageTk
import os
import re
class mbmExtractor:
def __init__(self, root):
self.root = root
self.uiInit()
self.mbmFile = ""
self.currentImageIndex = 0
self.bmpFiles = []
self.tempDir = "temp"
if not os.path.exists(self.tempDir):
os.makedirs(self.tempDir)
def uiInit(self):
self.root.title("MultiBitMap Extractor")
self.root.geometry('800x600')
self.previewAreaPanel = tk.Label(self.root, text="Preview Area", relief=tk.SUNKEN)
self.previewAreaPanel.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
navigationFrame = tk.Frame(self.root)
navigationFrame.pack(side=tk.TOP, fill=tk.X)
self.counterLabel = tk.Label(navigationFrame, text="No Bitmaps")
self.counterLabel.pack(side=tk.LEFT, padx=5)
self.prevButton = tk.Button(navigationFrame, text="Prev", command=self.prevImage)
self.prevButton.pack(side=tk.LEFT, padx=5)
self.nextButton = tk.Button(navigationFrame, text="Next", command=self.nextImage)
self.nextButton.pack(side=tk.LEFT, padx=5)
actionFrame = tk.Frame(self.root)
actionFrame.pack(side=tk.BOTTOM, fill=tk.X)
self.openButton = tk.Button(actionFrame, text="Open", command=self.askOpenFile)
self.openButton.pack(side=tk.LEFT, padx=5)
self.extractButton = tk.Button(actionFrame, text="Extract", state='disabled', command=self.extractMbm)
self.extractButton.pack(side=tk.LEFT, padx=5)
self.debugButton = tk.Button(actionFrame, text="Debug", command=self.debugInfoForm)
self.debugButton.pack(side=tk.LEFT, padx=5)
self.progressBar = Progressbar(actionFrame, orient=tk.HORIZONTAL, length=100, mode='determinate')
self.progressBar.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
def askOpenFile(self):
self.mbmFile = filedialog.askopenfilename(
title="Choose MBM file",
filetypes=(("MultiBitMap File", "*.mbm"), ("All Files", "*.*"))
)
if self.mbmFile:
self.extractButton['state'] = 'normal'
mbmFilename = os.path.basename(self.mbmFile)
self.root.title(f"MultiBitMap Extractor - {mbmFilename}")
def extractMbm(self):
if not self.mbmFile:
messagebox.showerror("ERROR", "No MBM file selected.")
return
bitmapCount = self.counterBitmap()
if bitmapCount > 0:
bmpArgs = " ".join(f'"{os.path.join(self.tempDir, f"{i}.bmp")}"' for i in range(1, bitmapCount + 1))
for i in range(1, bitmapCount + 1):
self.bmconvAdapter(f'/u "{self.mbmFile}" {bmpArgs}')
self.progressBar['value'] = (i / bitmapCount) * 100
self.root.update_idletasks()
self.loadBitmap()
self.displayBitmap(self.currentImageIndex)
self.progressBar['value'] = 0
else:
messagebox.showinfo("INFO", "No bitmaps found in the MBM file.")
def counterBitmap(self):
output = self.bmconvAdapter(f'/v "{self.mbmFile}"')
match = re.search(r'containing (\d+) bitmaps', output)
return int(match.group(1)) if match else 0
def loadBitmap(self):
self.bmpFiles = self.sortNumber(os.listdir(self.tempDir))
self.currentImageIndex = 0
self.updateNavigationButtonStatus()
self.updateCounterLabel()
@staticmethod
def sortNumber(data):
convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanumKey = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
return sorted(data, key=alphanumKey)
def displayBitmap(self, index):
if 0 <= index < len(self.bmpFiles):
imgPath = os.path.join(self.tempDir, self.bmpFiles[index])
try:
img = Image.open(imgPath)
imgtk = ImageTk.PhotoImage(image=img)
self.previewAreaPanel.config(image=imgtk)
self.previewAreaPanel.image = imgtk
except IOError as e:
messagebox.showerror("ERROR", f"Can't open bitmap file {imgPath}:\n{e}")
def prevImage(self):
if self.currentImageIndex > 0:
self.currentImageIndex -= 1
self.displayBitmap(self.currentImageIndex)
self.updateNavigationButtonStatus()
self.updateCounterLabel()
def nextImage(self):
if self.currentImageIndex < len(self.bmpFiles) - 1:
self.currentImageIndex += 1
self.displayBitmap(self.currentImageIndex)
self.updateNavigationButtonStatus()
self.updateCounterLabel()
def updateCounterLabel(self):
text = f"{self.currentImageIndex + 1}/{len(self.bmpFiles)}"
self.counterLabel.config(text=text)
def updateNavigationButtonStatus(self):
self.prevButton['state'] = 'normal' if self.currentImageIndex > 0 else 'disabled'
self.nextButton['state'] = 'normal' if self.currentImageIndex < len(self.bmpFiles) - 1 else 'disabled'
def debugInfoForm(self):
debugForm = Toplevel(self.root)
debugForm.title("Debug Info")
debugForm.geometry('400x300')
scrollbar = Scrollbar(debugForm)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
text = Text(debugForm, yscrollcommand=scrollbar.set)
text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=text.yview)
debugOutput = self.bmconvAdapter(f'/v "{self.mbmFile}"')
text.insert(tk.END, debugOutput)
def bmconvAdapter(self, command):
bmconvLocalPath = os.path.join(os.path.dirname(__file__), 'bmconv')
process = Popen(f'{bmconvLocalPath} {command}', stdout=PIPE, stderr=PIPE, shell=True)
output, error = process.communicate()
if error:
messagebox.showerror("ERROR",
f"Not Found BMCONV Executable File! Please Download S60 SDK and Copy bmconv to {bmconvLocalPath}")
return output.decode("utf-8")
def getBinaryVersion(self):
output = self.bmconvAdapter('')
match = re.search(r'version (\d+)', output)
return match.group(1) if match else 'Unknown'
def clearTempDir(self):
for file in os.listdir(self.tempDir):
os.remove(os.path.join(self.tempDir, file))
os.rmdir(self.tempDir)
def Starter(self):
version = self.getBinaryVersion()
self.root.title(f"MultiBitMap Extractor - BMCONV Version {version}")
self.root.mainloop()
if __name__ == "__main__":
root = tk.Tk()
exec = mbmExtractor(root)
exec.Starter()
exec.clearTempDir()
整合包是一个彩蛋
可在OBJect找到
其中的可执行文件来自于Symbian^3 SDK for Belle
感谢Symbian Foundation(虽然其已在法理上消失)