twtitch emote support
This commit is contained in:
parent
525cb6116e
commit
f7e3248b90
7 changed files with 218 additions and 166 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -104,4 +104,5 @@ src/sounds/tts/*
|
|||
loquendoBot_backend.spec
|
||||
forge.config.js
|
||||
backend/*
|
||||
src/backend/loquendoBot_backend.exe
|
||||
src/backend/loquendoBot_backend.exe
|
||||
src/config/twitch-emotes.json
|
||||
|
|
|
|||
|
|
@ -336,6 +336,17 @@
|
|||
tip="Test Twitch credentials"
|
||||
></i>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow inputTwitch">
|
||||
<div class="AdvancedMenuLabel">Get Twitch emotes</div>
|
||||
<button type="text" class="AdvancedMenuButton" id="GetTwitchEmotes">
|
||||
<img src="https://static-cdn.jtvnw.net/emoticons/v2/25/static/light/1.0" />
|
||||
</button>
|
||||
<i
|
||||
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||
id="Info_TWITCH_GET_EMOTES"
|
||||
tip="Get Twitch emotes available to you"
|
||||
></i>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset id="AdvancedMenuServer" class="AdvancedMenu">
|
||||
|
|
|
|||
122
src/js/auth.js
122
src/js/auth.js
|
|
@ -4,7 +4,7 @@ const twitchAuthentication = () =>
|
|||
new Promise(resolve => {
|
||||
const http = require('http');
|
||||
const redirectUri = 'http://localhost:1989/auth';
|
||||
const scopes = ['chat:edit', 'chat:read'];
|
||||
const scopes = ['chat:edit', 'chat:read', 'user:read:follows', 'user:read:subscriptions'];
|
||||
|
||||
const express = require('express');
|
||||
const tempAuthServer = express();
|
||||
|
|
@ -24,10 +24,6 @@ const twitchAuthentication = () =>
|
|||
next();
|
||||
});
|
||||
|
||||
// function stopServer() {
|
||||
// tempAuthServer.close();
|
||||
// }
|
||||
|
||||
const htmlString = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
|
@ -99,119 +95,11 @@ function getTwitchUserId() {
|
|||
});
|
||||
}
|
||||
|
||||
function getTwitchSubscriptions(channelId) {
|
||||
// Get user Logo with access token
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelId}`,
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
console.log(responseLogoUrl);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchChannelEmotes(channelId) {
|
||||
// Get user Logo with access token
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelId}`,
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
console.log(responseLogoUrl);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchChannelFollows(channelId) {
|
||||
// Get user Logo with access token
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: 'https://api.twitch.tv/helix/streams/followed',
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
console.log(responseLogoUrl);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchChannelSubscriptions(channelId) {
|
||||
// Get user Logo with access token
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelId}`,
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
console.log(responseLogoUrl);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchChannelId() {
|
||||
// Get user Logo with access token
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: 'https://api.twitch.tv/helix/users?login=MelvyCoral',
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
// console.log(responseLogoUrl);
|
||||
getTwitchChannelEmotes(responseLogoUrl.data.data[0].id);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchOauthToken() {
|
||||
// getTwitchChannelId();
|
||||
getTwitchGLobalEmotes();
|
||||
// return twitchAuthentication().then(res => {
|
||||
// getTwitchUserId();
|
||||
// return res;
|
||||
// });
|
||||
return twitchAuthentication().then(res => {
|
||||
getTwitchUserId();
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { getTwitchOauthToken };
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
const customEmojis = [
|
||||
{
|
||||
name: 'sakuraestaKleefeliz',
|
||||
shortcodes: ['sakuraestaKleefeliz'],
|
||||
url: 'https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_0cb536ddb6e143ab87ffeccb160a4d45/default/dark/1.0'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports = { customEmojis };
|
||||
|
|
@ -25,6 +25,8 @@ const settings = main.settings;
|
|||
const googleVoices = fs.readFileSync(path.join(__dirname, './config/googleVoices.txt')).toString().split('\r\n');
|
||||
// TODO: remove amazon voices txt and use api instead (sakura project has it)
|
||||
const amazonVoices = fs.readFileSync(path.join(__dirname, './config/amazonVoices.txt')).toString().split('\r\n');
|
||||
const emoteListSavePath =
|
||||
main.isPackaged === true ? path.join(resourcesPath, './twitch-emotes.json') : path.join(resourcesPath, './config/twitch-emotes.json');
|
||||
|
||||
// html elements
|
||||
const root = document.documentElement;
|
||||
|
|
@ -273,25 +275,13 @@ function setZoomLevel(currentZoom, zoomIn) {
|
|||
document.body.querySelector('#ZOOMLEVEL').value = (settings.GENERAL.ZOOMLEVEL * 100).toFixed(0);
|
||||
}
|
||||
|
||||
// const customEmojix = [
|
||||
// {
|
||||
// name: 'sakuraestaKleefeliz',
|
||||
// shortcodes: ['sakuraestaKleefeliz'],
|
||||
// url: 'https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_0cb536ddb6e143ab87ffeccb160a4d45/default/dark/1.0',
|
||||
// category: 'Sakura'
|
||||
// }
|
||||
// ];
|
||||
|
||||
// const customEmojiy = [
|
||||
// {
|
||||
// name: 'sakuraestaKleefeliz',
|
||||
// shortcodes: ['sakuraestaKleefeliz'],
|
||||
// url: 'https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_0cb536ddb6e143ab87ffeccb160a4d45/default/dark/1.0',
|
||||
// category: 'Sakurax'
|
||||
// }
|
||||
// ];
|
||||
|
||||
// emojiPicker.customEmoji = customEmojix;
|
||||
// emojiPicker.customEmoji = customEmojiy;
|
||||
|
||||
// console.log(emojiPicker.database.getEmojiBySearchQuery('Kappa'));
|
||||
if (fs.existsSync(emoteListSavePath)) {
|
||||
fs.readFile(emoteListSavePath, 'utf8', (error, data) => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return;
|
||||
}
|
||||
const emotes = JSON.parse(data);
|
||||
emojiPicker.customEmoji = emotes;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,19 +137,12 @@ document.body.querySelector('#notificationSoundAudioDevice').addEventListener('c
|
|||
document.body.querySelector('#TWITCH_CHANNEL_NAME').addEventListener('change', () => {
|
||||
settings.TWITCH.CHANNEL_NAME = document.body.querySelector('#TWITCH_CHANNEL_NAME').value;
|
||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||
|
||||
const button = document.body.querySelector('#TestTwitchCredentials');
|
||||
button.className = 'AdvancedMenuButton';
|
||||
createNotification('Saved Channel name, please restart the application to reset twitch service', 'warning');
|
||||
});
|
||||
|
||||
document.body.querySelector('#TWITCH_OAUTH_TOKEN').addEventListener('change', () => {
|
||||
settings.TWITCH.OAUTH_TOKEN = document.body.querySelector('#TWITCH_OAUTH_TOKEN').value;
|
||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||
createNotification('Saved OAuth token!', 'success');
|
||||
|
||||
const button = document.body.querySelector('#TestTwitchCredentials');
|
||||
button.className = 'AdvancedMenuButton';
|
||||
createNotification('Saved OAuth token, please restart the application to reset twitch service', 'warning');
|
||||
});
|
||||
|
||||
|
|
@ -340,6 +333,11 @@ document.body.querySelector('#TestTwitchCredentials').addEventListener('click',
|
|||
// resetTwitch(;
|
||||
});
|
||||
|
||||
document.body.querySelector('#GetTwitchEmotes').addEventListener('click', () => {
|
||||
twitch.getUserAvailableTwitchEmotes('#GetTwitchEmotes');
|
||||
// resetTwitch(;
|
||||
});
|
||||
|
||||
function toggleTwitch() {
|
||||
const toggle = settings.TWITCH.USE_TWITCH;
|
||||
const inputs = document.getElementsByClassName('inputTwitch');
|
||||
|
|
|
|||
193
src/js/twitch.js
193
src/js/twitch.js
|
|
@ -1,10 +1,11 @@
|
|||
/* global client, customEmojis, emojiPicker, settings, options, sound, showChatMessage, messageTemplates, getPostTime */
|
||||
/* global client, fs, main, path, resourcesPath, customEmojis, emojiPicker, settings, options, sound, showChatMessage, messageTemplates, getPostTime */
|
||||
|
||||
const tmi = require('tmi.js');
|
||||
const axios = require('axios');
|
||||
|
||||
let client = null;
|
||||
let logoUrl = null;
|
||||
const twitchChannels = [];
|
||||
|
||||
function sendMessage(message) {
|
||||
client.say(settings.TWITCH.CHANNEL_NAME, message).catch(console.error);
|
||||
|
|
@ -144,17 +145,156 @@ client.on('message', (channel, tags, message, self) => {
|
|||
getProfileImage(tags['user-id'], tags['display-name'], messageObject, filteredMessage);
|
||||
});
|
||||
|
||||
function formatTwitchEmojis(emojis, name) {
|
||||
emojis.forEach(emoji => {
|
||||
function saveTwitchEmotesToFile(TwitchEmotes) {
|
||||
const data = JSON.stringify(TwitchEmotes);
|
||||
const savePath =
|
||||
main.isPackaged === true ? path.join(resourcesPath, './twitch-emotes.json') : path.join(resourcesPath, './config/twitch-emotes.json');
|
||||
// console.log(savePath);
|
||||
fs.writeFile(savePath, data, error => {
|
||||
// throwing the error
|
||||
// in case of a writing problem
|
||||
if (error) {
|
||||
// logging the error
|
||||
console.error(error);
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
// console.log('twitch-emotes.json written correctly');
|
||||
});
|
||||
}
|
||||
|
||||
async function formatGlobalTwitchEmotes(emotes, name) {
|
||||
for (const emote of emotes) {
|
||||
const emojiToBeAdded = {
|
||||
name: emoji.name,
|
||||
shortcodes: [emoji.name],
|
||||
url: emoji.images.url_1x,
|
||||
name: emote.name,
|
||||
shortcodes: [emote.name],
|
||||
url: emote.images.url_1x,
|
||||
category: name
|
||||
};
|
||||
await customEmojis.push(emojiToBeAdded);
|
||||
}
|
||||
emojiPicker.customEmoji = customEmojis;
|
||||
saveTwitchEmotesToFile(customEmojis);
|
||||
}
|
||||
|
||||
function formatFollowedChannelsTwitchEmotes(channel) {
|
||||
if (channel.emotes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
channel.emotes.forEach(emote => {
|
||||
if (emote.emote_type === 'bitstier') {
|
||||
return;
|
||||
}
|
||||
if (emote.emote_type === 'subscriptions' && parseInt(channel.tier) < parseInt(emote.tier)) {
|
||||
return;
|
||||
}
|
||||
if (emote.emote_type === 'follower ' && parseInt(channel.tier) === '0') {
|
||||
return;
|
||||
}
|
||||
const emojiToBeAdded = {
|
||||
name: emote.name,
|
||||
shortcodes: [emote.name],
|
||||
url: emote.images.url_1x,
|
||||
category: channel.broadcaster_name
|
||||
};
|
||||
customEmojis.push(emojiToBeAdded);
|
||||
});
|
||||
emojiPicker.customEmoji = customEmojis;
|
||||
saveTwitchEmotesToFile(customEmojis);
|
||||
}
|
||||
|
||||
function getTwitchChannelFollows(paginationToken) {
|
||||
let url = '';
|
||||
if (!paginationToken) {
|
||||
url = `https://api.twitch.tv/helix/channels/followed?user_id=${settings.TWITCH.USER_ID}&first=100`;
|
||||
} else {
|
||||
url = `https://api.twitch.tv/helix/channels/followed?user_id=${settings.TWITCH.USER_ID}&after=${paginationToken}`;
|
||||
}
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: url,
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
// console.log(responseLogoUrl);
|
||||
|
||||
responseLogoUrl.data.data.forEach(channel => {
|
||||
twitchChannels.push({ broadcaster_id: channel.broadcaster_id, broadcaster_name: channel.broadcaster_name, tier: '0' });
|
||||
});
|
||||
|
||||
if (Object.keys(responseLogoUrl.data.pagination).length !== 0) {
|
||||
getTwitchChannelFollows(responseLogoUrl.data.pagination.cursor);
|
||||
} else {
|
||||
getTwitchChannelSubscriptions(twitchChannels);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchChannelSubscriptions(channels) {
|
||||
channels.forEach(channel => {
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: `https://api.twitch.tv/helix/subscriptions/user?broadcaster_id=${channel.broadcaster_id}&user_id=${settings.TWITCH.USER_ID}`,
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
// console.log(responseLogoUrl);
|
||||
const objIndex = twitchChannels.findIndex(obj => obj.broadcaster_id === channel.broadcaster_id);
|
||||
twitchChannels[objIndex].tier = responseLogoUrl.data.data[0].tier;
|
||||
getTwitchChannelEmotes(channel);
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.response.status !== 404) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchChannelEmotes(channel) {
|
||||
// Get user Logo with access token
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channel.broadcaster_id}`,
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
// console.log(channel.broadcaster_id);
|
||||
if (channel.broadcaster_id === '98553286') {
|
||||
// console.log(responseLogoUrl);
|
||||
// console.log(channel);
|
||||
}
|
||||
if (responseLogoUrl.data.data.length !== 0) {
|
||||
channel.emotes = responseLogoUrl.data.data;
|
||||
formatFollowedChannelsTwitchEmotes(channel);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
function getTwitchGLobalEmotes() {
|
||||
|
|
@ -171,7 +311,7 @@ function getTwitchGLobalEmotes() {
|
|||
axios
|
||||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
formatTwitchEmojis(responseLogoUrl.data.data, 'Twitch Global');
|
||||
formatGlobalTwitchEmotes(responseLogoUrl.data.data, 'Twitch Global');
|
||||
// console.log(responseLogoUrl);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -179,8 +319,41 @@ function getTwitchGLobalEmotes() {
|
|||
});
|
||||
}
|
||||
|
||||
if (settings.TWITCH.OAUTH_TOKEN) {
|
||||
getTwitchGLobalEmotes();
|
||||
function getCurrentTwitchChannelId(channelId) {
|
||||
let channel = {};
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: `https://api.twitch.tv/helix/users?${channelId !== undefined ? 'id=' + channelId : 'login=' + settings.TWITCH.CHANNEL_NAME}`,
|
||||
headers: {
|
||||
'Client-ID': settings.TWITCH.CLIENT_ID,
|
||||
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
|
||||
}
|
||||
};
|
||||
|
||||
axios
|
||||
.request(options)
|
||||
.then(responseData => {
|
||||
// console.log(responseData);
|
||||
channel = { broadcaster_id: responseData.data.data[0].id, broadcaster_name: responseData.data.data[0].display_name, tier: '0' };
|
||||
if (responseData.data.data[0].id !== settings.TWITCH.USER_ID) {
|
||||
getCurrentTwitchChannelId(settings.TWITCH.USER_ID);
|
||||
channel.tier = '0';
|
||||
} else {
|
||||
channel.tier = '3000';
|
||||
}
|
||||
getTwitchChannelEmotes(channel);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { sendMessage, ping, client };
|
||||
async function getUserAvailableTwitchEmotes() {
|
||||
if (settings.TWITCH.OAUTH_TOKEN) {
|
||||
await getTwitchGLobalEmotes();
|
||||
await getTwitchChannelFollows();
|
||||
await getCurrentTwitchChannelId();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { sendMessage, ping, client, getUserAvailableTwitchEmotes };
|
||||
|
|
|
|||
Loading…
Reference in a new issue