ComfyUI-SEEDVR2
功能:修复视频像素

“一句有哲理的话”
跑了一下午,40min才能修1s 修了跟没修差不多…
可能是我的电脑显卡还是太垃圾了
Life begins on the other side of despair.
生活在绝望的另一端开始。
ComfyUI-SEEDVR2
功能:修复视频像素

“一句有哲理的话”
跑了一下午,40min才能修1s 修了跟没修差不多…
可能是我的电脑显卡还是太垃圾了
Life begins on the other side of despair.
生活在绝望的另一端开始。

ESP8266电子时钟
功能:自定义API访问
显示天气
显示时间
#include <U8g2lib.h>
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
// ==================== OLED配置 ====================
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 5, /* data=*/ 4);
// ==================== 蜂鸣器配置 ====================
#define BUZZER_PIN 0 // D3 (GPIO0)
// ==================== WiFi配置 ====================
const char* ssid = "N/A";
const char* password = "N/A";
// ==================== API配置 ====================
const char* timeUrl = "N/A";
const char* serverUrl = "N/A";
// 心知天气配置(免费注册:https://www.seniverse.com/)
const char* xinzhiKey = "N/A";
const char* city = "N/A";
const char* weatherUrl = "https://api.seniverse.com/v3/weather/now.json";
WiFiClientSecure client;
// ==================== 全局变量 ====================
int currentHour = 0;
int currentMinute = 0;
int currentSecond = 0;
int currentWeekday = 0;
String currentDateFormatted = "";
// 天气
String weatherText = "";
String weatherTemp = "";
// 通知
String notifications[30];
int notificationCount = 0;
int currentNotificationIndex = 0;
// 定时
unsigned long lastTimeUpdate = 0;
unsigned long lastWeatherUpdate = 0;
unsigned long lastDataUpdate = 0;
unsigned long lastModeSwitch = 0;
int displayMode = 0; // 0:时间界面, 1:通知界面
bool notificationJustShown = false;
// ==================== 辅助函数 ====================
String getWeekdayCN(int w) {
String weekdays[] = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
if (w >= 0 && w <= 6) return weekdays[w];
return "周一";
}
String getWeatherCN(String weather) {
if (weather.indexOf("Clear") >= 0) return "晴";
if (weather.indexOf("Cloud") >= 0) return "多云";
if (weather.indexOf("Overcast") >= 0) return "阴";
if (weather.indexOf("Light Rain") >= 0) return "小雨";
if (weather.indexOf("Moderate Rain") >= 0) return "中雨";
if (weather.indexOf("Heavy Rain") >= 0) return "大雨";
if (weather.indexOf("Rain") >= 0) return "雨";
if (weather.indexOf("Snow") >= 0) return "雪";
if (weather.indexOf("Fog") >= 0) return "雾";
return weather;
}
void beepLight() {
digitalWrite(BUZZER_PIN, LOW);
delay(80);
digitalWrite(BUZZER_PIN, HIGH);
}
// ==================== 获取数据 ====================
void updateTime() {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient https;
client.setInsecure();
https.setTimeout(5000);
if (!https.begin(client, timeUrl)) return;
int httpCode = https.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = https.getString();
DynamicJsonDocument doc(512);
deserializeJson(doc, payload);
currentHour = doc["hour"];
currentMinute = doc["minute"];
currentWeekday = doc["weekday"];
String timeStr = doc["time"].as<String>();
if (timeStr.length() >= 19) {
currentSecond = timeStr.substring(17, 19).toInt();
}
String dateStr = doc["date"].as<String>();
if (dateStr.length() >= 10) {
String month = dateStr.substring(5, 7);
String day = dateStr.substring(8, 10);
currentDateFormatted = month + "月" + day + "日";
}
}
https.end();
}
void updateWeather() {
if (WiFi.status() != WL_CONNECTED) return;
if (String(xinzhiKey).length() == 0) return;
String url = String(weatherUrl) + "?key=" + xinzhiKey + "&location=" + city + "&language=en&unit=c";
HTTPClient https;
client.setInsecure();
https.setTimeout(5000);
if (!https.begin(client, url)) return;
int httpCode = https.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = https.getString();
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
if (doc.containsKey("results")) {
JsonObject now = doc["results"][0]["now"];
weatherText = now["text"].as<String>();
float temp = now["temperature"];
weatherTemp = String(temp, 0);
}
}
https.end();
}
void fetchNotifications() {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient https;
client.setInsecure();
https.setTimeout(10000);
if (!https.begin(client, serverUrl)) return;
int httpCode = https.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = https.getString();
DynamicJsonDocument doc(4096);
deserializeJson(doc, payload);
if (doc["status"] == "success") {
notificationCount = 0;
JsonArray notificationsArr = doc["notifications"];
for (JsonObject n : notificationsArr) {
if (notificationCount < 30) {
notifications[notificationCount] = n["content"].as<String>();
notificationCount++;
}
}
}
}
https.end();
}
// ==================== 手表界面 ====================
void displayWatchFace() {
u8g2.firstPage();
do {
// ========== 顶部区域 ==========
u8g2.setFont(u8g2_font_wqy12_t_chinese3);
u8g2.drawHLine(0, 15, 128); // 顶部分割线
// 日期(左上角)
u8g2.setCursor(5, 12);
if (currentDateFormatted.length() > 0) {
u8g2.print(currentDateFormatted);
} else {
u8g2.print("03月24日");
}
// 星期(右上角)
u8g2.setCursor(95, 12);
u8g2.print(getWeekdayCN(currentWeekday));
// ========== 中间时间区域 ==========
// 时间往下移(从y=42移到y=48)
u8g2.setFont(u8g2_font_logisoso24_tf);
u8g2.setCursor(25, 48);
char timeBuf[6];
sprintf(timeBuf, "%02d:%02d", currentHour, currentMinute);
u8g2.print(timeBuf);
// 秒数(放在时间右侧)
u8g2.setFont(u8g2_font_helvB08_tf);
u8g2.setCursor(105, 38);
char secBuf[3];
sprintf(secBuf, "%02d", currentSecond);
u8g2.print(secBuf);
// ========== 底部区域 ==========
// 底部文字(放在线下方,y=63)
u8g2.setCursor(10, 63);
if (weatherText.length() > 0 && weatherTemp.length() > 0) {
u8g2.print(getWeatherCN(weatherText));
u8g2.print(" ");
u8g2.print(weatherTemp);
u8g2.print("°C");
} else if (String(xinzhiKey).length() > 0) {
u8g2.print("天气加载中");
} else {
u8g2.print("WiFi:");
u8g2.print(WiFi.RSSI());
u8g2.print("dBm");
}
// 通知数量(右侧)
if (notificationCount > 0) {
u8g2.setCursor(100, 63);
u8g2.print("[");
u8g2.print(notificationCount);
u8g2.print("]");
}
} while (u8g2.nextPage());
}
// ==================== 通知界面 ====================
void displayNotification() {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_wqy12_t_chinese3);
u8g2.drawHLine(0, 15, 128);
u8g2.setCursor(45, 12);
u8g2.print("通 知");
u8g2.drawHLine(0, 22, 128);
if (notificationCount > 0 && currentNotificationIndex < notificationCount) {
String content = notifications[currentNotificationIndex];
int lineHeight = 12;
int startPos = 0;
int lines = 0;
while (startPos < content.length() && lines < 3) {
int endPos = startPos + 18;
if (endPos > content.length()) endPos = content.length();
u8g2.setCursor(5, 32 + lines * lineHeight);
u8g2.print(content.substring(startPos, endPos));
startPos = endPos;
lines++;
}
u8g2.setCursor(100, 63);
u8g2.print(currentNotificationIndex + 1);
u8g2.print("/");
u8g2.print(notificationCount);
} else {
u8g2.setCursor(35, 40);
u8g2.print("暂无通知");
}
} while (u8g2.nextPage());
}
// ==================== 初始化 ====================
void setup() {
Serial.begin(115200);
delay(100);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, HIGH);
u8g2.begin();
u8g2.enableUTF8Print();
u8g2.setFont(u8g2_font_wqy12_t_chinese3);
u8g2.firstPage();
do {
u8g2.setCursor(35, 30);
u8g2.print("连接WiFi");
} while (u8g2.nextPage());
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 25) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi已连接");
u8g2.firstPage();
do {
u8g2.setCursor(40, 30);
u8g2.print("WiFi已连");
} while (u8g2.nextPage());
delay(1000);
}
client.setInsecure();
updateTime();
updateWeather();
fetchNotifications();
beepLight();
}
// ==================== 主循环 ====================
void loop() {
unsigned long now = millis();
if (now - lastTimeUpdate >= 1000) {
updateTime();
lastTimeUpdate = now;
}
if (now - lastWeatherUpdate >= 300000) {
updateWeather();
lastWeatherUpdate = now;
}
// 每15分钟检查通知
if (now - lastDataUpdate >= 900000) {
fetchNotifications();
lastDataUpdate = now;
if (notificationCount > 0) {
displayMode = 1;
lastModeSwitch = now;
currentNotificationIndex = 0;
notificationJustShown = true;
beepLight();
}
}
// 通知界面显示10秒后切回
if (displayMode == 1 && notificationJustShown) {
if (now - lastModeSwitch >= 10000) {
displayMode = 0;
notificationJustShown = false;
lastModeSwitch = now;
}
}
// 通知界面自动翻页
if (displayMode == 1 && notificationCount > 0 && notificationJustShown) {
static unsigned long lastNotiSwitch = 0;
if (now - lastNotiSwitch >= 3000) {
currentNotificationIndex = (currentNotificationIndex + 1) % notificationCount;
lastNotiSwitch = now;
}
}
if (displayMode == 0) {
displayWatchFace();
} else {
displayNotification();
}
delay(50);
}C++“记住他人名字带给他人被记住的感觉是这个时代所稀缺的,因为效率至上的时代,每个人都忽视了彼此包括自己”
–
“Making someone feel remembered just by knowing their name—that’s something rare in today’s world. In an era that prioritizes efficiency, people often neglect others, and even themselves.“
What lies behind us and what lies before us are tiny matters compared to what lies within us.
与我们内心的事物相比,身后和眼前的事物都是微不足道的。

