generated from nhcarrigan/template
feat: site-wide content and feature updates (#2)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 2m7s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 2m7s
A wide-ranging set of updates across multiple pages that accumulated over time. ## Tarot - Expanded spread descriptions and added "good for" guidance to help users pick the right spread - Cards now start face-down and flip individually on click, with a synthesised flip sound and text fade-in - "Click card to reveal" hint shown on each unflipped card - Spread selection and draw button are locked until all cards in the current reading have been revealed ## Nocturne - Added dedicated sacred scriptures showcase section - Added patron saints section with avatar images - Added Naomi's Prayer - Added sacred practices section (expanded to six cards) - Added clergy and hierarchy section - Added titles of address section - Added testimonial and expanded FAQ - Capitalised She/Her pronouns referring to Naomi ## Scripture - Converted page to interactive book with page-turning - Expanded canon through the Fourth Edition across multiple updates - Synced the Ten Commandments with Nocturne - Fixed meta description to reflect fourteen books - Capitalised She/Her pronouns referring to Naomi ## Other Pages - Books, games, and music pages now redirect to `library.nhcarrigan.com` - Updated user manual with additional context - Added 404 error page ## Chore / Fixes - Updated sitemap with new and corrected entries - Fixed null-safe while loop for filename handling in scripts - Updated scripts to use correct Windows paths via WSL - Cleaned up data files and added JSON to `.gitignore` - Added secret #13 ✨ This PR was created with help from Hikari~ 🌸 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Reviewed-on: #2 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #2.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
*.json
|
||||
tarot/generate.py
|
||||
tarot/.venv/
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>404 — Lost in the Void</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="The page you sought has slipped into the void. Even a 525-year-old vampire cannot find it."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
/* ========== LAYOUT ========== */
|
||||
|
||||
main {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
footer {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* ========== HERO ========== */
|
||||
|
||||
.error-hero {
|
||||
text-align: center;
|
||||
padding: 2em 1em 2.5em;
|
||||
border-bottom: 2px solid var(--witch-plum);
|
||||
margin-bottom: 2.5em;
|
||||
}
|
||||
|
||||
.error-code {
|
||||
font-family: 'Griffy', cursive;
|
||||
font-size: 7rem;
|
||||
line-height: 1;
|
||||
color: var(--witch-plum);
|
||||
letter-spacing: 0.1em;
|
||||
margin: 0 0 0.15em;
|
||||
text-shadow: 0 0 32px rgba(130, 80, 120, 0.35);
|
||||
}
|
||||
|
||||
.error-seal {
|
||||
font-size: 3.5rem;
|
||||
display: block;
|
||||
margin: 0 auto 0.5em;
|
||||
animation: floatSeal 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes floatSeal {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
.error-hero h1 {
|
||||
font-size: 2rem;
|
||||
letter-spacing: 0.06em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
.error-tagline {
|
||||
font-size: 1.05rem;
|
||||
color: var(--witch-plum);
|
||||
font-style: italic;
|
||||
max-width: 560px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* ========== MESSAGE SCROLL ========== */
|
||||
|
||||
.void-section {
|
||||
margin: 0 auto 3em;
|
||||
max-width: 680px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.void-section > h2 {
|
||||
border-bottom: 2px solid var(--witch-plum);
|
||||
padding-bottom: 0.4em;
|
||||
margin-bottom: 1em;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.void-scroll {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 15px;
|
||||
padding: 1.75em 2em;
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.void-scroll p + p {
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
|
||||
.void-scroll .accent {
|
||||
color: var(--witch-plum);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ========== NAVIGATION CARDS ========== */
|
||||
|
||||
.nav-section {
|
||||
margin: 0 auto 3em;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.nav-section > h2 {
|
||||
border-bottom: 2px solid var(--witch-plum);
|
||||
padding-bottom: 0.4em;
|
||||
margin-bottom: 1.25em;
|
||||
letter-spacing: 0.05em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nav-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
gap: 1.25em;
|
||||
}
|
||||
|
||||
.nav-card {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 15px;
|
||||
padding: 1.25em 1.5em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition:
|
||||
background 0.2s ease,
|
||||
transform 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'),
|
||||
pointer;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-card:hover {
|
||||
background: rgba(212, 165, 199, 0.2);
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 20px rgba(130, 80, 120, 0.2);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-card-icon {
|
||||
font-size: 2rem;
|
||||
display: block;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
.nav-card h3 {
|
||||
font-family: 'Griffy', cursive;
|
||||
font-size: 1.1rem;
|
||||
margin: 0 0 0.3em;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--witch-plum);
|
||||
}
|
||||
|
||||
.nav-card p {
|
||||
font-size: 0.88rem;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* ========== RESPONSIVE ========== */
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.error-code {
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
||||
.error-hero h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.void-scroll {
|
||||
padding: 1.25em 1.25em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<!-- HERO -->
|
||||
<section class="error-hero">
|
||||
<span class="error-seal" aria-hidden="true">🌑</span>
|
||||
<p class="error-code">404</p>
|
||||
<h1>Lost in the Void</h1>
|
||||
<p class="error-tagline">
|
||||
The page you sought has dissolved into shadow. Even after 525 years,
|
||||
some things cannot be found.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- MESSAGE -->
|
||||
<section class="void-section">
|
||||
<h2>✦ What Happened? ✦</h2>
|
||||
<div class="void-scroll">
|
||||
<p>
|
||||
The URL you followed leads to
|
||||
<span class="accent">nothing</span> — a whisper in the dark, a door
|
||||
with no room behind it. This could mean a few things:
|
||||
</p>
|
||||
<p>
|
||||
The page may have been <span class="accent">moved</span>, renamed,
|
||||
or quietly retired into the archives of history (much like certain
|
||||
empires I have personally watched crumble).
|
||||
</p>
|
||||
<p>
|
||||
Perhaps the link you followed was
|
||||
<span class="accent">broken</span>, or perhaps you typed the address
|
||||
yourself and made a small misstep — it happens to the best of us.
|
||||
Even vampires miscount sometimes.
|
||||
</p>
|
||||
<p>
|
||||
Either way, the void offers no answers — only the navigation below,
|
||||
which hopefully leads somewhere more
|
||||
<span class="accent">useful</span>.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- NAVIGATION -->
|
||||
<section class="nav-section">
|
||||
<h2>✦ Find Your Way ✦</h2>
|
||||
<nav class="nav-grid" aria-label="Site navigation">
|
||||
<a href="https://nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🏠</span>
|
||||
<h3>Home</h3>
|
||||
<p>Return to the main site and start fresh.</p>
|
||||
</a>
|
||||
<a href="https://chat.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">💬</span>
|
||||
<h3>Chat</h3>
|
||||
<p>Join the community and say hello.</p>
|
||||
</a>
|
||||
<a href="https://support.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🛟</span>
|
||||
<h3>Support</h3>
|
||||
<p>Need help? Find support resources here.</p>
|
||||
</a>
|
||||
<a href="https://donate.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">💜</span>
|
||||
<h3>Donate</h3>
|
||||
<p>Support the work if you find it valuable.</p>
|
||||
</a>
|
||||
<a href="https://socials.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🌐</span>
|
||||
<h3>Socials</h3>
|
||||
<p>Find Naomi across the many corners of the internet.</p>
|
||||
</a>
|
||||
<a href="https://git.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">💻</span>
|
||||
<h3>Code</h3>
|
||||
<p>Browse the source code and open-source projects.</p>
|
||||
</a>
|
||||
<a href="https://library.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">📚</span>
|
||||
<h3>Library</h3>
|
||||
<p>Explore the ever-growing collection of books.</p>
|
||||
</a>
|
||||
<a href="https://nocturne.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🧛</span>
|
||||
<h3>Nocturne</h3>
|
||||
<p>The sacred faith of Naomi's Nocturne. No garlic bread.</p>
|
||||
</a>
|
||||
<a href="https://sitemap.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🗺️</span>
|
||||
<h3>Sitemap</h3>
|
||||
<p>See everything — every page, every corner of the site.</p>
|
||||
</a>
|
||||
</nav>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,36 +0,0 @@
|
||||
IFS=$'\n'
|
||||
|
||||
# Initialize an empty string to hold the list of books in JSON-like format
|
||||
books=""
|
||||
filecount=$(find /home/naomi/cloud/Books -type f | wc -l)
|
||||
echo "Found $filecount files."
|
||||
current=0
|
||||
|
||||
# Loop over each file found by find
|
||||
for file in $(find /home/naomi/cloud/Books -type f -print0 | tr '\0' '\n'); do
|
||||
current=$((current + 1))
|
||||
echo -ne "Processing $current/$filecount\r"
|
||||
title=$(exiftool "$file" | grep "^Title\s*:" | cut -d ":" -f 2 | sed -e 's/^[[:space:]]*//')
|
||||
author=$(exiftool "$file" | grep "^Creator\s*:" | cut -d ":" -f 2 | sed -e 's/^[[:space:]]*//')
|
||||
|
||||
if [ -z "$title" ]; then
|
||||
# remove .mp3 from the title
|
||||
title=$(basename "$file" | sed -e 's/\.*//g')
|
||||
fi
|
||||
if [ -z "$author" ]; then
|
||||
author=$(exiftool "$file" | grep "^Author\s*:" | cut -d ":" -f 2 | sed -e 's/^[[:space:]]*//')
|
||||
fi
|
||||
if [ -z "$author" ]; then
|
||||
author="Unknown Author"
|
||||
fi
|
||||
|
||||
# use jq to add the book to the list
|
||||
books="$books$(jq -n --arg title "$title" --arg author "$author" '{title: $title, author: $author}'),"
|
||||
done
|
||||
|
||||
# Remove trailing comma and add square brackets to complete the list
|
||||
books="[${books%,}]"
|
||||
|
||||
# Write to ./books/books.json
|
||||
echo "$books" > ./books/books.json
|
||||
echo -ne "Done!\r"
|
||||
-1210
File diff suppressed because it is too large
Load Diff
+5
-104
@@ -4,114 +4,15 @@
|
||||
<title>Naomi's Book Library</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="An interactive explorer for the books Naomi reads." />
|
||||
<meta name="description" content="Naomi's book library has moved to library.nhcarrigan.com." />
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Naomi's Book Library</h1>
|
||||
<section>
|
||||
<p>An interactive explorer for the books Naomi reads.</p>
|
||||
<p id="count">Loading library...</p>
|
||||
</section>
|
||||
<div style="display: none;">
|
||||
<span>Search Authors: </span>
|
||||
<input type="text" id="author" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<span>Search Titles: </span>
|
||||
<input type="text" id="title" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<button type="button" id="clear">Clear Filters</button>
|
||||
</div>
|
||||
<table id="books">
|
||||
|
||||
</table>
|
||||
<h1>Naomi's Book Library</h1>
|
||||
<section>
|
||||
<p>This page has moved! You can find Naomi's book library at <a href="https://library.nhcarrigan.com">library.nhcarrigan.com</a>.</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
<script>
|
||||
const authorQuery = document.getElementById('author');
|
||||
const titleQuery = document.getElementById('title');
|
||||
const resetButton = document.getElementById('clear');
|
||||
const bookTable = document.getElementById('books');
|
||||
const filterBooks = (author, title) => {
|
||||
let result = [...bookList];
|
||||
if(author) {
|
||||
result = result.filter(book => book.author.toLowerCase().includes(author.toLowerCase()));
|
||||
}
|
||||
if(title) {
|
||||
result = result.filter(book => book.title.toLowerCase().includes(title.toLowerCase()));
|
||||
}
|
||||
resetButton.parentElement.style.display = author || title ? "block" : "none";
|
||||
document.getElementById('count').innerText = author || title ? `Filtered to ${result.length} books from ${bookList.length}.` : `Naomi currently has ${bookList.length} books.`;
|
||||
updateTable(result);
|
||||
}
|
||||
const loadBooks = (books) => {
|
||||
bookList.push(...books);
|
||||
authorQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
authorQuery.parentElement.style.display = "block";
|
||||
titleQuery.parentElement.style.display = "block";
|
||||
document.getElementById('count').innerText = `Naomi currently has ${books.length} books.`;
|
||||
updateTable(books);
|
||||
}
|
||||
const updateTable = (books) => {
|
||||
books = books.sort((a, b) => a.title.localeCompare(b.title));
|
||||
bookTable.innerHTML = "";
|
||||
const header = document.createElement('tr');
|
||||
const authorHeader = document.createElement('th');
|
||||
authorHeader.innerText = "Author";
|
||||
const titleHeader = document.createElement('th');
|
||||
titleHeader.innerText = "Title";
|
||||
header.appendChild(titleHeader);
|
||||
header.appendChild(authorHeader);
|
||||
bookTable.appendChild(header);
|
||||
books.forEach(book => {
|
||||
const row = document.createElement('tr');
|
||||
const author = document.createElement('td');
|
||||
author.innerText = book.author;
|
||||
const title = document.createElement('td');
|
||||
title.innerText = book.title;
|
||||
row.appendChild(title);
|
||||
row.appendChild(author);
|
||||
bookTable.appendChild(row);
|
||||
});
|
||||
}
|
||||
const bookList = [];
|
||||
fetch("./books.json").then(res => res.json()).then(data => loadBooks(data))
|
||||
|
||||
authorQuery?.addEventListener("input", (e) => filterBooks(e.target.value, titleQuery.value));
|
||||
titleQuery?.addEventListener("input", (e) => filterBooks(authorQuery.value, e.target.value));
|
||||
resetButton?.addEventListener("click", () => {
|
||||
authorQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
filterBooks("", "");
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
tr:nth-of-type(even) {
|
||||
background-color: #db7093dd;
|
||||
color: #ffefef;
|
||||
}
|
||||
input {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem
|
||||
}
|
||||
button {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem;
|
||||
cursor:url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
|
||||
}
|
||||
</style>
|
||||
</html>
|
||||
+3
-24
@@ -4,36 +4,15 @@
|
||||
<title>Games</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="These are the various games we have developed!" />
|
||||
<meta name="description" content="Naomi's game library has moved to library.nhcarrigan.com." />
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Games</h1>
|
||||
<section>
|
||||
<p>These are the various games we have developed.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Links</h2>
|
||||
<p>
|
||||
<a href="https://beccalia.nhcarrigan.com/">
|
||||
🩵 Beccalia Series
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://goblin.nhcarrigan.com">
|
||||
🩷 Ruu's Goblin Quest
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://loan.nhcarrigan.com">
|
||||
🩵 Life of a Naomi
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
We are currently on a hiatus from game development. But we may return in the future - be sure to join our Discord server so you don't miss any updates~!
|
||||
</p>
|
||||
<p>This page has moved! You can find Naomi's game library at <a href="https://library.nhcarrigan.com">library.nhcarrigan.com</a>.</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+31
-9
@@ -51,9 +51,10 @@
|
||||
<li>
|
||||
First and foremost, do not pass judgement. I will not begrudge you
|
||||
for your religious beliefs, political alignments, or any other
|
||||
aspects of your life. And I expect the same courtesy in return. You
|
||||
do not have to accept who I am, or support my choices, but we need
|
||||
to maintain a respectful and cordial professional relationship.
|
||||
aspects of your life. And I expect the same courtesy in return. I am
|
||||
a transgender woman and a proud member of the LGBTQ+ community. You
|
||||
do not have to agree with who I am or support my choices, but we
|
||||
need to maintain a respectful and cordial professional relationship.
|
||||
Expressing hateful, mean-spirited, or vitriolic comments does not
|
||||
foster such an environment, and my tolerance for such is nil.
|
||||
</li>
|
||||
@@ -64,6 +65,19 @@
|
||||
with pale imitations, or harass/target someone, or restrict access
|
||||
to information.
|
||||
</li>
|
||||
<li>
|
||||
Third, technology should be inclusive, ethical, and sustainable.
|
||||
These are not buzzwords to me — they are the foundation of every
|
||||
project I take on. I learned to code through a free, open curriculum
|
||||
during the pandemic, and that experience shaped everything. Knowledge
|
||||
hoarded helps no one. Knowledge shared changes lives. I build with
|
||||
that in mind.
|
||||
</li>
|
||||
<li>
|
||||
Finally, autonomy is sacred. I will never build something designed
|
||||
to manipulate, coerce, or remove agency from the people using it.
|
||||
If a project asks me to do that, the answer is no.
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
</section>
|
||||
@@ -102,6 +116,12 @@
|
||||
hours are the best. Too early and I'll likely fail to wake up. Too
|
||||
late and I might be incoherent.
|
||||
</li>
|
||||
<li>
|
||||
I have nerve damage and lumbar spine degeneration, which means I
|
||||
need to step away from the screen and move around regularly. If I go
|
||||
quiet for a few minutes mid-conversation, I haven't disappeared —
|
||||
I'm just stretching. Please do not interpret this as disengagement.
|
||||
</li>
|
||||
<li>
|
||||
If given something like a Trello or a Monday board, I will 100% make
|
||||
it pretty and load every single task ever on there. I'm a sucker for
|
||||
@@ -126,12 +146,14 @@
|
||||
it all at once, or save the ping for the last part.
|
||||
</li>
|
||||
<li>
|
||||
I have generalised anxiety disorder. Please for the love of all
|
||||
things, do NOT say "we need to talk" or "do you have time to meet".
|
||||
I will 100% sit there right up until the meeting starts stressing
|
||||
about getting fired and not actually getting any work done. If you
|
||||
need to call me out, just rip the bandage off and come out of the
|
||||
gate with it.
|
||||
I have generalised anxiety disorder and depression. Please for the
|
||||
love of all things, do NOT say "we need to talk" or "do you have
|
||||
time to meet". I will 100% sit there right up until the meeting
|
||||
starts stressing about getting fired and not actually getting any
|
||||
work done. If you need to call me out, just rip the bandage off and
|
||||
come out of the gate with it. Likewise, if I've done something well,
|
||||
please tell me — words of encouragement genuinely land for me and
|
||||
will make me work even harder for you.
|
||||
</li>
|
||||
<li>
|
||||
I dunno if you noticed the tone changed in this document about a
|
||||
|
||||
+5
-113
@@ -4,123 +4,15 @@
|
||||
<title>Naomi's Music Library</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="An interactive explorer for the music Naomi listens to." />
|
||||
<meta name="description" content="Naomi's music library has moved to library.nhcarrigan.com." />
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Naomi's Music Library</h1>
|
||||
<section>
|
||||
<p>An interactive explorer for the music Naomi listens to.</p>
|
||||
<p id="count">Loading library...</p>
|
||||
</section>
|
||||
<div style="display: none;">
|
||||
<span>Search Artists: </span>
|
||||
<input type="text" id="artist" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<span>Search Titles: </span>
|
||||
<input type="text" id="title" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<button type="button" id="clear">Clear Filters</button>
|
||||
</div>
|
||||
<table id="songs">
|
||||
|
||||
</table>
|
||||
<h1>Naomi's Music Library</h1>
|
||||
<section>
|
||||
<p>This page has moved! You can find Naomi's music library at <a href="https://library.nhcarrigan.com">library.nhcarrigan.com</a>.</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
<script>
|
||||
const artistQuery = document.getElementById('artist');
|
||||
const titleQuery = document.getElementById('title');
|
||||
const resetButton = document.getElementById('clear');
|
||||
const songTable = document.getElementById('songs');
|
||||
const filterSongs = (artist, title) => {
|
||||
let result = [...songList];
|
||||
if(artist) {
|
||||
result = result.filter(song => song.artist.toLowerCase().includes(artist.toLowerCase()));
|
||||
}
|
||||
if(title) {
|
||||
result = result.filter(song => song.title.toLowerCase().includes(title.toLowerCase()));
|
||||
}
|
||||
resetButton.parentElement.style.display = artist || title ? "block" : "none";
|
||||
document.getElementById('count').innerText = artist || title ? `Filtered to ${result.length} songs from ${songList.length}.` : `Naomi currently has ${songList.length} songs.`;
|
||||
updateTable(result);
|
||||
}
|
||||
const loadSongs = (songs) => {
|
||||
songList.push(...songs);
|
||||
artistQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
artistQuery.parentElement.style.display = "block";
|
||||
titleQuery.parentElement.style.display = "block";
|
||||
document.getElementById('count').innerText = `Naomi currently has ${songs.length} songs.`;
|
||||
updateTable(songs);
|
||||
}
|
||||
const updateTable = (songs) => {
|
||||
songs = songs.sort((a, b) => a.title.localeCompare(b.title));
|
||||
songTable.innerHTML = "";
|
||||
const header = document.createElement('tr');
|
||||
const artistHeader = document.createElement('th');
|
||||
artistHeader.innerText = "Artist";
|
||||
const titleHeader = document.createElement('th');
|
||||
titleHeader.innerText = "Title";
|
||||
header.appendChild(titleHeader);
|
||||
header.appendChild(artistHeader);
|
||||
songTable.appendChild(header);
|
||||
songs.forEach(song => {
|
||||
const row = document.createElement('tr');
|
||||
const artist = document.createElement('td');
|
||||
artist.innerText = song.artist;
|
||||
const title = document.createElement('td');
|
||||
title.innerText = song.title;
|
||||
row.appendChild(title);
|
||||
row.appendChild(artist);
|
||||
songTable.appendChild(row);
|
||||
});
|
||||
}
|
||||
const songList = [];
|
||||
fetch("./songs.json").then(res => res.json()).then(data => loadSongs(data))
|
||||
|
||||
artistQuery?.addEventListener("input", (e) => filterSongs(e.target.value, titleQuery.value));
|
||||
titleQuery?.addEventListener("input", (e) => filterSongs(artistQuery.value, e.target.value));
|
||||
resetButton?.addEventListener("click", () => {
|
||||
artistQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
filterSongs("", "");
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
tr:nth-of-type(even) {
|
||||
background-color: var(--foreground);
|
||||
color: var(--background);
|
||||
}
|
||||
input {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem
|
||||
}
|
||||
button {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem;
|
||||
cursor:url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
|
||||
}
|
||||
tr {
|
||||
max-width: 100%;
|
||||
}
|
||||
td {
|
||||
max-width: 50%;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
</html>
|
||||
-82528
File diff suppressed because it is too large
Load Diff
+1312
-11
File diff suppressed because it is too large
Load Diff
@@ -1,260 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "mod-logs",
|
||||
"description": "Logs for moderation actions taken on our platforms.",
|
||||
"url": "",
|
||||
"category": "archived"
|
||||
},
|
||||
{
|
||||
"name": "tingle-bot",
|
||||
"description": "Bot for my friend Ruu's server",
|
||||
"url": "",
|
||||
"category": "archived"
|
||||
},
|
||||
{
|
||||
"name": "announcements",
|
||||
"description": "Repository for our announcements page.",
|
||||
"url": "",
|
||||
"category": "archived"
|
||||
},
|
||||
{
|
||||
"name": "forms",
|
||||
"description": "Client and server monorepo for our various webforms",
|
||||
"url": "",
|
||||
"category": "archived"
|
||||
},
|
||||
{
|
||||
"name": "notes",
|
||||
"description": "",
|
||||
"url": "",
|
||||
"category": "private"
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"description": "Status updates for our client work.",
|
||||
"url": "",
|
||||
"category": "private"
|
||||
},
|
||||
{
|
||||
"name": "beaver-twitch",
|
||||
"description": "Twitch bot for BigBadBeaver",
|
||||
"url": "",
|
||||
"category": "private"
|
||||
},
|
||||
{
|
||||
"name": "obsidian",
|
||||
"description": "",
|
||||
"url": "",
|
||||
"category": "private"
|
||||
},
|
||||
{
|
||||
"name": "insomnium",
|
||||
"description": "Our Insomnium requests",
|
||||
"url": "",
|
||||
"category": "private"
|
||||
},
|
||||
{
|
||||
"name": "life-of-a-naomi",
|
||||
"description": "A little game",
|
||||
"url": "",
|
||||
"category": "games"
|
||||
},
|
||||
{
|
||||
"name": "naomis-adventure-1",
|
||||
"description": "Our first full-length, paid game!",
|
||||
"url": "",
|
||||
"category": "games"
|
||||
},
|
||||
{
|
||||
"name": "beccalia-origins",
|
||||
"description": "The story of how Becca and Rosalia first met, and how they came to be. Never moved past a demo state.",
|
||||
"url": "https://beccalia.nhcarrigan.com/origins",
|
||||
"category": "games"
|
||||
},
|
||||
{
|
||||
"name": "beccalia-prologue",
|
||||
"description": "A short adventure to introduce our characters Becca and Rosalia. Our first attempt at game development!",
|
||||
"url": "https://beccalia.nhcarrigan.com/prologue",
|
||||
"category": "games"
|
||||
},
|
||||
{
|
||||
"name": "ruu-goblin-quest",
|
||||
"description": "A quick game we made about our friend Ruu, as part of a game jam she was hosting.",
|
||||
"url": "https://goblin.nhcarrigan.com",
|
||||
"category": "games"
|
||||
},
|
||||
{
|
||||
"name": "template",
|
||||
"description": "",
|
||||
"url": "",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "a4p-bot",
|
||||
"description": "Bot for the Art 4 Palestine charity initiative.",
|
||||
"url": "https://a4p.nhcarrigan.com",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "boost-monitor",
|
||||
"description": "Discord bot that monitors boost status in the Caylus Crew server.",
|
||||
"url": "https://oogie.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "docs",
|
||||
"description": "Our documentation site.",
|
||||
"url": "https://docs.nhcarrigan.com",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "eslint-config",
|
||||
"description": "Our custom linter rules for our various TypeScript products.",
|
||||
"url": "https://www.npmjs.com/package/@nhcarrigan/eslint-config",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "espanso",
|
||||
"description": "Our shortcuts for Espanso.",
|
||||
"url": "",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "celestine",
|
||||
"description": "Moderation bot for Discord.",
|
||||
"url": "https://hooks.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "portfolio",
|
||||
"description": "Our main homepage",
|
||||
"url": "https://nhcarrigan.com",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "rig-task-bot",
|
||||
"description": "Task bot for a friend's organisation.",
|
||||
"url": "",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "security",
|
||||
"description": "A quick tool to scan our projects for security concerns.",
|
||||
"url": "https://security.nhcarrigan.com",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "website-headers",
|
||||
"description": "Our global styling and scripts for all of our pages.",
|
||||
"url": "https://cdn.nhcarrigan.com/headers/index.js",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "typescript-config",
|
||||
"description": "Our global TypeScript configuration.",
|
||||
"url": "https://www.npmjs.com/package/@nhcarrigan/typescript-config",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "blog",
|
||||
"description": "Naomi's personal musings.",
|
||||
"url": "https://blog.nhcarrigan.com",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "nginx-configs",
|
||||
"description": "A version controlled backup of our servers' NGINX configurations.",
|
||||
"url": "",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "vscode-themes",
|
||||
"description": "Custom colour schemes for VSCode.",
|
||||
"url": "https://marketplace.visualstudio.com/items?itemName=nhcarrigan.naomis-themes",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": ".gitea",
|
||||
"description": "This repository contains the files that customise our Gitea instance!",
|
||||
"url": "https://git.nhcarrigan.com",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "aria-iuvo",
|
||||
"description": "A user-installable translation application for Discord. Now you can translate messages directly on the platform!",
|
||||
"url": "https://trans-bot.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "cordelia-taryne",
|
||||
"description": "AI-powered virtual assistant for Discord",
|
||||
"url": "https://assistant.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "rosalia-nightsong",
|
||||
"description": "A webserver to handle alerting us to application logs and errors.",
|
||||
"url": "https://alerts.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "logger",
|
||||
"description": "Our custom logging package, which pipes logs to our alerts server.",
|
||||
"url": "https://www.npmjs.com/package/@nhcarrigan/logger",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "melody-iuvo",
|
||||
"description": "Task management bot for Discord",
|
||||
"url": "https://tasks.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "static-pages",
|
||||
"description": "The raw HTML pages served via our production box.",
|
||||
"url": "",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "becca-lyria",
|
||||
"description": "An AI-powered Discord bot that allows you to play an RPG without any friends!",
|
||||
"url": "https://becca.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "maylin-taryne",
|
||||
"description": "An AI-powered companion to help you through the tough times.",
|
||||
"url": "https://maylin.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "gwen-abalise",
|
||||
"description": "A ticket system for Discord!",
|
||||
"url": "https://gwen.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "nails",
|
||||
"description": "Nail polish tracker for my sister",
|
||||
"url": "",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "maribelle",
|
||||
"description": "",
|
||||
"url": "",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "mommy",
|
||||
"description": "Mommy loves you~!",
|
||||
"url": "https://mommy.nhcarrigan.com",
|
||||
"category": "public"
|
||||
},
|
||||
{
|
||||
"name": "mommy-bot",
|
||||
"description": "Mommy loves you everywhere~!",
|
||||
"url": "https://mommy-bot.nhcarrigan.com/",
|
||||
"category": "public"
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -281,7 +281,7 @@
|
||||
|
||||
<div class="secret">
|
||||
<div class="secret-number">Secret #13</div>
|
||||
<div class="unknown">??????</div>
|
||||
<div class="secret-text">Every choice you make leads you somewhere in life. So long as you find happiness, there are no wrong choices.</div>
|
||||
</div>
|
||||
|
||||
<div class="secret">
|
||||
|
||||
+7
-1
@@ -38,7 +38,7 @@
|
||||
<li><a href="https://amari.nhcarrigan.com" target="_blank"><code>amari</code> - Naomi's personal assistant bot, notifies her when people use her name</a></li>
|
||||
<li><a href="https://aria.nhcarrigan.com" target="_blank"><code>aria</code> - Translation bot</a></li>
|
||||
<li><a href="https://assistant.nhcarrigan.com" target="_blank"><code>assistant</code> - Cordelia Taryne</a></li>
|
||||
<li><a href="https://analytics.nhcarrigan.com" target="_blank"><code>becca</code> - Becca Lyria</a></li>
|
||||
<li><a href="https://becca.nhcarrigan.com" target="_blank"><code>becca</code> - Becca Lyria</a></li>
|
||||
<li><a href="https://caelia.nhcarrigan.com" target="_blank"><code>caelia</code> - Discord bot that reminds people to use inclusive language</a></li>
|
||||
<li><a href="https://callista.nhcarrigan.com" target="_blank"><code>callista</code> - Discord bot that allows you to "bookmark" messages</a></li>
|
||||
<li><a href="https://camperchan.nhcarrigan.com" target="_blank"><code>camperchan</code> - CamperChan (freeCodeCamp bot)</a></li>
|
||||
@@ -72,6 +72,7 @@
|
||||
<ul>
|
||||
<li><a href="https://beccalia.nhcarrigan.com" target="_blank"><code>beccalia</code> - Beccalia landing Page</a></li>
|
||||
<li><a href="https://games.nhcarrigan.com" target="_blank"><code>games</code> - Landing Page for All Games</a></li>
|
||||
<li><a href="https://elysium.nhcarrigan.com" target="_blank"><code>elysium</code> - Browser-based idle game</a></li>
|
||||
<li><a href="https://goblin.nhcarrigan.com" target="_blank"><code>goblin</code> - Ruu's Goblin Quest</a></li>
|
||||
<li><a href="https://loan.nhcarrigan.com" target="_blank"><code>loan</code> - Life of a Naomi</a></li>
|
||||
</ul>
|
||||
@@ -92,19 +93,23 @@
|
||||
<li><a href="https://git.nhcarrigan.com" target="_blank"><code>git</code> - Gitea Instance</a></li>
|
||||
<li><a href="https://hikari.nhcarrigan.com" target="_blank"><code>hikari</code> - Our unified dashboard (currently shows announcements, sanction logs, and product lists)</a></li>
|
||||
<li><a href="https://incidents.nhcarrigan.com" target="_blank"><code>incidents</code> - Uptime Kuma Instance</a></li>
|
||||
<li><a href="https://library.nhcarrigan.com" target="_blank"><code>library</code> - Naomi's media library (books, games, music, and more) with community suggestions</a></li>
|
||||
<li><a href="https://lore.nhcarrigan.com" target="_blank"><code>lore</code> - A fun li'l site offering the "lore" behind NHCarrigan</a></li>
|
||||
<li><a href="https://manual.nhcarrigan.com" target="_blank"><code>manual</code> - User Manual</a></li>
|
||||
<li><a href="https://moderation.nhcarrigan.com" target="_blank"><code>moderation</code> - Mod Logs</a></li>
|
||||
<li><a href="https://mommy.nhcarrigan.com" target="_blank"><code>mommy</code> - A site to get some motherly love</a></li>
|
||||
<li><a href="https://music.nhcarrigan.com" target="_blank"><code>music</code> - Music Library</a></li>
|
||||
<li><a href="https://nocturne.nhcarrigan.com" target="_blank"><code>nocturne</code> - Naomi's Nocturne (the official religion)</a></li>
|
||||
<li><a href="https://nails.nhcarrigan.com" target="_blank"><code>nails</code> - Nail Polish Tracker</a></li>
|
||||
<li><a href="https://notes.nhcarrigan.com" target="_blank"><code>notes</code> - Private Notes for Sponsors</a></li>
|
||||
<li><a href="https://quality.nhcarrigan.com" target="_blank"><code>quality</code> - SonarQube Instance</a></li>
|
||||
<li><a href="https://resume.nhcarrigan.com" target="_blank"><code>resume</code> - Web-based Resume</a></li>
|
||||
<li><a href="https://scripture.nhcarrigan.com" target="_blank"><code>scripture</code> - The Nocturne Scriptures</a></li>
|
||||
<li><a href="https://secrets.nhcarrigan.com" target="_blank"><code>secrets</code> - Naomi's Secrets to Success™</a></li>
|
||||
<li><a href="https://security.nhcarrigan.com" target="_blank"><code>security</code> - Automated Code Scanning Results</a></li>
|
||||
<li><a href="https://silly.nhcarrigan.com" target="_blank"><code>silly</code> - A collection of dumb little websites Naomi has built (usually as part of an event)</a></li>
|
||||
<li><a href="https://sitemap.nhcarrigan.com" target="_blank"><code>sitemap</code> - This page!</a></li>
|
||||
<li><a href="https://style.nhcarrigan.com" target="_blank"><code>style</code> - NHCarrigan Style & Branding Guide</a></li>
|
||||
<li><a href="https://socials.nhcarrigan.com" target="_blank"><code>socials</code> - Naomi's social media account list</a></li>
|
||||
<li><a href="https://support.nhcarrigan.com" target="_blank"><code>support</code> - Our product and community support forum</a></li>
|
||||
<li><a href="https://telemetry.nhcarrigan.com" target="_blank"><code>telemetry</code> - Our metrics dashboard</a></li>
|
||||
@@ -140,6 +145,7 @@
|
||||
<ul>
|
||||
<li><a href="https://naomi.lgbt" target="_blank"><code>naomi.lgbt</code> - Our Portfolio</a></li>
|
||||
<li><a href="https://naomi.party" target="_blank"><code>naomi.party</code> - BlueSky Username Service</a></li>
|
||||
<li><a href="https://lynira.link" target="_blank"><code>lynira.link</code> - Public paid link shortener service</a></li>
|
||||
<li><a href="https://nhcarrigan.link" target="_blank"><code>nhcarrigan.link</code> - Link Redirection Server</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
IFS=$'\n'
|
||||
|
||||
# Initialize an empty string to hold the list of songs in JSON-like format
|
||||
songs=""
|
||||
filecount=$(find /home/naomi/music -type f | wc -l)
|
||||
echo "Found $filecount files."
|
||||
current=0
|
||||
|
||||
# Loop over each file found by find
|
||||
for file in $(find /home/naomi/music -type f -print0 | tr '\0' '\n'); do
|
||||
current=$((current + 1))
|
||||
echo -ne "Processing $current/$filecount\r"
|
||||
title=$(mid3v2 -l "$file" | grep "TIT2\|TT2" | cut -d "=" -f 2)
|
||||
artist=$(mid3v2 -l "$file" | grep "TPE1\|TP1" | cut -d "=" -f 2)
|
||||
if [ -z "$title" ]; then
|
||||
# remove .mp3 from the title
|
||||
title=$(basename "$file" | sed -e 's/\.mp3//g')
|
||||
fi
|
||||
if [ -z "$artist" ]; then
|
||||
artist="Unknown Artist"
|
||||
fi
|
||||
|
||||
# use jq to add the song to the list
|
||||
songs="$songs$(jq -n --arg title "$title" --arg artist "$artist" '{title: $title, artist: $artist}'),"
|
||||
done
|
||||
|
||||
# Remove trailing comma and add square brackets to complete the list
|
||||
songs="[${songs%,}]"
|
||||
|
||||
# Write to ./music/songs.json
|
||||
echo "$songs" > ./music/songs.json
|
||||
echo -ne "Done!\r"
|
||||
+1215
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user