diff options
| author | moderndevslulw <moderndevslulw@alright.party> | 2025-07-06 02:06:25 +0500 |
|---|---|---|
| committer | moderndevslulw <moderndevslulw@alright.party> | 2025-07-06 02:06:25 +0500 |
| commit | 65ef7bc6c9a18e7421468d0853d0c67369c01f97 (patch) | |
| tree | aeca097ec1d647daed354660957931062e582f0d /public/channels/index.php | |
| parent | bb920b117c33c8f78331aa1aea0470efece356a5 (diff) | |
feat: channel pages
Diffstat (limited to 'public/channels/index.php')
| -rw-r--r-- | public/channels/index.php | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/public/channels/index.php b/public/channels/index.php new file mode 100644 index 0000000..b32b63b --- /dev/null +++ b/public/channels/index.php @@ -0,0 +1,372 @@ +<?php +include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php'; +include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/utils.php'; +include_once $_SERVER['DOCUMENT_ROOT'] . '/../config.php'; + +function get_twitch_users(string $ids): array +{ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, "https://api.twitch.tv/helix/users?id=$ids"); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . TWITCH_AUTHORIZATION_TOKEN, + 'Client-Id: ' . TWITCH_CLIENT_ID + ]); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + + $response = curl_exec($ch); + $response = json_decode($response, true); + + curl_close($ch); + + return $response['data'] ?? []; +} + +$channel = null; +$channels = []; + +$db = new PDO(DB_URL, DB_USER, DB_PASS); + +if (isset($_GET['alias_id'])) { + $stmt = $db->prepare('SELECT c.*, cp.*, array_to_json(cp.features) as features + FROM channels c + LEFT JOIN channel_preferences cp ON cp.id = c.id + WHERE c.alias_id = ? + '); + $stmt->execute([$_GET['alias_id']]); + $channel = $stmt->fetch(PDO::FETCH_ASSOC) ?: null; + + if (!isset($channel)) { + http_response_code(404); + exit; + } + + $channel['features'] = json_decode($channel['features'] ?: '[]', true); + + // fetching custom commands + $stmt = $db->prepare('SELECT *, array_to_json(messages) as messages + FROM custom_commands + WHERE channel_id = ? + ORDER BY created_at DESC + '); + $stmt->execute([$channel['id']]); + $channel['commands'] = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($channel['commands'] as &$c) { + $c['messages'] = json_decode($c['messages'], true); + } + unset($c); + + // fetching timers + $stmt = $db->prepare('SELECT *, array_to_json(messages) as messages + FROM timers + WHERE channel_id = ? + '); + $stmt->execute([$channel['id']]); + $channel['timers'] = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($channel['timers'] as &$c) { + $c['messages'] = json_decode($c['messages'], true); + } + unset($c); + + // fetching events + $stmt = $db->prepare('SELECT e.*, array_to_json(e.flags) as flags, COUNT(es.id) as subscription_count + FROM events e + LEFT JOIN event_subscriptions es ON es.event_id = e.id + WHERE e.channel_id = ? + GROUP BY e.id + ORDER BY subscription_count DESC + '); + $stmt->execute([$channel['id']]); + $channel['events'] = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // fetching event names + $twitch_types = ['live', 'offline', 'title', 'category']; + $channel_ids = []; + foreach ($channel['events'] as &$e) { + $e['flags'] = json_decode($e['flags'], true); + if (in_array($e['event_type'], $twitch_types)) { + array_push($channel_ids, $e['target_alias_id']); + } + } + unset($e); + if (!empty($channel_ids)) { + $event_users = get_twitch_users(implode('&id=', $channel_ids)); + foreach ($event_users as $user) { + foreach ($channel['events'] as &$e) { + if ($e['target_alias_id'] == $user['id']) { + $e['name'] = $user['login']; + } + } + unset($e); + } + } + + // translating features + foreach ($channel['features'] as &$f) { + if ($f == "notify_7tv_updates") { + $f = "7TV Updates"; + } + } + unset($f); + + if ($response = get_twitch_users($channel['alias_id'])) { + $user = $response[0]; + $channel['pfp'] = $user['profile_image_url']; + $channel['description'] = $user['description'] ?: null; + } + + $has_content = !empty($channel['events']) || !empty($channel['commands']) || !empty($channel['timers']); +} else if (!SHOW_CHANNEL_LIST) { + http_response_code(403); + exit; +} else { + $stmt = $db->query('SELECT alias_id, alias_name FROM channels WHERE opt_outed_at IS NULL ORDER BY joined_at DESC'); + $stmt->execute(); + + $channels = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: []; +} + +// fetching user pfps +if (!empty($channels)) { + $channel_ids = []; + foreach ($channels as $c) { + array_push($channel_ids, $c['alias_id']); + } + + $response = get_twitch_users(implode('&id=', $channel_ids)); + + if (!empty($response)) { + foreach ($response as $c) { + $index = array_search($c['id'], array_column($channels, 'alias_id')); + $channels[$index]['pfp'] = $c['profile_image_url']; + } + } +} +?> + +<html> + +<head> + <title>Channels - The Tinybot Project</title> + <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> + <link rel="stylesheet" href="/static/style.css"> + <link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon"> +</head> + +<body> + <main> + <?php html_navigation_bar() ?> + <content class="gap-16"> + <?php if (isset($channel)): ?> + <section class="card row p-16"> + <?php if (isset($channel['pfp'])): ?> + <div class="icon"> + <img src="<?= $channel['pfp'] ?>" alt=""> + </div> + <?php endif; ?> + <div class="column gap-8 grow"> + <h1>About <?= $channel['alias_name'] ?></h1> + <?php if (isset($channel['description'])): ?> + <p><i><?= $channel['description'] ?></i></p> + <?php endif; ?> + <div class="row gap-16 font-small"> + <p>Language: <img src="/static/img/icons/flags/<?= $channel['language'] ?>.png" alt=""> + <?= ucfirst($channel['language']) ?></p> + <p>Prefix: <b><?= $channel['prefix'] ?></b></p> + </div> + <?php if (!empty($channel['features'])): ?> + <div class="row gap-16 font-small"> + <p>Features: <b><?= implode(', ', $channel['features']) ?></b></p> + </div> + <?php endif; ?> + </div> + <div class="column gap-8"> + <p><img src="/static/img/icons/door_in.png" alt=""> Joined + <?= format_timestamp(time() - strtotime($channel['joined_at'])) ?> ago + </p> + <?php if (isset($channel['opt_outed_at'])): ?> + <p class="red box text-center"><img src="/static/img/icons/door_out.png" alt=""> Opted out!</p> + <?php endif; ?> + </div> + </section> + + <!-- CHANNEL CONTENT --> + <?php if ($has_content): ?> + <section class="box" id="channel-content"> + <div class="tabs row gap-8" id="channel-content-tabs" style="display: none"> + <?php if (!empty($channel['events'])): ?> + <button class="tab" id="events-button">Events</button> + <?php endif; ?> + <?php if (!empty($channel['commands'])): ?> + + <button class="tab" id="commands-button">Custom commands</button> + <?php endif; ?> + + <?php if (!empty($channel['timers'])): ?> + + <button class="tab" id="timers-button">Timers</button> + <?php endif; ?> + + </div> + <div class="content"> + <?php if (!empty($channel['events'])): ?> + <!-- Events --> + <div class="tab-content column" id="events"> + <h2>Events</h2> + <hr> + <table> + <tr> + <th>Name</th> + <th>Type</th> + <th>Message</th> + <th>Flags</th> + <th>Subscribers</th> + </tr> + <?php foreach ($channel['events'] as $e): ?> + <tr> + <td> + <?php if (in_array($e['event_type'], $twitch_types)): ?> + <a href="https://twitch.tv/<?= $e['name'] ?>"><?= $e['name'] ?></a> + <?php elseif ($e['event_type'] == 'github'): ?> + <a + href="https://github.com/<?= $e['custom_alias_id'] ?>"><?= $e['custom_alias_id'] ?></a> + <?php else: ?> + <?= $e['custom_alias_id'] ?> + <?php endif; ?> + </td> + <td><?= $e['event_type'] ?></td> + <td><?= $e['message'] ?></td> + <td> + <?= empty($e['flags']) ? '-' : implode(', ', $e['flags']) ?> + </td> + <td><?= $e['subscription_count'] ?></td> + </tr> + <?php endforeach; ?> + </table> + </div> + <?php endif; ?> + + <?php if (!empty($channel['commands'])): ?> + <!-- Commands --> + <div class="tab-content column" id="commands"> + <h2>Custom commands</h2> + <hr> + <table> + <tr> + <th>Name</th> + <th>Messages</th> + <th>Last executed</th> + </tr> + <?php foreach ($channel['commands'] as $c): ?> + <tr> + <td><?= $c['name'] ?></td> + <td class="column"> + <?php foreach ($c['messages'] as $m): ?> + <p><?= $m ?></p> + <?php endforeach; ?> + </td> + <td><?= isset($c['last_executed_at']) ? format_timestamp(time() - strtotime($c['last_executed_at'])) . ' ago' : '-' ?> + </td> + </tr> + <?php endforeach; ?> + </table> + </div> + <?php endif; ?> + + <?php if (!empty($channel['timers'])): ?> + <!-- Timers --> + <div class="tab-content column" id="timers"> + <h2>Timers</h2> + <hr> + <table> + <tr> + <th>Name</th> + <th>Messages</th> + <th>Interval</th> + <th>Last executed</th> + </tr> + <?php foreach ($channel['timers'] as $t): ?> + <tr> + <td><?= $t['name'] ?></td> + <td class="column"> + <?php foreach ($t['messages'] as $m): ?> + <p><?= $m ?></p> + <?php endforeach; ?> + </td> + <td><?= format_timestamp($t['interval_sec']) ?></td> + <td><?= format_timestamp(time() - strtotime($t['last_executed_at'])) ?> ago</td> + </tr> + <?php endforeach; ?> + </table> + </div> + <?php endif; ?> + </div> + </section> + <?php else: ?> + <p class="text-center"><i>Nothing found...</i></p> + <?php endif; ?> + <?php elseif (empty($channels)): ?> + <section class="column justify-center align-center background-colorful p-24"> + <h1>No one has joined yet... ;(</h1> + <a href="/!join">Be the first one!</a> + </section> + <?php else: ?> + <section class="column justify-center align-center background-colorful p-24"> + <h1><?= count($channels) ?> channels have already joined us</h1> + <a href="/!join">Check out the !join command to participate!</a> + </section> + <section class="grid-4 gap-16"> + <?php foreach ($channels as $c): ?> + <a href="/channels/?alias_id=<?= $c['alias_id'] ?>" class="card justify-center align-center"> + <div class="icon"> + <img src="<?= $c['pfp'] ?? '/static/img/default_avatar.webp' ?>" alt=""> + </div> + <p><b><?= $c['alias_name'] ?></b></p> + </a> + <?php endforeach; ?> + </section> + <?php endif; ?> + </content> + </main> + + <?php html_footer() ?> +</body> + +<?php if (isset($channel) && $has_content): ?> + <script> + for (const elem of document.querySelectorAll('#channel-content h2, #channel-content hr')) { + elem.remove(); + } + + document.getElementById('channel-content-tabs').style.display = 'flex'; + + const tabButtons = document.querySelectorAll('#channel-content-tabs button'); + const tabContent = document.querySelectorAll('.tab-content'); + + function enableTab(name) { + tabButtons.forEach(x => { + if (x.getAttribute('id') == name + '-button') { + x.setAttribute('disabled', ''); + } else { + x.removeAttribute('disabled'); + } + }); + + tabContent.forEach(x => { + x.style.display = x.getAttribute('id') == name ? 'flex' : 'none'; + }); + } + + enableTab(tabButtons[0].getAttribute('id').split('-')[0]); + + for (const tabButton of tabButtons) { + const id = tabButton.getAttribute('id'); + const name = id.split('-')[0]; + tabButton.addEventListener('click', () => enableTab(name)); + } + </script> +<?php endif; ?> + +</html>
\ No newline at end of file |
