diff --git a/_posts/index.xml b/_posts/index.xml index 9fe5696..8bcb850 100644 --- a/_posts/index.xml +++ b/_posts/index.xml @@ -70,6 +70,7 @@ pdf:uweb:echo file:///sdcard/uweb/app/pdf.js/web/viewer.html?file=%u djvu:uweb:e "colors.txt":护眼背景色 "default.css":勾选网址特定样式后无匹配情形下的默认样式 "night.css":夜间模式,代替超微内部实现 +"videoplayer.js":用户定义视频播放 "types.sniff":嗅探类型 "sniff.log":嗅探结果 "history.rec":访问历史 @@ -410,6 +411,7 @@ checked.js: 运行配置目录下checked.js,其返回值作为命令行标准 命名笔记::(cat;echo;echo;)>>%s 复制至PC剪贴板::ssh [user:password]@192.168.2.102 "DISPLAY=:0 xsel -i" 复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 "DISPLAY=:0 xsel -i" +复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done 如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。 此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。 重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。 @@ -557,6 +559,7 @@ apt update;apt install wget 下载必要离线数据,termux下运行如下命 https://jamesfengcao.gitee.io/uweb/video/ 本文以超微浏览器为例来说明。 +点击安装"视频播放增强(倍速等)" 长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/sdcard/uweb/types.sniff”控制。 很多视频解析结果在UA为PC的情况下非常干净,没什么广告。故用户可在播放前切换UA至PC。如:wn.run/解析结果对PC非常干净。 某些视频网站在全屏播放时都会出现广告占住屏幕一部分。点击全屏播放之前,长按[☰]按钮,超微浏览器将弹出全局脚本菜单,勾选“移除浮动广告”后再点全屏播放则完美播放。 也可利用全屏播放屏蔽一切广告。方法如下: 长按[☰]按钮,勾选“全屏视频”。此选项将让无法全屏播放的网站强制允许全屏播放。 对无法全屏、无法放大的视频网站,可长按[☰]按钮,勾选“强制缩放”,然后手动放大至全屏。 灵活应用JS、图像开关屏蔽一切广告:视频搜索前关闭JS开关,进入播放网页前关闭图像显示并打开JS。 视频解析之电视剧: 首先在视频网站搜索电视剧片名,下面会显示不同的剧集,点击它们再用视频解析即可观看。如果直接点击电视剧用视频解析则每次播放均为第一集。 视频搜索预配置(超过400个引擎) 视频资源: 视频解析配置 电视直播 OK资源 全国电视直播 免费视频 国外剧 纪录片 网络直播 diff --git a/filenames/index.html b/filenames/index.html index 0d74ca2..2d2d479 100644 --- a/filenames/index.html +++ b/filenames/index.html @@ -60,6 +60,7 @@ "colors.txt":护眼背景色
"default.css":勾选网址特定样式后无匹配情形下的默认样式
"night.css":夜间模式,代替超微内部实现
+"videoplayer.js":用户定义视频播放
"types.sniff":嗅探类型
"sniff.log":嗅探结果
"history.rec":访问历史
diff --git a/index.xml b/index.xml index baab4b7..9ab48bb 100644 --- a/index.xml +++ b/index.xml @@ -70,6 +70,7 @@ pdf:uweb:echo file:///sdcard/uweb/app/pdf.js/web/viewer.html?file=%u djvu:uweb:e "colors.txt":护眼背景色 "default.css":勾选网址特定样式后无匹配情形下的默认样式 "night.css":夜间模式,代替超微内部实现 +"videoplayer.js":用户定义视频播放 "types.sniff":嗅探类型 "sniff.log":嗅探结果 "history.rec":访问历史 @@ -410,6 +411,7 @@ checked.js: 运行配置目录下checked.js,其返回值作为命令行标准 命名笔记::(cat;echo;echo;)>>%s 复制至PC剪贴板::ssh [user:password]@192.168.2.102 "DISPLAY=:0 xsel -i" 复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 "DISPLAY=:0 xsel -i" +复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done 如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。 此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。 重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。 @@ -557,6 +559,7 @@ apt update;apt install wget 下载必要离线数据,termux下运行如下命 https://jamesfengcao.gitee.io/uweb/video/ 本文以超微浏览器为例来说明。 +点击安装"视频播放增强(倍速等)" 长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/sdcard/uweb/types.sniff”控制。 很多视频解析结果在UA为PC的情况下非常干净,没什么广告。故用户可在播放前切换UA至PC。如:wn.run/解析结果对PC非常干净。 某些视频网站在全屏播放时都会出现广告占住屏幕一部分。点击全屏播放之前,长按[☰]按钮,超微浏览器将弹出全局脚本菜单,勾选“移除浮动广告”后再点全屏播放则完美播放。 也可利用全屏播放屏蔽一切广告。方法如下: 长按[☰]按钮,勾选“全屏视频”。此选项将让无法全屏播放的网站强制允许全屏播放。 对无法全屏、无法放大的视频网站,可长按[☰]按钮,勾选“强制缩放”,然后手动放大至全屏。 灵活应用JS、图像开关屏蔽一切广告:视频搜索前关闭JS开关,进入播放网页前关闭图像显示并打开JS。 视频解析之电视剧: 首先在视频网站搜索电视剧片名,下面会显示不同的剧集,点击它们再用视频解析即可观看。如果直接点击电视剧用视频解析则每次播放均为第一集。 视频搜索预配置(超过400个引擎) 视频资源: 视频解析配置 电视直播 OK资源 全国电视直播 免费视频 国外剧 纪录片 网络直播 diff --git a/pccopy/index.html b/pccopy/index.html index c90cef7..586e965 100644 --- a/pccopy/index.html +++ b/pccopy/index.html @@ -49,7 +49,8 @@ html/text/html: 选中富文本为html格式, 输出mimetype为text/html。
富文本笔记:html:(cat;echo '<p></p>';echo;)>>notes.html
命名笔记::(cat;echo;echo;)>>%s
复制至PC剪贴板::ssh [user:password]@192.168.2.102 "DISPLAY=:0 xsel -i"
-复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 "DISPLAY=:0 xsel -i"

