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;)>>%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剪贴板工具。使用其它工具请酌情修改。
重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。
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;)>>%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剪贴板工具。使用其它工具请酌情修改。
重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。
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;)>>%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剪贴板工具。使用其它工具请酌情修改。
重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。
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;)>>%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剪贴板工具。使用其它工具请酌情修改。
重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。
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;)>>%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剪贴板工具。使用其它工具请酌情修改。
重启浏览器,长按“链接”按钮,将弹出菜单。若用户当前窗口并无选中文本,则选取整个页面作相应操作,否则以选中文本为准。
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/
本文以超微浏览器为例来说明。
+点击安装"视频播放增强(倍速等)"
长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/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/
本文以超微浏览器为例来说明。
+点击安装"视频播放增强(倍速等)"
长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/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/
本文以超微浏览器为例来说明。
+点击安装"视频播放增强(倍速等)"
长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/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 @@
本文以超微浏览器为例来说明。
+点击安装"视频播放增强(倍速等)"
- 长按设置按钮勾选“弹出视频地址”,则视频播放时会弹出真正的播放地址,点击地址播放可避免一切广告。如果点击后为下载操作,可长按链接分享给视频播放器。用户亦可配置在线播放或安装插件。嗅探的视频/资源类型可由文件“/sdcard/uweb/types.sniff”控制。
- 很多视频解析结果在UA为PC的情况下非常干净,没什么广告。故用户可在播放前切换UA至PC。如:wn.run/解析结果对PC非常干净。