diff --git a/bbcode/Editor.vue b/bbcode/Editor.vue
index 994d7e6..e2cf97a 100644
--- a/bbcode/Editor.vue
+++ b/bbcode/Editor.vue
@@ -58,8 +58,8 @@
             this.parser = new CoreBBCodeParser();
             this.resizeListener = () => {
                 const styles = getComputedStyle(this.element);
-                this.maxHeight = parseInt(styles.maxHeight!, 10) || 250;
-                this.minHeight = parseInt(styles.minHeight!, 10) || 60;
+                this.maxHeight = parseInt(styles.maxHeight, 10) || 250;
+                this.minHeight = parseInt(styles.minHeight, 10) || 60;
             };
         }
 
@@ -67,8 +67,8 @@
         mounted(): void {
             this.element = <HTMLTextAreaElement>this.$refs['input'];
             const styles = getComputedStyle(this.element);
-            this.maxHeight = parseInt(styles.maxHeight!, 10) || 250;
-            this.minHeight = parseInt(styles.minHeight!, 10) || 60;
+            this.maxHeight = parseInt(styles.maxHeight, 10) || 250;
+            this.minHeight = parseInt(styles.minHeight, 10) || 60;
             setInterval(() => {
                 if(Date.now() - this.lastInput >= 500 && this.text !== this.undoStack[0] && this.undoIndex === 0) {
                     if(this.undoStack.length >= 30) this.undoStack.pop();
@@ -164,8 +164,10 @@
             // Allow emitted variations for custom buttons.
             this.$once('insert', (startText: string, endText: string) => this.applyText(startText, endText));
             // noinspection TypeScriptValidateTypes
-            if(button.handler !== undefined)
+            if(button.handler !== undefined) {
+                // tslint:ignore-next-line:no-any
                 return button.handler.call(this as any, this);
+            }
             if(button.startText === undefined)
                 button.startText = `[${button.tag}]`;
             if(button.endText === undefined)
diff --git a/bbcode/parser.ts b/bbcode/parser.ts
index b0c6c60..8b9322f 100644
--- a/bbcode/parser.ts
+++ b/bbcode/parser.ts
@@ -192,7 +192,7 @@ export class BBCodeParser {
                     }
                     if(!selfAllowed) return mark - 1;
                     if(isAllowed(tagKey))
-                         this.warning(`Unexpected closing ${tagKey} tag. Needed ${self} tag instead.`);
+                         this.warning(`Unexpected closing ${tagKey} tag. Needed ${self.tag} tag instead.`);
                 } else if(isAllowed(tagKey)) this.warning(`Found closing ${tagKey} tag that was never opened.`);
             }
         }
@@ -203,4 +203,4 @@ export class BBCodeParser {
         if(self !== undefined) this.warning('Automatically closing tag at end of input.');
         return mark;
     }
-}
\ No newline at end of file
+}
diff --git a/chat/AdView.vue b/chat/AdView.vue
index 6f9f508..d8d592f 100644
--- a/chat/AdView.vue
+++ b/chat/AdView.vue
@@ -63,11 +63,13 @@ export default class AdView extends CustomDialog {
 
     async onOpen(): Promise<void> {
         // empty
+        return;
     }
 
 
     async onClose(): Promise<void> {
         // empty
+        return;
     }
 }
 </script>
diff --git a/chat/ImagePreview.vue b/chat/ImagePreview.vue
index 0befc8f..83c101c 100644
--- a/chat/ImagePreview.vue
+++ b/chat/ImagePreview.vue
@@ -100,7 +100,7 @@
         abstract show(url: string): void;
         abstract hide(): void;
         abstract match(domainName: string): boolean;
-        abstract renderStyle(): any;
+        abstract renderStyle(): Record<string, any>;
 
         constructor(parent: ImagePreview) {
             if (!parent) {
@@ -143,10 +143,10 @@
         }
 
 
-        renderStyle(): any {
+        renderStyle(): Record<string, any> {
             return this.isVisible()
                 ? { backgroundImage: `url(${this.getUrl()})`, display: 'block' }
-                : { display: 'none' }
+                : { display: 'none' };
         }
     }
 
@@ -180,7 +180,7 @@
         }
 
 
-        setRatio(ratio: number) {
+        setRatio(ratio: number): void {
             this.ratio = ratio;
         }
 
@@ -223,6 +223,7 @@
                     this.ratio = null;
 
                     // Broken promise chain on purpose
+                    // tslint:disable-next-line:no-floating-promises
                     this.urlMutator.resolve(url)
                         .then((finalUrl: string) => webview.loadURL(finalUrl));
                 }
