Compare commits
7 Commits
55e3f5a3c4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e022b2745 | |||
| ef7c90840b | |||
| 5045f30a4e | |||
| 1f13ba2afb | |||
| 9b66df772a | |||
| 76094830c4 | |||
| 39cdf17e3e |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
.env
|
.env
|
||||||
public/
|
public/
|
||||||
|
data/
|
||||||
@ -9,6 +9,7 @@ async function search(query) {
|
|||||||
let data = sc.search(query);
|
let data = sc.search(query);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// so um fuck lucida
|
// so um fuck lucida
|
||||||
// based on https://github.com/imputnet/cobalt/blob/58ea4aed01383ead74d5e32e75335eddc2f015be/api/src/processing/services/soundcloud.js
|
// based on https://github.com/imputnet/cobalt/blob/58ea4aed01383ead74d5e32e75335eddc2f015be/api/src/processing/services/soundcloud.js
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ const findBestForPreset = (transcodings, preset) => {
|
|||||||
return inferior;
|
return inferior;
|
||||||
}
|
}
|
||||||
async function download(obj) {
|
async function download(obj) {
|
||||||
const clientId = await findClientID();
|
const clientId = cachedID.id;
|
||||||
if (!clientId) return { error: "fetch.fail" };
|
if (!clientId) return { error: "fetch.fail" };
|
||||||
|
|
||||||
let link = obj;
|
let link = obj;
|
||||||
@ -150,4 +151,4 @@ async function download(obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { search, download };
|
export { search, download, findClientID };
|
||||||
192
edu/index.html
Normal file
192
edu/index.html
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="Open Learning Hub - Your gateway to free educational resources for coding, science, math, humanities, languages, and more.">
|
||||||
|
<meta name="keywords" content="education, free learning, online courses, coding, science, math, humanities, languages, study tools">
|
||||||
|
<meta name="author" content="Open Learning Hub">
|
||||||
|
<meta property="og:title" content="Open Learning Hub">
|
||||||
|
<meta property="og:description" content="Discover free educational resources and daily learning tips.">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<title>Open Learning Hub</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Open Learning Hub</h1>
|
||||||
|
<p>Your gateway to free educational resources across the web.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<section id="tip-section">
|
||||||
|
<h2>💡 Tip of the Day</h2>
|
||||||
|
<p id="daily-tip">Loading tip...</p>
|
||||||
|
<button id="new-tip-btn">Get Another Tip</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="resources">
|
||||||
|
<h2>Educational Resources</h2>
|
||||||
|
<div class="filter-controls">
|
||||||
|
<button class="filter-btn active" data-filter="all">All</button>
|
||||||
|
<button class="filter-btn" data-filter="coding">Coding</button>
|
||||||
|
<button class="filter-btn" data-filter="science">Science</button>
|
||||||
|
<button class="filter-btn" data-filter="math">Math</button>
|
||||||
|
<button class="filter-btn" data-filter="humanities">Humanities</button>
|
||||||
|
<button class="filter-btn" data-filter="languages">Languages</button>
|
||||||
|
<button class="filter-btn" data-filter="courses">Online Courses</button>
|
||||||
|
<button class="filter-btn" data-filter="tools">Study Tools</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="resource-grid">
|
||||||
|
<!-- Coding -->
|
||||||
|
<article class="card" data-category="coding">
|
||||||
|
<h3>freeCodeCamp</h3>
|
||||||
|
<p>Learn to code for free with interactive lessons and projects.</p>
|
||||||
|
<a href="https://www.freecodecamp.org" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="coding">
|
||||||
|
<h3>MDN Web Docs</h3>
|
||||||
|
<p>Resources for developers, by developers. The bible of web dev.</p>
|
||||||
|
<a href="https://developer.mozilla.org" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="coding">
|
||||||
|
<h3>GitHub</h3>
|
||||||
|
<p>The world's largest platform for software development and version control.</p>
|
||||||
|
<a href="https://github.com" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="coding">
|
||||||
|
<h3>The Odin Project</h3>
|
||||||
|
<p>A full stack curriculum that is free and supported by a passionate open source community.</p>
|
||||||
|
<a href="https://www.theodinproject.com/" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Science -->
|
||||||
|
<article class="card" data-category="science">
|
||||||
|
<h3>NASA</h3>
|
||||||
|
<p>Explore the universe with images, videos, and news from NASA.</p>
|
||||||
|
<a href="https://www.nasa.gov" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="science">
|
||||||
|
<h3>National Geographic</h3>
|
||||||
|
<p>World leader in geography, cartography and exploration.</p>
|
||||||
|
<a href="https://www.nationalgeographic.com" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="science">
|
||||||
|
<h3>Nature</h3>
|
||||||
|
<p>Leading international weekly journal of science.</p>
|
||||||
|
<a href="https://www.nature.com" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Math -->
|
||||||
|
<article class="card" data-category="math">
|
||||||
|
<h3>Khan Academy</h3>
|
||||||
|
<p>Free, world-class education for anyone, anywhere.</p>
|
||||||
|
<a href="https://www.khanacademy.org" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="math">
|
||||||
|
<h3>Wolfram MathWorld</h3>
|
||||||
|
<p>The web's most extensive mathematics resource.</p>
|
||||||
|
<a href="https://mathworld.wolfram.com" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="math">
|
||||||
|
<h3>Desmos</h3>
|
||||||
|
<p>Beautiful, free online graphing calculator.</p>
|
||||||
|
<a href="https://www.desmos.com" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Humanities -->
|
||||||
|
<article class="card" data-category="humanities">
|
||||||
|
<h3>Project Gutenberg</h3>
|
||||||
|
<p>A library of over 60,000 free eBooks.</p>
|
||||||
|
<a href="https://www.gutenberg.org" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="humanities">
|
||||||
|
<h3>Smithsonian</h3>
|
||||||
|
<p>Official website of the Smithsonian Institution.</p>
|
||||||
|
<a href="https://www.si.edu" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="humanities">
|
||||||
|
<h3>Internet Archive</h3>
|
||||||
|
<p>Non-profit library of millions of free books, movies, software, and music.</p>
|
||||||
|
<a href="https://archive.org" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Languages -->
|
||||||
|
<article class="card" data-category="languages">
|
||||||
|
<h3>Duolingo</h3>
|
||||||
|
<p>The world's most popular way to learn a language. It's 100% free.</p>
|
||||||
|
<a href="https://www.duolingo.com" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="languages">
|
||||||
|
<h3>BBC Languages</h3>
|
||||||
|
<p>Archived but excellent resources for learning 40 languages.</p>
|
||||||
|
<a href="https://www.bbc.co.uk/languages/" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Online Courses -->
|
||||||
|
<article class="card" data-category="courses">
|
||||||
|
<h3>Coursera</h3>
|
||||||
|
<p>Build skills with courses, certificates, and degrees online from world-class universities.</p>
|
||||||
|
<a href="https://www.coursera.org" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="courses">
|
||||||
|
<h3>edX</h3>
|
||||||
|
<p>Access 2000+ free online courses from 140 leading institutions worldwide.</p>
|
||||||
|
<a href="https://www.edx.org" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="courses">
|
||||||
|
<h3>MIT OpenCourseWare</h3>
|
||||||
|
<p>A web-based publication of virtually all MIT course content.</p>
|
||||||
|
<a href="https://ocw.mit.edu" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Study Tools -->
|
||||||
|
<article class="card" data-category="tools">
|
||||||
|
<h3>Anki</h3>
|
||||||
|
<p>Powerful, intelligent flashcards. Remembering things just became much easier.</p>
|
||||||
|
<a href="https://apps.ankiweb.net/" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="tools">
|
||||||
|
<h3>Notion</h3>
|
||||||
|
<p>The all-in-one workspace for your notes, tasks, wikis, and databases.</p>
|
||||||
|
<a href="https://www.notion.so/" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
<article class="card" data-category="tools">
|
||||||
|
<h3>Pomofocus</h3>
|
||||||
|
<p>A customizable Pomodoro timer that works on desktop & mobile browser.</p>
|
||||||
|
<a href="https://pomofocus.io/" target="_blank">Visit Site</a>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="learning-paths">
|
||||||
|
<h2>🚀 Learning Paths</h2>
|
||||||
|
<div class="paths-container">
|
||||||
|
<div class="path-card">
|
||||||
|
<h3>For Beginners</h3>
|
||||||
|
<p>Start with <strong>Khan Academy</strong> to build a strong foundation in Math and Science. Then, try <strong>Duolingo</strong> for a new language.</p>
|
||||||
|
</div>
|
||||||
|
<div class="path-card">
|
||||||
|
<h3>For Career Switchers</h3>
|
||||||
|
<p>Dive into <strong>freeCodeCamp</strong> or <strong>The Odin Project</strong> (add this!) to learn web development. Supplement with <strong>CS50</strong> on edX.</p>
|
||||||
|
</div>
|
||||||
|
<div class="path-card">
|
||||||
|
<h3>For Lifelong Learners</h3>
|
||||||
|
<p>Explore <strong>Project Gutenberg</strong> for classics, <strong>TED Talks</strong> for inspiration, and <strong>Coursera</strong> for specific interests.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<p>© 2025 Open Learning Hub.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
65
edu/script.js
Normal file
65
edu/script.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// --- Tip of the Day Logic ---
|
||||||
|
const tips = [
|
||||||
|
"Spaced repetition is a learning technique that incorporates increasing intervals of time between subsequent review of previously learned material.",
|
||||||
|
"The Pomodoro Technique uses a timer to break down work into intervals, traditionally 25 minutes in length, separated by short breaks.",
|
||||||
|
"Teaching someone else is one of the best ways to learn a new concept (The Feynman Technique).",
|
||||||
|
"Sleep is crucial for memory consolidation. Pulling an all-nighter is often counterproductive.",
|
||||||
|
"Active recall (testing yourself) is far more effective than passive re-reading.",
|
||||||
|
"Interleaving practice (mixing different subjects or topics) improves long-term retention compared to blocked practice.",
|
||||||
|
"Exercise increases blood flow to the brain and can improve cognitive performance.",
|
||||||
|
"Setting specific, measurable goals (SMART goals) helps maintain motivation.",
|
||||||
|
"Taking handwritten notes can improve conceptual understanding better than typing.",
|
||||||
|
"Mnemonic devices like acronyms or rhymes can help encode information into long-term memory."
|
||||||
|
];
|
||||||
|
|
||||||
|
const tipElement = document.getElementById('daily-tip');
|
||||||
|
const newTipBtn = document.getElementById('new-tip-btn');
|
||||||
|
|
||||||
|
function showRandomTip() {
|
||||||
|
const randomIndex = Math.floor(Math.random() * tips.length);
|
||||||
|
tipElement.textContent = tips[randomIndex];
|
||||||
|
|
||||||
|
// Add a subtle animation effect
|
||||||
|
tipElement.style.opacity = 0;
|
||||||
|
setTimeout(() => {
|
||||||
|
tipElement.style.opacity = 1;
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newTipBtn) {
|
||||||
|
newTipBtn.addEventListener('click', showRandomTip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show initial tip
|
||||||
|
if (tipElement) {
|
||||||
|
showRandomTip();
|
||||||
|
tipElement.style.transition = "opacity 0.5s ease-in-out";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Filtering Logic ---
|
||||||
|
const filterBtns = document.querySelectorAll('.filter-btn');
|
||||||
|
const cards = document.querySelectorAll('.card');
|
||||||
|
|
||||||
|
filterBtns.forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
// Remove active class from all buttons
|
||||||
|
filterBtns.forEach(b => b.classList.remove('active'));
|
||||||
|
// Add active class to clicked button
|
||||||
|
btn.classList.add('active');
|
||||||
|
|
||||||
|
const filterValue = btn.getAttribute('data-filter');
|
||||||
|
|
||||||
|
cards.forEach(card => {
|
||||||
|
if (filterValue === 'all' || card.getAttribute('data-category') === filterValue) {
|
||||||
|
card.style.display = 'flex';
|
||||||
|
// Add animation for appearing elements
|
||||||
|
card.style.animation = 'fadeIn 0.5s ease-in-out';
|
||||||
|
} else {
|
||||||
|
card.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
185
edu/style.css
Normal file
185
edu/style.css
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
:root {
|
||||||
|
--primary-color: #2c3e50;
|
||||||
|
--secondary-color: #3498db;
|
||||||
|
--accent-color: #e74c3c;
|
||||||
|
--bg-color: #f4f4f4;
|
||||||
|
--card-bg: #ffffff;
|
||||||
|
--text-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
padding: 2rem 0;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: var(--primary-color);
|
||||||
|
border-bottom: 2px solid var(--secondary-color);
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tip Section */
|
||||||
|
#tip-section {
|
||||||
|
background-color: var(--card-bg);
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
border-left: 5px solid var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#new-tip-btn {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 1rem;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#new-tip-btn:hover {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filter Controls */
|
||||||
|
.filter-controls {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: 2px solid var(--secondary-color);
|
||||||
|
color: var(--secondary-color);
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn:hover, .filter-btn.active {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resource Grid */
|
||||||
|
.resource-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: var(--card-bg);
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card h3 {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card p {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card a {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--secondary-color);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem 0;
|
||||||
|
margin-top: 2rem;
|
||||||
|
color: #777;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(10px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
header h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Learning Paths */
|
||||||
|
.paths-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-card {
|
||||||
|
background-color: #e8f4f8;
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
border-left: 4px solid var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-card h3 {
|
||||||
|
color: var(--primary-color);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
@ -5,15 +5,6 @@
|
|||||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||||
|
|
||||||
<!-- initialize externals -->
|
<!-- initialize externals -->
|
||||||
<meta property="og:title" content="Selenite" />
|
|
||||||
<meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
<meta content="/favicon.png" property="og:image" />
|
|
||||||
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
|
|
||||||
<meta name="googlebot" content="index, follow, snippet" />
|
|
||||||
<link rel="canonical" href="https://selenite.cc/" />
|
|
||||||
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
<meta property="og:title" content="Selenite">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
|
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
@ -59,6 +50,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function setRecat() {
|
||||||
|
let domain = prompt("domain");
|
||||||
|
if(domain) {
|
||||||
|
fetch("/api/recat", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({domain: domain})
|
||||||
|
})
|
||||||
|
.then(data => data.text())
|
||||||
|
.then(data => alert(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<alerts> </alerts>
|
<alerts> </alerts>
|
||||||
@ -66,6 +68,7 @@
|
|||||||
<h1 class="title">admin page</h1>
|
<h1 class="title">admin page</h1>
|
||||||
<sections>
|
<sections>
|
||||||
<button onclick="sendAnnouncement()">send announcement</button>
|
<button onclick="sendAnnouncement()">send announcement</button>
|
||||||
|
<button onclick="setRecat()">set a domain to recat</button>
|
||||||
</sections>
|
</sections>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -5,8 +5,6 @@
|
|||||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||||
|
|
||||||
<!-- initialize externals -->
|
<!-- initialize externals -->
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
|
||||||
<script src=" https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js "></script>
|
|
||||||
|
|
||||||
<!-- initialize my stuff -->
|
<!-- initialize my stuff -->
|
||||||
<script src="/js/all.min.js"></script>
|
<script src="/js/all.min.js"></script>
|
||||||
|
|||||||
@ -5,16 +5,6 @@
|
|||||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||||
|
|
||||||
<!-- initialize externals -->
|
<!-- initialize externals -->
|
||||||
<meta property="og:title" content="Selenite" />
|
|
||||||
<meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
|
|
||||||
<meta content="/favicon.png" property="og:image" />
|
|
||||||
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
|
|
||||||
<meta name="googlebot" content="index, follow, snippet" />
|
|
||||||
<link rel="canonical" href="https://selenite.cc/" />
|
|
||||||
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
<meta property="og:title" content="Selenite">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
|
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,16 +5,6 @@
|
|||||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||||
|
|
||||||
<!-- initialize externals -->
|
<!-- initialize externals -->
|
||||||
<meta property="og:title" content="Selenite" />
|
|
||||||
<meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
|
|
||||||
<meta content="/favicon.png" property="og:image" />
|
|
||||||
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
|
|
||||||
<meta name="googlebot" content="index, follow, snippet" />
|
|
||||||
<link rel="canonical" href="https://selenite.cc/" />
|
|
||||||
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
<meta property="og:title" content="Selenite">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
|
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,8 +5,6 @@
|
|||||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||||
|
|
||||||
<!-- initialize externals -->
|
<!-- initialize externals -->
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
|
||||||
<script src=" https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js "></script>
|
|
||||||
|
|
||||||
<!-- initialize my stuff -->
|
<!-- initialize my stuff -->
|
||||||
<script src="/js/all.min.js"></script>
|
<script src="/js/all.min.js"></script>
|
||||||
@ -14,7 +12,9 @@
|
|||||||
|
|
||||||
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="/style.css" />
|
<link rel="stylesheet" href="/css/main.css" />
|
||||||
|
<link rel="stylesheet" href="/css/pages.css" />
|
||||||
|
|
||||||
|
|
||||||
<!-- seo + other things -->
|
<!-- seo + other things -->
|
||||||
<title>Reset Password | Selenite</title>
|
<title>Reset Password | Selenite</title>
|
||||||
@ -62,26 +62,15 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<alerts> </alerts>
|
<alerts> </alerts>
|
||||||
<body id="noscroll">
|
<body>
|
||||||
<header>
|
<h2>reset password</h2>
|
||||||
<a href="/index.html">Home</a>
|
|
||||||
<a href="/bookmarklets.html">Bookmarklets</a>
|
|
||||||
<a href="/projects.html">Games</a>
|
|
||||||
<a href="/apps.html">Apps</a>
|
|
||||||
<a href="/settings.html">Settings</a>
|
|
||||||
<a id="blank" href="#">Open Blank</a>
|
|
||||||
<a href="/u/" class="usericon"><img src="/img/user.svg"></a>
|
|
||||||
</header>
|
|
||||||
<main id="main" class="noscroll">
|
|
||||||
<h2>Reset Password</h2>
|
|
||||||
<form action="" id="reset">
|
<form action="" id="reset">
|
||||||
<input type="text" id="username" placeholder="username" />
|
<input type="text" id="username" placeholder="username" />
|
||||||
<input type="password" id="key" placeholder="key" />
|
<input type="password" id="key" placeholder="key" />
|
||||||
<input type="password" id="password" placeholder="password" />
|
<input type="password" id="password" placeholder="password" />
|
||||||
<div class="h-captcha" id="hcaptcha" data-sitekey="1774ec96-39be-4fb0-9e82-f4c62354b8fa"></div>
|
<div class="h-captcha" id="hcaptcha" data-sitekey="1774ec96-39be-4fb0-9e82-f4c62354b8fa"></div>
|
||||||
<button type="submit" value="Submit">Reset Password</button>
|
<button type="submit" value="Submit">reset password</button>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
|
||||||
<popups>
|
<popups>
|
||||||
<div id="popup" style="display: none">
|
<div id="popup" style="display: none">
|
||||||
<h1 id="title"></h1>
|
<h1 id="title"></h1>
|
||||||
@ -89,13 +78,5 @@
|
|||||||
<button id="close">X</button>
|
<button id="close">X</button>
|
||||||
</div>
|
</div>
|
||||||
</popups>
|
</popups>
|
||||||
<footer class="noscroll">
|
|
||||||
<a href="https://gitlab.com/skysthelimit.dev/selenite">Source</a>
|
|
||||||
<a href="https://discord.gg/7jyufnwJNf">Discord</a>
|
|
||||||
<a href="/suggest.html">Suggestions & Bugs</a>
|
|
||||||
<a href="/contact.html">Contact</a>
|
|
||||||
<a href="/support.html">Donate</a>
|
|
||||||
<a href="/about.html">About</a>
|
|
||||||
</footer>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -5,15 +5,6 @@
|
|||||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||||
|
|
||||||
<!-- initialize externals -->
|
<!-- initialize externals -->
|
||||||
<meta property="og:title" content="Selenite" />
|
|
||||||
<meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
<meta content="/favicon.png" property="og:image" />
|
|
||||||
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
|
|
||||||
<meta name="googlebot" content="index, follow, snippet" />
|
|
||||||
<link rel="canonical" href="https://selenite.cc/" />
|
|
||||||
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
<meta property="og:title" content="Selenite">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
|
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,16 +5,6 @@
|
|||||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||||
|
|
||||||
<!-- initialize externals -->
|
<!-- initialize externals -->
|
||||||
<meta property="og:title" content="Selenite" />
|
|
||||||
<meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
|
|
||||||
<meta content="/favicon.png" property="og:image" />
|
|
||||||
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
|
|
||||||
<meta name="googlebot" content="index, follow, snippet" />
|
|
||||||
<link rel="canonical" href="https://selenite.cc/" />
|
|
||||||
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
|
|
||||||
<meta property="og:title" content="Selenite">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
|
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
|
|||||||
67
index.js
67
index.js
@ -10,18 +10,46 @@ import compression from "compression";
|
|||||||
// import { accs, infdb, polytrack } from "./database.js";
|
// import { accs, infdb, polytrack } from "./database.js";
|
||||||
import { accs } from "./database.js";
|
import { accs } from "./database.js";
|
||||||
import { } from "./accounts/friend.js";
|
import { } from "./accounts/friend.js";
|
||||||
import { search, download } from "./accounts/music.js";
|
import { findClientID, search, download } from "./accounts/music.js";
|
||||||
import { banUser, removeAccount, verifyCookie, getUserFromCookie, createAccount, resetPassword, loginAccount, addBadge } from "./accounts/manage.js";
|
import { banUser, removeAccount, verifyCookie, getUserFromCookie, createAccount, resetPassword, loginAccount, addBadge } from "./accounts/manage.js";
|
||||||
import { } from "./accounts/misc.js";
|
import { } from "./accounts/misc.js";
|
||||||
import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js";
|
import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js";
|
||||||
import { callAI } from "./ai.js";
|
import { callAI } from "./ai.js";
|
||||||
|
import { Readable } from 'stream';
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
|
import chokidar from 'chokidar';
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
let recatters = JSON.parse(await fs.readFile("./data/recats.json"));
|
||||||
|
const watcher = chokidar.watch('./data/recats.json', {
|
||||||
|
persistent: true,
|
||||||
|
awaitWriteFinish: {
|
||||||
|
stabilityThreshold: 500,
|
||||||
|
pollInterval: 100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
watcher.on('change', async (event, filePath) => {
|
||||||
|
recatters = JSON.parse(await fs.readFile("./data/recats.json"));
|
||||||
|
});
|
||||||
|
|
||||||
|
await findClientID();
|
||||||
|
setInterval(async () => {
|
||||||
|
await findClientID();
|
||||||
|
}, 1000 * 60 * 20);
|
||||||
|
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
let recatFolder = express.static("./edu", { extensions: ["html"] });
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
if(recatters.includes(req.hostname)) {
|
||||||
|
return recatFolder(req, res, next);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// why the fuck does this have to exist?
|
// why the fuck does this have to exist?
|
||||||
app.use("/resources/semag/hotline-miami/", (req,res,next) => {
|
app.use("/resources/semag/hotline-miami/", (req,res,next) => {
|
||||||
if(req.method == "HEAD") {
|
if(req.method == "HEAD") {
|
||||||
@ -85,7 +113,7 @@ wss.on("connection", function connection(ws, req, res) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on("close", () => {});
|
ws.on("close", () => {server.close()});
|
||||||
});
|
});
|
||||||
app.post(
|
app.post(
|
||||||
"/api/event",
|
"/api/event",
|
||||||
@ -160,6 +188,41 @@ app.post("/api/ai/sendMessage", async (req, res) => {
|
|||||||
// stream back reply
|
// stream back reply
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// music endpoints
|
||||||
|
app.get("/api/music/search", async (req, res) => {
|
||||||
|
res.status(200).send(await search(req.query.q))
|
||||||
|
})
|
||||||
|
|
||||||
|
app.use("/api/music/download", async (req, res, next) => {
|
||||||
|
// console.log()
|
||||||
|
let song = req.query.url;
|
||||||
|
song = song.replaceAll(" ", "");
|
||||||
|
const processor = Bun.spawn([
|
||||||
|
"yt-dlp",
|
||||||
|
"bestaudio[abr<=160]",
|
||||||
|
"-o", `-`,
|
||||||
|
"https://soundcloud.com/" + req.query.url
|
||||||
|
]);
|
||||||
|
for await (const chunk of processor.stdout) {
|
||||||
|
res.write(chunk);
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
app.post("/api/recat", async (req, res) => {
|
||||||
|
if(isAdmin(req.cookies.token)) {
|
||||||
|
let domain = JSON.parse(req.body)["domain"];
|
||||||
|
let message;
|
||||||
|
if(recatters.includes(domain)) {
|
||||||
|
recatters.pop(domain);
|
||||||
|
message = `Successfully set ${domain} to Selenite.`
|
||||||
|
} else {
|
||||||
|
recatters.push(domain);
|
||||||
|
message = `Successfully set ${domain} as educational.`
|
||||||
|
}
|
||||||
|
fs.writeFile("./data/recats.json", JSON.stringify(recatters));
|
||||||
|
res.send(message);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
// friends endpoints
|
// friends endpoints
|
||||||
app.get("/api/friends/list", async (req, res) => {
|
app.get("/api/friends/list", async (req, res) => {
|
||||||
|
|||||||
1356
package-lock.json
generated
1356
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
|||||||
"axios": "^1.12.2",
|
"axios": "^1.12.2",
|
||||||
"body-parser": "^2.2.0",
|
"body-parser": "^2.2.0",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
"compression": "^1.8.1",
|
"compression": "^1.8.1",
|
||||||
"cookie-parser": "^1.4.7",
|
"cookie-parser": "^1.4.7",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
|
import { appendFile } from 'fs/promises';
|
||||||
import WebSocket, { WebSocketServer } from "ws";
|
import WebSocket, { WebSocketServer } from "ws";
|
||||||
const wss = new WebSocketServer({ noServer: true });
|
const wss = new WebSocketServer({ noServer: true });
|
||||||
|
let dataFile = "data/online.txt";
|
||||||
|
|
||||||
|
|
||||||
wss.on("connection", function connection(ws, req, res) {
|
wss.on("connection", function connection(ws, req, res) {
|
||||||
ws.send(`online=${wss.clients.size}`);
|
ws.send(`online=${wss.clients.size}`);
|
||||||
@ -30,4 +33,7 @@ server.on("upgrade", (request, socket, head) => {
|
|||||||
wss.handleUpgrade(request, socket, head, (socket) => {
|
wss.handleUpgrade(request, socket, head, (socket) => {
|
||||||
wss.emit("connection", socket, request);
|
wss.emit("connection", socket, request);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
setInterval(async () => {
|
||||||
|
await appendFile(dataFile, String(wss.clients.size) + "\n")
|
||||||
|
}, 10000)
|
||||||
Reference in New Issue
Block a user