From e11f8338104f5f4223a5ea43ca11a38ccc1a0bbf Mon Sep 17 00:00:00 2001 From: "Mr. Stallion" Date: Fri, 5 Jul 2024 20:38:57 -0700 Subject: [PATCH] minor tweaks --- CHANGELOG.md | 27 +++++----- CONTRIBUTORS.md | 1 + bbcode/EIconSelector.vue | 18 +++---- chat/CharacterSearch.vue | 47 +++++++++++++++++- chat/ConversationView.vue | 46 ++++++++++++++++- chat/conversations.ts | 26 ++++++++++ chat/interfaces.ts | 2 + chat/preview/image-dom-mutator.ts | 2 +- docs/_config.yml | 2 +- electron/package.json | 2 +- learn/matcher.ts | 69 +++++++++++++++++++++++++- package.json | 2 +- site/character_page/character_page.vue | 4 ++ tsconfig.json | 3 +- 14 files changed, 217 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5299f6..786fe2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,19 @@ # Changelog -## Canary +## Next? +* Merge Ad Editor and Post Ads? +* Fix Yiffbot portrait updates +* Remove broadcasts from logs; maybe into a dialog? where do we store them tho? At least shouldn't orange-highlight all convos +* Notify when bookmark/friend says something on a channel? +* Clicking a log entry opens the conversation at that point + +## 1.27.0 * 'Non-binary' kink is now respected in gender matching (credit: [@FatCatClient](https://github.com/FatCatClient)) * OpenMoji is now treated as a fallback font (credit: [@FatCatClient](https://github.com/FatCatClient)) -* Added two new UI themes: 'Dracula', and 'Dark Dimmed' (credit: [@FatCatClient](https://github.com/FatCatClient)) - -* Add high-quality portraits to Profile Helper -* FBot should always be a UNICORN match -* FBot should have extra buttons to help one-handed -* FBot should show up in Search Results... if online -* Remove broadcasts from logs; maybe into a dialog? where do we store them tho? At least shouldn't orange-highlight all convos -* Update e-icons -* Merge Ad Editor and Post Ads? -* Notify when bookmark/friend says something on a channel? -* Fix image previews (redgifs?) -* Fix Yiffbot portrait updates -* Address scoring issues per FCR Notes -* Clicking a log entry opens the conversation at that point +* Added two UI themes: 'Dracula', and 'Dark Dimmed' (credit: [@FatCatClient](https://github.com/FatCatClient)) +* Each character can now set its own UI theme (credit: [@Nensec](https://github.com/Nensec)) +* Bugfix: Characters with 'None' gender are no longer considered a mismatch against other genders +* Fixed Redgifs previews (again) ## 1.26.2 * Fixed a few cases where high-quality portraits were not displayed diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index abb0398..cb91d9b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -11,6 +11,7 @@ This project contains contributions from: * [WhiteHusky](https://github.com/WhiteHusky) * [Abeehiltz](https://github.com/Abeehiltz) * [greyhoof](https://github.com/greyhoof) +* [Nensec](https://github.com/Nensec) * [F-List Team](https://github.com/f-list) (original F-Chat 3.0 client) diff --git a/bbcode/EIconSelector.vue b/bbcode/EIconSelector.vue index d232769..fdda053 100644 --- a/bbcode/EIconSelector.vue +++ b/bbcode/EIconSelector.vue @@ -141,7 +141,7 @@ export default class EIconSelector extends CustomDialog { case 'expressions': return ['coolemoji', 'coughing emoji', 'flushedemoji', 'eyerollemoji', 'cryinglaughing', 'grinning emoji', 'party emoji', 'pensiveemoji', 'lipbite emoji', 'nauseous emoji', 'angryemoji', 'love2', 'clapemoji', 'heart eyes', 'kissing heart', - 'flusteredcowboy', 'cowemoji', 'eggplantemoji', 'peachemoji', 'melting emoji', 'poopy', 'thinkingemoji', 'triumphemoji', + 'cowemoji', 'eggplantemoji', 'peachemoji', 'melting emoji', 'poopy', 'thinkingemoji', 'triumphemoji', 'uwuemoji', 'voremoji', 'skullemoji', 'smugemoji', 'heartflooshed', 'blushpanic', 'fluttersorry', 'snake emoji', 'horseeyes', 'thehorse', 'catblob', 'catblobangery', 'splashemoji', 'tonguemoji', 'blobhugs', 'lickscreen', 'eyes emoji', 'nerdmeme', 'horsepls', 'e62pog', 'thirstytwi', 'bangfingerbang', 'chefs kiss', 'excuse me', 'psychopath', 'ashemote3', 'whentheohitsright', @@ -158,7 +158,7 @@ export default class EIconSelector extends CustomDialog { 'suitclubs', 'suitdiamonds', 'suithearts', 'suitspades', 'chainscuffs', 'num-1', 'num-2', 'num-3', 'num-4', 'num-5', 'num-6', 'seven', 'eight', '9ball', 'discordeye', 'streamlive', 'check mark', 'x mark', 'question mark', 'lubimark', 'questget', - 'music', 'cam', 'phone', 'speaker emoji', 'laptop', + 'music', 'cam', 'speaker emoji', 'laptop', 'naughtyfood', 'open2', 'dont look away', 'milkcartonreal', ]; case 'bubbles': @@ -168,26 +168,26 @@ export default class EIconSelector extends CustomDialog { 'buttslutbb', 'notgayoranything', 'onlyfans', 'horsecockneed', 'crimes', 'breed143', 'nagagross', 'willrim', 'muskslut', '4lewdbubble', 'shimathatlewd', 'hypnosiss', 'imahypnoslut', 'sheepsass2', 'imahugeslut', 'notahealslut', 'ratedmilf', 'ratedstud', 'ratedslut', '5lewdbubble', 'xarcuminme', 'xarcumonme', 'choke me', 'iamgoingtopunchyou', 'snapmychoker', - 'rude1', 'fuckbun', 'iamindanger', 'elves', 'sluttery', 'helpicantstopsuckingcocks', 'talkpooltoy', 'thatskindahot', 'ygod', - 'simpbait', 'eyesuphere', 'fuckpiggy', 'peggable2', 'sydeanothere', 'nothingcan', 'pawslut', 'stupidboys', 'corpsestare-', + 'rude1', 'fuckbun', 'iamindanger', 'elves', 'helpicantstopsuckingcocks', 'talkpooltoy', 'thatskindahot', 'ygod', + 'simpbait', 'eyesuphere', 'fuckpiggy', 'peggable2', 'sydeanothere', 'nothingcan', 'pawslut', 'corpsestare-', 'dinnersex', 'plappening', 'fallout-standby', 'inbagg', 'request denied', 'goodboy0', 'goodending', 'milky2', 'howbadcanibe', 'gwanna', 'spitinmouth', 'bathwater']; case 'sexual': return ['kissspink', 'paytonkiss', 'coralbutt4', 'capstrip', 'pinkundress', 'collaredpet', 'jhab1', 'caninelover', 'pole', - 'rorobutt2', 'fingerlick', 'lapgrind', 'jackthighs', 'a condom', 'wolf abs', 'musclefuck2', 'verobutt3', 'bumsqueeze', - 'realahegao4', 'influencerhater', 'assfucker', 'gagged2', 'ballsack3', 'fingerblast3', 'sloppy01', 'sybian', + 'rorobutt2', 'fingerlick', 'lapgrind', 'jackthighs', 'a condom', 'wolf abs', 'musclefuck2', 'verobutt3', + 'realahegao4', 'influencerhater', 'gagged2', 'ballsack3', 'fingerblast3', 'sloppy01', 'sybian', 'floppyhorsecock', 'blackshem1', 'fingersucc', 'vullylick', 'fingersucc', 'cmontakeit', 'jessi flash', 'poju-butt', 'cheegrope2', 'patr1', 'ahega01 2', 'handjob1nuke', 'harmanfingers', '2buttw1', 'dropsqueeze', 'lixlove', 'bbctitjob6', 'appreciativetease', 'bimbowhisper', 'subj3', 'salivashare', 'ballsworship3', 'wolfsknot2', 'gaykiss', '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', 'cockloveeee', 'donglove', 'knotjob2', 'cummz', 'every drop', 'edgyoops', 'orccummies2', 'oralcreampie100px', 'horseoral9a', 'swallowit', 'realahegao4', 'gayicon2', 'slut4', 'hossspurties2', 'cumringgag', 'jillbimbogiffell2']; case 'memes': - return ['guncock', 'michaelguns', 'watchbadass', 'gonnabang', 'flirting101', 'monkeymeme', 'monkeymeme2', 'loudnoises', - 'nyancat', 'gayb', 'fortasshole', 'dickletsign', 'sausageface', 'siren0', 'apologize to god', 'jabbalick', 'zeldawink', + return ['guncock', 'michaelguns', 'watchbadass', 'gonnabang', 'flirting101', 'loudnoises', + 'nyancat', 'gayb', 'fortasshole', 'dickletsign', 'hotdogface', 'siren0', 'apologize to god', 'jabbalick', 'zeldawink', 'whatislove', 'surprisemothafucka', 'females', 'thanksihateit', 'hell is this', 'confused travolta', 'no words', 'coffindance', 'homelander', 'thatsapenis', 'pennyhee', 'kermitbusiness', 'goodbye', 'rickle', 'shiamagic', 'oag', ]; diff --git a/chat/CharacterSearch.vue b/chat/CharacterSearch.vue index de6f5fc..75c0eb5 100644 --- a/chat/CharacterSearch.vue +++ b/chat/CharacterSearch.vue @@ -73,12 +73,13 @@ import CharacterSearchHistory from './CharacterSearchHistory.vue'; import { Matcher } from '../learn/matcher'; import { + Gender, kinkMatchScoreMap, kinkMatchWeights, - nonAnthroSpecies, + nonAnthroSpecies, Orientation, Species, speciesMapping, - speciesNames + speciesNames, TagId } from '../learn/matcher-types'; import { CharacterCacheRecord } from '../learn/profile-cache'; import Bluebird from 'bluebird'; @@ -273,6 +274,34 @@ console.log('Done!'); } + getYiffBotCompatibleGender(): Character.Gender { + const g = Matcher.getTagValueList(TagId.Gender, core.characters.ownProfile.character); + const o = Matcher.getTagValueList(TagId.Orientation, core.characters.ownProfile.character); + + if (o === Orientation.Straight || o === Orientation.Unsure || _.isNil(o)) { + if (g === Gender.Male) { + return 'Female'; + } + + if (g === Gender.Female) { + return 'Male'; + } + } + + if (o === Orientation.Gay && g) { + return g === Gender.Male ? 'Male' : 'Female'; + } + + if (o === Orientation.BiFemalePreference) { + return 'Female'; + } + + if (o === Orientation.BiMalePreference) { + return 'Male'; + } + + return _.sample(['Male', 'Female']) as Character.Gender; + } @Hook('mounted') mounted(): void { @@ -311,6 +340,16 @@ this.hasReceivedResults = true; this.results = results; + if (this.isYiffBot4000Online()) { + const char = core.characters.get('YiffBot 4000'); + + (char as any).status = 'looking'; + (char as any).gender = this.getYiffBotCompatibleGender(); + (char as any).statusText = 'Try AI play with any gender, orientation & kink!'; + + this.results.push({ character: char, profile: core.cache.profileCache.getSync('YiffBot 4000') }); + } + this.resort(results); }); @@ -548,15 +587,19 @@ this.shouldShowAvatar = core.state.settings.risingShowPortraitInMessage; this.results = []; + this.state = 'results'; this.error = ''; + const data: Connection.ClientCommands['FKS'] & {[key: string]: (string | number)[]} = {kinks: []}; + for(const key in this.data) { const item = this.data[key]; // SearchData is correct if(item.length > 0 && key !== 'bodytypes') data[key] = key === 'kinks' ? (item).map((x) => x.id) : (item); } + core.connection.send('FKS', data); // tslint:disable-next-line diff --git a/chat/ConversationView.vue b/chat/ConversationView.vue index f9c1b03..dc22a84 100644 --- a/chat/ConversationView.vue +++ b/chat/ConversationView.vue @@ -108,6 +108,12 @@ +
+
+
#continue
+
#retry
+
+

