This commit is contained in:
yumoqing 2024-12-26 10:33:39 +08:00
parent 8462fdfe8d
commit 536adc7887
8 changed files with 300 additions and 71 deletions

View File

@ -26,7 +26,7 @@ bricks.AudioPlayer = class extends bricks.JsWidget {
this.audio = this._create('audio');
this.audio.controls = true;
if (this.opts.autoplay){
this.audio.addEventListener('canplay', this.play_audio.bind(this));
this.audio.addEventListener('canplay', this.play.bind(this));
}
this.audio.style.width = "100%"
this.dom_element.appendChild(this.audio);
@ -34,6 +34,58 @@ bricks.AudioPlayer = class extends bricks.JsWidget {
this.set_source(this.url);
}
}
set_stream_urls(response){
async function* dyn_urls(response) {
const reader = response.body.getReader();
var value;
var done;
while (true){
done, value = await reader.read();
if (value.done){
console.log('done=', done, 'value=', value);
break;
}
let result = '';
for (let i = 0; i < value.value.length; i++) {
result += String.fromCharCode(value.value[i]);
}
console.log('audio set url=', result);
yield result;
}
}
this.url_generator = dyn_urls(response);
this.srcList = [];
schedule_once(this.load_queue_url.bind(this), 0.1);
}
async load_queue_url(){
while (true){
var d = await this.url_generator.next();
if (d.done){
return;
}
this.srcList.push({played:false, url:d.value});
if (this.srcList.length < 2 ){
await this.play_srclist();
this.audio.addEventListener('ended',
this.play_srclist.bind(this));
}
}
}
async play_srclist(evnet){
if (event && ! this.audio.ended){
return;
}
for (var i=0;i<this.srcList.length;i++){
if (!this.srcList[i].played){
console.log('playit', i, this.srcList[i]);
this.set_url(this.srcList[i].url);
this.srcList[i].played = true;
await this.play();
return;
}
}
}
set_source(url){
if (! this.source){
this.source = this._create('source');
@ -49,14 +101,14 @@ bricks.AudioPlayer = class extends bricks.JsWidget {
// 播放音频
this.audio.play();
}
play(){
this.audio.play();
async play(){
await this.audio.play();
}
toggle_play(){
async toggle_play(){
if (this.audio.paused){
this.audio.play();
await this.audio.play();
} else {
this.audio.pause();
await this.audio.pause();
}
}
set_url(url){
@ -81,6 +133,7 @@ bricks.AudioRecorder = class extends bricks.HBox {
*/
constructor(opts){
super(opts);
this.set_css('clickable');
this.start_icon = opts.start_icon || bricks_resource('imgs/start_recording.png');
this.stop_icon = opts.stop_icon || bricks_resource('imgs/stop_recording.png');
this.rec_btn = new bricks.Icon({
@ -97,7 +150,7 @@ bricks.AudioRecorder = class extends bricks.HBox {
width:'120px'
});
this.upload_url = opts.upload_url;
this.rec_btn.bind('click', this.rec_btn_pressed.bind(this))
this.bind('click', this.rec_btn_pressed.bind(this))
this.URL = window.URL||webkitURL;
this.rec = null;
this.wave = null;

View File

@ -32,3 +32,25 @@ bricks.UpStreaming = class extends bricks.JsWidget {
this.stream_ctlr = controller;
}
}
bricks.down_streaming = async function*(response) {
if (! response){
return;
}
const reader = response.body.getReader();
var value;
var t = 0;
while (true){
done, value = await reader.read();
if (value.done){
break;
}
let result = '';
for (let i = 0; i < value.value.length; i++) {
result += String.fromCharCode(value.value[i]);
}
console.log('audio set url=', result);
yield result;
}
}

View File

@ -38,4 +38,5 @@ cp -a ../examples/* ../dist/examples
cp -a ../3parties/* ../dist/3parties
cp -a ../docs/* ../dist/docs
cp *.tmpl ../dist
cp -a ../dist /tmp
echo "Finished ..."

View File

@ -41,7 +41,7 @@ hr {
background-color: #eeeeee;
}
.clickable {
color: #80ff88;
color: #40cc40;
cursor: pointer;
}

View File

@ -4,11 +4,11 @@
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/bricks/3parties/xterm.css" />
<link rel="stylesheet" href="{{entire_url('/bricks/3parties/xterm.css')}}" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/js-docx-viewer/dist/css/docxviewer.min.css">
<link href="/bricks/3parties/video-js.css" rel="stylesheet" />
<link rel="stylesheet" href="/bricks/css/bricks.css">
<link rel="stylesheet", href="/css/myapp.css">
<link href="{{entire_url('/bricks/3parties/video-js.css')}}" rel="stylesheet" />
<link rel="stylesheet" href="{{entire_url('/bricks/css/bricks.css')}}">
<link rel="stylesheet", href="{{entire_url('/css/myapp.css')}}">
</head>
<body>
<!--
@ -23,17 +23,17 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.4.2/mammoth.browser.min.js"></script>
<script type="text/javascript" src="https://registry.npmmirror.com/echarts/5.5.1/files/dist/echarts.min.js"></script>
<script src="/bricks/3parties/marked.min.js"></script>
<script src="/bricks/3parties/xterm.js"></script>
<script src="/bricks/3parties/video.min.js"></script>
<script src="{{entire_url('/bricks/3parties/marked.min.js')}}"></script>
<script src="{{entire_url('/bricks/3parties/xterm.js')}}"></script>
<script src="{{entire_url('/bricks/3parties/video.min.js')}}"></script>
<!---
<link href="https://unpkg.com/video.js@6/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@6/dist/video.js"></script></head>
--->
<script src="/bricks/3parties/recorder.wav.min.js"></script>
<script src="/bricks/bricks.js"></script>
<script src="/js/myapp.js"></script>
<script src="{{entire_url('/bricks/3parties/recorder.wav.min.js')}}"></script>
<script src="{{entire_url('/bricks/bricks.js')}}"></script>
<script src="{{entire_url('/js/myapp.js')}}"></script>
<script>
const opts = {
"widget":

View File

@ -49,6 +49,47 @@ bricks.UiType =class extends bricks.Layout {
}
}
bricks.UiAudioRecorder = class extends bricks.AudioRecorder {
constructor(opts){
super(opts);
this.uitype = 'audiorecorder';
this.name = this.opts.name;
this.required = opts.required || false;
this.value = opts.value || opts.defaultvalue||'';
this.bind('record_ended', this.getValue.bind(this));
}
getValue(){
var o = {}
this.value = this.recordData.data;
o[this.name] = this.value;
return o;
}
set_formdata(formdata){
formdata.append(this.name, this.value, 'record.wav');
}
resultValue(){
return this.value;
}
focus(){
this.dom_element.focus();
}
reset(){
}
setValue(v){
return;
}
set_disabled(f){
this.dom_element.disabled = f;
}
set_readonly(f){
this.dom_element.readOnly = f;
}
set_required(f){
this.dom_element.required = f;
this.required = f;
}
}
bricks.UiAudioText = class extends bricks.UiType {
/*
{
@ -337,7 +378,7 @@ bricks.UiFile =class extends bricks.UiStr {
return this.dom_element.files;
}
resultValue(){
return this.get_files();
return this.get_files()[0];
}
setValue(v){
return;
@ -910,6 +951,7 @@ bricks.UiVideo =class extends bricks.UiStr {
}
}
var Input = new bricks._Input();
Input.register('UiAudioRecorder', 'audiorecorder', bricks.UiAudioRecorder);
Input.register('UiStr', 'str', bricks.UiStr);
Input.register('UiHide', 'hide', bricks.UiHide);
Input.register('UiTel', 'tel', bricks.UiTel);

View File

@ -102,7 +102,7 @@ bricks.HttpText = class {
}
return Object.assign(this.headers, headers);
}
async httpcall(url, {method='GET', headers=null, params=null}={}){
async bricks_fetch(url, {method='GET', headers=null, params=null}={}){
url = this.url_parse(url);
var data = this.add_own_params(params);
var header = this.add_own_headers(headers);
@ -120,8 +120,13 @@ bricks.HttpText = class {
_params.body = JSON.stringify(data);
}
}
const fetchResult = await fetch(url, _params);
// console.log('fetchResult.status=', fetchResult.status, url, 'login url=', bricks.app.login_url);
return await fetch(url, _params);
}
async httpcall(url, opts){
const fetchResult = await this.bricks_fetch(url, {
method: opts.method,
headers: opts.headers,
params: opts.params});
if (fetchResult.status == 401 && bricks.app.login_url){
console.log('go to login')
return await this.withLoginInfo(url, _params);

View File

@ -16,12 +16,12 @@ var inputdata2dic = function(data){
}
}
bricks.delete_null_values = function(obj) {
for (let key in obj) {
if (obj[key] === null) {
delete obj[key];
}
}
return obj;
for (let key in obj) {
if (obj[key] === null) {
delete obj[key];
}
}
return obj;
}
bricks.is_empty = function(obj){
@ -59,7 +59,7 @@ bricks.debug = function(...args){
}
bricks.is_mobile = function(){
var userAgent = navigator.userAgent;
var userAgent = navigator.userAgent;
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)) {
return true;
}
@ -105,9 +105,9 @@ var currentScriptPath = function () {
}
currentScript = scripts[ scripts.length - 1 ].src;
}
var currentScriptChunks = currentScript.split( '/' );
var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ];
return currentScript.replace( currentScriptFile, '' );
var currentScriptChunks = currentScript.split( '/' );
var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ];
return currentScript.replace( currentScriptFile, '' );
}
bricks.path = currentScriptPath();
@ -122,17 +122,17 @@ var bricks_resource = function(name){
* @see https://stackoverflow.com/a/71692555/2228771
*/
function querySelectorAllShadows(selector, el = document.body) {
// recurse on childShadows
const childShadows = Array.from(el.querySelectorAll('*')).
map(el => el.shadowRoot).filter(Boolean);
// recurse on childShadows
const childShadows = Array.from(el.querySelectorAll('*')).
map(el => el.shadowRoot).filter(Boolean);
bricks.debug('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`);
bricks.debug('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`);
const childResults = childShadows.map(child => querySelectorAllShadows(selector, child));
// fuse all results into singular, flat array
const result = Array.from(el.querySelectorAll(selector));
return result.concat(childResults).flat();
const childResults = childShadows.map(child => querySelectorAllShadows(selector, child));
// fuse all results into singular, flat array
const result = Array.from(el.querySelectorAll(selector));
return result.concat(childResults).flat();
}
var schedule_once = function(f, t){
@ -210,7 +210,7 @@ bricks.obj_fmtstr = function(obj, fmt){
'${name:}, ${age=}'
*/
var s = fmt;
s = s.replace(/\${(\w+)([:=]*)}/g, (k, key, op) => {
s = s.replace(/\${(\w+)([:=]*)}/g, (k, key, op) => {
if (obj.hasOwnProperty(key)){
if (op == ''){
return obj[key];
@ -285,7 +285,7 @@ var archorize = function(ele,archor){
}
Array.prototype.insert = function ( index, ...items ) {
this.splice( index, 0, ...items );
this.splice( index, 0, ...items );
};
Array.prototype.remove = function(item){
@ -325,26 +325,26 @@ var convert2int = function(s){
}
function setCookie(name,value,days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days*24*60*60*1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days*24*60*60*1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name) {
document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
function eraseCookie(name) {
document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
var set_max_height = function(w1, w2){
@ -358,13 +358,53 @@ var set_max_height = function(w1, w2){
}
}
var objcopy = function(obj){
var o = {}
for ( k in obj){
if (obj.hasOwnProperty(k)){
o[k] = obj[k];
}
}
return o;
var o = {}
for ( k in obj){
if (obj.hasOwnProperty(k)){
o[k] = obj[k];
}
}
return o;
}
bricks.set_stream_source = async function(target, url, params){
var widget;
if (typeof target == typeof ''){
widget = bricks.getWidgetById(target);
} else if (target instanceof bricks.JsWidget){
widget = target;
} else {
widget = await bricks.widgetBuild(target);
}
if (! widget){
bricks.debug('playResponseAudio():', target, 'can not found or build a widget');
return;
}
const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen);
widget.set_url(URL.createObjectURL(mediaSource));
function handleSourceOpen(){
const sourceBuffer = mediaSource.addSourceBuffer('audio/wav; codecs=1');
var ht = new bricks.HttpText();
ht.bricks_fetch(url, {params:params})
.then(response => response.body)
.then(body => {
const reader = body.getReader();
const read = () => {
reader.read().then(({ done, value }) => {
if (done) {
mediaSource.endOfStream();
return;
}
sourceBuffer.appendBuffer(value);
read();
}).catch(error => {
console.error('Error reading audio stream:', error);
});
};
read();
});
}
}
bricks.playResponseAudio = async function(response, target){
@ -382,8 +422,8 @@ bricks.playResponseAudio = async function(response, target){
bricks.debug('playResponseAudio():', target, 'can not found or build a widget');
return;
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
widget.set_url(url);
widget.play();
}
@ -410,12 +450,78 @@ bricks.Observable = class {
this.value = v;
}
set(v){
if (this.value != v){
var ov = this.value;
this.value = v;
if (this.value != ov){
this.owner.dispatch(this.name, v);
}
this.value = v;
}
get(){
return this.v;
}
}
bricks.Queue = class {
constructor() {
this.items = [];
this._done = false;
}
// 添加元素到队列尾部
enqueue(element) {
this.items.push(element);
}
done(){
this._done = true;
}
is_done(){
return this._done;
}
// 移除队列的第一个元素并返回
dequeue() {
if (this.isEmpty()) {
return null;
}
return this.items.shift();
}
// 查看队列的第一个元素
peek() {
if (this.isEmpty()) {
return null;
}
return this.items[0];
}
// 检查队列是否为空
isEmpty() {
return this.items.length === 0;
}
// 获取队列的大小
size() {
return this.items.length;
}
// 清空队列
clear() {
this.items = [];
}
// 打印队列元素
print() {
console.log(this.items.toString());
}
}
/*
// 使用队列
const queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.print(); // 输出: 1,2,3
console.log(queue.dequeue()); // 输出: 1
queue.print(); // 输出: 2,3
*/