drunk.pw — минималистичный счётчик трезвости
drunk.pw — это простой, автономный и немного ироничный проект, показывающий, сколько дней ты держишься трезвым. Ночь поздняя сейчас например, дабы себя занять расскажу, как он устроен.
Работает на Express, хранит данные в JSON-файле, фронтенд оформлен в духе «панк-минимализма» наверное я так думаю.
Как устроено
- Фронтенд: HTML + CSS + JavaScript
- Бэкенд: Node.js + Express
- Данные: обычный
data.json
- Запуск: через
pm2
- Веб Сервер: nginx
Структура
/var/www/drunk.pw/
├── index.html
├── server.js
├── data.json
└── package.json
Backend: server.js
Express. Обрабатывает /data
, читает и пишет JSON-файл:
const express = require("express");
const fs = require("fs");
const path = require("path");
const app = express();
const PORT = 3000;
const dataFile = path.join(__dirname, "data.json");
app.use(express.static(__dirname));
app.use(express.json());
app.get("/data", (req, res) => {
try {
const data = fs.readFileSync(dataFile);
res.setHeader("Content-Type", "application/json");
res.send(data);
} catch (err) {
res.status(500).json({ error: "Data read error" });
}
});
app.post("/data", (req, res) => {
try {
fs.writeFileSync(dataFile, JSON.stringify(req.body, null, 2));
res.status(200).json({ status: "OK" });
} catch (err) {
res.status(500).json({ error: "Data write error" });
}
});
app.listen(PORT, () => {
console.log(`Drunk server listening on port ${PORT}`);
});
Фронт: index.html (фрагмент)
Вся логика счётчика реализована прямо в браузере. Пример:
<body>
<h1>Live Fast, Die Last</h1>
<div id="daysCounter">0 дней</div>
<div id="lastRecord">0 дней</div>
<button onclick="requestReset()">Выпить</button>
<script>
const hashedPassword = "fc0bee91..."; // SHA-256 хэш
async function getData() {
const res = await fetch("/data");
const data = await res.json();
const diff = Math.floor((new Date() - new Date(data.soberStart)) / (1000*60*60*24));
document.getElementById("daysCounter").textContent = diff + " дней";
document.getElementById("lastRecord").textContent = data.lastRecord + " дней";
}
async function requestReset() {
const pass = prompt("Пароль:");
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(pass));
const hex = [...new Uint8Array(hash)].map(b => b.toString(16).padStart(2, "0")).join("");
if (hex === hashedPassword) resetCounter(); else alert("Хуй там!");
}
async function resetCounter() {
const res = await fetch("/data");
const data = await res.json();
const days = Math.floor((new Date() - new Date(data.soberStart)) / (1000*60*60*24));
data.records.push({ days, start: data.soberStart });
data.lastRecord = days;
data.soberStart = new Date().toISOString();
await fetch("/data", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
getData();
}
getData();
</script>
</body>
Установка и запуск
# Установка Node.js и менеджера процессов pm2
sudo apt update
sudo apt install nodejs npm -y
npm install -g pm2
# Развёртывание
cd /файлы
npm install
pm2 start server.js --name yourname
pm2 save
pm2 startup
Публикация
Ну через nginx конфиг. Проксируем локалхост:вашпорт
Заключение
drunk.pw — сделано по фану например.
Можно адаптировать под счётчик:
- курения
- дней без сахара
- дней до отпуска
✊ drunk.pw — no DB, no ads, no bullshit.