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_MAJOR 6)
set(VERSION_MINOR 14) set(VERSION_MINOR 14)
set(VERSION_PATCH 10) set(VERSION_PATCH 11)
set(VERSION_REVISION 0) set(VERSION_REVISION 0)
set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}") set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}")
add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp) 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 cishu.cishubase import DictTree
from myutils.config import isascii from myutils.config import isascii
from traceback import print_exc from traceback import print_exc
from myutils.audioplayer import bass_decode
class FlexBuffer: class FlexBuffer:
@ -2235,21 +2236,6 @@ class mdict(cishubase):
# print(html) # print(html)
return 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): def parse_url_in_mdd(self, index: IndexBuilder, url1: str):
url1 = url1.replace("/", "\\") url1 = url1.replace("/", "\\")
if not url1.startswith("\\"): if not url1.startswith("\\"):
@ -2282,12 +2268,17 @@ class mdict(cishubase):
return return
ext = os.path.splitext(url)[1].lower() ext = os.path.splitext(url)[1].lower()
if ext in (".aac", ".spx"): if ext in (".aac", ".spx"):
varname = "var_" + hashlib.md5(file_content).hexdigest() mp3 = bass_decode(file_content, ext)
audiob64vals[varname] = base64.b64encode(file_content).decode() if not mp3:
return 3, "javascript:safe_mdict_sound_call('{}',{})".format( print(ext, "decode error")
ext, varname return
) file_content = mp3
return 2, file_content ext = ".mp3"
varname = "var_" + hashlib.md5(file_content).hexdigest()
audiob64vals[varname] = base64.b64encode(file_content).decode()
return 3, "javascript:mdict_play_sound('{}',{})".format(
ext[1:], varname
)
file_content = self.parse_url_in_mdd(index, url) file_content = self.parse_url_in_mdd(index, url)
if not file_content: if not file_content:
return return
@ -2433,8 +2424,6 @@ class mdict(cishubase):
if css: if css:
csscollect[url] = css csscollect[url] = css
html_content = html_content.replace(url, "") html_content = html_content.replace(url, "")
elif _type == 2:
html_content = self.parseaudio(html_content, url, file_content)
elif _type == 0: elif _type == 0:
varname = "var_" + hashlib.md5(file_content).hexdigest() varname = "var_" + hashlib.md5(file_content).hexdigest()
hrefsrcvals[varname] = base64.b64encode(file_content).decode() hrefsrcvals[varname] = base64.b64encode(file_content).decode()
@ -2470,7 +2459,7 @@ class mdict(cishubase):
print_exc() print_exc()
if not results: if not results:
return return
divid = "luna_internal_" + str(uuid.uuid4()) divid = "luna_" + str(uuid.uuid4())
csscollect = {} csscollect = {}
for i in range(len(results)): for i in range(len(results)):
results[i] = self.repairtarget( results[i] = self.repairtarget(
@ -2648,11 +2637,16 @@ let elements = document.querySelectorAll('[src="'+varname+'"]');
for(let i=0;i<elements.length;i++) for(let i=0;i<elements.length;i++)
elements[i].src="data:application/octet-stream;base64," + varval elements[i].src="data:application/octet-stream;base64," + varval
} }
function safe_mdict_sound_call(ext, b64){ var lastmusicplayer=false;
if(window.mdict_sound_call) function mdict_play_sound(ext, b64){
window.mdict_sound_call(ext, b64) const music = new Audio();
else if(window.LUNAJSObject) music.src="data:audio/"+ext+";base64,"+b64
window.LUNAJSObject.mdict_sound_call(ext, b64) if(lastmusicplayer!=false)
{
lastmusicplayer.pause()
}
lastmusicplayer=music
music.play();
} }
function safe_mdict_entry_call(word){ function safe_mdict_entry_call(word){
if(window.mdict_entry_call) if(window.mdict_entry_call)

View File

@ -1168,7 +1168,6 @@ class searchwordW(closeashidewindow):
self.textOutput.bind( self.textOutput.bind(
"mdict_entry_call", lambda word: self.search_word.emit(word, False) "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.cache_results = {}
self.hiding = True self.hiding = True
@ -1187,12 +1186,6 @@ class searchwordW(closeashidewindow):
self.spliter.addWidget(w) 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): def onceaddankiwindow(self, idx):
if idx == 1: if idx == 1:
if self.isfirstshowanki: if self.isfirstshowanki:

View File

@ -2,8 +2,8 @@ import time
from traceback import print_exc from traceback import print_exc
from myutils.config import globalconfig from myutils.config import globalconfig
import threading import threading
import gobject import gobject, winsharedutils
from ctypes.wintypes import BOOL, DWORD, HWND from ctypes.wintypes import BOOL, DWORD, HWND, WORD
from ctypes import ( from ctypes import (
WinDLL, WinDLL,
WINFUNCTYPE, WINFUNCTYPE,
@ -13,6 +13,12 @@ from ctypes import (
c_int64, c_int64,
c_void_p, c_void_p,
c_char_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 HPLUGIN = c_ulong # Plugin handle
QWORD = c_int64 QWORD = c_int64
HSTREAM = c_ulong # sample stream handle HSTREAM = c_ulong # sample stream handle
BASS_SAMPLE_FLOAT = 0x100
BASS_STREAM_DECODE = 0x200000
BASS_UNICODE = 0x80000000 # -2147483648 BASS_UNICODE = 0x80000000 # -2147483648
BASS_ATTRIB_VOL = 2 BASS_ATTRIB_VOL = 2
BASS_ATTRIB_FREQ = 1
BASS_SAMPLE_8BITS = 1
BASS_POS_BYTE = 0 # byte position BASS_POS_BYTE = 0 # byte position
bass_module = WinDLL(gobject.GetDllpath("bass.dll")) 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: class playonce:
def __init__(self, fileormem, volume) -> None: def __init__(self, fileormem, volume) -> None:
self.handle = None self.handle = None
@ -100,6 +143,51 @@ BASS_Init(-1, 44100, 0, 0, 0)
# https://www.un4seen.com/ # https://www.un4seen.com/
plugins = {".spx": "bass_spx.dll"} 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: class series_audioplayer:
def __init__(self, playovercallback=None): def __init__(self, playovercallback=None):
@ -111,7 +199,6 @@ class series_audioplayer:
self.lock.acquire() self.lock.acquire()
self.timestamp = None self.timestamp = None
self.lastcontext = None self.lastcontext = None
self.plugins = {}
threading.Thread(target=self.__dotasks).start() threading.Thread(target=self.__dotasks).start()
def stop(self): def stop(self):
@ -126,10 +213,7 @@ class series_audioplayer:
if timestamp and (timestamp != self.timestamp): if timestamp and (timestamp != self.timestamp):
return return
self.timestamp = timestamp self.timestamp = timestamp
if ext and plugins.get(ext) and not self.plugins.get(ext): load_ext(ext)
self.plugins[ext] = BASS_PluginLoad(
gobject.GetDllpath(plugins.get(ext)).encode("utf8"), 0
)
try: try:
self.tasks = (binary, volume, force) self.tasks = (binary, volume, force)
self.lock.release() self.lock.release()