@@ -238,7 +239,7 @@
         }
 
 
-        determineScalingRatio(): any {
+        determineScalingRatio(): Record<string, any> {
             // ratio = width / height
             const ratio = this.ratio;
 
@@ -256,23 +257,23 @@
                 const presumedWidth = maxWidth;
                 const presumedHeight = presumedWidth / ratio;
 
+                return {
+                    width: `${presumedWidth}px`,
+                    height: `${presumedHeight}px`
+                };
+            // tslint:disable-next-line:unnecessary-else
+            } else {
+                const presumedHeight = maxHeight;
+                const presumedWidth = presumedHeight * ratio;
 
                 return {
                     width: `${presumedWidth}px`,
                     height: `${presumedHeight}px`
-                }
-            }
-
-            const presumedHeight = maxHeight;
-            const presumedWidth = presumedHeight * ratio;
-
-            return {
-                width: `${presumedWidth}px`,
-                height: `${presumedHeight}px`
+                };
             }
         }
 
-        renderStyle(): any {
+        renderStyle(): Record<string, any> {
             return this.isVisible()
                 ? _.merge({ display: 'flex' }, this.determineScalingRatio())
                 : { display: 'none' };
@@ -298,8 +299,8 @@
 
         jsMutator = new ImagePreviewMutator(this.debug);
 
-        externalPreviewStyle = {};
-        localPreviewStyle = {};
+        externalPreviewStyle: Record<string, any> = {};
+        localPreviewStyle: Record<string, any> = {};
 
 
         private interval: Timer | null = null;
@@ -429,7 +430,8 @@
                         console.log('ImagePreview ipc-message', event);
 
                     if (event.channel === 'webview.img') {
-                        this.updatePreviewSize(event.args[0], event.args[1]);
+                        // tslint:disable-next-line:no-unsafe-any
+                        this.updatePreviewSize(parseInt(event.args[0], 10), parseInt(event.args[1], 10));
                     }
                 }
             );
@@ -470,17 +472,23 @@
                         this.hide();
                     }
                 },
-                10
+                50
             );
         }
 
 
         reRenderStyles(): void {
+            // tslint:disable-next-line:no-unsafe-any
             this.externalPreviewStyle = this.externalPreviewHelper.renderStyle();
+            // 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)));
+                console.log(
+                    'ImagePreview: reRenderStyles', 'external',
+                    JSON.parse(JSON.stringify(this.externalPreviewStyle)),
+                    'local', JSON.parse(JSON.stringify(this.localPreviewStyle))
+                );
             }
         }
 