{{l('admgr.activeHeader')}}

{{adAutoPostUpdate}}
@@ -201,7 +207,7 @@ import CharacterAdView from './character/CharacterAdView.vue'; import {Editor} from './bbcode'; import CommandHelp from './CommandHelp.vue'; - import { characterImage, errorToString, getByteLength, getKey } from './common'; + import { characterImage, errorToString, getByteLength, getKey, Message } from './common'; import ConversationSettings from './ConversationSettings.vue'; import ConversationAdSettings from './ads/ConversationAdSettings.vue'; import core from './core'; @@ -698,6 +704,36 @@ const member = conv.channel.members[core.connection.character]; return member !== undefined && member.rank > Channel.Rank.Member; } + + isYiffBot(): boolean { + if (!this.isPrivate(this.conversation)) { + return false; + } + + return this.conversation.character.name === 'YiffBot 4000'; + } + + async onYiffBotContinuePost(): Promise { + if (!this.isPrivate(this.conversation)) { + return; + } + + const conv = (this.conversation); + + await conv.sendMessageEx('#continue'); + await this.messageAdded(this.conversation.messages as Message[]); + } + + async onYiffBotRetryPost(): Promise { + if (!this.isPrivate(this.conversation)) { + return; + } + + const conv = (this.conversation); + + await conv.sendMessageEx('#retry'); + await this.messageAdded(this.conversation.messages as Message[]); + } } @@ -1052,4 +1088,12 @@ min-width: 1.2em; max-width: 1.2em; } + + .yiffbot-controls { + .btn-group { + margin-left: 70px; + margin-top: 10px; + margin-bottom: 10px; + } + } diff --git a/chat/conversations.ts b/chat/conversations.ts index f62c812..e37a7d2 100644 --- a/chat/conversations.ts +++ b/chat/conversations.ts @@ -249,6 +249,32 @@ class PrivateConversation extends Conversation implements Interfaces.PrivateConv return state.savePinned(); } + public async sendMessageEx(messageText: string): Promise { + if(this.character.status === 'offline') { + this.errorText = l('chat.errorOffline', this.character.name); + return; + } + + if(this.character.isIgnored) { + this.errorText = l('chat.errorIgnored', this.character.name); + return; + } + + await Conversation.conversationThroat( + async() => { + await Conversation.testPostDelay(); + + core.connection.send('PRI', {recipient: this.name, message: messageText}); + core.cache.markLastPostTime(); + + const message = createMessage(MessageType.Message, core.characters.ownCharacter, messageText); + this.safeAddMessage(message); + + if(core.state.settings.logMessages) await core.logs.logMessage(this, message); + } + ); + } + protected async doSend(): Promise { await this.logPromise; if(this.character.status === 'offline') { diff --git a/chat/interfaces.ts b/chat/interfaces.ts index 4d39387..9c63370 100644 --- a/chat/interfaces.ts +++ b/chat/interfaces.ts @@ -67,6 +67,8 @@ export namespace Conversation { export interface PrivateConversation extends TabConversation { readonly character: Character readonly typingStatus: TypingStatus + + sendMessageEx(text: string): Promise; } export interface ChannelConversation extends TabConversation { diff --git a/chat/preview/image-dom-mutator.ts b/chat/preview/image-dom-mutator.ts index 2a3e87b..e357ea1 100644 --- a/chat/preview/image-dom-mutator.ts +++ b/chat/preview/image-dom-mutator.ts @@ -167,7 +167,7 @@ export class ImageDomMutator { 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('redgifs.com', this.getBaseJsMutatorScript(['video'], true, [], false, true)); + this.add('redgifs.com', this.getBaseJsMutatorScript(['video'])); // , true, [], false, true)); this.add('furaffinity.net', this.getBaseJsMutatorScript(['#submissionImg', 'video', 'img'])); this.add('rule34.paheal.net', this.getBaseJsMutatorScript(['#main_image', 'video', 'img'])); this.add('xhamster.com', this.getBaseJsMutatorScript(['#photo_slider video', '#photo_slider img', 'video', 'img'])); diff --git a/docs/_config.yml b/docs/_config.yml index 0c4dad1..9894991 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -51,7 +51,7 @@ changelog: https://github.com/hearmeneigh/fchat-rising/blob/master/CHANGELOG.md installurl: https://github.com/hearmeneigh/fchat-rising/wiki download: - version: 1.26.2 + version: 1.27.0 url: https://github.com/hearmeneigh/fchat-rising/releases/latest/download/F-Chat-Rising-%PLATFORM_TAIL% diff --git a/electron/package.json b/electron/package.json index 628c82d..d862e13 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "fchat", - "version": "1.26.2", + "version": "1.27.0", "author": "The F-List Team and Mister Stallion (Esq.)", "description": "F-List.net Chat Client", "main": "main.js", diff --git a/learn/matcher.ts b/learn/matcher.ts index 5c60f49..dbd1120 100644 --- a/learn/matcher.ts +++ b/learn/matcher.ts @@ -238,6 +238,62 @@ export class Matcher { return report; } + static getYiffBot4000MatchReport(you: Character, them: Character): MatchReport { + const scores: MatchResultScores = { + [TagId.Orientation]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.Gender]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.Age]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.FurryPreference]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.Species]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.SubDomRole]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.Kinks]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.PostLength]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.Position]: new Score(Scoring.MATCH, 'Perfect match!'), + [TagId.BodyType]: new Score(Scoring.MATCH, 'Perfect match!') + }; + + const yourAnalysis = new CharacterAnalysis(you); + const theirAnalysis = new CharacterAnalysis(them); + + return { + _isVue: true, + you: { + you, + them, + scores, + info: { + species: Matcher.species(you), + gender: Matcher.getTagValueList(TagId.Gender, you), + orientation: Matcher.getTagValueList(TagId.Orientation, you) + }, + total: _.sum(_.values(scores).map((s: Score) => s.score)), + yourAnalysis, + theirAnalysis + }, + them: { + you: them, + them: you, + scores, + info: { + species: Matcher.species(them), + gender: Matcher.getTagValueList(TagId.Gender, them), + orientation: Matcher.getTagValueList(TagId.Orientation, them) + } , + total: _.sum(_.values(scores).map((s: Score) => s.score)), + yourAnalysis: theirAnalysis, + theirAnalysis: yourAnalysis + }, + youMultiSpecies: false, + themMultiSpecies: false, + merged: scores, + score: Scoring.MATCH, + details: { + totalScoreDimensions: _.values(scores).length * 2, + dimensionsAtScoreLevel: _.values(scores).length * 2 + } + }; + } + static identifyBestMatchReport(you: Character, them: Character): MatchReport { const reportStartTime = Date.now(); @@ -248,6 +304,10 @@ export class Matcher { let bestScoreLevelCount = -10000; let bestReport: MatchReport; + if (you.name === 'YiffBot 4000' || them.name === 'YiffBot 4000') { + return Matcher.getYiffBot4000MatchReport(you, them); + } + for(const yourAnalysis of yourCharacterAnalyses) { for (const theirAnalysis of theirCharacterAnalyses) { const youThem = new Matcher(yourAnalysis.character, theirAnalysis.character, yourAnalysis.analysis, theirAnalysis.analysis); @@ -437,7 +497,7 @@ export class Matcher { static scoreOrientationByGender(yourGender: Gender | null, yourOrientation: Orientation | null, theirGender: Gender | null): Score { - if ((yourGender === null) || (theirGender === null) || (yourOrientation === null)) + if ((yourGender === null) || (theirGender === null) || (yourOrientation === null) || yourGender === Gender.None || theirGender === Gender.None) return new Score(Scoring.NEUTRAL); // CIS @@ -727,8 +787,9 @@ export class Matcher { const yourOrientation = this.yourAnalysis.orientation; const theirGender = this.theirAnalysis.gender; - if (theirGender === null) + if (theirGender === null) { return new Score(Scoring.NEUTRAL); + } const genderName = `${Gender[theirGender].toLowerCase()}s`; const genderKinkScore = Matcher.getKinkGenderPreference(you, theirGender); @@ -1375,6 +1436,10 @@ export class Matcher { match: MatchReport, penalty: number ): number { + if (match.you.you.name === 'YiffBot 4000' || match.you.them.name === 'YiffBot 4000') { + return kinkMatchWeights.unicornThreshold; + } + const totalScoreDimensions = match ? Matcher.countScoresTotal(match) : 0; const dimensionsAtScoreLevel = match ? (Matcher.countScoresAtLevel(match, score) || 0) : 0; const dimensionsAboveScoreLevel = match ? (Matcher.countScoresAboveLevel(match, Math.max(score, Scoring.WEAK_MATCH))) : 0; diff --git a/package.json b/package.json index 034a74e..d0d6237 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "f-list-rising", - "version": "1.26.2", + "version": "1.27.0", "author": "The F-List Team and and Mister Stallion (Esq.)", "description": "A heavily modded F-Chat 3.0 client for F-List", "license": "MIT", diff --git a/site/character_page/character_page.vue b/site/character_page/character_page.vue index 87d9d4d..ae217c6 100644 --- a/site/character_page/character_page.vue +++ b/site/character_page/character_page.vue @@ -203,6 +203,10 @@ shouldShowMatch(): boolean { + if (this.character?.character.name === 'YiffBot 4000') { + return false; + } + return core.state.settings.risingAdScore; } diff --git a/tsconfig.json b/tsconfig.json index 518cbeb..1cec51d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "noUnusedLocals": true, "noUnusedParameters": true, "allowSyntheticDefaultImports": true, - "esModuleInterop": true + "esModuleInterop": true, + "experimentalDecorators": true }, "include": ["./electron/main.ts"] }