This commit is contained in:
恍兮惚兮 2024-12-22 19:56:22 +08:00
parent c03c6ac257
commit e7adc51431
4 changed files with 116 additions and 45 deletions

View File

@ -1,7 +1,7 @@
set(VERSION_MAJOR 6)
set(VERSION_MINOR 14)
set(VERSION_PATCH 10)
set(VERSION_PATCH 11)
set(VERSION_REVISION 0)
set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}")
add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp)

View File

@ -2,6 +2,7 @@ import math, base64, uuid, gobject
from cishu.cishubase import DictTree
from myutils.config import isascii
from traceback import print_exc
from myutils.audioplayer import bass_decode
class FlexBuffer:
@ -2235,21 +2236,6 @@ class mdict(cishubase):
# print(html)
return html
def parseaudio(self, html_content, url, file_content):
base64_content = base64.b64encode(file_content).decode("utf-8")
uid = str(uuid.uuid4())
# with open(uid+'.mp3','wb') as ff:
# ff.write(file_content)
audio = '<audio controls id="{}" style="display: none"><source src="data:application/octet-stream;base64,{}"></audio>'.format(
uid, base64_content
)
html_content = audio + html_content.replace(
url,
"javascript:document.getElementById('{}').play()".format(uid),
)
return html_content
def parse_url_in_mdd(self, index: IndexBuilder, url1: str):
url1 = url1.replace("/", "\\")
if not url1.startswith("\\"):
@ -2282,12 +2268,17 @@ class mdict(cishubase):
return
ext = os.path.splitext(url)[1].lower()
if ext in (".aac", ".spx"):
mp3 = bass_decode(file_content, ext)
if not mp3:
print(ext, "decode error")
return
file_content = mp3
ext = ".mp3"
varname = "var_" + hashlib.md5(file_content).hexdigest()
audiob64vals[varname] = base64.b64encode(file_content).decode()
return 3, "javascript:safe_mdict_sound_call('{}',{})".format(
ext, varname
return 3, "javascript:mdict_play_sound('{}',{})".format(
ext[1:], varname
)
return 2, file_content
file_content = self.parse_url_in_mdd(index, url)
if not file_content:
return
@ -2433,8 +2424,6 @@ class mdict(cishubase):
if css:
csscollect[url] = css
html_content = html_content.replace(url, "")
elif _type == 2:
html_content = self.parseaudio(html_content, url, file_content)
elif _type == 0:
varname = "var_" + hashlib.md5(file_content).hexdigest()
hrefsrcvals[varname] = base64.b64encode(file_content).decode()
@ -2470,7 +2459,7 @@ class mdict(cishubase):
print_exc()
if not results:
return
divid = "luna_internal_" + str(uuid.uuid4())
divid = "luna_" + str(uuid.uuid4())
csscollect = {}
for i in range(len(results)):
results[i] = self.repairtarget(
@ -2648,11 +2637,16 @@ let elements = document.querySelectorAll('[src="'+varname+'"]');
for(let i=0;i<elements.length;i++)
elements[i].src="data:application/octet-stream;base64," + varval
}
function safe_mdict_sound_call(ext, b64){
if(window.mdict_sound_call)
window.mdict_sound_call(ext, b64)
else if(window.LUNAJSObject)
window.LUNAJSObject.mdict_sound_call(ext, b64)
var lastmusicplayer=false;
function mdict_play_sound(ext, b64){
const music = new Audio();
music.src="data:audio/"+ext+";base64,"+b64
if(lastmusicplayer!=false)
{
lastmusicplayer.pause()
}
lastmusicplayer=music
music.play();
}
function safe_mdict_entry_call(word){
if(window.mdict_entry_call)

View File

@ -1168,7 +1168,6 @@ class searchwordW(closeashidewindow):
self.textOutput.bind(
"mdict_entry_call", lambda word: self.search_word.emit(word, False)
)
self.textOutput.bind("mdict_sound_call", self.mdict_sound_call)
self.cache_results = {}
self.hiding = True
@ -1187,12 +1186,6 @@ class searchwordW(closeashidewindow):
self.spliter.addWidget(w)
def mdict_sound_call(self, ext, soundb64: str):
gobject.baseobject.audioplayer.play(
base64.b64decode(soundb64.encode()), force=True, ext=ext
)
def onceaddankiwindow(self, idx):
if idx == 1:
if self.isfirstshowanki:

View File

@ -2,8 +2,8 @@ import time
from traceback import print_exc
from myutils.config import globalconfig
import threading
import gobject
from ctypes.wintypes import BOOL, DWORD, HWND
import gobject, winsharedutils
from ctypes.wintypes import BOOL, DWORD, HWND, WORD
from ctypes import (
WinDLL,
WINFUNCTYPE,
@ -13,6 +13,12 @@ from ctypes import (
c_int64,
c_void_p,
c_char_p,
Structure,
POINTER,
pointer,
c_void_p,
create_string_buffer,
sizeof,
)
@ -21,9 +27,12 @@ HSAMPLE = c_ulong # sample handle
HPLUGIN = c_ulong # Plugin handle
QWORD = c_int64
HSTREAM = c_ulong # sample stream handle
BASS_SAMPLE_FLOAT = 0x100
BASS_STREAM_DECODE = 0x200000
BASS_UNICODE = 0x80000000 # -2147483648
BASS_ATTRIB_VOL = 2
BASS_ATTRIB_FREQ = 1
BASS_SAMPLE_8BITS = 1
BASS_POS_BYTE = 0 # byte position
bass_module = WinDLL(gobject.GetDllpath("bass.dll"))
@ -51,6 +60,40 @@ BASS_PluginLoad = WINFUNCTYPE(c_ulong, c_char_p, c_ulong)(
)
class WAVEFORMATEX(Structure):
_fields_ = [
("wFormatTag", WORD),
("nChannels", WORD),
("nSamplesPerSec", DWORD),
("nAvgBytesPerSec", DWORD),
("nBlockAlign", WORD),
("wBitsPerSample", WORD),
("cbSize", WORD),
]
class BASS_CHANNELINFO(Structure):
_fields_ = [
("freq", DWORD),
("chans", DWORD),
("flags", DWORD),
("ctype", DWORD),
("origres", DWORD),
("plugin", HPLUGIN),
("sample", HSAMPLE),
("filename", c_char_p),
]
BASS_ChannelGetInfo = WINFUNCTYPE(BOOL, DWORD, POINTER(BASS_CHANNELINFO))(
("BASS_ChannelGetInfo", bass_module)
)
BASS_ChannelIsActive = WINFUNCTYPE(DWORD, DWORD)(("BASS_ChannelIsActive", bass_module))
BASS_ChannelGetData = WINFUNCTYPE(DWORD, DWORD, c_void_p, DWORD)(
("BASS_ChannelGetData", bass_module)
)
class playonce:
def __init__(self, fileormem, volume) -> None:
self.handle = None
@ -100,6 +143,51 @@ BASS_Init(-1, 44100, 0, 0, 0)
# https://www.un4seen.com/
plugins = {".spx": "bass_spx.dll"}
pluginshandle = {}
def load_ext(ext=None):
if ext and plugins.get(ext) and not pluginshandle.get(ext):
pluginshandle[ext] = BASS_PluginLoad(
gobject.GetDllpath(plugins.get(ext)).encode("utf8"), 0
)
def bass_decode(bs, ext=None):
load_ext(ext)
stream = BASS_StreamCreateFile(True, bs, 0, len(bs), BASS_STREAM_DECODE)
if not stream:
return
info = BASS_CHANNELINFO()
if not BASS_ChannelGetInfo(stream, pointer(info)):
return
wf = WAVEFORMATEX()
wf.wFormatTag = 1
wf.nChannels = info.chans
wf.wBitsPerSample = 8 if info.flags & BASS_SAMPLE_8BITS else 16
wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample // 8
wf.nSamplesPerSec = info.freq
wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign
res = []
size = 0
buff = create_string_buffer(0x10000)
while BASS_ChannelIsActive(stream):
get = BASS_ChannelGetData(stream, buff, 0x10000)
res.append(buff[:get])
size += get
header = []
header.append(b"RIFF")
header.append(bytes(c_int(size + 44)))
header.append(b"WAVE")
header.append(b"fmt ")
header.append(bytes(c_int(sizeof(WAVEFORMATEX))))
header.append(bytes(wf))
header.append(b"data")
header.append(bytes(c_int(size)))
header.extend(res)
data = b"".join(header)
return winsharedutils.encodemp3(data)
class series_audioplayer:
def __init__(self, playovercallback=None):
@ -111,7 +199,6 @@ class series_audioplayer:
self.lock.acquire()
self.timestamp = None
self.lastcontext = None
self.plugins = {}
threading.Thread(target=self.__dotasks).start()
def stop(self):
@ -126,10 +213,7 @@ class series_audioplayer:
if timestamp and (timestamp != self.timestamp):
return
self.timestamp = timestamp
if ext and plugins.get(ext) and not self.plugins.get(ext):
self.plugins[ext] = BASS_PluginLoad(
gobject.GetDllpath(plugins.get(ext)).encode("utf8"), 0
)
load_ext(ext)
try:
self.tasks = (binary, volume, force)
self.lock.release()