Reconnect management for ad manager; Hide/show non-matching ads; throttle profile API queries

This commit is contained in:
Mr. Stallion 2019-10-21 17:55:05 -05:00
parent c8f0ffddd5
commit 727b3d5712
11 changed files with 139 additions and 9 deletions

View File

@ -19,7 +19,7 @@
</div>
<div v-else-if="results" class="results">
<h4>{{l('characterSearch.results')}}</h4>
<div v-for="character in results" :key="character.name" :class="'status-' + character.status">
<div v-for="character in results" :key="character.name" class="search-result" :class="'status-' + character.status">
<template v-if="character.status === 'looking'" v-once>
<img :src="characterImage(character.name)" v-if="showAvatars"/>
<user :character="character" :showStatus="true" :match="true"></user>
@ -243,6 +243,9 @@
.user-view {
display: block;
}
& > .search-result {
clear: both;
}
& > .status-looking {
margin-bottom: 5px;
min-height: 50px;

View File

@ -128,6 +128,11 @@
if(this.connected) core.notifications.playSound('logout');
this.connected = false;
this.connecting = false;
if (!isReconnect) {
core.conversations.channelConversations.forEach((chanConv) => chanConv.adManager.stop());
}
document.title = l('title');
});
core.connection.onEvent('connecting', async() => {

View File

@ -55,6 +55,10 @@
<a :class="isChannel(conversation) ? {active: conversation.mode == mode, disabled: conversation.channel.mode != 'both'} : undefined"
class="nav-link" href="#" @click.prevent="setMode(mode)">{{l('channel.mode.' + mode)}}</a>
</li>
<li>
<a @click.prevent="toggleNonMatchingAds()" :class="{active: showNonMatchingAds, disabled: !showNonMatchingAds}" v-show="(conversation.mode == 'both' || conversation.mode == 'ads')"
class="nav-link" href="#">Non-Matching</a>
</li>
</ul>
</div>
<div style="z-index:5;position:absolute;left:0;right:0;max-height:60%;overflow:auto"
@ -88,8 +92,8 @@
<a class="btn btn-sm btn-outline-primary renew-autoposts" @click="renewAutoPosting()">{{l('admgr.renew')}}</a>
</div>
<div class="border-top messages" :class="isChannel(conversation) ? 'messages-' + conversation.mode : undefined" ref="messages"
@scroll="onMessagesScroll" style="flex:1;overflow:auto;margin-top:2px">
<div class="border-top messages" :class="getMessageWrapperClasses()" ref="messages"
@scroll="onMessagesScroll" style="flex:1;overflow:auto;margin-top:2px">
<template v-for="message in messages">
<message-view :message="message" :channel="isChannel(conversation) ? conversation.channel : undefined" :key="message.id"
:classes="message == conversation.lastRead ? 'last-read' : ''">
@ -209,6 +213,7 @@
adAutoPostNextAd: string | null = null;
isChannel = Conversation.isChannel;
isPrivate = Conversation.isPrivate;
showNonMatchingAds = true;
@Hook('mounted')
mounted(): void {
@ -389,6 +394,27 @@
if(conv.channel.mode === 'both') conv.mode = mode;
}
toggleNonMatchingAds(): void {
this.showNonMatchingAds = !this.showNonMatchingAds;
}
/* tslint:disable */
getMessageWrapperClasses(): any {
if (!this.isChannel(this.conversation)) {
return {};
}
const conv = <Conversation.ChannelConversation>this.conversation;
const classes:any = {};
classes['messages-' + conv.mode] = true;
classes['hide-non-matching'] = !this.showNonMatchingAds;
return classes;
}
acceptReport(sfc: {callid: number}): void {
core.connection.send('SFC', {action: 'confirm', callid: sfc.callid});
}
@ -682,6 +708,13 @@
}
}
.messages.hide-non-matching .message.message-score {
&.mismatch {
display: none;
}
}
.message {
&.message-event {
font-size: 85%;

View File

@ -19,6 +19,31 @@
</template>
<script lang="ts">
/*
[url=https://giphy.com/gifs/arianagrande-ariana-grande-thank-u-next-you-uldtLAK6tSOKP5PWw3]Test[/url]
[url=https://media1.tenor.com/images/097ee180965dd336f470b77d064f198f/tenor.gif?itemid=13664909]Test[/url]
[url=https://tenor.com/view/thank-unext-ariana-grande-thank-you-next-wink-winking-gif-13664909]Test[/url]
[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=http://gfycatporn.com/deepthroat.php]Test[/url]
[url=https://imgur.com/LmEyXEM]Test[/url]
[url=https://static1.e621.net/data/6d/bf/6dbf0c369793dbb5a53d9814c17861eb.webm]Test[/url]
[url=https://www.youtube.com/watch?v=_52zdiltkRM]Test[/url]
[url=https://e621.net/post/show/1672753/2018-anthro-antlers-balls-bed-big_penis-black_hair]Test[/url]
[url=https://rule34.xxx/index.php?page=post&s=view&id=3213191]Test[/url]
*/
import * as _ from 'lodash';
import {Component, Hook} from '@f-list/vue-ts';
import Vue from 'vue';

View File

@ -1,12 +1,20 @@
import core from './core';
import { Conversation } from './interfaces';
import Timer = NodeJS.Timer;
import throat from 'throat';
const adManagerThroat = throat(1);
export class AdManager {
static readonly POSTING_PERIOD = 3 * 60 * 60 * 1000;
static readonly START_VARIANCE = 3 * 60 * 1000;
static readonly POST_VARIANCE = 8 * 60 * 1000;
static readonly POST_DELAY = 1.5 * 60 * 1000;
static readonly POST_MANUAL_THRESHOLD = 5 * 1000; // don't post anything within 5 seconds of other posts
private conversation: Conversation;
private adIndex = 0;
@ -24,6 +32,29 @@ export class AdManager {
return this.active;
}
// tslint:disable-next-line
private async delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// This makes sure there is a 5s delay between channel posts
private async sendAdToChannel(msg: string, conv: Conversation.ChannelConversation): Promise<void> {
await adManagerThroat(
async() => {
const delta = Date.now() - core.cache.getLastPost().getTime();
if ((delta > 0) && (delta < AdManager.POST_MANUAL_THRESHOLD)) {
await this.delay(delta);
}
await conv.sendAd(msg);
}
);
}
private async sendNextPost(): Promise<void> {
const msg = this.getNextAd();
@ -34,7 +65,7 @@ export class AdManager {
const chanConv = (<Conversation.ChannelConversation>this.conversation);
await chanConv.sendAd(msg);
await this.sendAdToChannel(msg, chanConv);
// post next ad every 12 - 22 minutes
const nextInMs = Math.max(0, (chanConv.nextAd - Date.now())) +

View File

@ -339,6 +339,8 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv
if(isAd)
this.nextAd = Date.now() + core.connection.vars.lfrp_flood * 1000;
else this.clearText();
core.cache.timeLastPost();
}
async sendAd(text: string): Promise<void> {

View File

@ -30,11 +30,22 @@ const parserSettings = {
};
import throat from 'throat';
// Throttle queries so that only two profile requests can run at any given time
const characterDataThroat = throat(2);
// tslint:disable-next-line: ban-ts-ignore
// @ts-ignore
async function characterData(name: string | undefined, id: number = -1, skipEvent: boolean = false): Promise<Character> {
// console.log('CharacterDataquery', name);
return characterDataThroat(async() => executeCharacterData(name, id, skipEvent));
}
// tslint:disable-next-line: ban-ts-ignore
// @ts-ignore
async function executeCharacterData(name: string | undefined, id: number = -1, skipEvent: boolean = false): Promise<Character> {
const data = await core.connection.queryApi<CharacterInfo & {
badges: string[]
customs_first: boolean

View File

@ -37,6 +37,16 @@ export class CacheManager {
protected profileStore?: IndexedStore;
protected lastPost: Date = new Date();
timeLastPost(): void {
this.lastPost = new Date();
}
getLastPost(): Date {
return this.lastPost;
}
async queueForFetching(name: string, skipCacheCheck: boolean = false): Promise<void> {
if (!skipCacheCheck) {
@ -65,7 +75,8 @@ export class CacheManager {
// console.log('AddProfileForFetching', name, this.queue.length);
}
async fetchProfile(name: string): Promise<void> {
async fetchProfile(name: string): Promise<ComplexCharacter | null> {
try {
await methods.fieldsGet();
@ -74,8 +85,12 @@ export class CacheManager {
const r = await this.profileCache.register(c);
this.updateAdScoringForProfile(c, r.matchScore);
return c;
} catch (err) {
console.error('Failed to fetch profile for cache', name, err);
return null;
}
}

View File

@ -31,6 +31,7 @@
"sass-loader": "^7.1.0",
"sortablejs": "^1.8.0-rc1",
"style-loader": "^0.23.1",
"throat": "^5.0.0",
"ts-loader": "^5.3.1",
"tslib": "^1.9.3",
"tslint": "^5.12.0",

View File

@ -14,6 +14,7 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Ads view
* Highlight ads from characters most interesting to you
* Hide obviously unmatching ads
* View characters' recent ads
* Ad auto-posting
* Manage channel ad settings via "Tab Settings"
@ -34,6 +35,7 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Cleaner presentation for the side bar details (age, etc.), sorted in most relevant order
* Less informative side bar details (views, contact) are separated and shown in a less prominent way
* Cleaner guestbook view
* Profiles, images, guestbook posts, and groups are cached for faster view
* Character Search
* Search results are sorted based on match scores
* Display match score in search results
@ -59,13 +61,10 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Split chat view
* Improvements to log browsing
* Fix broken BBCode, such as `[big]` in character profiles
* Which channels my chart partner is on?
* Reposition ad settings and toggle
* Cache image list, guestbook pages
* Save character status messages
* Bug: Invalid Ticket
* Bug: Posting on the same second
* Bug: Images tab count is off
* Logout cancels auto-ads

View File

@ -6178,6 +6178,11 @@ terser@^3.8.1:
source-map "~0.6.1"
source-map-support "~0.5.6"
throat@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
throttleit@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf"