diff --git a/commons/src/websites/furry-life/furry-life.file.options.ts b/commons/src/websites/furry-life/furry-life.file.options.ts deleted file mode 100644 index a209f994..00000000 --- a/commons/src/websites/furry-life/furry-life.file.options.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Expose } from 'class-transformer'; -import { IsArray, IsOptional, IsString } from 'class-validator'; -import { DefaultFileOptions } from '../../interfaces/submission/default-options.interface'; -import { FurryLifeFileOptions } from '../../interfaces/websites/furry-life/furry-life.file.options.interface'; -import { DefaultValue } from '../../models/decorators/default-value.decorator'; -import { DefaultFileOptionsEntity } from '../../models/default-file-options.entity'; - -export class FurryLifeFileOptionsEntity - extends DefaultFileOptionsEntity - implements FurryLifeFileOptions -{ - @Expose() - @IsOptional() - @IsString() - credit?: string; - - @Expose() - @IsOptional() - @IsString() - copyright?: string; - - @Expose() - @IsString() - @DefaultValue('general-sfw.712-sfw') - album!: string; - - constructor(entity?: Partial) { - super(entity as DefaultFileOptions); - } -} diff --git a/commons/src/websites/furry-life/furry-life.options.ts b/commons/src/websites/furry-life/furry-life.options.ts deleted file mode 100644 index 4f640496..00000000 --- a/commons/src/websites/furry-life/furry-life.options.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DefaultOptionsEntity } from '../../models/default-options.entity'; -import { FurryLifeFileOptionsEntity } from './furry-life.file.options'; - -export class FurryLife { - static readonly FileOptions = FurryLifeFileOptionsEntity; - static readonly NotificationOptions = DefaultOptionsEntity; -} diff --git a/commons/src/websites/twitter/twitter.file.options.ts b/commons/src/websites/twitter/twitter.file.options.ts deleted file mode 100644 index 76caefa3..00000000 --- a/commons/src/websites/twitter/twitter.file.options.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Expose } from 'class-transformer'; -import { IsString } from 'class-validator'; -import { DefaultFileOptions } from '../../interfaces/submission/default-options.interface'; -import { TwitterFileOptions } from '../../interfaces/websites/twitter/twitter.file.options.interface'; -import { DefaultFileOptionsEntity } from '../../models/default-file-options.entity'; - -export class TwitterFileOptionsEntity - extends DefaultFileOptionsEntity - implements TwitterFileOptions -{ - @Expose() - @IsString() - contentBlur?: 'other' | 'graphic_violence' | 'adult_content'; - - constructor(entity?: Partial) { - super(entity as DefaultFileOptions); - } -} diff --git a/commons/src/websites/twitter/twitter.options.ts b/commons/src/websites/twitter/twitter.options.ts deleted file mode 100644 index fa7f13c4..00000000 --- a/commons/src/websites/twitter/twitter.options.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DefaultOptionsEntity } from '../../models/default-options.entity'; -import { TwitterFileOptionsEntity } from './twitter.file.options'; - -export class Twitter { - static readonly FileOptions = TwitterFileOptionsEntity; - static readonly NotificationOptions = DefaultOptionsEntity; -} diff --git a/electron-app/src/server/websites/furry-life/furry-life.controller.ts b/electron-app/src/server/websites/furry-life/furry-life.controller.ts deleted file mode 100644 index 34a6541f..00000000 --- a/electron-app/src/server/websites/furry-life/furry-life.controller.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Controller } from '@nestjs/common'; -import { GenericWebsiteController } from '../generic/generic.controller'; -import { FurryLife } from './furry-life.service'; - -@Controller('furrylife') -export class FurryLifeController extends GenericWebsiteController { - constructor(readonly service: FurryLife) { - super(service); - } -} diff --git a/electron-app/src/server/websites/furry-life/furry-life.module.ts b/electron-app/src/server/websites/furry-life/furry-life.module.ts deleted file mode 100644 index bb18485b..00000000 --- a/electron-app/src/server/websites/furry-life/furry-life.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Module } from '@nestjs/common'; -import { FurryLife } from './furry-life.service'; -import { FurryLifeController } from './furry-life.controller'; - -@Module({ - providers: [FurryLife], - controllers: [FurryLifeController], - exports: [FurryLife], -}) -export class FurryLifeModule {} diff --git a/electron-app/src/server/websites/furry-life/furry-life.service.ts b/electron-app/src/server/websites/furry-life/furry-life.service.ts deleted file mode 100644 index 936c5723..00000000 --- a/electron-app/src/server/websites/furry-life/furry-life.service.ts +++ /dev/null @@ -1,381 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import cheerio from 'cheerio'; -import { - DefaultOptions, - FileRecord, - FileSubmission, - FileSubmissionType, - Folder, - FurryLifeFileOptions, - PostResponse, - Submission, - SubmissionPart, - SubmissionRating, -} from 'postybirb-commons'; -import UserAccountEntity from 'src/server//account/models/user-account.entity'; -import ImageManipulator from 'src/server/file-manipulation/manipulators/image.manipulator'; -import Http from 'src/server/http/http.util'; -import { CancellationToken } from 'src/server/submission/post/cancellation/cancellation-token'; -import { - FilePostData, - PostFile, -} from 'src/server/submission/post/interfaces/file-post-data.interface'; -import { PostData } from 'src/server/submission/post/interfaces/post-data.interface'; -import { ValidationParts } from 'src/server/submission/validator/interfaces/validation-parts.interface'; -import BrowserWindowUtil from 'src/server/utils/browser-window.util'; -import FileSize from 'src/server/utils/filesize.util'; -import FormContent from 'src/server/utils/form-content.util'; -import HtmlParserUtil from 'src/server/utils/html-parser.util'; -import WebsiteValidator from 'src/server/utils/website-validator.util'; -import { GenericAccountProp } from '../generic/generic-account-props.enum'; -import { LoginResponse } from '../interfaces/login-response.interface'; -import { ScalingOptions } from '../interfaces/scaling-options.interface'; -import { Website } from '../website.base'; - -@Injectable() -export class FurryLife extends Website { - readonly BASE_URL = 'https://furrylife.online'; - readonly acceptsFiles = ['jpeg', 'jpg', 'png', 'gif']; - readonly acceptsAdditionalFiles = true; - readonly PROP_ACCOUNT_ID: string = 'accountId'; - readonly SFW_ALBUM: string = 'general-sfw.712-sfw'; - readonly NSFW_ALBUM: string = 'explicit-nsfw.714-nsfw'; - - async checkLoginStatus(data: UserAccountEntity): Promise { - const status: LoginResponse = { loggedIn: false, username: null }; - const { body } = await Http.get(`${this.BASE_URL}/account`, data._id); - if (!body.includes('Log in')) { - status.loggedIn = true; - const $ = cheerio.load(body); - status.username = $('.avatar').siblings('.p-navgroup-linkText').text(); - const accountProfileId = `${status.username}.${$('.avatar').attr('data-user-id')}`; - this.storeAccountInformation(data._id, this.PROP_ACCOUNT_ID, accountProfileId); - try { - await this.loadAlbums(data._id, accountProfileId); - } catch { - this.logger.error('Unable to load albums'); - } - } - return status; - } - - private async loadAlbums(profileId: string, accountId: string) { - const { body } = await Http.get( - `${this.BASE_URL}/media/albums/users/${accountId}`, - profileId, - ); - const $ = cheerio.load(body); - const albumUrls: string[] = []; - $('a').each((i: number, el: any) => { - if ( - el.attribs.href && - el.attribs.href.includes('media/albums') && - el.parentNode.attribs.class?.includes('itemList-item') && - !albumUrls.includes(el.attribs.href) - ) { - albumUrls.push(el.attribs.href); - } - }); - - const data = await Promise.all( - albumUrls.map(async albumUrl => { - const res = await Http.get(`${this.BASE_URL}${albumUrl}`, profileId); - const $$ = cheerio.load(res.body); - const urlParts = albumUrl.split('/'); - urlParts.pop(); - const nsfw = !res.body.includes('general-sfw-albums.1'); - return { - value: `${urlParts.pop()}-${nsfw ? 'nsfw' : 'sfw'}`, - nsfw, - label: $$('.p-title-value').text().trim(), - }; - }), - ); - - const sfwFolder: Folder = { - value: 'sfw', - label: 'SFW', - children: [ - { - value: this.SFW_ALBUM, - label: 'General (SFW)', - nsfw: false, - }, - ...data.filter(d => !d.nsfw).sort((a, b) => a.label.localeCompare(b.label)), - ], - }; - - const nsfwFolder: Folder = { - value: 'nsfw', - label: 'NSFW', - children: [ - { - value: this.NSFW_ALBUM, - label: 'General (NSFW)', - nsfw: true, - }, - ...data.filter(d => d.nsfw).sort((a, b) => a.label.localeCompare(b.label)), - ], - }; - - this.storeAccountInformation(profileId, GenericAccountProp.FOLDERS, [sfwFolder, nsfwFolder]); - } - - getScalingOptions(file: FileRecord): ScalingOptions { - return { maxSize: FileSize.MBtoBytes(1023) }; - } - - parseDescription(text: string) { - return text; - } - - private async upload( - profileId: string, - token: string, - url: string, - file: PostFile, - ): Promise { - const data = { - _xfToken: token, - _xfResponseType: 'json', - _xfWithData: '1', - flowChunkNumber: '1', - flowChunkSize: '4294967296', - flowCurrentChunkSize: file.value.length, - flowCTotalSize: file.value.length, - flowIdentifier: `${file.value.length}-${file.options.filename.replace('.', '')}`, - flowFilename: file.options.filename, - flowRelativePath: file.options.filename, - flowTotalChunks: '1', - upload: file, - }; - - const res = await Http.post<{ status: string; attachment: any; errors: any[] }>( - url, - profileId, - { - type: 'multipart', - data, - requestOptions: { - json: true, - }, - }, - ); - - this.verifyResponse(res, 'Upload verify'); - - if (res.body.status === 'ok') { - return res.body.attachment; - } - - return Promise.reject( - this.createPostResponse({ message: Object.values(res.body.errors).join('\n') }), - ); - } - - async postFileSubmission( - cancellationToken: CancellationToken, - data: FilePostData, - ): Promise { - const { options } = data; - - const albumParts = options.album.split('-'); - albumParts.pop(); - const album = albumParts.join('-'); - - const isNotAlbum = options.album === this.SFW_ALBUM || options.album === this.NSFW_ALBUM; - - const files = [data.primary, ...data.additional].map(f => f.file); - - await BrowserWindowUtil.getPage( - data.part.accountId, - `${this.BASE_URL}/media/${isNotAlbum ? 'categories' : 'albums'}/${album}/add`, - false, - ); - - const { body } = await Http.get( - `${this.BASE_URL}/media/${isNotAlbum ? 'categories' : 'albums'}/${album}/add`, - data.part.accountId, - ); - - const token = body.match(/data-csrf="(.*?)"/)[1]; - const href = `${this.BASE_URL}${ - body.match(/href="\/attachments\/upload\?type=(.*?)"/)[0].match(/"(.*?)"/)[1] - }`.replace(/&/g, '&'); - const hash = HtmlParserUtil.getInputValue(body, 'attachment_hash'); - const hashCombined = HtmlParserUtil.getInputValue(body, 'attachment_hash_combined').replace( - /"/g, - '"', - ); - - this.checkCancelled(cancellationToken); - try { - const uploads = await Promise.all( - files.map(file => this.upload(data.part.accountId, token, href, file)), - ); - - const uploadData: any = { - attachment_hash: hash, - attachment_hash_combined: hashCombined, - _xfToken: token, - _xfRequestUri: `/media/${isNotAlbum ? 'categories' : 'albums'}/${album}/add`, - _xfWithData: '1', - _xfResponseType: 'json', - }; - - if (isNotAlbum) { - uploadData.category_id = album.split('.').pop(); - } else { - uploadData.album_id = album.split('.').pop(); - } - - uploads.forEach(u => { - const mediaId = `media[${u.temp_media_id}]`; - uploadData[`${mediaId}[title]`] = data.title; - uploadData[`${mediaId}[description]`] = ''; - uploadData[`${mediaId}[tags]`] = this.formatTags(data.tags).join(', '); - uploadData[`${mediaId}[temp_media_id]`] = u.temp_media_id; - uploadData[`${mediaId}[media_hash]`] = u.media_hash; - uploadData[`${mediaId}[media_type]`] = u.type_grouping; - uploadData[`${mediaId}[attachment_id]`] = u.attachment_id; - uploadData[`${mediaId}[custom_fields][caption_html]`] = data.description; - uploadData[`${mediaId}[custom_fields][artist]`] = data.options.credit || ''; - uploadData[`${mediaId}[custom_fields][artist_url]`] = ''; - uploadData[`${mediaId}[custom_fields][characters]`] = ''; - }); - - const { body } = await Http.post<{ status: string; errors: any[]; redirect: string }>( - `${this.BASE_URL}/media/save-media`, - data.part.accountId, - { - type: 'multipart', - data: uploadData, - requestOptions: { - json: true, - }, - }, - ); - - if (body.status === 'ok') { - return this.createPostResponse({ source: body.redirect }); - } else { - return Promise.reject( - this.createPostResponse({ error: Object.values(body.errors).join('\n') }), - ); - } - } catch (err) { - return Promise.reject(this.createPostResponse({ additionalInfo: err })); - } - } - - async postNotificationSubmission( - cancellationToken: CancellationToken, - data: PostData, - ): Promise { - await BrowserWindowUtil.getPage(data.part.accountId, this.BASE_URL, false); - - const { body } = await Http.get( - `${this.BASE_URL}/members/${this.getAccountInfo(data.part.accountId, this.PROP_ACCOUNT_ID)}`, - data.part.accountId, - ); - - const hash = HtmlParserUtil.getInputValue(body, 'attachment_hash'); - const hashCombined = HtmlParserUtil.getInputValue(body, 'attachment_hash_combined').replace( - /"/g, - '"', - ); - - const form = { - _xfToken: body.match(/data-csrf="(.*?)"/)[1], - message_html: data.description, - _xfWithData: '1', - _xfResponseType: 'json', - _xfRequestUri: `/members/${this.getAccountInfo(data.part.accountId, this.PROP_ACCOUNT_ID)}`, - attachment_hash: hash, - attachment_hash_combined: hashCombined, - }; - - this.checkCancelled(cancellationToken); - const post = await Http.post<{ status: string; errors: any[] }>( - `${this.BASE_URL}/members/${this.getAccountInfo( - data.part.accountId, - this.PROP_ACCOUNT_ID, - )}/post`, - data.part.accountId, - { - type: 'multipart', - data: form, - requestOptions: { - json: true, - }, - }, - ); - - if (post.body.status === 'ok') { - return this.createPostResponse({}); - } else { - return Promise.reject( - this.createPostResponse({ error: Object.values(post.body.errors).join('\n') }), - ); - } - - return Promise.reject(this.createPostResponse({ additionalInfo: post.body })); - } - - validateFileSubmission( - submission: FileSubmission, - submissionPart: SubmissionPart, - defaultPart: SubmissionPart, - ): ValidationParts { - const problems: string[] = []; - const warnings: string[] = []; - const isAutoscaling: boolean = submissionPart.data.autoScale; - - const folder = submissionPart.data.album; - const rating = submissionPart.data.rating || defaultPart.data.rating; - if (folder.endsWith('nsfw') && rating === SubmissionRating.GENERAL) { - warnings.push('Potentially uploading NSFW to SFW Album'); - } - - if ( - !WebsiteValidator.folderIdExists( - folder, - this.getAccountInfo(submissionPart.accountId, GenericAccountProp.FOLDERS), - ) - ) { - warnings.push(`Album (${folder}) not found.`); - } - - if (FormContent.getTags(defaultPart.data.tags, submissionPart.data.tags).length < 2) { - problems.push('Requires at least 2 tags.'); - } - - const files = [ - submission.primary, - ...(submission.additional || []).filter( - f => !f.ignoredAccounts!.includes(submissionPart.accountId), - ), - ]; - - const maxMB: number = 1023; - files.forEach(file => { - const { type, size, name, mimetype } = file; - if (!WebsiteValidator.supportsFileType(file, this.acceptsFiles)) { - problems.push(`Does not support file format: (${name}) ${mimetype}.`); - } - if (FileSize.MBtoBytes(maxMB) < size) { - if ( - isAutoscaling && - type === FileSubmissionType.IMAGE && - ImageManipulator.isMimeType(mimetype) - ) { - warnings.push(`${name} will be scaled down to ${maxMB}MB`); - } else { - problems.push(`FurryLife limits ${mimetype} to ${maxMB}MB`); - } - } - }); - - return { problems, warnings }; - } -} diff --git a/electron-app/src/server/websites/twitter/twitter-account.interface.ts b/electron-app/src/server/websites/twitter/twitter-account.interface.ts deleted file mode 100644 index 85f3cf32..00000000 --- a/electron-app/src/server/websites/twitter/twitter-account.interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface TwitterAccountData { - user_id: number; - screen_name: string; - oauth_token: string; - oauth_token_secret: string; -} diff --git a/electron-app/src/server/websites/twitter/twitter.module.ts b/electron-app/src/server/websites/twitter/twitter.module.ts deleted file mode 100644 index 51c36245..00000000 --- a/electron-app/src/server/websites/twitter/twitter.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Module } from '@nestjs/common'; -import { Twitter } from './twitter.service'; - -@Module({ - providers: [Twitter], - exports: [Twitter], -}) -export class TwitterModule {} diff --git a/electron-app/src/server/websites/twitter/twitter.service.ts b/electron-app/src/server/websites/twitter/twitter.service.ts deleted file mode 100644 index 17a9070b..00000000 --- a/electron-app/src/server/websites/twitter/twitter.service.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { SubmissionRating } from 'postybirb-commons'; -import { - DefaultOptions, - FileRecord, - FileSubmission, - FileSubmissionType, - PostResponse, - Submission, - SubmissionPart, - TwitterFileOptions, -} from 'postybirb-commons'; -import UserAccountEntity from 'src/server//account/models/user-account.entity'; -import { UsernameParser } from 'src/server/description-parsing/miscellaneous/username.parser'; -import { PlaintextParser } from 'src/server/description-parsing/plaintext/plaintext.parser'; -import ImageManipulator from 'src/server/file-manipulation/manipulators/image.manipulator'; -import Http from 'src/server/http/http.util'; -import { CancellationToken } from 'src/server/submission/post/cancellation/cancellation-token'; -import { FilePostData } from 'src/server/submission/post/interfaces/file-post-data.interface'; -import { PostData } from 'src/server/submission/post/interfaces/post-data.interface'; -import { ValidationParts } from 'src/server/submission/validator/interfaces/validation-parts.interface'; -import FileSize from 'src/server/utils/filesize.util'; -import FormContent from 'src/server/utils/form-content.util'; -import { OAuthUtil } from 'src/server/utils/oauth.util'; -import WebsiteValidator from 'src/server/utils/website-validator.util'; -import { LoginResponse } from '../interfaces/login-response.interface'; -import { ScalingOptions } from '../interfaces/scaling-options.interface'; -import { Website } from '../website.base'; -import { TwitterAccountData } from './twitter-account.interface'; - -@Injectable() -export class Twitter extends Website { - readonly BASE_URL = ''; - readonly acceptsAdditionalFiles = true; - readonly enableAdvertisement = false; - readonly defaultDescriptionParser = PlaintextParser.parse; - readonly acceptsFiles = ['jpeg', 'jpg', 'png', 'gif', 'webp', 'mp4', 'mov']; - readonly usernameShortcuts = [ - { - key: 'tw', - url: 'https://twitter.com/$1', - }, - ]; - - getScalingOptions(file: FileRecord): ScalingOptions { - return { maxSize: FileSize.MBtoBytes(5) }; - } - - preparseDescription(text: string) { - return UsernameParser.replaceText(text, 'tw', '@$1'); - } - - async checkLoginStatus(data: UserAccountEntity): Promise { - const status: LoginResponse = { loggedIn: false, username: null }; - const accountData: TwitterAccountData = data.data; - if (accountData && accountData.oauth_token) { - status.loggedIn = true; - status.username = accountData.screen_name; - } - return status; - } - - async postFileSubmission( - cancellationToken: CancellationToken, - data: FilePostData, - accountData: TwitterAccountData, - ): Promise { - let contentBlur = data?.options?.contentBlur; - - const form: any = { - token: accountData.oauth_token, - secret: accountData.oauth_token_secret, - title: '', - description: data.description, - tags: data.tags, - files: [data.primary, ...data.additional].map(f => ({ - data: f.file.value.toString('base64'), - ...f.file.options, - })), - rating: data.rating, - options: { - contentBlur, - }, - }; - - this.checkCancelled(cancellationToken); - const post = await Http.post<{ success: boolean; data: any; error: string }>( - OAuthUtil.getURL('twitter/v2/post'), - undefined, - { - type: 'json', - data: form, - requestOptions: { json: true }, - }, - ); - - if (post.body.success) { - return this.createPostResponse({ source: post.body.data.url }); - } - - return Promise.reject( - this.createPostResponse({ additionalInfo: post.body, message: post.body.error }), - ); - } - - async postNotificationSubmission( - cancellationToken: CancellationToken, - data: PostData, - accountData: TwitterAccountData, - ): Promise { - const form: any = { - token: accountData.oauth_token, - secret: accountData.oauth_token_secret, - title: '', - description: data.description, - tags: data.tags, - rating: data.rating, - options: {}, - }; - - this.checkCancelled(cancellationToken); - const post = await Http.post<{ success: boolean; data: { url: string }; error: string }>( - OAuthUtil.getURL('twitter/v2/post'), - undefined, - { - type: 'json', - data: form, - requestOptions: { json: true }, - }, - ); - - if (post.body.success) { - return this.createPostResponse({ source: post.body.data.url }); - } - - return Promise.reject( - this.createPostResponse({ additionalInfo: post.body, message: post.body.error }), - ); - } - - validateFileSubmission( - submission: FileSubmission, - submissionPart: SubmissionPart, - defaultPart: SubmissionPart, - ): ValidationParts { - const problems: string[] = []; - const warnings: string[] = []; - const isAutoscaling: boolean = submissionPart.data.autoScale; - - const description = PlaintextParser.parse( - FormContent.getDescription(defaultPart.data.description, submissionPart.data.description), - 23, - ); - - if (description.length > 280) { - warnings.push( - `Approximated description may surpass 280 character limit (${description.length})`, - ); - } - - const files = [ - submission.primary, - ...(submission.additional || []).filter( - f => !f.ignoredAccounts!.includes(submissionPart.accountId), - ), - ]; - - files.forEach(file => { - const { type, size, name, mimetype } = file; - if (!WebsiteValidator.supportsFileType(file, this.acceptsFiles)) { - problems.push(`Does not support file format: (${name}) ${mimetype}.`); - } - - let maxMB: number = mimetype === 'image/gif' ? 15 : 5; - if (type === FileSubmissionType.VIDEO) { - maxMB = 15; - } - if (FileSize.MBtoBytes(maxMB) < size) { - if ( - isAutoscaling && - type === FileSubmissionType.IMAGE && - ImageManipulator.isMimeType(mimetype) - ) { - warnings.push(`${name} will be scaled down to ${maxMB}MB`); - } else { - problems.push(`Twitter limits ${mimetype} to ${maxMB}MB`); - } - } - }); - - return { problems, warnings }; - } - - validateNotificationSubmission( - submission: Submission, - submissionPart: SubmissionPart, - defaultPart: SubmissionPart, - ): ValidationParts { - const warnings = []; - - const description = PlaintextParser.parse( - FormContent.getDescription(defaultPart.data.description, submissionPart.data.description), - 23, - ); - - if (description.length > 280) { - warnings.push( - `Approximated description may surpass 280 character limit (${description.length})`, - ); - } - - return { problems: [], warnings }; - } -} diff --git a/electron-app/src/server/websites/website-provider.service.ts b/electron-app/src/server/websites/website-provider.service.ts index ed755f77..20819ae3 100644 --- a/electron-app/src/server/websites/website-provider.service.ts +++ b/electron-app/src/server/websites/website-provider.service.ts @@ -16,7 +16,6 @@ import { Aryion } from './aryion/aryion.service'; import { Custom } from './custom/custom.service'; import { Newgrounds } from './newgrounds/newgrounds.service'; import { Pixiv } from './pixiv/pixiv.service'; -import { FurryLife } from './furry-life/furry-life.service'; import { Furtastic } from './furtastic/furtastic.service'; import { FurryNetwork } from './furry-network/furry-network.service'; import { Patreon } from './patreon/patreon.service'; @@ -24,7 +23,6 @@ import { Tumblr } from './tumblr/tumblr.service'; import { DeviantArt } from './deviant-art/deviant-art.service'; import { Manebooru } from './manebooru/manebooru.service'; import { Mastodon } from './mastodon/mastodon.service'; -import { Twitter } from './twitter/twitter.service'; import { Pillowfort } from './pillowfort/pillowfort.service'; import { Telegram } from './telegram/telegram.service'; import { Furbooru } from './furbooru/furbooru.service'; @@ -67,7 +65,6 @@ export class WebsiteProvider { readonly manebooru: Manebooru, readonly mastodon: Mastodon, readonly misskey: MissKey, - readonly twitter: Twitter, readonly pillowfort: Pillowfort, readonly telegram: Telegram, readonly furbooru: Furbooru, diff --git a/electron-app/src/server/websites/websites.module.ts b/electron-app/src/server/websites/websites.module.ts index 42406496..eca07fa4 100644 --- a/electron-app/src/server/websites/websites.module.ts +++ b/electron-app/src/server/websites/websites.module.ts @@ -19,7 +19,6 @@ import { AryionModule } from './aryion/aryion.module'; import { CustomModule } from './custom/custom.module'; import { NewgroundsModule } from './newgrounds/newgrounds.module'; import { PixivModule } from './pixiv/pixiv.module'; -import { FurryLifeModule } from './furry-life/furry-life.module'; import { FurryNetworkModule } from './furry-network/furry-network.module'; import { PatreonModule } from './patreon/patreon.module'; import { TumblrModule } from './tumblr/tumblr.module'; @@ -27,7 +26,6 @@ import { DeviantArtModule } from './deviant-art/deviant-art.module'; import { ManebooruModule } from './manebooru/manebooru.module'; import { MastodonModule } from './mastodon/mastodon.module'; import { MissKeyModule } from './misskey/misskey.module'; -import { TwitterModule } from './twitter/twitter.module'; import { PillowfortModule } from './pillowfort/pillowfort.module'; import { TelegramModule } from './telegram/telegram.module'; import { FurbooruModule } from './furbooru/furbooru.module'; @@ -53,7 +51,6 @@ import { BlueskyModule } from './bluesky/bluesky.module'; FurAffinityModule, FurtasticModule, FurbooruModule, - FurryLifeModule, FurryNetworkModule, HentaiFoundryModule, InkbunnyModule, @@ -71,7 +68,6 @@ import { BlueskyModule } from './bluesky/bluesky.module'; SubscribeStarAdultModule, TelegramModule, TumblrModule, - TwitterModule, WeasylModule, ItakuModule, PicartoModule, diff --git a/ui/src/websites/furry-life/FurryLife.tsx b/ui/src/websites/furry-life/FurryLife.tsx deleted file mode 100644 index 03946dd2..00000000 --- a/ui/src/websites/furry-life/FurryLife.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { Form, Input, Select } from 'antd'; -import { - DefaultOptions, - FileSubmission, - Folder, - FurryLifeFileOptions, - Submission -} from 'postybirb-commons'; -import React from 'react'; -import WebsiteService from '../../services/website.service'; -import { WebsiteSectionProps } from '../form-sections/website-form-section.interface'; -import GenericFileSubmissionSection from '../generic/GenericFileSubmissionSection'; -import { GenericSelectProps } from '../generic/GenericSelectProps'; -import GenericSubmissionSection from '../generic/GenericSubmissionSection'; -import { WebsiteImpl } from '../website.base'; - -export class FurryLife extends WebsiteImpl { - internalName: string = 'FurryLife'; - name: string = 'FurryLife'; - supportsAdditionalFiles: boolean = true; - supportsTags: boolean = true; - loginUrl: string = 'https://furrylife.online'; - - FileSubmissionForm = (props: WebsiteSectionProps) => ( - - ); - - NotificationSubmissionForm = (props: WebsiteSectionProps) => ( - - ); -} - -interface FurryLifeFileSubmissionState { - folders: Folder[]; -} - -export class FurryLifeFileSubmissionForm extends GenericFileSubmissionSection< - FurryLifeFileOptions -> { - state: FurryLifeFileSubmissionState = { - folders: [] - }; - - constructor(props: WebsiteSectionProps) { - super(props); - this.state = { - folders: [] - }; - - WebsiteService.getAccountFolders(this.props.part.website, this.props.part.accountId).then( - ({ data }) => { - if (data) { - this.setState({ folders: data }); - } - } - ); - } - - renderRightForm(data: FurryLifeFileOptions) { - const elements = super.renderRightForm(data); - elements.push( - - - , - - - , - - - - ); - return elements; - } -} diff --git a/ui/src/websites/twitter/Twitter.tsx b/ui/src/websites/twitter/Twitter.tsx deleted file mode 100644 index 628d50c3..00000000 --- a/ui/src/websites/twitter/Twitter.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { Form, Radio } from 'antd'; -import { - DefaultFileOptions, - DefaultOptions, - FileSubmission, - Submission, - SubmissionRating, - TwitterFileOptions -} from 'postybirb-commons'; -import React from 'react'; -import { WebsiteSectionProps } from '../form-sections/website-form-section.interface'; -import GenericFileSubmissionSection from '../generic/GenericFileSubmissionSection'; -import GenericSubmissionSection from '../generic/GenericSubmissionSection'; -import { LoginDialogProps } from '../interfaces/website.interface'; -import { WebsiteImpl } from '../website.base'; -import { TwitterLogin } from './TwitterLogin'; - -export class Twitter extends WebsiteImpl { - internalName: string = 'Twitter'; - name: string = 'Twitter'; - supportsAdditionalFiles: boolean = true; - supportsTags = false; - loginUrl: string = ''; - - LoginDialog = (props: LoginDialogProps) => ; - - FileSubmissionForm = (props: WebsiteSectionProps) => ( - - ); - - NotificationSubmissionForm = (props: WebsiteSectionProps) => ( - - ); -} - -export class TwitterFileSubmissionForm extends GenericFileSubmissionSection { - renderLeftForm(data: TwitterFileOptions) { - const elements = super.renderLeftForm(data); - elements.push( - - - None - Other - Adult Content - Graphic Violence - - - ); - return elements; - } - - renderRightForm(data: TwitterFileOptions) { - const elements = super.renderRightForm(data); - return elements; - } -} diff --git a/ui/src/websites/twitter/TwitterLogin.tsx b/ui/src/websites/twitter/TwitterLogin.tsx deleted file mode 100644 index 87bbd113..00000000 --- a/ui/src/websites/twitter/TwitterLogin.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { Button, Form, Input, message, Spin } from 'antd'; -import Axios from 'axios'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { TumblrAccountData } from 'postybirb-commons'; -import LoginService from '../../services/login.service'; -import { LoginDialogProps } from '../interfaces/website.interface'; - -interface State { - loading: boolean; - pin: string; -} - -export class TwitterLogin extends React.Component { - state: State = { - loading: true, - pin: '' - }; - - private oauth_token: string = ''; - - componentDidMount() { - const node = ReactDOM.findDOMNode(this); - if (node instanceof HTMLElement) { - const view: any = node.querySelector('.webview'); - view.addEventListener('did-stop-loading', () => { - if (this.state.loading) this.setState({ loading: false }); - }); - view.allowpopups = true; - view.partition = `persist:${this.props.account._id}`; - Axios.get<{ data: { url: string; oauth_token: string } }>( - `${window.AUTH_SERVER_URL}/twitter/v2/authorize` - ) - .then(({ data }) => { - view.src = data.data.url; - this.oauth_token = data.data.oauth_token; - this.setState({ loading: false }); - }) - .catch(() => { - message.error('A problem occurred when attempting to contact authentication server.'); - }); - } - } - - updateAuthData(data: TumblrAccountData) { - LoginService.setAccountData(this.props.account._id, data).then(() => { - message.success('Twitter Authenticated.'); - }); - } - - isValid(): boolean { - return !!this.state.pin; - } - - submit() { - Axios.post<{ success: boolean; error: string; data: any }>( - `${window.AUTH_SERVER_URL}/twitter/v2/authorize/`, - { - verifier: this.state.pin.trim(), - oauth_token: this.oauth_token - }, - { responseType: 'json' } - ) - .then(({ data }) => { - if (data.success) { - LoginService.setAccountData(this.props.account._id, data.data).then(() => { - message.success('Twitter authenticated.'); - }); - } else { - message.error(data.error); - } - }) - .catch(() => { - message.error('Failed to authenticate Twitter.'); - }); - } - - render() { - return ( -
-
-
- - this.setState({ pin: target.value })} - addonAfter={ - - } - /> - -
-
- - - -
- ); - } -} diff --git a/ui/src/websites/website-registry.ts b/ui/src/websites/website-registry.ts index 0451443c..29a636d1 100644 --- a/ui/src/websites/website-registry.ts +++ b/ui/src/websites/website-registry.ts @@ -16,7 +16,6 @@ import { Aryion } from './aryion/Aryion'; import { Custom } from './custom/Custom'; import { Newgrounds } from './newgrounds/Newgrounds'; import { Pixiv } from './pixiv/Pixiv'; -import { FurryLife } from './furry-life/FurryLife'; import { FurryNetwork } from './furry-network/FurryNetwork'; import { Patreon } from './patreon/Patreon'; import { Tumblr } from './tumblr/Tumblr'; @@ -24,7 +23,6 @@ import { DeviantArt } from './deviant-art/DeviantArt'; import { Manebooru } from './manebooru/Manebooru'; import { Mastodon } from './mastodon/Mastodon'; import { MissKey } from './misskey/MissKey'; -import { Twitter } from './twitter/Twitter'; import { Pillowfort } from './pillowfort/Pillowfort'; import { Telegram } from './telegram/Telegram'; import { Furbooru } from './furbooru/Furbooru'; @@ -66,7 +64,6 @@ export class WebsiteRegistry { SubscribeStarAdult: new SubscribeStarAdult(), Telegram: new Telegram(), Tumblr: new Tumblr(), - Twitter: new Twitter(), Weasyl: new Weasyl(), e621: new e621() };