@@ -616,7 +624,7 @@
             // -- you actually have to pause on it
             // tslint:disable-next-line no-unnecessary-type-assertion
             this.interval = setTimeout(
-                async () => {
+                () => {
                     if (this.debug)
                         console.log('ImagePreview: show.timeout', this.url);
 
@@ -628,11 +636,13 @@
                         ? this.externalPreviewHelper.show(this.url as string)
                         : this.externalPreviewHelper.hide();
 
+                    this.interval = null;
                     this.visible = true;
                     this.visibleSince = Date.now();
 
                     this.initialCursorPosition = screen.getCursorScreenPoint();
 
+
                     this.reRenderStyles();
                 },
                 due
@@ -721,7 +731,7 @@
             return this.$refs.imagePreviewExt as WebviewTag;
         }
 
-        reset() {
+        reset(): void {
             this.externalPreviewHelper = new ExternalImagePreviewHelper(this);
             this.localPreviewHelper = new LocalImagePreviewHelper(this);
 
diff --git a/chat/common.ts b/chat/common.ts
index d241a91..2f70686 100644
--- a/chat/common.ts
+++ b/chat/common.ts
@@ -2,15 +2,15 @@ import {isToday} from 'date-fns';
 import {Keys} from '../keys';
 import {Character, Conversation, Settings as ISettings} from './interfaces';
 
-export function profileLink(this: void | never, character: string): string {
+export function profileLink(this: any | never, character: string): string {
     return `https://www.f-list.net/c/${character}`;
 }
 
-export function characterImage(this: void | never, character: string): string {
+export function characterImage(this: any | never, character: string): string {
     return `https://static.f-list.net/images/avatar/${character.toLowerCase()}.png`;
 }
 
-export function getByteLength(this: void | never, str: string): number {
+export function getByteLength(this: any | never, str: string): number {
     let byteLen = 0;
     for(let i = 0; i < str.length; i++) {
         let c = str.charCodeAt(i);
@@ -67,12 +67,12 @@ function pad(num: number): string | number {
     return num < 10 ? `0${num}` : num;
 }
 
-export function formatTime(this: void | never, date: Date, noDate: boolean = false): string {
+export function formatTime(this: any | never, date: Date, noDate: boolean = false): string {
     if(!noDate && isToday(date)) return `${pad(date.getHours())}:${pad(date.getMinutes())}`;
     return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
 }
 
-export function messageToString(this: void | never, msg: Conversation.Message, timeFormatter: (date: Date) => string = formatTime): string {
+export function messageToString(this: any | never, msg: Conversation.Message, timeFormatter: (date: Date) => string = formatTime): string {
     let text = `[${timeFormatter(msg.time)}] `;
     if(msg.type !== Conversation.Message.Type.Event)
         text += (msg.type === Conversation.Message.Type.Action ? '*' : '') + msg.sender.name +
@@ -114,4 +114,4 @@ export class EventMessage implements Conversation.EventMessage {
 
     constructor(readonly text: string, readonly time: Date = new Date()) {
     }
-}
\ No newline at end of file
+}
diff --git a/chat/conversations.ts b/chat/conversations.ts
index ef2cce0..5fa5bd2 100644
--- a/chat/conversations.ts
+++ b/chat/conversations.ts
@@ -10,7 +10,7 @@ import {CommandContext, isAction, isCommand, isWarn, parse as parseCommand} from
 import MessageType = Interfaces.Message.Type;
 import {EventBus} from '../chat/event-bus';
 
-function createMessage(this: void, type: MessageType, sender: Character, text: string, time?: Date): Message {
+function createMessage(this: any, type: MessageType, sender: Character, text: string, time?: Date): Message {
     if(type === MessageType.Message && isAction(text)) {
         type = MessageType.Action;
         text = text.substr(text.charAt(4) === ' ' ? 4 : 3);
@@ -18,7 +18,7 @@ function createMessage(this: void, type: MessageType, sender: Character, text: s
     return new Message(type, sender, text, time);
 }
 
-function safeAddMessage(this: void, messages: Interfaces.Message[], message: Interfaces.Message, max: number): void {
+function safeAddMessage(this: any, messages: Interfaces.Message[], message: Interfaces.Message, max: number): void {
     if(messages.length >= max) messages.shift();
     messages.push(message);
 }
@@ -123,7 +123,7 @@ abstract class Conversation implements Interfaces.Conversation {
         safeAddMessage(this.messages, message, this.maxMessages);
     }
 
-    protected abstract doSend(): Promise<void> | void;
+    protected abstract doSend(): void | Promise<void>;
 }
 
 class PrivateConversation extends Conversation implements Interfaces.PrivateConversation {
@@ -470,17 +470,17 @@ class State implements Interfaces.State {
 
 let state: State;
 
-async function addEventMessage(this: void, message: Interfaces.Message): Promise<void> {
+async function addEventMessage(this: any, message: Interfaces.Message): Promise<void> {
     await state.consoleTab.addMessage(message);
     if(core.state.settings.eventMessages && state.selectedConversation !== state.consoleTab)
         await state.selectedConversation.addMessage(message);
 }
 
-function isOfInterest(this: void, character: Character): boolean {
+function isOfInterest(this: any, character: Character): boolean {
     return character.isFriend || character.isBookmarked || state.privateMap[character.name.toLowerCase()] !== undefined;
 }
 
-export default function(this: void): Interfaces.State {
+export default function(this: any): Interfaces.State {
     state = new State();
     window.addEventListener('focus', () => {
         state.windowFocused = true;
diff --git a/chat/core.ts b/chat/core.ts
index 3c533c1..40efa21 100644
--- a/chat/core.ts
+++ b/chat/core.ts
@@ -79,7 +79,7 @@ const data = {
     }
 };
 
-export function init(this: void, connection: Connection, logsClass: new() => Logs, settingsClass: new() => Settings.Store,
+export function init(this: any, connection: Connection, logsClass: new() => Logs, settingsClass: new() => Settings.Store,
                      notificationsClass: new() => Notifications): void {
     data.connection = connection;
     data.logs = new logsClass();
diff --git a/chat/image-preview-mutator.ts b/chat/image-preview-mutator.ts
index 45847ea..bf4d4a5 100644
--- a/chat/image-preview-mutator.ts
+++ b/chat/image-preview-mutator.ts
@@ -209,7 +209,7 @@ export class ImagePreviewMutator {
                 selected = selected.concat(selectedElements);
             }
 
-            ${this.debug ? `console.log('Selector', '${elSelector}'); console.log('Selected', selected);` : ''}
+            ${this.debug ? `console.log('Selector', '${elSelector.toString()}'); console.log('Selected', selected);` : ''}
 
             const img = selected.shift();
 
diff --git a/electron/Index.vue b/electron/Index.vue
index 6855474..22104e6 100644
--- a/electron/Index.vue
+++ b/electron/Index.vue
@@ -289,7 +289,7 @@
         }
 
         async openProfileInBrowser(): Promise<void> {
-            electron.remote.shell.openExternal(`https://www.f-list.net/c/${this.profileName}`);
+            await electron.remote.shell.openExternal(`https://www.f-list.net/c/${this.profileName}`);
 
             // tslint:disable-next-line: no-any no-unsafe-any
             (this.$refs.profileViewer as any).hide();
@@ -315,7 +315,7 @@
 
         get styling(): string {
             try {
-                return `<style>${fs.readFileSync(path.join(__dirname, `themes/${this.settings.theme}.css`))}</style>`;
+                return `<style>${fs.readFileSync(path.join(__dirname, `themes/${this.settings.theme}.css`), 'utf8').toString()}</style>`;
             } catch(e) {
                 if((<Error & {code: string}>e).code === 'ENOENT' && this.settings.theme !== 'default') {
                     this.settings.theme = 'default';
diff --git a/electron/Window.vue b/electron/Window.vue
index f03514e..b5374bf 100644
--- a/electron/Window.vue
+++ b/electron/Window.vue
@@ -168,7 +168,7 @@
 
         get styling(): string {
             try {
-                return `<style>${fs.readFileSync(path.join(__dirname, `themes/${this.settings.theme}.css`))}</style>`;
+                return `<style>${fs.readFileSync(path.join(__dirname, `themes/${this.settings.theme}.css`, 'utf8')).toString()}</style>`;
             } catch(e) {
                 if((<Error & {code: string}>e).code === 'ENOENT' && this.settings.theme !== 'default') {
                     this.settings.theme = 'default';
diff --git a/learn/ad-cache.ts b/learn/ad-cache.ts
index f3e2cf2..8fd4721 100644
--- a/learn/ad-cache.ts
+++ b/learn/ad-cache.ts
@@ -61,6 +61,6 @@ export class AdCache<RecordType extends AdCacheRecord = AdCacheRecord> extends C
             return;
         }
 
-        this.cache[k] = new AdCacheRecord(name, ad) as RecordType;
+        this.cache[k] = new AdCacheRecord(ad.name, ad) as RecordType;
     }
 }
diff --git a/learn/channel-conversation-cache.ts b/learn/channel-conversation-cache.ts
index 6385848..d2dd478 100644
--- a/learn/channel-conversation-cache.ts
+++ b/learn/channel-conversation-cache.ts
@@ -27,7 +27,7 @@ export class ChannelConversationCache extends AdCache<ChannelCacheRecord> {
             return;
         }
 
-        this.cache[k] = new ChannelCacheRecord(name, ad);
+        this.cache[k] = new ChannelCacheRecord(ad.name, ad);
     }
 
 }
diff --git a/learn/matcher.ts b/learn/matcher.ts
index b91ac14..b39553e 100644
--- a/learn/matcher.ts
+++ b/learn/matcher.ts
@@ -664,7 +664,9 @@ export class Matcher {
                 return new Score(Scoring.MISMATCH, 'No <span>dominants</span>');
 
             return new Score(Scoring.WEAK_MISMATCH, 'Hesitant on <span>dominants</span>');
-        } else if ((yourSubDomRole === SubDomRole.AlwaysSubmissive) || (yourSubDomRole === SubDomRole.UsuallySubmissive)) {
+        }
+
+        if ((yourSubDomRole === SubDomRole.AlwaysSubmissive) || (yourSubDomRole === SubDomRole.UsuallySubmissive)) {
             if (theirSubDomRole === SubDomRole.Switch)
                 return new Score(Scoring.WEAK_MATCH, `Likes <span>switches</span>`);
 
@@ -708,7 +710,7 @@ export class Matcher {
     }
 
     static getTagValueList(tagId: number, c: Character): number | null {
-        const t = this.getTagValue(tagId, c);
+        const t = Matcher.getTagValue(tagId, c);
 
         if ((!t) || (!t.list))
             return null;
@@ -747,11 +749,11 @@ export class Matcher {
         if (!(gender in genderKinkMapping))
             return null;
 
-        return this.getKinkPreference(c, genderKinkMapping[gender]);
+        return Matcher.getKinkPreference(c, genderKinkMapping[gender]);
     }
 
     static getKinkSpeciesPreference(c: Character, species: Species): KinkPreference | null {
-        return this.getKinkPreference(c, species);
+        return Matcher.getKinkPreference(c, species);
     }
 
     static has(c: Character, kinkId: Kink): boolean {
@@ -770,12 +772,12 @@ export class Matcher {
     }
 
     static isAnthro(c: Character): boolean | null {
-        const bodyTypeId = this.getTagValueList(TagId.BodyType, c);
+        const bodyTypeId = Matcher.getTagValueList(TagId.BodyType, c);
 
         if (bodyTypeId === BodyType.Anthro)
             return true;
 
-        const speciesId = this.species(c);
+        const speciesId = Matcher.species(c);
 
         if (!speciesId)
             return null;
@@ -784,12 +786,12 @@ export class Matcher {
     }
 
     static isHuman(c: Character): boolean | null {
-        const bodyTypeId = this.getTagValueList(TagId.BodyType, c);
+        const bodyTypeId = Matcher.getTagValueList(TagId.BodyType, c);
 
         if (bodyTypeId === BodyType.Human)
             return true;
 
-        const speciesId = this.species(c);
+        const speciesId = Matcher.species(c);
 
         return (speciesId === Species.Human);
     }
@@ -798,7 +800,7 @@ export class Matcher {
         let foundSpeciesId: Species | null = null;
         let match = '';
 
-        const mySpecies = this.getTagValue(TagId.Species, c);
+        const mySpecies = Matcher.getTagValue(TagId.Species, c);
 
         if ((!mySpecies) || (!mySpecies.string))
             return Species.Human; // best guess
diff --git a/learn/profile-cache.ts b/learn/profile-cache.ts
index 72166a4..9dbbdcc 100644
--- a/learn/profile-cache.ts
+++ b/learn/profile-cache.ts
@@ -58,10 +58,10 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
 
         if (key in this.cache) {
             return this.cache[key];
-        } else {
-            if ((!this.store) || (skipStore)) {
-                return null;
-            }
+        }
+
+        if ((!this.store) || (skipStore)) {
+            return null;
         }
 
         const pd = await this.store.getProfile(name);
diff --git a/site/character_page/match-report.vue b/site/character_page/match-report.vue
index 92f5728..aefcc51 100644
--- a/site/character_page/match-report.vue
+++ b/site/character_page/match-report.vue
@@ -87,5 +87,4 @@
             this.isMinimized = !this.isMinimized;
         }
     }
-
 </script>
diff --git a/tslint.json b/tslint.json
index 595d45d..3b1884e 100644
--- a/tslint.json
+++ b/tslint.json
@@ -62,6 +62,7 @@
     "increment-decrement": false,
     "interface-name": false,
     "interface-over-type-literal": false,
+    "invalid-void": false,
     "linebreak-style": false,
     "max-classes-per-file": false,
     "max-line-length": [
@@ -75,14 +76,18 @@
     "member-ordering": false,
     "newline-before-return": false,
     "newline-per-chained-call": false,
+    "no-any": false,
     "no-angle-bracket-type-assertion": false,
+    "no-async-without-await": false,
     "no-bitwise": false,
     "no-conditional-assignment": false,
     "no-consecutive-blank-lines": [true, 2],
     "no-console": false,
     "no-default-export": false,
     "no-default-import": false,
+    "no-duplicate-imports": false,
     "no-dynamic-delete": false,
+    "no-for-in": false,
     "no-floating-promises": [true, "AxiosPromise"],
     "no-implicit-dependencies": false,
     "no-import-side-effect": [
@@ -99,6 +104,7 @@
     "no-parameter-reassignment": false,
     "no-string-literal": false,
     "no-submodule-imports": [true, "lodash"],
+    "no-unnecessary-type-assertion": false,
     "no-unused-variable": false,
     "no-void-expression": false,
     //covered by no-var-keyword and compiler