From 8240ae3e7272273ccf4d029225a2fbc8aa67423f Mon Sep 17 00:00:00 2001 From: "Mr. Stallion" Date: Mon, 30 Mar 2020 16:52:25 -0500 Subject: [PATCH] Better video loading support --- chat/preview/ImagePreview.vue | 137 +++++++++++++------------- chat/preview/assets/browser.pre.js | 67 ++++++++++++- chat/preview/image-preview-mutator.ts | 40 +++++++- chat/preview/image-url-mutator.ts | 12 +++ chat/preview/integration/pornhub.ts | 77 +++++++++++++++ chat/preview/test-urls.txt | 29 +++++- 6 files changed, 289 insertions(+), 73 deletions(-) create mode 100644 chat/preview/integration/pornhub.ts diff --git a/chat/preview/ImagePreview.vue b/chat/preview/ImagePreview.vue index 25ebcea..04e0f4a 100644 --- a/chat/preview/ImagePreview.vue +++ b/chat/preview/ImagePreview.vue @@ -125,11 +125,8 @@ const url = webview.getURL(); const js = this.jsMutator.getMutatorJsForSite(url, 'update-target-url'); - if (this.debug) - console.log('ImagePreview update-target', event, js); - - if ((js) && (this.runJs)) - webview.executeJavaScript(js); + // tslint:disable-next-line + this.executeJavaScript(js, 'update-target-url', event); } ); @@ -140,11 +137,8 @@ const url = webview.getURL(); const js = this.jsMutator.getMutatorJsForSite(url, 'dom-ready'); - if (this.debug) - console.log('ImagePreview dom-ready', event, js); - - if ((js) && (this.runJs)) - webview.executeJavaScript(js, true); + // tslint:disable-next-line + this.executeJavaScript(js, 'dom-ready', event); } ); @@ -154,13 +148,28 @@ (event: Event) => { const e = event as DidFailLoadEvent; + if (e.errorCode < 0) { + const url = webview.getURL(); + const qjs = this.jsMutator.getMutatorJsForSite(url, 'update-target-url'); + + // tslint:disable-next-line + this.executeJavaScript(qjs, 'did-fail-load-but-still-loading', event); + return; + } + + // if (e.errorCode < 100) { + // const url = webview.getURL(); + // const js = this.jsMutator.getMutatorJsForSite(url, 'update-target-url'); + // + // this.executeJavaScript(js, 'did-fail-load-but-still-loading', event); + // + // return; + // } + const js = this.jsMutator.getErrorMutator(e.errorCode, e.errorDescription); - if (this.debug) - console.log('ImagePreview did-fail-load', event, js); - - if ((js) && (this.runJs) && (e.errorCode >= 400)) - webview.executeJavaScript(js); + // tslint:disable-next-line + this.executeJavaScript(js, 'did-fail-load', event); } ); @@ -172,11 +181,8 @@ if (e.httpResponseCode >= 400) { const js = this.jsMutator.getErrorMutator(e.httpResponseCode, e.httpStatusText); - if (this.debug) - console.log('ImagePreview did-navigate', event, js); - - if ((js) && (this.runJs)) - webview.executeJavaScript(js); + // tslint:disable-next-line + this.executeJavaScript(js, 'did-navigate', event); } } ); @@ -185,8 +191,7 @@ webview.addEventListener( 'did-finish-load', (event: Event) => { - if (this.debug) - console.log('ImagePreview did-finish-load', event); + this.debugLog('ImagePreview did-finish-load', event); } ); @@ -194,8 +199,7 @@ webview.addEventListener( 'ipc-message', (event: IpcMessageEvent) => { - if (this.debug) - console.log('ImagePreview ipc-message', event); + this.debugLog('ImagePreview ipc-message', event); if (event.channel === 'webview.img') { // tslint:disable-next-line:no-unsafe-any @@ -219,8 +223,7 @@ webview.addEventListener( en, (event: Event) => { - if (this.debug) - console.log(`ImagePreview ${en} ${Date.now()}`, event); + this.debugLog(`ImagePreview ${en} ${Date.now()}`, event); } ); } @@ -233,9 +236,7 @@ this.initialCursorPosition = screen.getCursorScreenPoint(); if ((this.visible) && (this.shouldDismiss) && (this.hasMouseMovedSince()) && (!this.exitInterval) && (!this.interval)) { - if (this.debug) { - console.log('ImagePreview: call hide from interval'); - } + this.debugLog('ImagePreview: call hide from interval'); this.hide(); } @@ -251,13 +252,11 @@ // tslint:disable-next-line:no-unsafe-any this.localPreviewStyle = this.localPreviewHelper.renderStyle(); - if (this.debug) { - console.log( - 'ImagePreview: reRenderStyles', 'external', - JSON.parse(JSON.stringify(this.externalPreviewStyle)), - 'local', JSON.parse(JSON.stringify(this.localPreviewStyle)) - ); - } + this.debugLog( + 'ImagePreview: reRenderStyles', 'external', + JSON.parse(JSON.stringify(this.externalPreviewStyle)), + 'local', JSON.parse(JSON.stringify(this.localPreviewStyle)) + ); } @@ -267,9 +266,7 @@ } if ((width) && (height)) { - if (this.debug) { - console.log('ImagePreview: updatePreviewSize', width, height, width / height); - } + this.debugLog('ImagePreview: updatePreviewSize', width, height, width / height); this.externalPreviewHelper.setRatio(width / height); this.reRenderStyles(); @@ -278,8 +275,7 @@ hide(): void { - if (this.debug) - console.log('ImagePreview: hide', this.externalPreviewHelper.isVisible(), this.localPreviewHelper.isVisible()); + this.debugLog('ImagePreview: hide', this.externalPreviewHelper.isVisible(), this.localPreviewHelper.isVisible()); this.cancelExitTimer(); @@ -302,9 +298,7 @@ dismiss(initialUrl: string, force: boolean = false): void { const url = this.jsMutator.mutateUrl(initialUrl); - if (this.debug) { - console.log('ImagePreview: dismiss', url); - } + this.debugLog('ImagePreview: dismiss', url); if (this.url !== url) return; // simply ignore @@ -330,8 +324,7 @@ if ((!this.hasMouseMovedSince()) && (!force)) return; - if (this.debug) - console.log('ImagePreview: dismiss.exec', this.externalPreviewHelper.isVisible(), this.localPreviewHelper.isVisible(), url); + this.debugLog('ImagePreview: dismiss.exec', this.externalPreviewHelper.isVisible(), this.localPreviewHelper.isVisible(), url); // This timeout makes the preview window disappear with a slight delay, which helps UX // when dealing with situations such as quickly scrolling text that moves the cursor away @@ -346,39 +339,27 @@ show(initialUrl: string): void { const url = this.jsMutator.mutateUrl(initialUrl); - if (this.debug) - console.log('ImagePreview: show', this.externalPreviewHelper.isVisible(), this.localPreviewHelper.isVisible(), + this.debugLog('ImagePreview: show', this.externalPreviewHelper.isVisible(), this.localPreviewHelper.isVisible(), this.visible, this.hasMouseMovedSince(), !!this.interval, this.sticky, url); // console.log('SHOW'); if ((this.visible) && (!this.exitInterval) && (!this.hasMouseMovedSince())) { - if (!this.sticky) { - if (this.debug) { - console.log('ImagePreview: show cancel: visible & not moved'); - } - return; - } + this.debugLog('ImagePreview: show cancel: visible & not moved'); + return; } if ((this.url === url) && ((this.visible) || (this.interval))) { - if (this.debug) { - console.log('ImagePreview: same url', url, this.url); - } - + this.debugLog('ImagePreview: same url', url, this.url); return; } if ((this.url) && (this.sticky) && (this.visible)) { - if (this.debug) { - console.log('ImagePreview: sticky visible'); - } - + this.debugLog('ImagePreview: sticky visible'); return; } - if (this.debug) - console.log('ImagePreview: show.exec', url); + this.debugLog('ImagePreview: show.exec', url); const due = ((url === this.exitUrl) && (this.exitInterval)) ? 0 : 100; @@ -393,8 +374,7 @@ // tslint:disable-next-line no-unnecessary-type-assertion this.interval = setTimeout( () => { - if (this.debug) - console.log('ImagePreview: show.timeout', this.url); + this.debugLog('ImagePreview: show.timeout', this.url); this.localPreviewHelper.match(this.domain as string) ? this.localPreviewHelper.show(this.url as string) @@ -476,6 +456,31 @@ } } + + async executeJavaScript(js: string | undefined, context: string = 'unknown', logDetails?: any): Promise { + const webview = this.getWebview(); + + if (!js) { + this.debugLog(`ImagePreview ${context}: No JavaScript to execute`, logDetails); + return; + } + + this.debugLog(`ImagePreview ${context}`, js, logDetails); + + const result = await (webview.executeJavaScript(js) as unknown as Promise); + + this.debugLog(`ImagePreview result-${context}`, result); + + return result; + } + + debugLog(...args: any[]): void { + if (this.debug) { + console.log(...args); + } + } + + toggleStickyMode(): void { this.sticky = !this.sticky; diff --git a/chat/preview/assets/browser.pre.js b/chat/preview/assets/browser.pre.js index 7146060..f1840b2 100644 --- a/chat/preview/assets/browser.pre.js +++ b/chat/preview/assets/browser.pre.js @@ -1,11 +1,72 @@ (() => { try { - console.log('RUNNING RUNNING RUNNING', Date.now()); - document.querySelectorAll('iframe').forEach((e) => e.remove()); + const clear = () => { + if (window.location.href.match(/https?:\/\/(www.)?pornhub.com/)) { + if (!window.zest) { + window.zest = (q) => (document.querySelectorAll(q)); + } + + return; + } + + try { + const frameCount = window.frames.length; + + for (let i = 0; i < frameCount; i++) { + window.frames[i].location = 'about:blank'; + } + } catch (e) { + console.error('Frame location', e); + } + + try { + const scriptCount = document.scripts.length; + + for (let i = 0; i < scriptCount; i++) { + document.scripts[i].src = 'about:blank'; + } + } catch (e) { + console.error('Script location', e); + } + + try { + document.querySelectorAll('iframe, script' /*, style, head' */ ) + .forEach((e) => e.remove()); + } catch (e) { + console.error('Element remove', e); + } + + + const intervalCount = setInterval(() => {}, 10000); + + for (let i = 0; i <= intervalCount; i++) { + try { + clearInterval(i); + } catch (e) { + console.error('Clear interval', i, e); + } + } + + + const timeoutCount = setTimeout(() => {}, 10000); + + for (let i = 0; i <= timeoutCount; i++) { + try { + clearTimeout(i); + } catch (e) { + console.error('Clear timeout', i, e); + } + } + }; + + console.log('Document loading', Date.now()); + clear(); + + // window.stop(); window.addEventListener('DOMContentLoaded', (event) => { - document.querySelectorAll('iframe').forEach((e) => e.remove()); console.log('DOM fully loaded and parsed', Date.now()); + clear(); }); } catch(e) { console.error(e); diff --git a/chat/preview/image-preview-mutator.ts b/chat/preview/image-preview-mutator.ts index 54a85bd..6719be2 100644 --- a/chat/preview/image-preview-mutator.ts +++ b/chat/preview/image-preview-mutator.ts @@ -5,6 +5,7 @@ import * as urlHelper from 'url'; import { domain as extractDomain } from '../../bbcode/core'; +import { PornhubIntegration } from './integration/pornhub'; export interface PreviewMutator { match: string | RegExp; @@ -34,7 +35,8 @@ export class ImagePreviewMutator { constructor(debug: boolean) { this.init(); - this.debug = debug; + // this.debug = debug; + this.debug = debug || true; } setDebug(debug: boolean): void { @@ -126,7 +128,6 @@ export class ImagePreviewMutator { this.add('youtube.com', this.getBaseJsMutatorScript(['video']), undefined, 'dom-ready'); this.add('instantfap.com', this.getBaseJsMutatorScript(['#post video', '#post img'])); this.add('webmshare.com', this.getBaseJsMutatorScript(['video'])); - this.add('pornhub.com', this.getBaseJsMutatorScript(['#video, video', '.mainPlayerDiv video', '.photoImageSection img'])); this.add('vimeo.com', this.getBaseJsMutatorScript(['#video, video', '#image, img'])); this.add('sex.com', this.getBaseJsMutatorScript(['.image_frame video', '.image_frame img'])); this.add('redirect.media.tumblr.com', this.getBaseJsMutatorScript(['picture video', 'picture img'])); @@ -138,6 +139,13 @@ export class ImagePreviewMutator { this.add(/^media[0-9]\.tenor\.com$/, this.getBaseJsMutatorScript(['#view .file video', '#view .file img'])); this.add('tenor.com', this.getBaseJsMutatorScript(['#view video', '#view img'])); + this.add( + 'pornhub.com', + PornhubIntegration.preprocess() + + this.getBaseJsMutatorScript(['#__flistCore', '#player'], true) + + PornhubIntegration.postprocess() + ); + this.add( 'i.imgur.com', ` @@ -222,7 +230,31 @@ export class ImagePreviewMutator { if (!img) { return; } - ipcRenderer.sendToHost('webview.img', img.width || img.naturalWidth || img.videoWidth, img.height || img.naturalHeight || img.videoHeight); + const sizePairs = [ + ['naturalWidth', 'naturalHeight'], + ['videoWidth', 'videoHeight'], + ['width', 'height'], + ]; + + const imSize = sizePairs.reduce( + (acc, val) => { + if ((acc.width) && (acc.height)) { + return acc; + } + + if ((img[val[0]]) && (img[val[1]])) { + return { + width: img[val[0]], + height: img[val[1]] + } + } + + return acc; + }, + {} + ); + + ipcRenderer.sendToHost('webview.img', imSize.width, imSize.height); const el = document.createElement('div'); el.id = 'flistWrapper'; @@ -337,6 +369,8 @@ export class ImagePreviewMutator { ${skipElementRemove ? '' : 'removeList.forEach((el) => el.remove());'} removeList = []; + + window.stop(); `; } diff --git a/chat/preview/image-url-mutator.ts b/chat/preview/image-url-mutator.ts index 67b0e04..fa3c8e3 100644 --- a/chat/preview/image-url-mutator.ts +++ b/chat/preview/image-url-mutator.ts @@ -25,6 +25,18 @@ export class ImageUrlMutator { } protected init(): void { + this.add( + /^https?:\/\/(www.)?pornhub.com\/view_video.php\?viewkey=([a-z0-9A-Z]+)/, + async(_url: string, match: RegExpMatchArray): Promise => { + // https://www.pornhub.com/view_video.php?viewkey=ph5e11b975327f2 + // https://www.pornhub.com/embed/ph5e11b975327f2 + + const videoId = match[2]; + + return `https://pornhub.com/embed/${videoId}`; + } + ); + this.add( /^https?:\/\/imgur.com\/gallery\/([a-zA-Z0-9]+)/, async(url: string, match: RegExpMatchArray): Promise => { diff --git a/chat/preview/integration/pornhub.ts b/chat/preview/integration/pornhub.ts new file mode 100644 index 0000000..060d380 --- /dev/null +++ b/chat/preview/integration/pornhub.ts @@ -0,0 +1,77 @@ + +// tslint:disable-next-line +export class PornhubIntegration { + + static preprocess(): string { + return ` + const phCreateElement = (html) => { + const range = document.createRange(); + + range.selectNode(document.body); + + const el = range.createContextualFragment(html); + + document.body.appendChild(el); + } + + const phGifImg = document.querySelector('[data-mp4],[data-webm],[data-gif]'); + + if (phGifImg) { + const phGifVideoUrl = phGifImg.dataset.mp4 || phGifImg.dataset.webm; + + if (phGifVideoUrl) { + phCreateElement(\`\`); + } + + const phGifUrl = phGifImg.dataset.gif; + + if (phGifUrl) { + phCreateElement(\`\`); + } + } + `; + } + + + static postprocess(): string { + return ` + document.addEventListener('load', (event) => { + const phVideo = document.querySelector('video'); + + console.log('LOAD LOAD', phVideo); + + if ( + (phVideo) && (phVideo.play) + && ((!phVideo.ended) && (!(phVideo.currentTime > 0))) + ) + { + console.log('LOAD PLAYPLAY'); + + phVideo.muted = true; + phVideo.loop = true; + phVideo.play(); + } + }); + + try { + const phVideo = document.querySelector('video'); + + console.log('TRY TRY', phVideo); + + if ( + (phVideo) && (phVideo.play) + && ((!phVideo.ended) && (!(phVideo.currentTime > 0))) + ) + { + console.log('TRY PLAYPLAY'); + + phVideo.muted = true; + phVideo.loop = true; + phVideo.play(); + } + } catch (err) { + console.error('Failed phVideo.play()', err); + } + `; + } +} diff --git a/chat/preview/test-urls.txt b/chat/preview/test-urls.txt index 1dd8d4b..94c4539 100644 --- a/chat/preview/test-urls.txt +++ b/chat/preview/test-urls.txt @@ -7,7 +7,7 @@ [url=https://www.sex.com/pin/58497794/]Test[/url] - [url=https://images.sex.com/images/pinporn/2019/09/10/620/21790701.gif]Test[/url] + [url=https://cdn.sex.com/images/pinporn/2020/03/03/22687557.gif?width=620]Test[/url] [url=http://gfycatporn.com/deepthroat.php]Test[/url] @@ -41,7 +41,34 @@ [url=https://www.pornhub.com/view_video.php?viewkey=ph5b2c03dc1e23b]Test[/url] + [url=https://www.pornhub.com/gif/28316052]Test[/url] + [url=https://vimeo.com/265884960]Test[/url] + [url=https://gelbooru.com/index.php?page=post&s=view&id=5210847&tags=tits]Test[/url] + + [url=https://danbooru.donmai.us/posts/3841490]Test[/url] + + [url=https://danbooru.donmai.us/posts/3709493]Test[/url] + + + +Broken + +https://wwebm.rule34.xxx//images/1727/43fe58fd8d576246510cb94c6d8353b2.webm (not resizing) + +https://giant.gfycat.com/PessimisticGargantuanCaribou.webm (not resizing) + +https://e621.net/posts/1766079 (not loading, has a popup) + +https://www.pornhub.com/gif/12174171 (doesn't play) + +https://www.youtube.com/watch?v=fk6JtDhA7WI (audio on, video doesn't show, audio stays in the background) + + + +Slow +https://giphy.com/gifs/arianagrande-ariana-grande-thank-u-next-you-uldtLAK6tSOKP5PWw3 +http://gfycatporn.com/deepthroat.php