Skip to content

Commit

Permalink
feat(donatello): add donatello support and UAH currency
Browse files Browse the repository at this point in the history
  • Loading branch information
sogehige committed Sep 11, 2022
1 parent 7c34645 commit 537d120
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 3 deletions.
8 changes: 8 additions & 0 deletions locales/en/ui/integrations/donatello.json
@@ -0,0 +1,8 @@
{
"settings": {
"token": {
"title": "Token",
"help": "Get your token at https://donatello.to/panel/doc-api"
}
}
}
4 changes: 2 additions & 2 deletions src/currency.ts
Expand Up @@ -26,15 +26,15 @@ class Currency extends Core {
@settings('currency')
@ui({
type: 'selector',
values: ['USD', 'AUD', 'BGN', 'BRL', 'CAD', 'CHF', 'CNY', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HRK', 'HUF', 'IDR', 'ILS', 'INR', 'ISK', 'JPY', 'KRW', 'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RON', 'RUB', 'SEK', 'SGD', 'THB', 'TRY', 'ZAR'],
values: ['USD', 'AUD', 'BGN', 'BRL', 'CAD', 'CHF', 'CNY', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HRK', 'HUF', 'IDR', 'ILS', 'INR', 'ISK', 'JPY', 'KRW', 'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RON', 'RUB', 'SEK', 'SGD', 'THB', 'TRY', 'ZAR', 'UAH'],
})
public mainCurrency: CurrencyType = 'EUR';

public rates: { [key in CurrencyType]: number } = {
AUD: 0, BGN: 0, BRL: 0, CAD: 0, CHF: 0, CNY: 0, CZK: 1 /* CZK:CZK 1:1 */,
DKK: 0, EUR: 0, GBP: 0, HKD: 0, HRK: 0, HUF: 0, IDR: 0, ILS: 0, INR: 0,
ISK: 0, JPY: 0, KRW: 0, MXN: 0, MYR: 0, NOK: 0, NZD: 0, PHP: 0, PLN: 0,
RON: 0, RUB: 0, SEK: 0, SGD: 0, THB: 0, TRY: 0, USD: 0, ZAR: 0,
RON: 0, RUB: 0, SEK: 0, SGD: 0, THB: 0, TRY: 0, USD: 0, ZAR: 0, UAH: 1.494,
};

public timeouts: any = {};
Expand Down
2 changes: 1 addition & 1 deletion src/database/entity/user.ts
Expand Up @@ -2,7 +2,7 @@ import { EntitySchema } from 'typeorm';

import { ColumnNumericTransformer, SafeNumberTransformer } from './_transformer';

export type Currency = 'USD' | 'AUD' | 'BGN' | 'BRL' | 'CAD' | 'CHF' | 'CNY' | 'CZK' | 'DKK' | 'EUR' | 'GBP' | 'HKD' | 'HRK' | 'HUF' | 'IDR' | 'ILS' | 'INR' | 'ISK' | 'JPY' | 'KRW' | 'MXN' | 'MYR' | 'NOK' | 'NZD' | 'PHP' | 'PLN' | 'RON' | 'RUB' | 'SEK' | 'SGD' | 'THB' | 'TRY' | 'ZAR';
export type Currency = 'USD' | 'AUD' | 'BGN' | 'BRL' | 'CAD' | 'CHF' | 'CNY' | 'CZK' | 'DKK' | 'EUR' | 'GBP' | 'HKD' | 'HRK' | 'HUF' | 'IDR' | 'ILS' | 'INR' | 'ISK' | 'JPY' | 'KRW' | 'MXN' | 'MYR' | 'NOK' | 'NZD' | 'PHP' | 'PLN' | 'RON' | 'RUB' | 'SEK' | 'SGD' | 'THB' | 'TRY' | 'ZAR' | 'UAH';

export interface UserInterface {
userId: string; userName: string; displayname?: string; profileImageUrl?: string;
Expand Down
196 changes: 196 additions & 0 deletions src/integrations/donatello.ts
@@ -0,0 +1,196 @@
import { Currency, UserTip, UserTipInterface } from '@entity/user';
import * as constants from '@sogebot/ui-helpers/constants';
import axios from 'axios';
import { getRepository } from 'typeorm';

import currency from '../currency';
import { persistent, settings } from '../decorators';
import { onStartup } from '../decorators/on.js';
import eventlist from '../overlays/eventlist.js';
import alerts from '../registries/alerts.js';
import users from '../users.js';
import Integration from './_interface';

import { isStreamOnline, stats } from '~/helpers/api/index.js';
import { mainCurrency } from '~/helpers/currency';
import { eventEmitter } from '~/helpers/events';
import { triggerInterfaceOnTip } from '~/helpers/interface/triggers.js';
import {
error, tip,
} from '~/helpers/log.js';

type DonatelloResponse = {
content: {
pubId: string;
clientName: string;
message: string;
amount: string;
currency: Currency;
goal: string;
isPublished: boolean;
createdAt: string; // Eastern European Standard Time (EET)
}[],
page: number;
size: number;
pages: number;
first: boolean;
last: boolean;
total: number;
};

const DONATES_URL = 'https://donatello.to/api/v1/donates' as const;

function getTips (page: number, jwtToken: string, lastPubId: string): Promise<[isProcessed: boolean, tips: DonatelloResponse['content']]> {
return new Promise((resolve, reject) => {
axios.get<DonatelloResponse>(`${DONATES_URL}?size=100&page=${page}`, {
headers: {
Accept: 'application/json',
'X-Token': jwtToken,
},
}).then(response => {
const data = response.data;
const isLastPage = data.last;
const lastIdx = data.content.findIndex(o => o.pubId === lastPubId);
let tips: DonatelloResponse['content'] = data.content;
if (lastIdx !== -1) {
tips = data.content.slice(0, lastIdx);
}
resolve([isLastPage || lastIdx !== -1, tips]);
}).catch(e => reject(e));
});
}

class Donatello extends Integration {
@persistent()
lastPubId = '';

@settings()
token = '';

@onStartup()
interval() {
setInterval(async () => {
if (this.token.length === 0 || !this.enabled) {
return;
}

try {
let page = 0;
const aggregatedTips: DonatelloResponse['content'] = [];
let isProcessed = false;
while(!isProcessed) {
const data = await getTips(page, this.token, this.lastPubId);
isProcessed = data[0];
const tips = data[1];

if (isProcessed) {
aggregatedTips.push(...tips);
break;
}

page++;
}

if (aggregatedTips.length > 0) {
this.lastPubId = aggregatedTips[0].pubId;
}
for (const item of aggregatedTips) {
this.parse(item);
}
} catch (e) {
error('DONATELLO: Something wrong during tips fetch.');
error(e);
}
}, 10 * constants.SECOND);
}

async parse(data: DonatelloResponse['content'][number], isAnonymous = false): Promise<void> {
const timestamp = Date.now();

const username = data.clientName;
const amount = Number(data.amount);

isAnonymous = isAnonymous || username === '' || username === null ;

if (!isAnonymous) {
try {
const user = await users.getUserByUsername(username);
tip(`${username.toLowerCase()}${user.userId ? '#' + user.userId : ''}, amount: ${amount.toFixed(2)}${data.currency}, message: ${data.message}`);

eventlist.add({
event: 'tip',
amount: amount,
currency: data.currency,
userId: String(await users.getIdByName(username.toLowerCase()) ?? '0'),
message: data.message,
timestamp,
});

eventEmitter.emit('tip', {
isAnonymous: false,
userName: username.toLowerCase(),
amount: amount.toFixed(2),
currency: data.currency,
amountInBotCurrency: Number(currency.exchange(amount, data.currency, mainCurrency.value)).toFixed(2),
currencyInBot: mainCurrency.value,
message: data.message,
});

alerts.trigger({
event: 'tips',
service: 'donationalerts',
name: username.toLowerCase(),
amount: Number(amount.toFixed(2)),
tier: null,
currency: data.currency,
monthsName: '',
message: data.message,
});

const newTip: UserTipInterface = {
amount: Number(amount),
currency: data.currency,
sortAmount: currency.exchange(Number(amount), data.currency, mainCurrency.value),
message: data.message,
tippedAt: timestamp,
exchangeRates: currency.rates,
userId: user.userId,
};
getRepository(UserTip).save(newTip);
} catch {
return this.parse(data, true);
}
} else {
tip(`${username}#__anonymous__, amount: ${Number(amount).toFixed(2)}${data.currency}, message: ${data.message}`);
alerts.trigger({
event: 'tips',
name: username,
amount: Number(amount.toFixed(2)),
tier: null,
currency: data.currency,
monthsName: '',
message: data.message,
});
eventlist.add({
event: 'tip',
amount: amount,
currency: data.currency,
userId: `${username}#__anonymous__`,
message: data.message,
timestamp,
});
}
triggerInterfaceOnTip({
userName: username.toLowerCase(),
amount: amount,
message: data.message,
currency: data.currency,
timestamp,
});
if (isStreamOnline.value) {
stats.value.currentTips = stats.value.currentTips + Number(currency.exchange(amount, data.currency, mainCurrency.value));
}
}
}

export default new Donatello();

0 comments on commit 537d120

Please sign in to comment.