+复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 "DISPLAY=:0 xsel -i"
+复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done

如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。
此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。

重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。

diff --git a/searchurl/txt/checked.js b/searchurl/txt/checked.js index f023a67..ade4911 100644 --- a/searchurl/txt/checked.js +++ b/searchurl/txt/checked.js @@ -4,9 +4,8 @@ for(let i=0;i fn.apply(this, args), ms); + }; +}; + +function throttle(fn, wait) { + let inThrottle, lastFn, lastTime; + return function(...args) { + if (!inThrottle) { + fn.apply(this, args); + lastTime = Date.now(); + inThrottle = true; + } else { + clearTimeout(lastFn); + lastFn = setTimeout(function() { + if (Date.now() - lastTime >= wait) { + fn.apply(this, args); + lastTime = Date.now(); + } + }, Math.max(wait - (Date.now() - lastTime), 0)); + } + }; +}; + +function is_same_size_position(ele1, ele2) { + try { + return ele1.clientWidth == ele2.clientWidth && + ele1.clientHeight == ele2.clientHeight && + ele1.scrollHeight == ele2.scrollHeight; + } catch { + return false; + } +} + +function find_top_wrap_ele(ele) { + let wrap = ele; + while (ele.tagName !== 'BODY') { + ele = ele.parentElement; + if (is_same_size_position(wrap, ele)) { + wrap = ele; + } + } + return wrap; +} + +function is_parent(ele, parent) { + while (ele.tagName !== 'BODY' && + ele !== parent && ele.parentElement !== parent) { + ele = ele.parentElement; + } + return ele.parentElement === parent; +} + +function flatten(array) { + if (!Array.isArray(array)) { + return [array]; + } else if (array.length == 0) { + return []; + } else { + return flatten(array[0]).concat(flatten(array.slice(1))); + } +} + +function zero_padding(number, length = 2) { + return Array(Math.max(length - number.toString().length, 0) + 1).join(0) + number; +} + +function sec2HHMMSS(time, sec_base = 1) { + const sec = sec_base, min = 60 * sec, hour = 60 * min; + const h = Math.floor(time / hour); + const m = Math.floor(time % hour / min); + const s = Math.floor(time % min / sec); + let result = zero_padding(m) + ':' + zero_padding(s); + if (h) { + return zero_padding(h) + ':' + result; + } else { + return result; + } +} + +function HHMMSS2sec(time, sec_base = 1) { + const sec = sec_base, min = 60 * sec, hour = 60 * min; + const split = time.split(':'); + if (split.length < 3) { + split.unshift(0); + } + const h = split[0]; + const m = split[1]; + const s = split[2]; + return h * hour + m * min + s * sec; +} + +function get_1cm_pixel_num() { + const div = document.createElement('div'); + div.style.cssText = ['position: fixed', 'width: 1cm', 'visibility: hidden'].join('; '); + document.body.append(div); + const pixel = div.clientWidth; + div.remove(); + get_1cm_pixel_num = () => pixel; + return pixel; +} + +function px2cm(px) { + return px / get_1cm_pixel_num(); +} + +/* lib end */ + +/* add custom event begin */ + +function copy(obj) { + const new_obj = {}; + for (let i in obj) { + new_obj[i] = obj[i]; + } + return new_obj; +} + +function TapEvent(touch_event) { + return new TouchEvent('tap', + Object.assign(copy(touch_event), + { bubbles: true, cancelable: true, composed: true })); +} + +function DoubleTapEvent(touch_event) { + return new TouchEvent('doubletap', + Object.assign(copy(touch_event), + { bubbles: true, cancelable: true, composed: true })); +} + +function TouchEvent2MouseEvent(event_type, event) { + const touch = event.targetTouches && event.targetTouches[0] || {}; + return new MouseEvent(event_type, + Object.assign({}, copy(event), copy(touch), + { bubbles: true, cancelable: true, composed: true })); +} + +function add_tap_event_hook(element) { + let start_touch, end_touch, end_event = {}; + const start = e => { + start_touch = end_touch = copy(e.touches[0]); + end_event = copy(e); + }; + const move = e => { + end_touch = copy(e.touches[0]); + end_event = copy(e); + }; + const end = e => { + if (Math.abs(start_touch.clientX - end_touch.clientX) <= 10 && + Math.abs(start_touch.clientY - end_touch.clientY) <= 10) { + e.target.dispatchEvent(new TapEvent(end_event)); + e.preventDefault(); + e.target.dispatchEvent(TouchEvent2MouseEvent('click', end_event)); + } + }; + + element.addEventListener('touchstart', start, true); + element.addEventListener('touchmove', move, true); + element.addEventListener('touchend', end, true); + + return function event_clearer() { + element.removeEventListener('touchstart', start, true); + element.removeEventListener('touchmove', move, true); + element.removeEventListener('touchend', end, true); + }; +} + +function add_doubletap_event_hook(element) { + let start_time = 0; + const doubletap_judge = e => { + if (Date.now() - start_time <= 250) { + start_time = 0; + e.target.dispatchEvent(new DoubleTapEvent(e)); + } else { + start_time = Date.now(); + } + }; + + element.addEventListener('tap', doubletap_judge, true); + + return function event_clearer() { + element.removeEventListener('tap', doubletap_judge, true); + }; +} + +/* add custom event end */ + +function create_prompt_panel() { + const prompt_div = document.createElement('div'); + const prompt_symbol_div = document.createElement('div'); + const prompt_time_div = document.createElement('div'); + const prompt_time_begin_span = document.createElement('span'); + const prompt_time_end_span = document.createElement('span'); + + prompt_div.append(prompt_symbol_div, prompt_time_div); + prompt_time_div.append(prompt_time_begin_span, ' / ', prompt_time_end_span); + + prompt_div.style.cssText = ` + width: 10em; + position: absolute; + z-index: 99999999; + left: 50%; + top: 50%; + padding: 15px 0px; + margin: calc(-0.5em - 15px) auto auto -5em; + background-color: rgba(51, 51, 51, 0.8); + border-radius: 15px; + text-align: center; + font-size: 0.5cm; + color: white; + display: none; + `; + prompt_time_begin_span.style.color = '#2fb3ff'; + + return { + div: prompt_div, + symbol: prompt_symbol_div, + left_time: prompt_time_begin_span, + right_time: prompt_time_end_span, + }; +} + +function create_control_panel() { + const div = document.createElement('div'); + const content_divs = Array(5).fill().map(() => document.createElement('div')); + div.append.apply(div, content_divs); + + div.style.cssText = ` + width: 100%; + height: 100%; + margin: 0; + padding: 0; + position: absolute; + z-index: 9999999999; + top: 0; + background-color: rgba(51, 51, 51, 0.8); + color: white; + box-sizing: border-box; + display: none; + justify-content: center; + align-items: center; + font-size: 1cm; + pointer-events: auto; + `; + + return { + display() { + div.style.display = 'flex'; + }, + hidden() { + div.style.display = 'none'; + }, + toggle() { + if (div.style.display === 'flex') { + this.hidden(); + } else { + this.display(); + } + }, + div, + content_divs, + }; +} + +const get_video_touch_hook = (video, e) => { + let top_wrap = find_top_wrap_ele(video); + if (top_wrap === video) { + top_wrap = document.createElement('div'); + video.parentElement.insertBefore(top_wrap, video); + top_wrap.append(video); + } + + const event_clearer = [add_tap_event_hook, add_doubletap_event_hook].map(x => x(top_wrap)); + + const hook_fn = { + start: [], + move: [], + end: [], + }; + + let start_x, start_time; + const touch_start = e => { + start_x = e.touches[0].screenX; + start_time = video.currentTime; + + hook_fn.start.forEach(fn => fn(e, start_time)); + }; + if (e) { + setTimeout(touch_start, 0, e); + } + + const touch_move = e => { + const end_x = e.touches[0].screenX; + const x_distance_px = end_x - start_x; + const time_length = px2cm(x_distance_px) * (this.sec_1cm || 1); + + hook_fn.move.forEach(fn => fn(e, start_time, x_distance_px, time_length)); + }; + + const touch_end = e => { + hook_fn.end.forEach(fn => fn(e)); + }; + + top_wrap.addEventListener('touchstart', touch_start, { passive: false }); + top_wrap.addEventListener('touchmove', touch_move, { passive: false }); + top_wrap.addEventListener('touchend', touch_end, { passive: false }); + + const remove_hook = () => { + top_wrap.removeEventListener('touchstart', touch_start); + top_wrap.removeEventListener('touchmove', touch_move); + top_wrap.removeEventListener('touchend', touch_end); + }; + + return { video, hook_fn, wrap: top_wrap, event_clearer: event_clearer.concat(remove_hook) }; +}; + +const hook_video_move = hook => { + const {video, hook_fn} = hook; + + hook_fn.start.push(() => { + paused = video.paused; + }); + + let playing; + const pause = () => { + if (!video.paused) { + video.pause(); + playing = true; + } + }; + const play = debounce(() => { + if (playing) { + video.play(); + playing = false; + } + }, 100); + + hook_fn.move.push((e, start_time, x_distance_px, time_length) => { + pause(); + video.currentTime = Math.max(Math.min(start_time + time_length, + video.duration), + 0); + play(); + }); +}; + +const hook_video_time_change = hook => { + const {video, hook_fn, event_clearer} = hook; + const top_wrap = find_top_wrap_ele(video); + const video_prompt = create_prompt_panel(); + top_wrap.append(video_prompt.div); + + event_clearer.push(() => video_prompt.div.remove()); + + hook_fn.start.push(() => { + video_prompt.right_time.innerText = sec2HHMMSS(video.duration); + }); + + hook_fn.move.push((e, start_time, x_distance_px, time_length) => { + video_prompt.div.style.display = 'block'; + time_length = video.currentTime - start_time; + video_prompt.symbol.innerText = time_length < 0 ? '-' : '+'; + video_prompt.symbol.innerText += sec2HHMMSS(Math.abs(time_length)); + video_prompt.left_time.innerText = sec2HHMMSS(video.currentTime); + }); + + hook_fn.end.push(() => { + video_prompt.div.style.display = 'none'; + }); +}; + +const hook_video_control = hook => { + const {video, hook_fn, event_clearer} = hook; + const top_wrap = find_top_wrap_ele(video); + const wrap = document.createElement('div'); + const paddle_div = document.createElement('div'); + const speed_div = document.createElement('div'); + const jump_div = document.createElement('div'); + const skip_div = document.createElement('div'); + const fullscreen_div = document.createElement('div'); + const control = create_control_panel(); + + top_wrap.append(wrap); + const buttons = [paddle_div, speed_div, jump_div, skip_div, fullscreen_div]; + wrap.append.apply(wrap, buttons); + wrap.append(control.div); + + wrap.style.cssText = ` + width: 100%; + height: 100%; + position: absolute; + top: 0px; + left: 0px; + pointer-events: none; + z-index: 9999999999; + display: none; + `; + + const update_wrap_size = () => { + wrap.style.fontSize = `${Math.min(video.clientHeight, video.clientWidth) / buttons.length / 4}px`; + }; + + update_wrap_size(); + + buttons.forEach(div => div.style.cssText = + ` + width: 3em; + height: 3em; + line-height: 3em; + text-align: center; + border: solid white; + border-radius: 100%; + color: white; + pointer-events: auto; + `); + + paddle_div.style.pointerEvents = 'none'; + paddle_div.style.visibility = 'hidden'; + + const skip_video = throttle(e => { + video.currentTime = video.duration; + }, 500); + const toggle_play_state = throttle(e => { + if (video.paused) { + video.play(); + } else { + video.pause(); + } + }, 500); + const toggle_fullscreen = throttle(e => { + if (document.fullscreen) { + document.exitFullscreen(); + } else { + top_wrap.requestFullscreen(); + } + }, 500); + + const update_button = () => { + speed_div.innerText = video.playbackRate + 'x'; + jump_div.innerText = sec2HHMMSS(video.currentTime); + }; + const hidden_wrap = () => { + control.hidden(); + wrap.style.display = 'none'; + wrap.style.pointerEvents = 'none'; + }; + + const hidden_wrap_delay = debounce(hidden_wrap, 3000); + + const display_wrap = throttle((e) => { + update_wrap_size(); + wrap.style.display = 'block'; + update_button(); + hidden_wrap_delay(); + }, 1000); + + const prevent_event = e => { + if (e.cancelable) { + e.preventDefault(); + } + e.stopImmediatePropagation(); + }; + + skip_div.innerText = 'skip'; + fullscreen_div.innerText = 'FS'; + + skip_div.addEventListener('tap', skip_video); + fullscreen_div.addEventListener('tap', toggle_fullscreen); + + wrap.addEventListener('touchend', prevent_event); + + wrap.addEventListener('touchmove', e => { + prevent_event(e); + update_button(); + hidden_wrap_delay(); + }); + + top_wrap.addEventListener('tap', display_wrap); + top_wrap.addEventListener('doubletap', toggle_play_state); + + event_clearer.push(() => { + top_wrap.removeEventListener('tap', display_wrap); + top_wrap.removeEventListener('doubletap', toggle_play_state); + wrap.remove(); + }); + + function speed_activate() { + video.playbackRate = parseFloat(control.div.innerText.replace(/[\r\n]+/g, '')); + update_button(); + hidden_wrap(); + } + + function jump_activate() { + video.currentTime = HHMMSS2sec(control.div.innerText.replace(/[\r\n]+/g, '')); + update_button(); + hidden_wrap(); + } + + function clear_content() { + control.content_divs.forEach(div => div.innerHTML = ''); + } + + const set_content_tap_fn = (() => { + let bind_fn = []; + return fn => { + bind_fn.forEach(([div, fn]) => div.removeEventListener('tap', fn)); + bind_fn = []; + control.content_divs.forEach(div => { + bind_fn.push([div, fn]); + div.addEventListener('tap', fn); + }); + }; + })(); + + let state = []; + function set_state() { + control.content_divs.forEach((div, i) => state[i] = div.innerText); + } + + let start_y, modifier; + const start = e => { + start_y = e.touches[0].screenY; + set_state(); + }; + const move = e => { + const end_y = e.touches[0].screenY; + const y_distance_px = start_y - end_y; + const increase = Math.floor(px2cm(y_distance_px) * (this.increase_1cm || 1)); + const idx = Array.from(e.target.parentElement.children).indexOf(e.target); + if (modifier[idx]) { + modifier[idx](increase); + } + }; + + const increase_helper = (state_idx, increase, + limit, pre_ele_modifier, wrap = x => x) => { + const v = parseFloat(state[state_idx]) + increase; + if (limit !== undefined) { + if (pre_ele_modifier) { + if (v >= limit) { + pre_ele_modifier(Math.floor(v / limit)); + control.content_divs[state_idx].innerText = wrap(v % limit); + } else if (v < 0) { + pre_ele_modifier(-1); + control.content_divs[state_idx].innerText = wrap(limit + v); + } else { + control.content_divs[state_idx].innerText = wrap(v); + } + } else { + control.content_divs[state_idx].innerText = + wrap(Math.min(Math.max(v, 0), limit)); + } + } else { + control.content_divs[state_idx].innerText = wrap(v); + } + }; + + const speed_modifier = []; + speed_modifier[0] = (increase) => { + increase_helper(0, increase); + }; + speed_modifier[2] = (increase) => { + increase_helper(2, increase, 10, speed_modifier[0]); + }; + speed_modifier[3] = (increase) => { + increase_helper(3, increase, 10, speed_modifier[2]); + }; + + + const jump_modifier = []; + jump_modifier[0] = (increase) => { + increase_helper(0, increase, undefined, undefined, zero_padding); + }; + jump_modifier[2] = (increase) => { + increase_helper(2, increase, 60, jump_modifier[0], zero_padding); + }; + jump_modifier[4] = (increase) => { + increase_helper(4, increase, 60, jump_modifier[2], zero_padding); + }; + + speed_div.addEventListener('tap', throttle(e => { + e.stopImmediatePropagation(); + clear_content(); + const split = video.playbackRate.toString().split('.'); + control.content_divs[0].innerText = split[0]; + control.content_divs[1].innerText = '.'; + control.content_divs[2].innerText = (split[1] || '00').split('')[0] || 0; + control.content_divs[3].innerText = (split[1] || '00').split('')[1] || 0; + control.content_divs[4].innerText = 'x'; + modifier = speed_modifier; + set_content_tap_fn(speed_activate); + control.display(); + wrap.style.pointerEvents = 'auto'; + }, 500)); + + jump_div.addEventListener('tap', throttle(e => { + e.stopImmediatePropagation(); + clear_content(); + const time = sec2HHMMSS(video.currentTime); + const split = time.split(':'); + if (split.length < 3) { + split.unshift('00'); + } + control.content_divs[0].innerText = split[0]; + control.content_divs[1].innerText = ':'; + control.content_divs[2].innerText = split[1]; + control.content_divs[3].innerText = ':'; + control.content_divs[4].innerText = split[2]; + modifier = jump_modifier; + set_content_tap_fn(jump_activate); + control.display(); + wrap.style.pointerEvents = 'auto'; + }, 500)); + + control.content_divs.forEach(div => { + div.addEventListener('touchstart', start, { passive: false }); + div.addEventListener('touchmove', move, { passive: false }); + }); +}; + +function get_frames(window) { + const frames = [window]; + for (let i = 0; i < window.frames.length; i++) { + try { + window.frames[i].document; + } catch { + continue; + } + + frames.push(...get_frames(window.frames[i])) + } + return frames; +} + +function get_videos() { + const frames = get_frames(window); + const frame_video = frame => Array.from(frame.document.querySelectorAll('video')); + const shadow = frame => Array.from(frame.document.querySelectorAll("shadow-output")); + const shadow_video = shadow => Array.from(shadow.shadowRoot.querySelectorAll("video")); + return flatten(frames.map(frame_video) + .concat(frames.map(f => shadow(f).map(shadow_video)))); +} + +function find_hook(video) { + window.__hook_video__ = window.__hook_video__ || []; + const exist_video = window.__hook_video__.find(v => v.video === video); + return exist_video; +} + +function register_hook(hook) { + if (!find_hook(hook.video)) { + window.__hook_video__.push(hook); + return hook; + } +} + +const hook_video = (video) => { + const exist_video = find_hook(video); + if (video.clientWidth && video.clientHeight && + (!exist_video || is_parent(exist_video.wrap, find_top_wrap_ele(video)))) { + const hook = get_video_touch_hook(video); + hook_video_move(hook); + hook_video_time_change(hook); + hook_video_control(hook); + + if (exist_video) { + exist_video.event_clearer.forEach(x => x()); + Object.assign(exist_video, hook); + console.log('video-improve: reloaded for ', video, ', wrapped by ', find_top_wrap_ele(video)); + } else { + register_hook(hook); + console.log('video-improve: loaded for ', video, ', wrapped by ', find_top_wrap_ele(video)); + } + } +}; + +get_videos().forEach(hook_video); +})() diff --git a/tags/pc/index.xml b/tags/pc/index.xml index ea17189..95dcb60 100644 --- a/tags/pc/index.xml +++ b/tags/pc/index.xml @@ -29,6 +29,7 @@ checked.js: 运行配置目录下checked.js,其返回值作为命令行标准 命名笔记::(cat;echo;echo;)&gt;&gt;%s 复制至PC剪贴板::ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; 复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; +复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done 如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。 此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。 重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。 diff --git a/tags/ssh/index.xml b/tags/ssh/index.xml index cdb228b..5793417 100644 --- a/tags/ssh/index.xml +++ b/tags/ssh/index.xml @@ -53,6 +53,7 @@ checked.js: 运行配置目录下checked.js,其返回值作为命令行标准 命名笔记::(cat;echo;echo;)&gt;&gt;%s 复制至PC剪贴板::ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; 复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; +复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done 如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。 此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。 重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。 diff --git a/tags/termux/index.xml b/tags/termux/index.xml index 21147ac..263aa58 100644 --- a/tags/termux/index.xml +++ b/tags/termux/index.xml @@ -126,6 +126,7 @@ checked.js: 运行配置目录下checked.js,其返回值作为命令行标准 命名笔记::(cat;echo;echo;)&gt;&gt;%s 复制至PC剪贴板::ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; 复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; +复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done 如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。 此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。 重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。 diff --git a/tags/windows/index.xml b/tags/windows/index.xml index 1ded023..6bd13de 100644 --- a/tags/windows/index.xml +++ b/tags/windows/index.xml @@ -29,6 +29,7 @@ checked.js: 运行配置目录下checked.js,其返回值作为命令行标准 命名笔记::(cat;echo;echo;)&gt;&gt;%s 复制至PC剪贴板::ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; 复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; +复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done 如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。 此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。 重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。 diff --git a/tags/剪贴板/index.xml b/tags/剪贴板/index.xml index 98645cd..16a92e9 100644 --- a/tags/剪贴板/index.xml +++ b/tags/剪贴板/index.xml @@ -53,6 +53,7 @@ checked.js: 运行配置目录下checked.js,其返回值作为命令行标准 命名笔记::(cat;echo;echo;)&gt;&gt;%s 复制至PC剪贴板::ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; 复制富文本至PC剪贴板:html:ssh [user:password]@192.168.2.102 &quot;DISPLAY=:0 xsel -i&quot; +复制文件至PC:checked.js:while read fname;do scp $fname [user:password]@192.168.2.102:Downloads/.; done 如使用剪贴板功能手机需安装uweb定制Termux,并在termux下安装openssl。 此处假定远程PC的IP地址为192.168.2.102,PC已经开通了ssh服务。建议用户配置ssh服务为免密码登录,此时用户无需将密码写入文件default.select。用户PC上安装有xsel剪贴板工具。使用其它工具请酌情修改。 重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。 diff --git a/tags/广告屏蔽/index.xml b/tags/广告屏蔽/index.xml index 8101aeb..0ad4b02 100644 --- a/tags/广告屏蔽/index.xml +++ b/tags/广告屏蔽/index.xml @@ -105,6 +105,7 @@ ad.xiaomi.com https://jamesfengcao.gitee.io/uweb/video/ 本文以超微浏览器为例来说明。 +点击安装&quot;视频播放增强(倍速等)&quot; 长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/sdcard/uweb/types.sniff”控制。 很多视频解析结果在UA为PC的情况下非常干净,没什么广告。故用户可在播放前切换UA至PC。如:wn.run/解析结果对PC非常干净。 某些视频网站在全屏播放时都会出现广告占住屏幕一部分。点击全屏播放之前,长按[☰]按钮,超微浏览器将弹出全局脚本菜单,勾选“移除浮动广告”后再点全屏播放则完美播放。 也可利用全屏播放屏蔽一切广告。方法如下: 长按[☰]按钮,勾选“全屏视频”。此选项将让无法全屏播放的网站强制允许全屏播放。 对无法全屏、无法放大的视频网站,可长按[☰]按钮,勾选“强制缩放”,然后手动放大至全屏。 灵活应用JS、图像开关屏蔽一切广告:视频搜索前关闭JS开关,进入播放网页前关闭图像显示并打开JS。 视频解析之电视剧: 首先在视频网站搜索电视剧片名,下面会显示不同的剧集,点击它们再用视频解析即可观看。如果直接点击电视剧用视频解析则每次播放均为第一集。 视频搜索预配置(超过400个引擎) 视频资源: 视频解析配置 电视直播 OK资源 全国电视直播 免费视频 国外剧 纪录片 网络直播 diff --git a/tags/搜索/index.xml b/tags/搜索/index.xml index b81420b..ebb5b5d 100644 --- a/tags/搜索/index.xml +++ b/tags/搜索/index.xml @@ -35,6 +35,7 @@ d:mimetype:[含%s的命令行]:[外部资源url] https://jamesfengcao.gitee.io/uweb/video/ 本文以超微浏览器为例来说明。 +点击安装&quot;视频播放增强(倍速等)&quot; 长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/sdcard/uweb/types.sniff”控制。 很多视频解析结果在UA为PC的情况下非常干净,没什么广告。故用户可在播放前切换UA至PC。如:wn.run/解析结果对PC非常干净。 某些视频网站在全屏播放时都会出现广告占住屏幕一部分。点击全屏播放之前,长按[☰]按钮,超微浏览器将弹出全局脚本菜单,勾选“移除浮动广告”后再点全屏播放则完美播放。 也可利用全屏播放屏蔽一切广告。方法如下: 长按[☰]按钮,勾选“全屏视频”。此选项将让无法全屏播放的网站强制允许全屏播放。 对无法全屏、无法放大的视频网站,可长按[☰]按钮,勾选“强制缩放”,然后手动放大至全屏。 灵活应用JS、图像开关屏蔽一切广告:视频搜索前关闭JS开关,进入播放网页前关闭图像显示并打开JS。 视频解析之电视剧: 首先在视频网站搜索电视剧片名,下面会显示不同的剧集,点击它们再用视频解析即可观看。如果直接点击电视剧用视频解析则每次播放均为第一集。 视频搜索预配置(超过400个引擎) 视频资源: 视频解析配置 电视直播 OK资源 全国电视直播 免费视频 国外剧 纪录片 网络直播 diff --git a/tags/资源/index.xml b/tags/资源/index.xml index 87b73fa..d8d6765 100644 --- a/tags/资源/index.xml +++ b/tags/资源/index.xml @@ -37,6 +37,7 @@ mv BaiduPCS-Go /data/data/com.termux/files/usr/bin/. 配置/sdcard/uweb/default. https://jamesfengcao.gitee.io/uweb/video/ 本文以超微浏览器为例来说明。 +点击安装&quot;视频播放增强(倍速等)&quot; 长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/sdcard/uweb/types.sniff”控制。 很多视频解析结果在UA为PC的情况下非常干净,没什么广告。故用户可在播放前切换UA至PC。如:wn.run/解析结果对PC非常干净。 某些视频网站在全屏播放时都会出现广告占住屏幕一部分。点击全屏播放之前,长按[☰]按钮,超微浏览器将弹出全局脚本菜单,勾选“移除浮动广告”后再点全屏播放则完美播放。 也可利用全屏播放屏蔽一切广告。方法如下: 长按[☰]按钮,勾选“全屏视频”。此选项将让无法全屏播放的网站强制允许全屏播放。 对无法全屏、无法放大的视频网站,可长按[☰]按钮,勾选“强制缩放”,然后手动放大至全屏。 灵活应用JS、图像开关屏蔽一切广告:视频搜索前关闭JS开关,进入播放网页前关闭图像显示并打开JS。 视频解析之电视剧: 首先在视频网站搜索电视剧片名,下面会显示不同的剧集,点击它们再用视频解析即可观看。如果直接点击电视剧用视频解析则每次播放均为第一集。 视频搜索预配置(超过400个引擎) 视频资源: 视频解析配置 电视直播 OK资源 全国电视直播 免费视频 国外剧 纪录片 网络直播 diff --git a/video/index.html b/video/index.html index a823e1c..d2c092a 100644 --- a/video/index.html +++ b/video/index.html @@ -30,6 +30,7 @@

本文以超微浏览器为例来说明。

+

点击安装"视频播放增强(倍速等)"