今天是昨天的明天
写了个轻量级个人知识库系统,融合了笔记、时间追踪、关系图谱和日历视图。它支持类 Obsidian 的 [[@页面链接]] 和 [[标签]] 语法,内置待办清单、提醒组件和 Markdown 渲染。
Notiobsidian(Nobsidian)作为开源版本
🌐 Notiobsidian
把 Notion 的交互美学 + Obsidian 的本地自由 + AI Agent 原生接口 揉在一起
一个完全自托管、可编程、跑在你电脑上的个人第二大脑(目前已是我本人的主力生产力工具)
.png)
.png)
.png)
.png)
git clone https://github.com/NanamiChiaki-7/Notiobsidian.git
cd NotiobsidianBash pip install -r requirements.txtBash python Notiobsidian.pyBash→ 默认监听 http://0.0.0.0:5004
生产建议:
--host 0.0.0.0 --port 你的端口 或用 gunicorn / uvicorn 部署nation_pro_v3.db(SQLite),记得定期备份!欢迎 PR 加速这些功能!
欢迎 issue、PR、想法!
喜欢就点个 ⭐ 支持一下~
Last updated: February 2026 · 最后更新:2026年2月
I am no bird; and no net ensnares me: I am a free human being with an independent will.
我不是鸟,也没有网能捕捉我:我是一个有独立意志的自由人。
静态资源请求被错误地当成了动态路由处理,导致路径被二次编码。
你的预期:
浏览器请求 /LifeDrive/static/css/style.css
→ Nginx 静态 location
→ 直接读硬盘文件 ✅
实际发生:
浏览器请求 /LifeDrive/static/css/style.css
→ Nginx 无静态 location(或被覆盖)
→ 转发给 Flask 代理
→ Flask 的 ReverseProxied 剥离 /LifeDrive
→ Flask 收到 /static/css/style.css
→ Flask 把它当作路由去找 @app.route('/static/...')
→ 找不到,返回 404 ❌
^~ /Project/static/ 没写alias 路径错误/少斜杠 <!-- 这会让静态请求也经过 Flask 路由系统 -->
<link href="{{ url_for('static', filename='css/style.css') }}">
url_for('static') → 生成 /LifeDrive/static/css/style.css → 同上死循环
| 方案 | 静态文件处理 | 动态路由 | HTML写法 | 适用场景 |
|---|---|---|---|---|
| ❌ 全代理 | Flask处理 | Flask处理 | url_for | 单项目,无Nginx静态 |
| ✅ 组合拳 | Nginx直出 | Flask处理 | 写死路径 | 多项目同域名,性能最优 |
| ⚠️ 全直出 | Nginx直出 | Nginx直出 | 写死路径 | 纯静态站 |
你最终选的是「组合拳」——工业标准做法。
# ✅ 正确顺序
location ^~ /Project/static/ { ... } # 1. 精确匹配优先
location /Project/ { ... } # 2. 模糊匹配在后
<!-- ✅ 静态资源:直接写死,不走 Flask -->
<link href="/Project/static/css/style.css">
<!-- ✅ 动态链接:用 url_for,自动加前缀 -->
<a href="{{ url_for('view_page', id=1) }}">
# ✅ 只有 Flask 需要知道
export BASE_PATH=/Project
# ❌ Nginx 静态 location 完全不需要
# alias 直接写绝对路径即可
^~ /项目名/static/)/项目名/)/项目名/static/xxxexport BASE_PATH=/项目名问题发现:浏览器控制台 404
定位过程:curl → Nginx 404 → 检查 alias → 发现少斜杠
深层原因:发现静态请求进了 Flask
解决方案:Nginx 静态直出 + HTML写死路径
最终验证:静态文件 200,动态页面 200,完美
耗时:一下午
收获:多项目反代的标准模式固化
^~(被正则覆盖)staticcss 经典错误)url_for(本末倒置)这次 BUG 修完,你已经是 Nginx + Flask 多项目部署的专家了。
这套组合拳可以复用到以后所有项目,不会再卡一下午了。
Good actions give strength to ourselves and inspire good actions in others.
善行给我们力量,并激励他人行善。
*当初为了项目反代问题处理一下午,今天又处理一下午,要吸取教训了*