This commit is contained in:
Mr. Stallion 2024-01-28 17:21:09 -08:00
parent 2a0a0d3761
commit 1a2cc1e6f0
10 changed files with 129 additions and 22 deletions

View File

@ -1,5 +1,11 @@
# Changelog # Changelog
## Canary
* Added high-quality portrait check to Profile Helper
* Added option for disabling high-quality portraits
* Added cleaner `[quote][/quote]` style for profiles
* Fixed Redgifs previews (again)
## 1.26.0 ## 1.26.0
* High-quality portraits * High-quality portraits
* Override the default 100x100px portrait with a high-resolution image * Override the default 100x100px portrait with a high-resolution image
@ -18,7 +24,7 @@
* High-quality portraits are only visible to other F-Chat Rising users; users on other clients will see your regular portrait. * High-quality portraits are only visible to other F-Chat Rising users; users on other clients will see your regular portrait.
* If your image is not a square, [you're gonna have a bad time](https://www.youtube.com/watch?v=6Ls5j5iz2eA). * If your image is not a square, [you're gonna have a bad time](https://www.youtube.com/watch?v=6Ls5j5iz2eA).
* [YiffBot 4000](https://www.f-list.net/c/YiffBot%204000) integration * [YiffBot 4000](https://www.f-list.net/c/YiffBot%204000) integration
* Fix "select/unselect all" behavior in Post Ads (credit: [@FatCatClient](https://github.com/FatCatClient)) * Fixed "select/unselect all" behavior in Post Ads (credit: [@FatCatClient](https://github.com/FatCatClient))
* Extended emoji support (credit: [@FatCatClient](https://github.com/FatCatClient)) * Extended emoji support (credit: [@FatCatClient](https://github.com/FatCatClient))
## 1.25.1 ## 1.25.1

View File

@ -151,8 +151,8 @@ export default class EIconSelector extends CustomDialog {
case 'symbols': case 'symbols':
return ['loveslove', 'pimpdcash', 'pls stop', 'paw2', 'gender-female', 'gender-male', 'gendershemale', 'gender-cuntboy', 'gender-mherm', return ['loveslove', 'pimpdcash', 'pls stop', 'paw2', 'gender-female', 'gender-male', 'gendershemale', 'gender-cuntboy', 'gender-mherm',
'gender-transgender', 'usflag', 'europeflag', 'lgbt', 'transflag', 'sunnyuhsuperlove', 'discovered', 'thbun', 'gender-transgender', 'usflag', 'europeflag', 'lgbt', 'transflag', 'sunnyuhsuperlove', 'discovered',
'goldcoin1', 'star', 'full moon', 'sunshine', 'pinetree', 'carrots1', 'smashletter', 'chemicalscience', 'ghostbuster', 'goldcoin1', 'star', 'full moon', 'sunshine', 'pinetree', 'carrots1', 'smashletter', 'ghostbuster',
'cuckquean', 'goldendicegmgolddicegif', 'pentagramo', 'sexsymbol', 'idnd1', 'instagram', 'twitterlogo', 'snapchaticon', 'cuckquean', 'goldendicegmgolddicegif', 'pentagramo', 'sexsymbol', 'idnd1', 'instagram', 'twitterlogo', 'snapchaticon',
'tiktok', 'twitchlogo', 'discord', 'uber', 'google', 'nvidia', 'playstation', 'tiktok', 'twitchlogo', 'discord', 'uber', 'google', 'nvidia', 'playstation',
'suitclubs', 'suitdiamonds', 'suithearts', 'suitspades', 'chainscuffs', 'suitclubs', 'suitdiamonds', 'suithearts', 'suitspades', 'chainscuffs',
@ -164,11 +164,11 @@ export default class EIconSelector extends CustomDialog {
case 'bubbles': case 'bubbles':
return ['takemetohornyjail', 'notcashmoney', 'lickme', 'iacs', 'imahugeslut', 'fuckyouasshole', 'bubblecute', 'pat my head', return ['takemetohornyjail', 'notcashmoney', 'lickme', 'iacs', 'imahugeslut', 'fuckyouasshole', 'bubblecute', 'pat my head',
'chorse', 'knotslutbubble', 'toofuckinghot', 'pbmr', 'imabimbo', 'dicefuck', 'ciaig', 'horseslut', 'fatdick', 'tomboypussy', 'chorse', 'knotslutbubble', 'toofuckinghot', 'pbmr', 'imabimbo', 'dicefuck', 'ciaig', 'horseslut', 'fatdick', 'tomboypussy',
'breakthesubs', 'fuckingnya', 'iltclion', 'suckfuckobey', 'shemale', 'breedmaster', 'imastepfordwife', 'prier ahegao', 'breakthesubs', 'fuckingnya', 'iltclion', 'suckfuckobey', 'shemale', 'breedmaster', 'imastepfordwife', 'ahegaoalert2',
'buttslutbb', 'notgayoranything', 'onlyfans', 'horsecockneed', 'crimes', 'breed143', 'nagagross', 'willrim', 'muskslut', 'buttslutbb', 'notgayoranything', 'onlyfans', 'horsecockneed', 'crimes', 'breed143', 'nagagross', 'willrim', 'muskslut',
'4lewdbubble', 'shimathatlewd', 'hypnosiss', 'imahypnoslut', 'sheepsass2', 'imahugeslut', 'notahealslut', 'ratedmilf', '4lewdbubble', 'shimathatlewd', 'hypnosiss', 'imahypnoslut', 'sheepsass2', 'imahugeslut', 'notahealslut', 'ratedmilf',
'ratedstud', 'ratedslut', '5lewdbubble', 'xarcuminme', 'xarcumonme', 'choke me', 'iamgoingtopunchyou', 'snapmychoker', 'ratedstud', 'ratedslut', '5lewdbubble', 'xarcuminme', 'xarcumonme', 'choke me', 'iamgoingtopunchyou', 'snapmychoker',
'rude1', 'fuckbun', 'iamindanger', 'fuckingelves', 'sluttery', 'helpicantstopsuckingcocks', 'talkpooltoy', 'thatskindahot', 'ygod', 'rude1', 'fuckbun', 'iamindanger', 'elves', 'sluttery', 'helpicantstopsuckingcocks', 'talkpooltoy', 'thatskindahot', 'ygod',
'simpbait', 'eyesuphere', 'fuckpiggy', 'peggable2', 'sydeanothere', 'nothingcan', 'pawslut', 'stupidboys', 'corpsestare-', 'simpbait', 'eyesuphere', 'fuckpiggy', 'peggable2', 'sydeanothere', 'nothingcan', 'pawslut', 'stupidboys', 'corpsestare-',
'dinnersex', 'plappening', 'fallout-standby', 'inbagg', 'request denied', 'goodboy0', 'goodending', 'milky2', 'howbadcanibe', 'dinnersex', 'plappening', 'fallout-standby', 'inbagg', 'request denied', 'goodboy0', 'goodending', 'milky2', 'howbadcanibe',
'gwanna', 'spitinmouth', 'bathwater']; 'gwanna', 'spitinmouth', 'bathwater'];
@ -178,15 +178,15 @@ export default class EIconSelector extends CustomDialog {
'rorobutt2', 'fingerlick', 'lapgrind', 'jackthighs', 'a condom', 'wolf abs', 'musclefuck2', 'verobutt3', 'bumsqueeze', 'rorobutt2', 'fingerlick', 'lapgrind', 'jackthighs', 'a condom', 'wolf abs', 'musclefuck2', 'verobutt3', 'bumsqueeze',
'realahegao4', 'influencerhater', 'assfucker', 'gagged2', 'ballsack3', 'fingerblast3', 'sloppy01', 'sybian', 'realahegao4', 'influencerhater', 'assfucker', 'gagged2', 'ballsack3', 'fingerblast3', 'sloppy01', 'sybian',
'floppyhorsecock', 'blackshem1', 'fingersucc', 'vullylick', 'fingersucc', 'cmontakeit', 'jessi flash', 'poju-butt', 'floppyhorsecock', 'blackshem1', 'fingersucc', 'vullylick', 'fingersucc', 'cmontakeit', 'jessi flash', 'poju-butt',
'cheegrope2', 'patr1', 'ahega01 2', 'handjob1nuke', 'harmanfingers', 'hermione1', '2buttw1', 'dropsqueeze', 'cheegrope2', 'patr1', 'ahega01 2', 'handjob1nuke', 'harmanfingers', '2buttw1', 'dropsqueeze',
'lixlove', 'bbctitjob6', 'appreciativetease', 'bimbowhisper', 'subj3', 'salivashare', 'ballsworship3', 'wolfsknot2', 'gaykiss', 'lixlove', 'bbctitjob6', 'appreciativetease', 'bimbowhisper', 'subj3', 'salivashare', 'ballsworship3', 'wolfsknot2', 'gaykiss',
'slurpkiss', 'absbulge', 'cockiss', 'horsedick11', 'knot1', 'g4ebulge', 'blackadamrough', 'knotdog', 'flaunt', 'cummiefj', 'lovetosuck', 'slurpkiss', 'absbulge', 'cockiss', 'horsedick11', 'knotknotknot', 'g4ebulge', 'blackadamrough', 'knotdog', 'flaunt', 'cummiefj', 'lovetosuck',
'worship', 'hopelessly in love', 'knotts', 'cockloveeee', 'donglove', 'knotjob2', 'cummz', 'every drop', 'edgyoops', 'worship', 'hopelessly in love', 'knotts', 'cockloveeee', 'donglove', 'knotjob2', 'cummz', 'every drop', 'edgyoops',
'orccummies2', 'oralcreampie100px', 'horseoral9a', 'swallowit', 'realahegao4', 'gayicon2', 'slut4', 'hossspurties2', 'cumringgag', 'orccummies2', 'oralcreampie100px', 'horseoral9a', 'swallowit', 'realahegao4', 'gayicon2', 'slut4', 'hossspurties2', 'cumringgag',
'jillbimbogiffell2']; 'jillbimbogiffell2'];
case 'memes': case 'memes':
return ['guncock', 'michaelguns', 'watchbadass', 'gonnabang', 'flirting101', 'monkeymeme', 'monkeymeme2', 'horsenoises', return ['guncock', 'michaelguns', 'watchbadass', 'gonnabang', 'flirting101', 'monkeymeme', 'monkeymeme2', 'loudnoises',
'nyancat', 'gayb', 'fortasshole', 'dickletsign', 'sausageface', 'siren0', 'apologize to god', 'jabbalick', 'zeldawink', 'nyancat', 'gayb', 'fortasshole', 'dickletsign', 'sausageface', 'siren0', 'apologize to god', 'jabbalick', 'zeldawink',
'whatislove', 'surprisemothafucka', 'females', 'thanksihateit', 'hell is this', 'confused travolta', 'no words', 'coffindance', 'whatislove', 'surprisemothafucka', 'females', 'thanksihateit', 'hell is this', 'confused travolta', 'no words', 'coffindance',
'homelander', 'thatsapenis', 'pennyhee', 'kermitbusiness', 'goodbye', 'rickle', 'shiamagic', 'oag', ]; 'homelander', 'thatsapenis', 'pennyhee', 'kermitbusiness', 'goodbye', 'rickle', 'shiamagic', 'oag', ];

View File

@ -52,6 +52,7 @@
</template> </template>
</div> </div>
</div> </div>
<div class="search-yiffbot-suggestion" v-if="isYiffBot4000Online()" @click.prevent="showYiffBot4000()"><div class="btn">No luck? Try AI play with <span>YiffBot 4000</span></div></div>
</modal> </modal>
</template> </template>
@ -94,7 +95,6 @@
profile: CharacterCacheRecord | null; profile: CharacterCacheRecord | null;
} }
function sort(resultX: SearchResult, resultY: SearchResult): number { function sort(resultX: SearchResult, resultY: SearchResult): number {
const x = resultX.character; const x = resultX.character;
const y = resultY.character; const y = resultY.character;
@ -185,6 +185,29 @@
// tslint:disable-next-line no-any // tslint:disable-next-line no-any
scoreWatcher: ((event: any) => void) | null = null; scoreWatcher: ((event: any) => void) | null = null;
isYiffBot4000Online(): boolean {
return core.characters.get('YiffBot 4000').status !== 'offline';
}
showYiffBot4000(): void {
const character = core.characters.get('YiffBot 4000');
if (character.status === 'offline') {
return;
}
const conversation = core.conversations.getPrivate(character);
conversation.show();
this.hide();
const last = _.last(conversation.messages);
if (!last || last.time.getTime() < Date.now() - 1000 * 60 * 30) {
conversation.enteredText = 'Hello!';
conversation.send();
}
}
@Hook('created') @Hook('created')
async created(): Promise<void> { async created(): Promise<void> {
@ -695,5 +718,24 @@
.search-spinner { .search-spinner {
// float: right; // float: right;
} }
.search-yiffbot-suggestion .btn {
padding-left: 5px;
padding-right: 5px;
margin-top: 1em;
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
background-color: var(--secondary);
&:hover {
background-color: var(--blue);
}
span {
color: var(--yellow);
font-weight: bold;
}
}
} }
</style> </style>

View File

@ -212,6 +212,13 @@
Show character portrait with each message Show character portrait with each message
</label> </label>
</div> </div>
<div class="form-group">
<label class="control-label" for="risingShowHighQualityPortraits">
<input type="checkbox" id="risingShowHighQualityPortraits" v-model="risingShowHighQualityPortraits"/>
Show high-quality portraits
</label>
</div>
</div> </div>
<div v-show="selectedTab === '3'"> <div v-show="selectedTab === '3'">
@ -383,6 +390,7 @@
risingShowPortraitNearInput!: boolean; risingShowPortraitNearInput!: boolean;
risingShowPortraitInMessage!: boolean; risingShowPortraitInMessage!: boolean;
risingShowHighQualityPortraits!: boolean;
risingFilter!: SmartFilterSettings = {} as any; risingFilter!: SmartFilterSettings = {} as any;
@ -427,6 +435,7 @@
this.risingColorblindMode = settings.risingColorblindMode; this.risingColorblindMode = settings.risingColorblindMode;
this.risingShowPortraitNearInput = settings.risingShowPortraitNearInput; this.risingShowPortraitNearInput = settings.risingShowPortraitNearInput;
this.risingShowPortraitInMessage = settings.risingShowPortraitInMessage; this.risingShowPortraitInMessage = settings.risingShowPortraitInMessage;
this.risingShowHighQualityPortraits = settings.risingShowHighQualityPortraits;
this.risingFilter = settings.risingFilter; this.risingFilter = settings.risingFilter;
} }
@ -490,6 +499,7 @@
risingShowUnreadOfflineCount: this.risingShowUnreadOfflineCount, risingShowUnreadOfflineCount: this.risingShowUnreadOfflineCount,
risingShowPortraitNearInput: this.risingShowPortraitNearInput, risingShowPortraitNearInput: this.risingShowPortraitNearInput,
risingShowPortraitInMessage: this.risingShowPortraitInMessage, risingShowPortraitInMessage: this.risingShowPortraitInMessage,
risingShowHighQualityPortraits: this.risingShowHighQualityPortraits,
risingColorblindMode: this.risingColorblindMode, risingColorblindMode: this.risingColorblindMode,
risingFilter: { risingFilter: {

View File

@ -63,6 +63,7 @@ export class Settings implements ISettings {
risingColorblindMode = false; risingColorblindMode = false;
risingShowPortraitNearInput = true; risingShowPortraitNearInput = true;
risingShowPortraitInMessage = true; risingShowPortraitInMessage = true;
risingShowHighQualityPortraits = true;
risingFilter = { risingFilter = {
hideAds: false, hideAds: false,

View File

@ -237,6 +237,7 @@ export namespace Settings {
readonly risingColorblindMode: boolean; readonly risingColorblindMode: boolean;
readonly risingShowPortraitNearInput: boolean; readonly risingShowPortraitNearInput: boolean;
readonly risingShowPortraitInMessage: boolean; readonly risingShowPortraitInMessage: boolean;
readonly risingShowHighQualityPortraits: boolean;
readonly risingFilter: SmartFilterSettings; readonly risingFilter: SmartFilterSettings;
} }

View File

@ -5,6 +5,7 @@ import path from 'path';
import fs from 'fs'; import fs from 'fs';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as electron from 'electron'; import * as electron from 'electron';
import { NetworkFilter } from '@cliqz/adblocker';
export class BlockerIntegration { export class BlockerIntegration {
protected static readonly adBlockerLists = [ protected static readonly adBlockerLists = [
@ -53,13 +54,17 @@ export class BlockerIntegration {
log.debug('adblock.session.created'); log.debug('adblock.session.created');
blocker.update({
newNetworkFilters: [
NetworkFilter.parse('@@||redgifs.com')!,
]
});
blocker.enableBlockingInSession(session); blocker.enableBlockingInSession(session);
// blocker.enableBlockingInSession(electron.session.defaultSession);
log.debug('adblock.enabled'); log.debug('adblock.enabled');
BlockerIntegration.configureBlocker(blocker, session); BlockerIntegration.configureBlocker(blocker, session);
// BlockerIntegration.configureBlocker(blocker, electron.session.defaultSession);
log.debug('adblock.session.attached'); log.debug('adblock.session.attached');

View File

@ -72,7 +72,7 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
} }
async get(name: string, skipStore: boolean = false, fromChannel?: string): Promise<CharacterCacheRecord | null> { async get(name: string, skipStore: boolean = false, _fromChannel?: string): Promise<CharacterCacheRecord | null> {
const key = AsyncCache.nameKey(name); const key = AsyncCache.nameKey(name);
if (key in this.cache) { if (key in this.cache) {
@ -149,7 +149,7 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
} }
} }
isSafeImageURL(url: string): boolean { static isSafeRisingPortraitURL(url: string): boolean {
if (url.match(/^https?:\/\/static\.f-list\.net\//i)) { if (url.match(/^https?:\/\/static\.f-list\.net\//i)) {
return true; return true;
} }
@ -177,14 +177,26 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
return false; return false;
} }
updateOverrides(c: ComplexCharacter): void { static detectRisingPortraitURL(description: string): string | null {
const match = c.character.description.match(/\[url=(.*?)]\s*?Rising\s*?Portrait\s*?\[\/url]/i); if (!core.state.settings.risingShowHighQualityPortraits) {
return null;
}
const match = description.match(/\[url=(.*?)]\s*?Rising\s*?Portrait\s*?\[\/url]/i);
if (match && match[1]) { if (match && match[1]) {
const avatarUrl = match[1].trim(); return match[1].trim();
}
if (!this.isSafeImageURL(avatarUrl)) { return null;
log.info('portrait.hq.invalid.domain', { name: c.character.name, url: avatarUrl }); }
updateOverrides(c: ComplexCharacter): void {
const avatarUrl = ProfileCache.detectRisingPortraitURL(c.character.description);
if (avatarUrl) {
if (!ProfileCache.isSafeRisingPortraitURL(avatarUrl)) {
log.info('portrait.hq.invalid.domain', { name, url: avatarUrl });
return; return;
} }
@ -199,7 +211,6 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
} }
} }
async register(c: ComplexCharacter, skipStore: boolean = false): Promise<CharacterCacheRecord> { async register(c: ComplexCharacter, skipStore: boolean = false): Promise<CharacterCacheRecord> {
const k = AsyncCache.nameKey(c.character.name); const k = AsyncCache.nameKey(c.character.name);
const match = ProfileCache.match(c); const match = ProfileCache.match(c);

View File

@ -4,6 +4,7 @@ import Axios from 'axios';
import { CharacterAnalysis, Matcher } from '../matcher'; import { CharacterAnalysis, Matcher } from '../matcher';
import { FurryPreference, Kink, mammalSpecies, Species } from '../matcher-types'; import { FurryPreference, Kink, mammalSpecies, Species } from '../matcher-types';
import { characterImage } from '../../chat/common'; import { characterImage } from '../../chat/common';
import { ProfileCache } from '../profile-cache';
export enum ProfileRecommendationLevel { export enum ProfileRecommendationLevel {
INFO = 'info', INFO = 'info',
@ -39,6 +40,7 @@ export class ProfileRecommendationAnalyzer {
this.recommendations = []; this.recommendations = [];
await this.checkPortrait(); await this.checkPortrait();
await this.checkHqPortrait();
this.checkMissingProperties(); this.checkMissingProperties();
this.checkSpeciesPreferences(); this.checkSpeciesPreferences();
@ -53,15 +55,25 @@ export class ProfileRecommendationAnalyzer {
} }
protected async checkPortrait(): Promise<void> { protected async checkPortrait(): Promise<void> {
const profileUrl = characterImage(this.profile.character.name); const portraitUrl = characterImage(this.profile.character.name);
const result = await Axios.head(profileUrl); const result = await Axios.head(portraitUrl);
if (_.trim(result.headers['etag'] || '', '"').trim().toLowerCase() === '639d154d-16c3') { if (_.trim(result.headers['etag'] || '', '"').trim().toLowerCase() === '639d154d-16c3') {
this.add(`ADD_AVATAR`, ProfileRecommendationLevel.CRITICAL, 'Add an avatar portrait', 'Profiles with an avatar portrait stand out in chats.', 'https://wiki.f-list.net/Guide:_Character_Profiles#Avatar'); this.add(`ADD_AVATAR`, ProfileRecommendationLevel.CRITICAL, 'Add an avatar portrait', 'Profiles with an avatar portrait stand out in chats.', 'https://wiki.f-list.net/Guide:_Character_Profiles#Avatar');
} }
} }
protected async checkHqPortrait(): Promise<void> {
const profileUrl = ProfileCache.detectRisingPortraitURL(this.profile.character.description);
if (!profileUrl) {
this.add(`ADD_HQ_AVATAR`, ProfileRecommendationLevel.CRITICAL, 'Add a high-quality portrait', 'Profiles with a high-quality portraits stand out in chats with other F-Chat Rising players.', 'https://github.com/hearmeneigh/fchat-rising/wiki/High%E2%80%90Quality-Portraits');
} else if (!ProfileCache.isSafeRisingPortraitURL(profileUrl)) {
this.add(`ADD_HQ_AVATAR_SAFE_DOMAIN`, ProfileRecommendationLevel.CRITICAL, 'Unsupported high-quality portrait URL', 'High-quality portraits can only point to f-list.net, freeimages.host, e621.net, iili.io, imgur.com, or redgifs.com domains.', 'https://github.com/hearmeneigh/fchat-rising/wiki/High%E2%80%90Quality-Portraits');
}
}
protected checkImages(): void { protected checkImages(): void {
if (!this.profile.character.image_count) { if (!this.profile.character.image_count) {
this.add(`ADD_IMAGE`, ProfileRecommendationLevel.CRITICAL, 'Add a profile image', 'Profiles with images are more attractive to other players.', 'https://wiki.f-list.net/Guide:_Character_Profiles#Images'); this.add(`ADD_IMAGE`, ProfileRecommendationLevel.CRITICAL, 'Add a profile image', 'Profiles with images are more attractive to other players.', 'https://wiki.f-list.net/Guide:_Character_Profiles#Images');

View File

@ -39,7 +39,7 @@
<div role="tabpanel" v-show="tab === '0'" id="overview"> <div role="tabpanel" v-show="tab === '0'" id="overview">
<match-report :characterMatch="characterMatch" v-if="shouldShowMatch()"></match-report> <match-report :characterMatch="characterMatch" v-if="shouldShowMatch()"></match-report>
<div style="margin-bottom:10px"> <div style="margin-bottom:10px" class="character-description">
<bbcode :text="character.character.description"></bbcode> <bbcode :text="character.character.description"></bbcode>
</div> </div>
@ -934,4 +934,23 @@
background: var(--headerBackgroundMaskColor) !important; background: var(--headerBackgroundMaskColor) !important;
} }
.character-description .bbcode {
white-space: pre-line !important;
blockquote {
margin: 0;
background-color: var(--characterImageWrapperBg);
padding: 1em;
border-radius: 3px;
.quoteHeader {
border-bottom: 1px solid;
text-transform: uppercase;
font-weight: bold;
font-size: 80%;
opacity: 0.7;
}
}
}
</style> </style>