diff --git a/assets/LighterFuel.psd b/assets/LighterFuel.psd new file mode 100644 index 0000000..cd4a005 Binary files /dev/null and b/assets/LighterFuel.psd differ diff --git a/assets/LighterfuelPromo1.png b/assets/LighterfuelPromo1.png new file mode 100644 index 0000000..cb37fa9 Binary files /dev/null and b/assets/LighterfuelPromo1.png differ diff --git a/assets/LighterfuelPromo1.psd b/assets/LighterfuelPromo1.psd new file mode 100644 index 0000000..bf87ba1 Binary files /dev/null and b/assets/LighterfuelPromo1.psd differ diff --git a/assets/banner.png b/assets/banner.png new file mode 100644 index 0000000..e21708d Binary files /dev/null and b/assets/banner.png differ diff --git a/assets/banner.psd b/assets/banner.psd new file mode 100644 index 0000000..4405a88 Binary files /dev/null and b/assets/banner.psd differ diff --git a/assets/promoBanner.png b/assets/promoBanner.png new file mode 100644 index 0000000..9cfb790 Binary files /dev/null and b/assets/promoBanner.png differ diff --git a/assets/promoBanner.psd b/assets/promoBanner.psd new file mode 100644 index 0000000..b39c003 Binary files /dev/null and b/assets/promoBanner.psd differ diff --git a/assets/smallPromo.png b/assets/smallPromo.png new file mode 100644 index 0000000..7c90e39 Binary files /dev/null and b/assets/smallPromo.png differ diff --git a/assets/smallPromo.psd b/assets/smallPromo.psd new file mode 100644 index 0000000..9ae36f0 Binary files /dev/null and b/assets/smallPromo.psd differ diff --git a/package.json b/package.json index 959b1d7..ed06929 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "lighter-fuel-for-tinder", "displayName": "LighterFuel for tinder", - "version": "1.4.7", - "description": "LighterFuel helps you to identify catfish, letting you see when profile images were uploaded and reverse image search photos!", + "version": "1.4.8", + "description": "LighterFuel helps you see when accounts were created, see enlarged photos and reverse image search photos!", "author": "James", "scripts": { "dev": "plasmo dev", diff --git a/src/background/PeopleHandler.ts b/src/background/PeopleHandler.ts new file mode 100644 index 0000000..ec73fe1 --- /dev/null +++ b/src/background/PeopleHandler.ts @@ -0,0 +1,84 @@ +/* eslint-disable class-methods-use-this */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable no-underscore-dangle */ +import type { Person } from '~src/misc/tinderTypes'; + +export type photoInfo = { + hqUrl: string; + accountCreated: number; + original: string; +} | undefined; + +const dateFromObjectId = (objectId) => new Date(parseInt(objectId.substring(0, 8), 16) * 1000); + +const extractRecPhotoId = (url: string) => { + const regex = /\/u\/([^/]+)/; + const match = url.match(regex); + return match ? match[1] : null; +}; + +// this gets the uuid of the photo from the url +const extractUuidFromUrl = (url) => { + const regex = /_(.*?)\./; + const match = url.match(regex); + if (match && match[1]) { + const uuid = match[1].replace(/^(\d+)_/, ''); + return uuid; + } + return null; +}; + +export class PeopleHandler { + people: Person[] = []; + + handleNewPeople(people: Person[]) { + people.forEach((person) => { + if (!this.people.find((p) => p._id === person._id)) { + this.people.push(person); + } + }); + + console.log('people', this.people); + } + + /** + * This + * @param url the photo URL attached to the account + */ + getInfoFromPhoto(url: string): photoInfo { + // search through all of the people + for (const person of this.people) { + if (person.type === 'match') { + const photoId = extractUuidFromUrl(url); + // search through person's photos + for (const photo of person.photos) { + if (photo.id === photoId) { + // return photoRecord details immediately when you get a match + return { + original: url, + hqUrl: photo.url, + accountCreated: dateFromObjectId(person._id).getTime(), + }; + } + } + } else if (person.type === 'rec') { + const id = extractRecPhotoId(url); + // search through person's photos + for (const photo of person.photos) { + if (extractRecPhotoId(photo.url) === id) { + if (!photo.url) console.error('no photo url, recs', photo); + + // return photoRecord details immediately when you get a match + return { + original: url, + hqUrl: photo.url, + accountCreated: dateFromObjectId(person._id).getTime(), + }; + } + } + } + } + console.error('no match found for url', url); + return undefined; + } +} diff --git a/src/background/index.ts b/src/background/index.ts index d196bab..8f93dc4 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -7,6 +7,7 @@ import { Sites } from '@/misc/types'; import ImageRequestCapturer from './imageRequestCapturer'; import { SENTRY_DSN } from './Misc'; import { AnalyticsEvent } from '~src/misc/GA'; +import { PeopleHandler } from './PeopleHandler'; const setAndCheckDefaultSettings = async () => { const storage = new Storage(); @@ -40,25 +41,27 @@ const setupSentry = async () => { } }; -let tinderRequestCap: ImageRequestCapturer; let mambaRequestCap: ImageRequestCapturer; +let peopleHandler: PeopleHandler; try { setupSentry(); setAndCheckDefaultSettings(); - tinderRequestCap = new ImageRequestCapturer(['*://*.gotinder.com/*/*.jpg*', '*://*.gotinder.com/*/*.webp*', '*://*.gotinder.com/*/*.mp4*'], Sites.TINDER); + peopleHandler = new PeopleHandler(); + mambaRequestCap = new ImageRequestCapturer(['*://*.wmbcdn.com/*'], Sites.MAMBA, 1000); // prints the bg instance to the console for debugging! - if (debug) console.log(tinderRequestCap, mambaRequestCap); + if (debug) console.log(mambaRequestCap); + if (debug) console.log('people handler', peopleHandler); } catch (err: any) { console.error(`Error caught in background.js: ${err.stack}`); } // exporting so the message handlers can access the images export { - tinderRequestCap, + peopleHandler, mambaRequestCap, }; diff --git a/src/background/messages/getImageInfo.ts b/src/background/messages/getImageInfo.ts new file mode 100644 index 0000000..8badbad --- /dev/null +++ b/src/background/messages/getImageInfo.ts @@ -0,0 +1,20 @@ +import type { PlasmoMessaging } from '@plasmohq/messaging'; +import { peopleHandler } from '..'; +import type { photoInfo } from '../PeopleHandler'; + +export type getImageInfoRequest = { + url: string; +}; + +export type getImageInfoResponse = { + info: photoInfo; +}; + +const handler: PlasmoMessaging.MessageHandler = async (req, res) => { + const info = peopleHandler.getInfoFromPhoto(req.body.url); + res.send({ + info, + }); +}; + +export default handler; diff --git a/src/background/messages/getImages.ts b/src/background/messages/getImages.ts index d51d016..6f3148f 100644 --- a/src/background/messages/getImages.ts +++ b/src/background/messages/getImages.ts @@ -1,5 +1,5 @@ import type { PlasmoMessaging } from '@plasmohq/messaging'; -import { tinderRequestCap, mambaRequestCap } from '@/background/index'; +import { mambaRequestCap } from '@/background/index'; import { type ImageType, Sites } from '@/misc/types'; export type getImagesRequest = { @@ -21,9 +21,6 @@ const handler: PlasmoMessaging.MessageHandler { + peopleHandler.handleNewPeople(req.body.people); + res.send({ + recieved: true, + }); +}; + +export default handler; diff --git a/src/contents/relay.ts b/src/contents/relay.ts index b6feb31..ec9402c 100644 --- a/src/contents/relay.ts +++ b/src/contents/relay.ts @@ -1,6 +1,7 @@ import { relay } from '@plasmohq/messaging/relay'; import { sendToBackground } from '@plasmohq/messaging'; import type { getImagesRequest, getImagesResponse } from '~src/background/messages/getImages'; +import type { getImageInfoRequest, getImageInfoResponse } from '~src/background/messages/getImageInfo'; relay( { @@ -21,3 +22,33 @@ relay( return res; }, ); + +relay( + { + name: 'getPeople', + }, + async (req) => { + let res: getImagesResponse = { + images: [], + }; + try { + res = await sendToBackground({ + name: 'getPeople', + body: req.body, + }); + } catch (e) { + console.log(`Error thrown in getPeople relay, ${e}`); + } + return res; + }, +); + +relay( + { + name: 'getImageInfo', + }, + async (req) => sendToBackground({ + name: 'getImageInfo', + body: req.body, + }), +); diff --git a/src/contents/tinderProfileGetter.ts b/src/contents/tinderProfileGetter.ts new file mode 100644 index 0000000..847ec7d --- /dev/null +++ b/src/contents/tinderProfileGetter.ts @@ -0,0 +1,16 @@ +import type { PlasmoCSConfig } from 'plasmo'; +import ProfileGetter from '~src/contentsHelpers/ProfileGetter'; + +export const config: PlasmoCSConfig = { + matches: ['*://tinder.com/*'], + run_at: 'document_start', + world: 'MAIN', +}; + +try { + const getter = new ProfileGetter(); + + console.log('Getter created!'); +} catch (e) { + console.error(`Error in profile getter: ${e}`); +} diff --git a/src/contentsHelpers/ImageHandler.ts b/src/contentsHelpers/ImageHandler.ts index ac39420..1b8a812 100644 --- a/src/contentsHelpers/ImageHandler.ts +++ b/src/contentsHelpers/ImageHandler.ts @@ -3,7 +3,7 @@ /* eslint-disable no-restricted-syntax */ import browser from 'webextension-polyfill'; import { Storage } from '@plasmohq/storage'; -import { sendToBackground } from '@plasmohq/messaging'; +import { sendToBackground, sendToBackgroundViaRelay } from '@plasmohq/messaging'; import EventEmitter from 'events'; import { diff --git a/src/contentsHelpers/LighterFuel.ts b/src/contentsHelpers/LighterFuel.ts index dc0ebfa..6cf4a5a 100644 --- a/src/contentsHelpers/LighterFuel.ts +++ b/src/contentsHelpers/LighterFuel.ts @@ -3,6 +3,9 @@ /* eslint-disable no-restricted-syntax */ import browser from 'webextension-polyfill'; +import { Storage } from '@plasmohq/storage'; +import { sendToBackgroundViaRelay } from '@plasmohq/messaging'; +import EventEmitter from 'events'; import { createButton, getTimeOld, @@ -13,8 +16,7 @@ import { getDomsWithBGImages, getProfileImages, } from '@/contentsHelpers/Misc'; - -import { debug, text } from '@/misc/config'; +import { debug, defaultSettings, text } from '@/misc/config'; import { type ImageType, @@ -25,8 +27,37 @@ import { } from '@/misc/types'; import ImageHandler, { Events } from '@/contentsHelpers/ImageHandler'; +import type { photoInfo } from '~src/background/PeopleHandler'; +import type { getImageInfoRequest, getImageInfoResponse } from '~src/background/messages/getImageInfo'; + +/** + * Returns visibility ratio of element within viewport. + * + * @param {Element} target - DOM element to observe + * @return {Promise} Promise that resolves with visibility ratio + */ +const getVisibility = (target: Element) => new Promise((resolve) => { + const options = { + root: null, // viewport + rootMargin: '0px', + threshold: 0, // get ratio, even if only 1px is in view + }; + + const observer = new IntersectionObserver(([entry]) => { + resolve(entry.intersectionRatio); + observer.disconnect(); + }, options); + + observer.observe(target); +}); + +class LighterFuel { + showSettings: ShowSettings = defaultSettings; + + storage: Storage; + + site: Sites; -class LighterFuel extends ImageHandler { profileSliderContainers: profileSliderContainer[]; mainMutationObserver: MutationObserver; @@ -35,24 +66,107 @@ class LighterFuel extends ImageHandler { shownProfileImages: Element[]; - constructor() { - super(Sites.TINDER); // Call the parent class constructor + emitter: EventEmitter; + constructor() { this.profileSliderContainers = []; - this.initialiseMessageListner = this.initialiseMessageListner.bind(this); + this.startMonitorInterval(); + + this.emitter = new EventEmitter(); + this.storage = new Storage(); + this.initialiseEventListeners(); + this.getSettings(); + } - this.getData = this.getData.bind(this); + getSettings() { + // gets the initial settings from storage + this.storage.get('showSettings').then((c) => { + if (c === undefined) return; + this.showSettings = c; + this.emitter.emit(Events.settingsUpdate, this.showSettings); + }); - this.startMonitorInterval(); + // watching the storage for changes, for live updating + this.storage.watch({ + showSettings: (c) => { + if (c === undefined) return; + this.showSettings = c.newValue; + this.emitter.emit(Events.settingsUpdate, this.showSettings); + }, + }); + } + + /** + * Sets the overlay display status to shown/hidden + * + * @param {Boolean} status Whether or not to display the overlay + */ + setDisplayStatus() { + let styleElem = document.querySelector('#overlayDisplay'); + if (!styleElem) { + styleElem = document.createElement('style'); + styleElem.setAttribute('id', 'overlayDisplay'); + document.head.append(styleElem); + } + styleElem.textContent = ` + .overlayBox { ${this.showSettings.overlayButton ? '' : 'display: none'} } + .topBox { ${this.showSettings.overlayButton ? '' : 'display: none'} } + .search { ${this.showSettings.searchButton ? '' : 'display: none'} }`; + consoleOut(this.showSettings); + } + + initialiseEventListeners() { + this.emitter.on(Events.settingsUpdate, (settings) => { + this.setDisplayStatus(); + }); } + async getImageInfo(url: string) { + const res = await sendToBackgroundViaRelay({ + name: 'getImageInfo', + body: { + url, + }, + }); + + return res.info; + } + + // startMonitorInterval() { + // setInterval(async () => { + // const images = [...document.querySelectorAll('div .profileCard__slider__img, StretchedBox')].filter((x) => { + // const src = x.style.backgroundImage; + // return src.includes('https://images-ssl.gotinder.com/u/') || src.includes('https://images-ssl.gotinder.com/'); + // }); + + // images.forEach((image) => { + // getVisibility(image).then((ratio: number) => { + // const imageURL = getImageURLfromNode(image); + // console.log(`${imageURL} is ${ratio * 100}% visible`); + // }); + // }); + // }, 50); + // } + startMonitorInterval() { - setInterval(() => { - const keenSlider = [...document.querySelectorAll('div.keen-slider, div.profileCard__slider')]; - if (keenSlider.length > 0) { + setInterval(async () => { + const keenSlider = [...document.querySelectorAll('div.keen-slider, div.profileCard__slider')].reverse(); + + const shown = await Promise.all(keenSlider.map(async (slider) => { + const ratio = await getVisibility(slider); + return { + slider, + ratio, + }; + })); + + // filter out the ones that are not visible + const visible = shown.filter((x) => (x.ratio as number) > 0).map((x) => x.slider); + + if (visible.length > 0) { // For every slider, make sure there's the overlay - for (const slider of keenSlider) { + for (const slider of visible) { // check to see if the overlay 'aria-url' matches the current image const profileImages = [...slider.querySelectorAll('div.StretchedBox, div.profileCard__slider__img')]; if (profileImages.length === 0) { @@ -64,52 +178,53 @@ class LighterFuel extends ImageHandler { if (firstParent || secondParent) return curr; return acc; }); + const imageURL = getImageURLfromNode(currentImage); + console.log('currentImage', imageURL); if (!imageURL) { if (debug) { console.log('getImageURLfromNode returned undefined, skipping this image'); } break; } - const imageRecord = this.images.find((image) => imageURL.includes(image.url)); - - // this doesn't seem to be problematic, it sometimes just doesn't find the image - if (!imageRecord) { - break; - } - let existingOverlay = slider.parentNode.querySelector('p.overlayBox, p.topBox'); - const sliderParent = slider.parentNode; + this.getImageInfo(imageURL).then((info) => { + if (!info) { + return; + } + let existingOverlay = slider.parentNode.querySelector('p.overlayBox, p.topBox'); + const sliderParent = slider.parentNode; - if (existingOverlay) { - if (existingOverlay.parentNode) { - const existingOverlayInCorrectPlace = (existingOverlay.parentNode as HTMLElement).classList.contains('keen-slider') + if (existingOverlay) { + if (existingOverlay.parentNode) { + const existingOverlayInCorrectPlace = (existingOverlay.parentNode as HTMLElement).classList.contains('keen-slider') || (existingOverlay.parentNode as HTMLElement).classList.contains('tappable-view'); - if (!existingOverlayInCorrectPlace) { - existingOverlay.parentNode.removeChild(existingOverlay); - existingOverlay = undefined; - if (debug) { - console.log('Existing overlay not in correct place, removing it'); + if (!existingOverlayInCorrectPlace) { + existingOverlay.parentNode.removeChild(existingOverlay); + existingOverlay = undefined; + if (debug) { + console.log('Existing overlay not in correct place, removing it'); + } } } } - } - if (!existingOverlay) { - const overlay = this.createOverlayNode(imageRecord); - sliderParent.appendChild(overlay.overlayNode); - overlay.onPlaced(); - consoleOut('Added overlay'); - } else // check to see if the overlay 'aria-url' matches the current image - if (existingOverlay.getAttribute('aria-url') !== imageRecord.url) { - // if not, update the overlay - existingOverlay.parentNode.removeChild(existingOverlay); - const overlay = this.createOverlayNode(imageRecord); + if (!existingOverlay) { + const overlay = this.createOverlayNode(info); sliderParent.appendChild(overlay.overlayNode); overlay.onPlaced(); - consoleOut('Updated overlay'); - } + consoleOut('Added overlay'); + } else // check to see if the overlay 'aria-url' matches the current image + if (existingOverlay.getAttribute('aria-url') !== info.original) { + // if not, update the overlay + existingOverlay.parentNode.removeChild(existingOverlay); + const overlay = this.createOverlayNode(info); + sliderParent.appendChild(overlay.overlayNode); + overlay.onPlaced(); + consoleOut('Updated overlay'); + } + }); } } }, 50); @@ -123,14 +238,17 @@ class LighterFuel extends ImageHandler { * @param data The data for the image (using the last modified date and url for reverse lookup) * @returns The element with an onPlaced method */ - createOverlayNode(data: ImageType) { - const { lastModified } = data; + createOverlayNode(data: photoInfo) { const overlayNode = document.createElement('p'); - const date = new Date(lastModified); + const date = new Date(data.accountCreated); const xOld = getTimeOld(date.getTime()); - overlayNode.innerHTML = `${text.overlay.uploadedAt}: ${date.getHours()}:${date.getMinutes()} ${date.toLocaleDateString()} ${xOld} Old`; - overlayNode.appendChild(createButton(data.url)); - overlayNode.setAttribute('aria-url', data.url); + overlayNode.innerHTML = `${text.overlay.createdAt}: ${date.getHours()}:${date.getMinutes()} ${date.toLocaleDateString()} ${xOld} Ago`; + if (!data.hqUrl) { + console.log('no hqUrl', data); + } + + overlayNode.appendChild(createButton(data.hqUrl)); + overlayNode.setAttribute('aria-url', data.original); const onPlaced = () => { const bounds = overlayNode.getBoundingClientRect(); // * whenever there's 100px above, we have room to place the box above diff --git a/src/contentsHelpers/Misc.ts b/src/contentsHelpers/Misc.ts index 67d895c..cfaa806 100644 --- a/src/contentsHelpers/Misc.ts +++ b/src/contentsHelpers/Misc.ts @@ -28,6 +28,18 @@ export const createButton = (url: string): HTMLElement => { }; parent.appendChild(searchButton); } + + const openHighQuality = document.createElement('a'); + openHighQuality.classList.add('buttonLF'); + openHighQuality.classList.add('search'); + openHighQuality.style.color = 'black'; + openHighQuality.href = url; + openHighQuality.innerText = 'Open High Quality'; + openHighQuality.style.outline = 'black solid 1px'; + openHighQuality.target = '_blank'; + + parent.appendChild(openHighQuality); + return parent; }; @@ -191,7 +203,7 @@ export const getTextButtonParent = (): HTMLElement | null => { * a console log facade for the debug bool */ export const consoleOut = (message: string | any[] | any) => { - if (debug) console.log(message); + // if (debug) console.log(message); }; /** @@ -276,7 +288,7 @@ export const createMambaOverlayNode = (image: Element, imageRecord: ImageType) = overlay.setAttribute('aria-label', imageRecord.url); const date = new Date(imageRecord.lastModified); const xOld = getTimeOld(date.getTime()); - overlay.innerHTML = `${text.overlay.uploadedAt}: ${date.getHours()}:${date.getMinutes()} ${date.toLocaleDateString()} ${xOld} Old`; + overlay.innerHTML = `Uploaded At: ${date.getHours()}:${date.getMinutes()} ${date.toLocaleDateString()} ${xOld} Old`; overlay.appendChild(createSearchButton(imageRecord.url)); return overlay; }; diff --git a/src/contentsHelpers/ProfileGetter.ts b/src/contentsHelpers/ProfileGetter.ts new file mode 100644 index 0000000..525aa45 --- /dev/null +++ b/src/contentsHelpers/ProfileGetter.ts @@ -0,0 +1,135 @@ +/* eslint-disable class-methods-use-this */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable no-underscore-dangle */ +import { sendToBackgroundViaRelay } from '@plasmohq/messaging'; +import type { Match, Person } from '~src/misc/tinderTypes'; + +type rec = { + user: Person; +}; + +class ProfileGetter { + constructor() { + this.setCustomFetch(); + } + + /** + * Sets a passthrough for the fetch so we can monitor requests + * TODO: make this look nicer + */ + setCustomFetch() { + // save default fetch + console.log('Setting custom fetch'); + + const nativeFetch = window.fetch; + window.fetch = (...args) => new Promise((resolve, reject) => { + nativeFetch(...args).then((result) => { + this.handleFetchResponse(result.clone(), args); + resolve(result); + }).catch((err) => reject(err)); + }); + } + + /** + * TODO: move this to an external helper file + * This method is to handle the response from the custom fetch when one appears + * @param {Response} result The result from the fetch + * @param {Array} args The arguments sent back + */ + async handleFetchResponse(result: Response, args: any[]) { + const regexChecks = { + matches: /https:\/\/api.gotinder.com\/v2\/matches\?/g, + core: /https:\/\/api.gotinder.com\/v2\/recs\/core\/*/g, + profile: /https:\/\/api.gotinder.com\/v2\/profile\/*/g, + user: /https:\/\/api.gotinder.com\/user\/([A-z0-9]+)/g, + messages: /https:*:\/\/api.gotinder.com\/v2\/matches\/([A-z0-9]+)\/messages\?/g, + }; + + try { + const jsonOut = await result.json(); + + if (args[0].match(regexChecks.matches)) { + this.handleNewMatches(jsonOut); + } else if (args[0].match(regexChecks.core)) { + this.handleNewCore(jsonOut); + // TODO: handle core recs + } + } catch (e) { + console.error(e); + // if the response is not json, ignore it + } + } + + handleNewMatches(jsonOut: any) { + if (!Array.isArray(jsonOut?.data?.matches)) console.error('Invalid matches response'); + + const newMatches: Match[] = jsonOut.data.matches; + + const people = []; + + newMatches.forEach((match) => { + // getting the person from the match + const { person } = match; + person.type = 'match'; + people.push(person); + }); + + this.sendPeopleToBackground(people); + } + + handleNewCore(jsonOut: any) { + console.log('core recs', jsonOut); + if (!Array.isArray(jsonOut?.data?.results)) console.error('Invalid core response'); + + const newRecs: rec[] = jsonOut.data.results; + const people = []; + + newRecs.forEach((rec) => { + const person = rec.user; + + person.type = 'rec'; + people.push(person); + console.log('new person added from core!', person); + }); + + this.sendPeopleToBackground(people); + } + + sendPeopleToBackground(people: Person[]) { + sendToBackgroundViaRelay({ + name: 'getPeople', + body: { + people, + }, + }); + } + + // infoFromPhoto(url: string) { + // // search through all of the matches for the photo with the same URL + // return this.people.find((person) => { + // let found: Person | undefined; + // if (person.type === 'match') { + // const photoId = extractUuidFromUrl(url); + // const photoRecord = person.photos.find((photo) => photo.id === photoId); + + // if (photoRecord) { + // return { + // hqUrl: photoRecord.url, + // accountCreated: dateFromObjectId(person._id), + // }; + // } + // } else if (person.type === 'rec') { + // const id = extractRecPhotoId(url); + // const photoRecord = person.photos.find((photo) => extractRecPhotoId(photo.url) === id); + // if (photoRecord) { + // return { + // hqUrl: photoRecord.url, + // accountCreated: dateFromObjectId(person._id), + // }; + // } + // } + // }); + // } +} + +export default ProfileGetter; diff --git a/src/misc/languages.json b/src/misc/languages.json index 2269098..8082c48 100644 --- a/src/misc/languages.json +++ b/src/misc/languages.json @@ -6,7 +6,7 @@ "buttonText": "Donate Here" }, "enableOverlay": "Enable overlay", - "enableSearchButton": "Enable search button", + "enableSearchButton": "Enable Buttons", "info": { "title": "Info", "text": "Lighterfuel allows you to see when profile images were uploaded to get an idea of when they made their account and reverse image search your matches photos!" @@ -16,134 +16,8 @@ "text": "Enable the search button and click on it (only for matches) and see if that image is publicly available online (if it is, they're probably a catfish)" }, "overlay": { - "uploadedAt": "Time", + "createdAt": "Created", "search": "Search" } - }, - "de": { - "donate": { - "title": "Spenden", - "location": "Spenden gehen an den humanitären Appell der Ukraine, Slava Ukraini!", - "buttonText": "Spenden Sie hier" - }, - "enableOverlay": "Überlagerung aktivieren", - "reverseImageSearch": { - "text": "Aktivieren Sie die Suchschaltfläche und klicken Sie darauf (nur für Übereinstimmungen) und prüfen Sie, ob dieses Bild online öffentlich verfügbar ist (wenn dies der Fall ist, handelt es sich wahrscheinlich um einen Wels).", - "title": "Umgekehrte Bildsuche" - }, - "enableSearchButton": "Suchschaltfläche aktivieren", - "overlay": { - "search": "Suchen", - "uploadedAt": "Zeit" - }, - "info": { - "text": "Mit Lighterfuel können Sie sehen, wann Profilbilder hochgeladen wurden, um sich ein Bild davon zu machen, wann sie ihr Konto erstellt haben, und nach Ihren Übereinstimmungsfotos suchen!", - "title": "Die Info" - } - }, - "fr": { - "donate": { - "title": "Donner", - "location": "", - "buttonText": "Faites un don ici" - }, - "enableOverlay": "Activer la superposition", - "reverseImageSearch": { - "text": "Activez le bouton de recherche et cliquez dessus (uniquement pour les correspondances) et voyez si cette image est accessible au public en ligne (si c'est le cas, il s'agit probablement d'un poisson-chat)", - "title": "" - }, - "enableSearchButton": "Activer le bouton de recherche", - "overlay": { - "search": "Recherche", - "uploadedAt": "Temps" - }, - "info": { - "text": "Lighterfuel vous permet de voir quand les images de profil ont été téléchargées pour avoir une idée du moment où ils ont créé leur compte et inverser la recherche d'images de vos photos de correspondance !", - "title": "Info" - } - }, - "nl": { - "donate": { - "title": "Doneer", - "location": "", - "buttonText": "Doneer hier" - }, - "enableOverlay": "Overlay inschakelen", - "reverseImageSearch": { - "text": "Schakel de zoekknop in en klik erop (alleen voor overeenkomsten) en kijk of die afbeelding openbaar online beschikbaar is (als dat zo is, is het waarschijnlijk een meerval)", - "title": "" - }, - "enableSearchButton": "Schakel de zoekknop in", - "overlay": { - "search": "Zoekopdracht", - "uploadedAt": "Tijd" - }, - "info": { - "text": "Met Lighterfuel kun je zien wanneer profielafbeeldingen zijn geüpload om een idee te krijgen van wanneer ze hun account hebben gemaakt en om afbeeldingen van je matches te zoeken!", - "title": "Info" - } - }, - "ru": { - "donate": { - "title": "Пожертвовать", - "location": "Пожертвования идут на Гуманитарный призыв Украины, Слава України!", - "buttonText": "Пожертвовать здесь" - }, - "enableOverlay": "Включить наложение", - "enableSearchButton": "Включить кнопку поиска", - "info": { - "title": "Информация", - "text": "Lighterfuel позволяет вам видеть, когда изображения профилей были загружены, чтобы получить представление о том, когда они создали свою учетную запись, и выполнять обратный поиск изображений по вашим фотографиям!" - }, - "reverseImageSearch": { - "title": "Обратный поиск изображений", - "text": "Включите кнопку поиска и нажмите на нее (только для совпадений) и посмотрите, есть ли это изображение в общедоступном Интернете (если это так, это, вероятно, сом)" - }, - "overlay": { - "uploadedAt": "Время", - "search": "Поиск" - } - }, - "uk": { - "donate": { - "title": "Пожертвуйте", - "location": "Пожертви передаємо до Української гуманітарної акції Слава Україні!", - "buttonText": "Пожертвуйте тут" - }, - "enableOverlay": "Увімкнути накладання", - "enableSearchButton": "Увімкнути кнопку пошуку", - "info": { - "title": "Інформація", - "text": "Lighterfuel дозволяє вам побачити, коли було завантажено зображення профілю, щоб отримати уявлення про те, коли вони створили свій обліковий запис, і здійснити зворотній пошук зображень, які відповідають фотографіям!" - }, - "reverseImageSearch": { - "title": "Зворотний пошук зображень", - "text": "Увімкніть кнопку пошуку та натисніть на неї (лише для збігів) і подивіться, чи це зображення є загальнодоступним в Інтернеті (якщо так, це, ймовірно, сом)" - }, - "overlay": { - "uploadedAt": "час", - "search": "Пошук" - } - }, - "zh": { - "donate": { - "title": "捐", - "location": "向乌克兰人道主义呼吁 Slava Ukraini 捐款!", - "buttonText": "在这里捐款" - }, - "enableOverlay": "启用覆盖", - "enableSearchButton": "启用搜索按钮", - "info": { - "title": "信息", - "text": "Lighterfuel 允许您查看上传个人资料图片的时间,以了解他们何时创建帐户并反向搜索您的匹配照片!" - }, - "reverseImageSearch": { - "title": "反向图像搜索", - "text": "启用搜索按钮并单击它(仅用于匹配)并查看该图像是否可在线公开获取(如果是,则它们可能是鲶鱼)" - }, - "overlay": { - "uploadedAt": "时间", - "search": "搜索" - } } } \ No newline at end of file diff --git a/src/misc/tinderTypes.ts b/src/misc/tinderTypes.ts new file mode 100644 index 0000000..b0d6482 --- /dev/null +++ b/src/misc/tinderTypes.ts @@ -0,0 +1,201 @@ +export type ProcessedFile = { + url: string; + height: number; + width: number; +}; + +export interface Photos { + id: string; + url: string; + processedFiles: ProcessedFile[]; + extention: string; + rank: number; + score?: number; + win_count?: number; + media_type: 'image' | 'video'; +} + +export type badge = { + type: string; +} + +export type job = { + title: { + name: string; + } +} + +export type school = { + displayed: boolean; + name: string; +} + +export type album = { + id: string; + images: { + height: number; + width: number; + url: string; + }[]; + name: string; + preview_url: string; + uri: string; +}; + +export type spotify_artist = { + // todo + id: string; + images: { + height: number; + width: number; + url: string; + }[]; + name: string; + top_track: { + album: album; + artists: { + id: string; + name: string; + }[]; + id: string; + name: string; + preview_url: string; + uri: string; + }; +} + +export type spotify_theme_track = { + id: string; + name: string; + album: album; + artists: { + id: string; + name: string; + }[]; + preview_url: string; + uri: string; +} + +export interface UserResults { + badges: badge[], + bio: string; + city?: { + name: string; + }; + birth_date: string; + common_connections: any[]; + common_interests: any[]; + common_likes: any[]; + common_friends: any[]; + connection_count: number; + distance_mi: number; + gender: number; + is_traveling: boolean; + jobs: job[]; + name: string; + photos: Photos[]; + schools: school[]; + spotify_top_artists?: spotify_artist[]; + spotify_theme_track?: spotify_theme_track; + teasers: { + type: string; + string: string; + }[]; + user_interests?: { + selected_interests: { + id: string; + name: string; + }[]; + }; + relationship_intent?: { + body_text: string; + descriptor_choice_id: string; + emoji: string; + hidden_intent?: { + body_text: string; + emoji: string; + image_url: string; + title_text: string; + }; + image_url: string; + style: string; + title_text: string; + }; + sexual_orientations?: { + id: string; + name: string; + }[]; + selected_descriptors?: { + id: string; + name: string; + prompt: string; + type: string; + icon_url: string; + choice_selections: { + id: string; + name: string; + }[]; + }[]; + + _id: string; +} + +export type Message = { + _id: string; + match_id: string; + sent_date: string; + message: string; + to: string; + from: string; + timestamp: number; + matchId: string; +}; + +export interface Person { + _id: string; + bio?: string; + birth_date: string; + gender: number; + name: string; + photos: Photos[]; + userResults?: UserResults; + type?: 'match' | 'rec'; +} + +export interface liked_content_child { + user_id: string; + type: string; + is_swipe_note?: boolean; + photo?: Photos; +} + +export interface liked_content { + by_opener?: liked_content_child, + by_closer?: liked_content_child +} + +export interface Match { + seen: { + match_seen: boolean; + last_seen_msg_id: string; + } + _id: string; + dead: boolean; + last_activity_date: string; + created_date: string; + message_count: number; + messages: Message[]; + person: Person; + is_super_like: boolean; + is_boost_match: boolean; + is_super_boost_match: boolean; + is_experiences_match: boolean; + has_shown_initial_interest: boolean; + readreceipt: { + enabled: boolean; + } + has_harassing_feedback: boolean; + harassing_message_id: string; + liked_content: liked_content; + is_archived: boolean; +}