hj-stream-bot/index.js

188 lines
4.6 KiB
JavaScript
Raw Normal View History

2026-01-14 15:54:22 +02:00
import fs from 'node:fs';
2021-06-09 13:22:07 +03:00
import fetch from 'node-fetch';
2026-01-14 17:03:22 +02:00
//const botBearerFile = process.env.BOT_BEARER_FILE;
//const userBearerFile = process.env.USER_BEARER_FILE;
2026-01-14 17:02:09 +02:00
const instance = process.env.INSTANCE || 'shigusegubu.club';
2026-01-13 22:16:12 +02:00
const videoId = process.env.VIDEO_ID;
2021-06-09 13:22:07 +03:00
2026-01-14 17:03:22 +02:00
const botBearer = fs.readFileSync(botBearerFile, 'utf-8');
const userBearer = fs.readFileSync(userBearerFile, 'utf-8');
2026-01-14 15:54:22 +02:00
2026-01-14 15:14:14 +02:00
const globalState = {
exit: false,
currentlyLive: false,
};
2026-01-14 17:02:09 +02:00
console.log(userBearer.trim());
2021-06-09 13:22:07 +03:00
2026-01-13 22:16:12 +02:00
const headers = (bearer) => ({
2026-01-14 16:30:06 +02:00
accept: 'application/json',
2026-01-14 15:59:17 +02:00
authorization: `Bearer ${bearer.trim()}`,
2026-01-13 22:16:12 +02:00
'cache-control': 'no-cache',
'content-type': 'application/json',
pragma: 'no-cache',
2021-06-09 13:22:07 +03:00
});
2026-01-14 16:30:06 +02:00
/*
const app = await fetch(`https://${instance}/api/v1/apps`, {
headers: {
accept: 'application/json',
'cache-control': 'no-cache',
'content-type': 'application/json',
pragma: 'no-cache',
},
body: JSON.stringify({
client_name: 'HJ Stream Bot',
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
scopes: 'write:scrobbles',
}),
method: 'POST',
mode: 'cors',
2026-01-14 17:02:09 +02:00
});
console.log('APP REG STATUS', app.status);
const { client_id, client_secret } = await app.json();
console.log({ client_id, client_secret });
2026-01-14 16:30:06 +02:00
const bearer = await fetch(`https://${instance}/oauth/token`, {
headers: {
accept: 'application/json',
'cache-control': 'no-cache',
'content-type': 'application/json',
pragma: 'no-cache',
},
body: JSON.stringify({
client_id,
client_secret,
grant_type: 'client_credentials',
}),
method: 'POST',
mode: 'cors',
2026-01-14 17:02:09 +02:00
});
console.log('TOKEN STATUS', bearer.status);
console.log('TOKEN RESPONSE', await bearer.json());
const data = {
response_type: 'code',
client_id,
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
scope: 'write:scrobbles',
};
const dataString = Object.entries(data).reduce((acc, [k, v]) => {
const encoded = `${k}=${encodeURIComponent(v)}`;
if (!acc) {
return encoded;
} else {
return `${acc}&${encoded}`;
}
}, '');
console.log(`AUTH: ${instance}/oauth/authorize?${dataString}`);
const auth = await fetch(`https://${instance}/oauth/authorize`, {
headers: {
accept: 'application/json',
'cache-control': 'no-cache',
'content-type': 'application/json',
pragma: 'no-cache',
},
body: JSON.stringify({
client_id,
response_type: 'code',
grant_type: 'client_credentials',
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
}),
method: 'POST',
mode: 'cors',
});
2026-01-14 16:30:06 +02:00
/* */
2026-01-13 22:16:12 +02:00
const post = ({
status,
spoiler_text,
visibility = 'direct',
content_type = 'text/plain',
}) =>
fetch(`https://${instance}/api/v1/statuses`, {
headers: headers(botBearer),
referrerPolicy: 'same-origin',
body: JSON.stringify({
spoiler_text,
status,
source: "HJ's twitch bot",
visibility,
content_type,
}),
method: 'POST',
mode: 'cors',
credentials: 'include',
});
2021-06-09 13:22:07 +03:00
2026-01-13 22:16:12 +02:00
const scrobble = ({ title, external_link }) =>
fetch(`https://${instance}/api/v1/pleroma/scrobble`, {
headers: headers(userBearer),
referrerPolicy: 'same-origin',
body: JSON.stringify({
title,
external_link,
}),
method: 'POST',
mode: 'cors',
credentials: 'include',
});
2021-06-09 13:22:07 +03:00
2026-01-13 22:16:12 +02:00
// await post({
// spoiler_text: 'Debug',
// status: '@hj twitch bot initialized',
// });
2021-06-09 13:22:07 +03:00
2026-01-13 22:16:12 +02:00
process.on('SIGINT', () => {
2026-01-14 15:14:14 +02:00
globalState.exit = true;
2026-01-13 22:16:12 +02:00
process.exit();
});
2021-06-09 14:19:48 +03:00
2026-01-13 22:16:12 +02:00
const loop = async () => {
const response = await fetch(
`https://tube.ebin.club/api/v1/videos/${videoId}`,
);
const { state } = await response.json();
const isLive = state.id === 1; // published
2026-01-14 16:33:01 +02:00
// console.info('Live: ', isLive, globalState.currentlyLive);
2026-01-13 22:16:12 +02:00
const stateChange = isLive !== globalState.currentlyLive;
2026-01-14 16:33:01 +02:00
// console.info('State change', stateChange);
2026-01-13 22:16:12 +02:00
globalState.currentlyLive = isLive;
2021-06-09 13:22:07 +03:00
2026-01-14 16:33:01 +02:00
// console.info('State: ', state);
2026-01-13 22:16:12 +02:00
if (stateChange) {
if (isLive) {
2026-01-14 15:54:22 +02:00
console.info('Went live!');
2026-01-14 16:33:01 +02:00
// const postResult = await post({
// spoiler_text: 'Stream announcment',
// status: [
// '@hj just went live on peertube',
// '',
// `https://tube.ebin.club/w/${videoId}`,
// ].join('\n'),
// visibility: 'public',
// });
// console.info('post: ' + postResult.status);
2026-01-13 22:16:12 +02:00
2026-01-14 15:43:47 +02:00
const scrobbleResult = await scrobble({
2026-01-14 16:33:01 +02:00
// artist: 'Peertube',
2026-01-13 22:16:12 +02:00
title: 'Streaming on PeerTube',
external_link: `https://tube.ebin.club/w/${videoId}`,
});
2026-01-14 16:02:22 +02:00
console.info('scrobble: ' + scrobbleResult.status);
2026-01-13 22:16:12 +02:00
} else {
2026-01-14 15:54:22 +02:00
console.info('Went offline...');
2026-01-13 22:16:12 +02:00
await scrobble({
title: 'Stream over',
});
2021-06-09 13:22:07 +03:00
}
}
2026-01-14 15:14:14 +02:00
if (!globalState.exit) setTimeout(loop, 30 * 1000);
2026-01-13 22:16:12 +02:00
};
loop();
console.info('Ready!');