diff --git a/chat/Chat.vue b/chat/Chat.vue index 4a401bb..61b2cd0 100644 --- a/chat/Chat.vue +++ b/chat/Chat.vue @@ -44,6 +44,7 @@ import {InlineDisplayMode} from '../interfaces'; import l from './localize'; import Logs from './Logs.vue'; import {init as profileApiInit} from './profile_api'; + import { AdManager } from './ads/ad-manager'; type BBCodeNode = Node & {bbcodeTag?: string, bbcodeParam?: string}; @@ -127,19 +128,7 @@ import {InlineDisplayMode} from '../interfaces'; this.connected = false; this.connecting = false; - if (!isReconnect) { - core.conversations.channelConversations.forEach( - (chanConv) => { - try { - if (chanConv.adManager) { - chanConv.adManager.stop(); - } - } catch (e) { - console.error(e); - } - } - ); - } + AdManager.onConnectionClosed(); document.title = l('title'); }); diff --git a/chat/ads/ad-manager.ts b/chat/ads/ad-manager.ts index 58e6198..4001fba 100644 --- a/chat/ads/ad-manager.ts +++ b/chat/ads/ad-manager.ts @@ -1,12 +1,24 @@ +import throat from 'throat'; +import * as _ from 'lodash'; + import core from '../core'; import { Conversation } from '../interfaces'; import Timer = NodeJS.Timer; +import ChannelConversation = Conversation.ChannelConversation; -import throat from 'throat'; const adManagerThroat = throat(1); +export interface RecoverableAd { + channel: string; + index: number; + nextPostDue: Date | undefined, + firstPost: Date | undefined, + expireDue: Date | undefined; +} + + export class AdManager { static readonly POSTING_PERIOD = 3 * 60 * 60 * 1000; static readonly START_VARIANCE = 3 * 60 * 1000; @@ -129,6 +141,22 @@ export class AdManager { ) as Timer; } + + protected forceTimeout(waitTime: number): void { + if (this.interval) { + clearTimeout(this.interval); + } + + // tslint:disable-next-line: no-unnecessary-type-assertion + this.interval = setTimeout( + async() => { + await this.sendNextPost(); + }, + waitTime + ) as Timer; + } + + stop(): void { if (this.interval) clearTimeout(this.interval); @@ -151,4 +179,66 @@ export class AdManager { this.expireDue = new Date(Date.now() + 3 * 60 * 60 * 1000); } + + + protected static recoverableCharacter: string = ''; + protected static recoverableAds: RecoverableAd[] = []; + + + static onConnectionClosed() { + AdManager.recoverableCharacter = core.characters.ownCharacter.name; + + AdManager.recoverableAds = _.map( + _.filter(core.conversations.channelConversations, (c) => ((c.adManager) && (c.adManager.isActive()))), + (chanConv): RecoverableAd => { + const adManager = chanConv.adManager; + + return { + channel : chanConv.name, + index : adManager.adIndex, + nextPostDue : adManager.nextPostDue, + firstPost : adManager.firstPost, + expireDue : adManager.expireDue + }; + } + ); + + _.each( + _.filter(core.conversations.channelConversations, (c) => ((c.adManager) && (c.adManager.isActive()))), + (c) => c.adManager.stop() + ); + } + + + static onNewChannelAvailable(channel: ChannelConversation) { + if (AdManager.recoverableCharacter !== core.characters.ownCharacter.name) { + AdManager.recoverableAds = []; + AdManager.recoverableCharacter = ''; + + return; + } + + const ra = _.find(AdManager.recoverableAds, (r) => (r.channel === channel.name)); + + if (!ra) { + return; + } + + const adManager = channel.adManager; + + adManager.stop(); + adManager.start(); + + adManager.adIndex = ra.index; + adManager.firstPost = ra.firstPost; + adManager.nextPostDue = ra.nextPostDue || new Date(); + adManager.expireDue = ra.expireDue; + + adManager.forceTimeout( + Date.now() - adManager.nextPostDue.getTime() + ); + + AdManager.recoverableAds = _.filter(AdManager.recoverableAds, (r) => (r.channel !== ra.channel)); + } } + diff --git a/chat/conversations.ts b/chat/conversations.ts index 80c2f83..76bd7e8 100644 --- a/chat/conversations.ts +++ b/chat/conversations.ts @@ -519,6 +519,8 @@ export default function(this: any): Interfaces.State { if(state.recentChannels.length >= 50) state.recentChannels.pop(); state.recentChannels.unshift({channel: channel.id, name: conv.channel.name}); core.settingsStore.set('recentChannels', state.recentChannels); //tslint:disable-line:no-floating-promises + + AdManager.onNewChannelAvailable(conv); } else { const conv = state.channelMap[channel.id]; if(conv === undefined) return; diff --git a/chat/preview/image-dom-mutator.ts b/chat/preview/image-dom-mutator.ts index cc9763f..5eeb765 100644 --- a/chat/preview/image-dom-mutator.ts +++ b/chat/preview/image-dom-mutator.ts @@ -130,7 +130,7 @@ export class ImageDomMutator { async init(): Promise { await this.loadScripts(); - this.add('default', this.getBaseJsMutatorScript(['#video, video', '#image, img'])); + this.add('default', this.getBaseJsMutatorScript(['.content video', '.content img', '#video, video', '#image, img'])); this.add('e621.net', this.getBaseJsMutatorScript(['video', '#image'])); this.add('e-hentai.org', this.getBaseJsMutatorScript(['video', '#img'])); this.add('gelbooru.com', this.getBaseJsMutatorScript(['video', '#image'])); @@ -146,7 +146,7 @@ export class ImageDomMutator { this.add('redirect.media.tumblr.com', this.getBaseJsMutatorScript(['picture video', 'picture img'])); this.add('postimg.cc', this.getBaseJsMutatorScript(['video', '#main-image'])); this.add('gifsauce.com', this.getBaseJsMutatorScript(['video'])); - this.add('motherless.com', this.getBaseJsMutatorScript(['.content video', '.content img'])); + // this.add('motherless.com', this.getBaseJsMutatorScript(['.content video', '.content img'])); this.add(/^media[0-9]\.giphy\.com$/, this.getBaseJsMutatorScript(['video', 'img[alt]'])); this.add('giphy.com', this.getBaseJsMutatorScript(['video', 'a > div > img'])); this.add(/^media[0-9]\.tenor\.com$/, this.getBaseJsMutatorScript(['#view .file video', '#view .file img'])); @@ -155,6 +155,7 @@ export class ImageDomMutator { this.add('derpibooru.org', this.getBaseJsMutatorScript(['video', '#image-display', 'img'])); this.add('sexbot.gallery', this.getBaseJsMutatorScript(['video.hero', 'video'])); this.add('imagefap.com', this.getBaseJsMutatorScript(['.image-wrapper img', 'video', 'img'])); + this.add('myhentaicomics.com', this.getBaseJsMutatorScript(['#entire_image img', 'video', 'img'])); this.add( 'pornhub.com', diff --git a/chat/preview/test-urls.txt b/chat/preview/test-urls.txt index 6f3ca73..f62ab6d 100644 --- a/chat/preview/test-urls.txt +++ b/chat/preview/test-urls.txt @@ -69,6 +69,9 @@ [url=https://www.imagefap.com/photo/786507225/?pgid=&gid=6802322&page=0&idx=11]ImageFap[/url] + [url=https://xbooru.com/index.php?page=post&s=view&id=775278]XBooru[/url] + + Broken https://giphy.com/gifs/arianagrande-ariana-grande-thank-u-next-you-uldtLAK6tSOKP5PWw3 diff --git a/electron/main.ts b/electron/main.ts index 919a60b..39bbbbe 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -91,13 +91,13 @@ if(!settings.hwAcceleration) { export function updateSpellCheckerLanguages(langs: string[]): void { // console.log('Language support:', langs); + electron.session.defaultSession.setSpellCheckerLanguages(langs); for (const w of windows) { // console.log('LANG SEND'); + w.webContents.session.setSpellCheckerLanguages(langs); w.webContents.send('update-dictionaries', langs); } - - electron.session.defaultSession.setSpellCheckerLanguages(langs); } @@ -183,6 +183,7 @@ function createWindow(): Electron.BrowserWindow | undefined { const safeLanguages = settings.spellcheckLang ? _.castArray(settings.spellcheckLang) : []; electron.session.defaultSession.setSpellCheckerLanguages(safeLanguages); + window.webContents.session.setSpellCheckerLanguages(safeLanguages); // tslint:disable-next-line:no-floating-promises ElectronBlocker.fromLists(