batman
This commit is contained in:
parent
05324771cf
commit
b8cc774517
|
|
@ -0,0 +1,116 @@
|
||||||
|
import express from "express";
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const usernames = [
|
||||||
|
{name: "rubylium__", status: "off", id: ""},
|
||||||
|
{name: "lukkstv", status: "off", id: ""},
|
||||||
|
{name: "havvenfr", status: "off", id: ""},
|
||||||
|
{name: "olmanntv", status: "off", id: ""},
|
||||||
|
{name: "nina_asmr", status: "off", id: ""},
|
||||||
|
{name: "krw_aka", status: "off", id: ""},
|
||||||
|
{name: "leetgamer54", status: "off", id: ""},
|
||||||
|
{name: "coshiho", status: "off", id: ""},
|
||||||
|
{name: "soramicia", status: "off", id: ""},
|
||||||
|
{name: "entocraft", status: "off", id: ""},
|
||||||
|
{name: "steakfritees_", status: "off", id: ""},
|
||||||
|
{name: "dancyy_", status: "off", id: ""},
|
||||||
|
{name: "tchoupyy_", status: "off", id: ""},
|
||||||
|
{name: "thesollann", status: "off", id: ""},
|
||||||
|
];
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
let token = "";
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
const checkEnvVars = () => {
|
||||||
|
const requiredEnvVars = ["CLIENT_ID", "CLIENT_SECRET"];
|
||||||
|
let error = false;
|
||||||
|
requiredEnvVars.forEach((envVar) => {
|
||||||
|
if (process.env[envVar] === undefined) {
|
||||||
|
error = true;
|
||||||
|
console.log(`${envVar} is undefined`);
|
||||||
|
} else {
|
||||||
|
config[envVar] = process.env[envVar];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (error) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkEnvVars();
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
const url = `https://id.twitch.tv/oauth2/token?client_id=${config.CLIENT_ID}&client_secret=${config.CLIENT_SECRET}&grant_type=client_credentials`;
|
||||||
|
|
||||||
|
fetch(url, { method: "POST" })
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
token = data.access_token;
|
||||||
|
getAllUsersStatus();
|
||||||
|
setInterval(getAllUsersStatus, 60000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
async function getAllUsersStatus() {
|
||||||
|
for (let i = 0; i < usernames.length; i++) {
|
||||||
|
const userData = await getUserStatus(usernames[i].name, usernames[i].id);
|
||||||
|
usernames[i] = { ...usernames[i], ...userData };
|
||||||
|
if (i === usernames.length - 1) {
|
||||||
|
console.log("Successfully updated all users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use("/api/status", api);
|
||||||
|
|
||||||
|
function api(req, res, next) {
|
||||||
|
res.json(usernames);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUserStatus(username, id) {
|
||||||
|
const userData = {};
|
||||||
|
if (id === "") {
|
||||||
|
const userUrl = `https://api.twitch.tv/helix/users?login=${username}`;
|
||||||
|
const response = await fetch(userUrl, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Client-ID": config.CLIENT_ID,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
userData.id = data.data[0].id;
|
||||||
|
userData.profilePicture = data.data[0].profile_image_url;
|
||||||
|
id = data.data[0].id;
|
||||||
|
}
|
||||||
|
const streamUrl = `https://api.twitch.tv/helix/streams?user_id=${id}`;
|
||||||
|
const streamResponse = await fetch(streamUrl, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Client-ID": config.CLIENT_ID,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const streamData = await streamResponse.json();
|
||||||
|
if (streamData.data.length > 0) {
|
||||||
|
userData.status = "live";
|
||||||
|
} else {
|
||||||
|
userData.status = "offline";
|
||||||
|
}
|
||||||
|
return userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const staticDist = express.static(path.join(path.resolve(), "./public"));
|
||||||
|
|
||||||
|
app.use(staticDist);
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server listening on port ${port}`);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "donatien",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js"
|
||||||
|
},
|
||||||
|
"entry": "index.js",
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"express": "^4.21.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,485 @@
|
||||||
|
lockfileVersion: '6.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
dotenv:
|
||||||
|
specifier: ^16.4.5
|
||||||
|
version: 16.4.5
|
||||||
|
express:
|
||||||
|
specifier: ^4.21.1
|
||||||
|
version: 4.21.1
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
/accepts@1.3.8:
|
||||||
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dependencies:
|
||||||
|
mime-types: 2.1.35
|
||||||
|
negotiator: 0.6.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/array-flatten@1.1.1:
|
||||||
|
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/body-parser@1.20.3:
|
||||||
|
resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
|
||||||
|
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||||
|
dependencies:
|
||||||
|
bytes: 3.1.2
|
||||||
|
content-type: 1.0.5
|
||||||
|
debug: 2.6.9
|
||||||
|
depd: 2.0.0
|
||||||
|
destroy: 1.2.0
|
||||||
|
http-errors: 2.0.0
|
||||||
|
iconv-lite: 0.4.24
|
||||||
|
on-finished: 2.4.1
|
||||||
|
qs: 6.13.0
|
||||||
|
raw-body: 2.5.2
|
||||||
|
type-is: 1.6.18
|
||||||
|
unpipe: 1.0.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/bytes@3.1.2:
|
||||||
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/call-bind@1.0.7:
|
||||||
|
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
es-define-property: 1.0.0
|
||||||
|
es-errors: 1.3.0
|
||||||
|
function-bind: 1.1.2
|
||||||
|
get-intrinsic: 1.2.4
|
||||||
|
set-function-length: 1.2.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/content-disposition@0.5.4:
|
||||||
|
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/content-type@1.0.5:
|
||||||
|
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/cookie-signature@1.0.6:
|
||||||
|
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/cookie@0.7.1:
|
||||||
|
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/debug@2.6.9:
|
||||||
|
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||||
|
peerDependencies:
|
||||||
|
supports-color: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
supports-color:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
ms: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/define-data-property@1.1.4:
|
||||||
|
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
es-define-property: 1.0.0
|
||||||
|
es-errors: 1.3.0
|
||||||
|
gopd: 1.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/depd@2.0.0:
|
||||||
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/destroy@1.2.0:
|
||||||
|
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
|
||||||
|
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/dotenv@16.4.5:
|
||||||
|
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ee-first@1.1.1:
|
||||||
|
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/encodeurl@1.0.2:
|
||||||
|
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/encodeurl@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/es-define-property@1.0.0:
|
||||||
|
resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
get-intrinsic: 1.2.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/es-errors@1.3.0:
|
||||||
|
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/escape-html@1.0.3:
|
||||||
|
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/etag@1.8.1:
|
||||||
|
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/express@4.21.1:
|
||||||
|
resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==}
|
||||||
|
engines: {node: '>= 0.10.0'}
|
||||||
|
dependencies:
|
||||||
|
accepts: 1.3.8
|
||||||
|
array-flatten: 1.1.1
|
||||||
|
body-parser: 1.20.3
|
||||||
|
content-disposition: 0.5.4
|
||||||
|
content-type: 1.0.5
|
||||||
|
cookie: 0.7.1
|
||||||
|
cookie-signature: 1.0.6
|
||||||
|
debug: 2.6.9
|
||||||
|
depd: 2.0.0
|
||||||
|
encodeurl: 2.0.0
|
||||||
|
escape-html: 1.0.3
|
||||||
|
etag: 1.8.1
|
||||||
|
finalhandler: 1.3.1
|
||||||
|
fresh: 0.5.2
|
||||||
|
http-errors: 2.0.0
|
||||||
|
merge-descriptors: 1.0.3
|
||||||
|
methods: 1.1.2
|
||||||
|
on-finished: 2.4.1
|
||||||
|
parseurl: 1.3.3
|
||||||
|
path-to-regexp: 0.1.10
|
||||||
|
proxy-addr: 2.0.7
|
||||||
|
qs: 6.13.0
|
||||||
|
range-parser: 1.2.1
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
send: 0.19.0
|
||||||
|
serve-static: 1.16.2
|
||||||
|
setprototypeof: 1.2.0
|
||||||
|
statuses: 2.0.1
|
||||||
|
type-is: 1.6.18
|
||||||
|
utils-merge: 1.0.1
|
||||||
|
vary: 1.1.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/finalhandler@1.3.1:
|
||||||
|
resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dependencies:
|
||||||
|
debug: 2.6.9
|
||||||
|
encodeurl: 2.0.0
|
||||||
|
escape-html: 1.0.3
|
||||||
|
on-finished: 2.4.1
|
||||||
|
parseurl: 1.3.3
|
||||||
|
statuses: 2.0.1
|
||||||
|
unpipe: 1.0.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/forwarded@0.2.0:
|
||||||
|
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/fresh@0.5.2:
|
||||||
|
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/function-bind@1.1.2:
|
||||||
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/get-intrinsic@1.2.4:
|
||||||
|
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
es-errors: 1.3.0
|
||||||
|
function-bind: 1.1.2
|
||||||
|
has-proto: 1.0.3
|
||||||
|
has-symbols: 1.0.3
|
||||||
|
hasown: 2.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/gopd@1.0.1:
|
||||||
|
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
||||||
|
dependencies:
|
||||||
|
get-intrinsic: 1.2.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/has-property-descriptors@1.0.2:
|
||||||
|
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
|
||||||
|
dependencies:
|
||||||
|
es-define-property: 1.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/has-proto@1.0.3:
|
||||||
|
resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/has-symbols@1.0.3:
|
||||||
|
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/hasown@2.0.2:
|
||||||
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
function-bind: 1.1.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/http-errors@2.0.0:
|
||||||
|
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dependencies:
|
||||||
|
depd: 2.0.0
|
||||||
|
inherits: 2.0.4
|
||||||
|
setprototypeof: 1.2.0
|
||||||
|
statuses: 2.0.1
|
||||||
|
toidentifier: 1.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/iconv-lite@0.4.24:
|
||||||
|
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dependencies:
|
||||||
|
safer-buffer: 2.1.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/inherits@2.0.4:
|
||||||
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ipaddr.js@1.9.1:
|
||||||
|
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||||
|
engines: {node: '>= 0.10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/media-typer@0.3.0:
|
||||||
|
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/merge-descriptors@1.0.3:
|
||||||
|
resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/methods@1.1.2:
|
||||||
|
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/mime-db@1.52.0:
|
||||||
|
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/mime-types@2.1.35:
|
||||||
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dependencies:
|
||||||
|
mime-db: 1.52.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/mime@1.6.0:
|
||||||
|
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ms@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ms@2.1.3:
|
||||||
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/negotiator@0.6.3:
|
||||||
|
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/object-inspect@1.13.2:
|
||||||
|
resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/on-finished@2.4.1:
|
||||||
|
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dependencies:
|
||||||
|
ee-first: 1.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/parseurl@1.3.3:
|
||||||
|
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/path-to-regexp@0.1.10:
|
||||||
|
resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/proxy-addr@2.0.7:
|
||||||
|
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||||
|
engines: {node: '>= 0.10'}
|
||||||
|
dependencies:
|
||||||
|
forwarded: 0.2.0
|
||||||
|
ipaddr.js: 1.9.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/qs@6.13.0:
|
||||||
|
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
dependencies:
|
||||||
|
side-channel: 1.0.6
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/range-parser@1.2.1:
|
||||||
|
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/raw-body@2.5.2:
|
||||||
|
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dependencies:
|
||||||
|
bytes: 3.1.2
|
||||||
|
http-errors: 2.0.0
|
||||||
|
iconv-lite: 0.4.24
|
||||||
|
unpipe: 1.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/safe-buffer@5.2.1:
|
||||||
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/safer-buffer@2.1.2:
|
||||||
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/send@0.19.0:
|
||||||
|
resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
debug: 2.6.9
|
||||||
|
depd: 2.0.0
|
||||||
|
destroy: 1.2.0
|
||||||
|
encodeurl: 1.0.2
|
||||||
|
escape-html: 1.0.3
|
||||||
|
etag: 1.8.1
|
||||||
|
fresh: 0.5.2
|
||||||
|
http-errors: 2.0.0
|
||||||
|
mime: 1.6.0
|
||||||
|
ms: 2.1.3
|
||||||
|
on-finished: 2.4.1
|
||||||
|
range-parser: 1.2.1
|
||||||
|
statuses: 2.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/serve-static@1.16.2:
|
||||||
|
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
encodeurl: 2.0.0
|
||||||
|
escape-html: 1.0.3
|
||||||
|
parseurl: 1.3.3
|
||||||
|
send: 0.19.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/set-function-length@1.2.2:
|
||||||
|
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
define-data-property: 1.1.4
|
||||||
|
es-errors: 1.3.0
|
||||||
|
function-bind: 1.1.2
|
||||||
|
get-intrinsic: 1.2.4
|
||||||
|
gopd: 1.0.1
|
||||||
|
has-property-descriptors: 1.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/setprototypeof@1.2.0:
|
||||||
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/side-channel@1.0.6:
|
||||||
|
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
call-bind: 1.0.7
|
||||||
|
es-errors: 1.3.0
|
||||||
|
get-intrinsic: 1.2.4
|
||||||
|
object-inspect: 1.13.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/statuses@2.0.1:
|
||||||
|
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/toidentifier@1.0.1:
|
||||||
|
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/type-is@1.6.18:
|
||||||
|
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dependencies:
|
||||||
|
media-typer: 0.3.0
|
||||||
|
mime-types: 2.1.35
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/unpipe@1.0.0:
|
||||||
|
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/utils-merge@1.0.1:
|
||||||
|
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||||
|
engines: {node: '>= 0.4.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/vary@1.1.2:
|
||||||
|
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dev: false
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta content="donathon interface" property="og:title" />
|
||||||
|
<meta content="Interface pour le planning du Donathon" property="og:description" />
|
||||||
|
<meta content="https://able.moe/" property="og:url" />
|
||||||
|
<meta content="https://able.moe/images/literallyme.png" property="og:image" />
|
||||||
|
<meta content="#e858de" data-react-helmet="true" name="theme-color" />
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="icon" type="image/jpg" href="images/favicon.png">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<title>interface dnth</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<style>
|
||||||
|
.live-indicator { display: none; }
|
||||||
|
</style>
|
||||||
|
<div></div>
|
||||||
|
<div id="streamersContainer">
|
||||||
|
<h2>En ligne</h2>
|
||||||
|
<span class="small" id="onlineCount"></span>
|
||||||
|
<div id="onlineStreamers" class="streamers-category">
|
||||||
|
<span class="loader" id="loader1"></span>
|
||||||
|
<span class="loadertext" id="onlineLoaderText">Le premier chargement peut être long...</span>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<h2>Hors ligne</h2> <span class="small" id="offlineCount"></span>
|
||||||
|
<div id="offlineStreamers" class="streamers-category">
|
||||||
|
<span class="loader" id="loader2"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="scripts/infos.js"></script>
|
||||||
|
<script src="scripts/twitch.js"></script>
|
||||||
|
</body>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,245 @@
|
||||||
|
// Fonction pour obtenir l'access token Twitch
|
||||||
|
async function getAccessToken() {
|
||||||
|
const clientId = 'z2tcrq9oeynzf4ijgzhv6br5feoprr';
|
||||||
|
const clientSecret = 'ybm8e512lrsylqqkl78ow08nv3jgx9';
|
||||||
|
const url = `https://id.twitch.tv/oauth2/token?client_id=${clientId}&client_secret=${clientSecret}&grant_type=client_credentials`;
|
||||||
|
|
||||||
|
const response = await fetch(url, { method: 'POST' });
|
||||||
|
const data = await response.json();
|
||||||
|
return data.access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fonction pour obtenir les informations utilisateur et le statut du stream
|
||||||
|
async function getUserInfoAndStreamStatus(username, accessToken, clientId) {
|
||||||
|
const userUrl = `https://api.twitch.tv/helix/users?login=${username}`;
|
||||||
|
const userResponse = await fetch(userUrl, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
'Client-ID': clientId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (userResponse.status !== 200) {
|
||||||
|
console.error('Erreur lors de la récupération des informations utilisateur.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userData = await userResponse.json();
|
||||||
|
if (userData.data.length === 0) {
|
||||||
|
console.error('Utilisateur non trouvé.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userId = userData.data[0].id;
|
||||||
|
const profileImageUrl = userData.data[0].profile_image_url;
|
||||||
|
const displayName = userData.data[0].display_name;
|
||||||
|
|
||||||
|
const streamUrl = `https://api.twitch.tv/helix/streams?user_id=${userId}`;
|
||||||
|
const streamResponse = await fetch(streamUrl, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
'Client-ID': clientId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const streamData = await streamResponse.json();
|
||||||
|
let streamType = 'offline';
|
||||||
|
|
||||||
|
if (streamData.data.length > 0) {
|
||||||
|
streamType = streamData.data[0].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
profileImageUrl,
|
||||||
|
displayName,
|
||||||
|
streamType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lire le fichier streamers.json depuis le localStorage
|
||||||
|
function readStreamersFile() {
|
||||||
|
const fileContent = localStorage.getItem('streamers');
|
||||||
|
return fileContent ? JSON.parse(fileContent) : { streamers: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sauvegarder dans streamers.json dans le localStorage
|
||||||
|
function saveStreamersFile(streamersData) {
|
||||||
|
localStorage.setItem('streamers', JSON.stringify(streamersData, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier et ajouter les streamers manquants
|
||||||
|
async function updateMissingStreamers(usernames) {
|
||||||
|
let streamersData = readStreamersFile();
|
||||||
|
|
||||||
|
const currentStreamers = streamersData.streamers.map(streamer => streamer.username);
|
||||||
|
|
||||||
|
const missingUsernames = usernames.filter(username => !currentStreamers.includes(username));
|
||||||
|
|
||||||
|
if (missingUsernames.length === 0) {
|
||||||
|
console.log("Tous les streamers sont déjà présents.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Les streamers suivants sont manquants: ${missingUsernames.join(', ')}`);
|
||||||
|
|
||||||
|
const accessToken = await getAccessToken();
|
||||||
|
const clientId = 'z2tcrq9oeynzf4ijgzhv6br5feoprr';
|
||||||
|
|
||||||
|
for (const username of missingUsernames) {
|
||||||
|
const data = await getUserInfoAndStreamStatus(username, accessToken, clientId);
|
||||||
|
if (data) {
|
||||||
|
streamersData.streamers.push({
|
||||||
|
username: username,
|
||||||
|
displayName: data.displayName,
|
||||||
|
profileImageUrl: data.profileImageUrl,
|
||||||
|
streamType: data.streamType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveStreamersFile(streamersData);
|
||||||
|
console.log("Les streamers manquants ont été ajoutés.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fonction pour afficher les streamers
|
||||||
|
async function displayStreamers(usernames) {
|
||||||
|
const accessToken = await getAccessToken();
|
||||||
|
const clientId = 'z2tcrq9oeynzf4ijgzhv6br5feoprr';
|
||||||
|
|
||||||
|
const streamersData = readStreamersFile();
|
||||||
|
const onlineStreamers = [];
|
||||||
|
const offlineStreamers = [];
|
||||||
|
|
||||||
|
for (const username of usernames) {
|
||||||
|
const streamerInfo = streamersData.streamers.find(streamer => streamer.username === username);
|
||||||
|
|
||||||
|
if (streamerInfo && streamerInfo.streamType === 'live') {
|
||||||
|
onlineStreamers.push(streamerInfo);
|
||||||
|
} else {
|
||||||
|
offlineStreamers.push(streamerInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trier les streamers par nom
|
||||||
|
onlineStreamers.sort((a, b) => a.displayName.localeCompare(b.displayName));
|
||||||
|
offlineStreamers.sort((a, b) => a.displayName.localeCompare(b.displayName));
|
||||||
|
|
||||||
|
// Mettre à jour le nombre de streamers en ligne et hors ligne
|
||||||
|
document.getElementById('onlineCount').textContent = onlineStreamers.length;
|
||||||
|
document.getElementById('offlineCount').textContent = offlineStreamers.length;
|
||||||
|
|
||||||
|
const onlineContainer = document.getElementById('onlineStreamers');
|
||||||
|
const offlineContainer = document.getElementById('offlineStreamers');
|
||||||
|
|
||||||
|
// Réinitialiser les conteneurs
|
||||||
|
onlineContainer.innerHTML = '';
|
||||||
|
offlineContainer.innerHTML = '';
|
||||||
|
|
||||||
|
if (onlineStreamers.length > 0) {
|
||||||
|
// Supprimer le texte de chargement
|
||||||
|
const loaderText = document.getElementById('loadertext');
|
||||||
|
if (loaderText) {
|
||||||
|
loaderText.style.display = 'none';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Ajouter le texte de chargement si aucun streamer en ligne
|
||||||
|
const loaderText = document.getElementById('loadertext');
|
||||||
|
if (loaderText) {
|
||||||
|
loaderText.textContent = "Il n'y a aucun streamer en ligne actuellement";
|
||||||
|
loaderText.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onlineStreamers.forEach(data => {
|
||||||
|
const profileLink = `https://twitch.tv/${data.displayName}`;
|
||||||
|
|
||||||
|
const image = document.createElement('img');
|
||||||
|
image.src = data.profileImageUrl;
|
||||||
|
image.alt = data.displayName;
|
||||||
|
image.className = 'streamer-image';
|
||||||
|
|
||||||
|
const liveIndicator = document.createElement('div');
|
||||||
|
liveIndicator.className = 'live-indicator';
|
||||||
|
liveIndicator.style.display = 'block';
|
||||||
|
|
||||||
|
const name = document.createElement('div');
|
||||||
|
name.className = 'streamer-name';
|
||||||
|
name.textContent = data.displayName;
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = profileLink;
|
||||||
|
link.target = '_blank';
|
||||||
|
link.appendChild(image);
|
||||||
|
link.appendChild(liveIndicator);
|
||||||
|
|
||||||
|
const infoDiv = document.createElement('div');
|
||||||
|
infoDiv.className = 'streamer-info';
|
||||||
|
infoDiv.appendChild(link);
|
||||||
|
infoDiv.appendChild(name);
|
||||||
|
|
||||||
|
onlineContainer.appendChild(infoDiv);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Réinitialiser et remplir le conteneur des streamers hors ligne
|
||||||
|
if (offlineStreamers.length === 0) {
|
||||||
|
// Ajouter le texte de chargement si aucun streamer hors ligne
|
||||||
|
const loaderText = document.getElementById('loadertext');
|
||||||
|
if (loaderText) {
|
||||||
|
loaderText.textContent = "Il n'y a aucun streamer hors ligne actuellement";
|
||||||
|
loaderText.style.display = 'block';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Supprimer le texte de chargement
|
||||||
|
const loaderText = document.getElementById('loadertext');
|
||||||
|
if (loaderText) {
|
||||||
|
loaderText.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offlineStreamers.forEach(data => {
|
||||||
|
const profileLink = `https://twitch.tv/${data.displayName}`;
|
||||||
|
|
||||||
|
const image = document.createElement('img');
|
||||||
|
image.src = data.profileImageUrl;
|
||||||
|
image.alt = data.displayName;
|
||||||
|
image.className = 'streamer-image';
|
||||||
|
image.classList.toggle('offline', data.streamType !== 'live');
|
||||||
|
|
||||||
|
const liveIndicator = document.createElement('div');
|
||||||
|
liveIndicator.className = 'live-indicator';
|
||||||
|
liveIndicator.style.display = 'none';
|
||||||
|
|
||||||
|
const name = document.createElement('div');
|
||||||
|
name.className = 'streamer-name';
|
||||||
|
name.textContent = data.displayName;
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = profileLink;
|
||||||
|
link.target = '_blank';
|
||||||
|
link.appendChild(image);
|
||||||
|
link.appendChild(liveIndicator);
|
||||||
|
|
||||||
|
const infoDiv = document.createElement('div');
|
||||||
|
infoDiv.className = 'streamer-info';
|
||||||
|
infoDiv.appendChild(link);
|
||||||
|
infoDiv.appendChild(name);
|
||||||
|
|
||||||
|
offlineContainer.appendChild(infoDiv);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (onlineStreamers.length > 0) {
|
||||||
|
// Supprimer le texte "aucun streamer en ligne" et le texte de chargement
|
||||||
|
const loaderText = document.getElementById('onlineLoaderText');
|
||||||
|
if (loaderText) {
|
||||||
|
loaderText.style.display = 'none';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Ajouter le texte "aucun streamer en ligne"
|
||||||
|
const loaderText = document.getElementById('onlineLoaderText');
|
||||||
|
if (loaderText) {
|
||||||
|
loaderText.textContent = "Il n'y a aucun streamer en ligne actuellement";
|
||||||
|
loaderText.style.display = 'block'; // Assurez-vous que le texte est visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
console.log("twitch.js chargé");
|
||||||
|
|
||||||
|
const usernames = ['rubylium__', 'lukkstv', 'havvenfr', 'olmanntv', 'nina_asmr', 'krw_aka', 'leetgamer54', 'coshiho', 'soramicia', 'entocraft', 'steakfritees_', 'dancyy_', 'tchoupyy_', 'thesollann'];
|
||||||
|
|
||||||
|
(async function() {
|
||||||
|
// Vérifier et ajouter les streamers manquants dans streamers.json
|
||||||
|
await updateMissingStreamers(usernames);
|
||||||
|
|
||||||
|
// Une fois que tout est à jour, afficher les streamers
|
||||||
|
displayStreamers(usernames);
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,207 @@
|
||||||
|
/* work-sans-regular - latin */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:ital,wght@0,400;0,700;1,400;1,700&display=swap');
|
||||||
|
.atkinson-hyperlegible-regular {
|
||||||
|
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.atkinson-hyperlegible-bold {
|
||||||
|
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.atkinson-hyperlegible-regular-italic {
|
||||||
|
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.atkinson-hyperlegible-bold-italic {
|
||||||
|
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
/* Contenu principal */
|
||||||
|
/* Contenu principal */
|
||||||
|
/* Contenu principal */
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: rgb(29, 25, 27);
|
||||||
|
color: rgba(161, 208, 252);
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Catégories */
|
||||||
|
/* Catégories */
|
||||||
|
/* Catégories */
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2, .small {
|
||||||
|
display: inline;
|
||||||
|
margin: 0; /* Supprime les marges par défaut */
|
||||||
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-style: italic;
|
||||||
|
color: rgba(161, 208, 252, 0.49);
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Throbber */
|
||||||
|
/* HTML: <div class="loader"></div> */
|
||||||
|
/* HTML: <div class="loader"></div> */
|
||||||
|
.loadertext {
|
||||||
|
width: 140px;
|
||||||
|
font-style: italic;
|
||||||
|
color: rgba(161, 208, 252, 0.49);
|
||||||
|
}
|
||||||
|
|
||||||
|
#loadertext {
|
||||||
|
margin-left: 20px;
|
||||||
|
width: 140px;
|
||||||
|
font-style: italic;
|
||||||
|
color: rgba(161, 208, 252, 0.49);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
width: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
.loader:before,
|
||||||
|
.loader:after {
|
||||||
|
content: "";
|
||||||
|
flex: 1;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
--g: conic-gradient(from -90deg at 10px 10px, #a1d0fc 90deg,#0000 0);
|
||||||
|
background: var(--g), var(--g), var(--g);
|
||||||
|
filter: drop-shadow(30px 30px 0 #A1D0FC);
|
||||||
|
animation: l20 1s infinite;
|
||||||
|
}
|
||||||
|
.loader:after {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
@keyframes l20 {
|
||||||
|
0% {background-position:0 0, 10px 10px, 20px 20px}
|
||||||
|
33% {background-position:10px 10px}
|
||||||
|
66% {background-position:0 20px,10px 10px,20px 0 }
|
||||||
|
100% {background-position:0 0, 10px 10px, 20px 20px}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contenu */
|
||||||
|
/* Contenu */
|
||||||
|
/* Contenu */
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#streamersContainer {
|
||||||
|
margin: 4rem;
|
||||||
|
width: 50%;
|
||||||
|
padding: 1rem;
|
||||||
|
border: 1px solid #A1D0FC;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamers-container {
|
||||||
|
margin-right: 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamers-category {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px; /* Espace entre les images */
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamer-info {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
width: 60px; /* Assurez-vous que la largeur est fixe */
|
||||||
|
margin: 0; /* Supprime les marges éventuelles */
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamer-image {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 50%; /* Pour une image ronde */
|
||||||
|
transition: filter 0.3s ease, transform 0.3s ease;
|
||||||
|
justify-content: center; /* Centre les images horizontalement */
|
||||||
|
transform: scale(1); /* Échelle normale par défaut */
|
||||||
|
z-index: 1; /* Assure que l'image est au-dessus des autres éléments */
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamer-info:hover .streamer-image {
|
||||||
|
filter: grayscale(0%); /* Réduit le niveaux de gris à 0% lors du survol */
|
||||||
|
transform: scale(1.2); /* Zoom de 10% sur l'image lors du survol */
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); /* Optionnel : ajout d'une ombre portée pour plus d'effet */
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline:hover {
|
||||||
|
filter: grayscale(0%); /* Réduit le niveaux de gris à 0% lors du survol */
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
background-color: red;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 0.25rem solid rgb(29, 25, 27);
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamer-name {
|
||||||
|
z-index: 999;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
color: white;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 99999px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
white-space: nowrap;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamer-info:hover .streamer-name {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue