Flash收藏站
我的个人Flash收藏站首页装修完毕!顺带用C++写了俩RSS、站点地图生成器
首页图片:
页脚:
这是我搜刮的Flash游戏收藏站,今天装修了页面颜色和页脚,新颜色看着舒服多了
RSS订阅文件生成器:
此RSS订阅生成器是通过读取我预留的Json元信息生成的,新链接的时间为第一次运行时间,链接的时间会储存在日志中,xml的优先级大于日志,可以手动修改xml RSS订阅时间,手动修改xml中的时间会在下一次程序运行时被更新进日志。
Json格式为:
[
{
"name": "驾驶TU-95",
"desc": "驾驶战略轰炸机TU-95!带有汉化"
},
{
"name": "文具防御",
"desc": "使用文具打击来犯之敌!带有汉化"
}
]
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <set>
#include <vector>
#include <ctime>
#include <json.hpp>
using json = nlohmann::json;
// RFC-822 格式时间
std::string getCurrentTime() {
std::time_t now = std::time(nullptr);
char buf[80];
std::strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&now));
return std::string(buf);
}
std::string extractBetween(const std::string& str, const std::string& start_delim, const std::string& end_delim) {
size_t start = str.find(start_delim);
if (start == std::string::npos) return "";
start += start_delim.size();
size_t end = str.find(end_delim, start);
if (end == std::string::npos) return "";
return str.substr(start, end - start);
}
json readXmlPubDates(const std::string& xmlFilename) {
json xmlMap = json::object();
std::ifstream xmlFile(xmlFilename);
if (!xmlFile.is_open())
return xmlMap;
std::string line;
std::string currentLink;
while (std::getline(xmlFile, line)) {
if (line.find("<link>") != std::string::npos) {
currentLink = extractBetween(line, "<link>", "</link>");
} else if (line.find("<pubDate>") != std::string::npos) {
std::string pubDate = extractBetween(line, "<pubDate>", "</pubDate>");
if (!currentLink.empty()) {
xmlMap[currentLink] = pubDate;
currentLink.clear();
}
}
}
xmlFile.close();
return xmlMap;
}
// 加载日志文件(日志是记录链接RSS时间的)
json loadLog(const std::string& logFilename) {
json logData;
std::ifstream logFile(logFilename);
if (logFile.is_open()){
try {
logFile >> logData;
} catch (json::parse_error& e) {
std::cerr << "日志文件解析错误: " << e.what() << std::endl;
}
logFile.close();
} else {
logData = json::object();
}
return logData;
}
// 保存日志
void saveLog(const json& logData, const std::string& logFilename) {
std::ofstream logFile(logFilename);
if (logFile.is_open()){
logFile << logData.dump(4);
logFile.close();
} else {
std::cerr << "无法保存日志文件: " << logFilename << std::endl;
}
}
#ifdef _WIN32
#include <windows.h>
#define timegm _mkgmtime
#endif
int main(int argc, char* argv[]) {
std::string jsonInputFilename = "api/games_name.json";
std::string xmlOutputFilename = "rss.xml";
std::string logFilename = "rss_log.json";
// --- 1. 读取 JSON ---
std::ifstream inputFile(jsonInputFilename);
if (!inputFile.is_open()){
std::cerr << "无法打开文件 " << jsonInputFilename << std::endl;
return 1;
}
json jsonData;
inputFile >> jsonData;
inputFile.close();
// --- 2. 加载日志 ---
json logData = loadLog(logFilename);
// --- 3. 尝试读取当前目录下的 rss.xml 中记录的时间(若已运行过) ---
json xmlMap = readXmlPubDates(xmlOutputFilename);
// 存储JSON链接
std::set<std::string> jsonLinks;
// --- 4. 生成 RSS XML 内容 ---
std::ostringstream xmlContent;
xmlContent << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
xmlContent << "<rss version=\"2.0\">\n";
xmlContent << " <channel>\n";
xmlContent << " <title>Flash收藏站</title>\n";
xmlContent << " <link>https://flash.100713.xyz/</link>\n";
xmlContent << " <description>最新Flash游戏列表 RSS 订阅</description>\n";
xmlContent << " <language>zh-CN</language>\n";
xmlContent << " <lastBuildDate>" << getCurrentTime() << "</lastBuildDate>\n";
for (const auto& item : jsonData) {
std::string name = item["name"];
std::string desc = item["desc"];
std::string link = "https://flash.100713.xyz/" + name;
jsonLinks.insert(link);
std::string pubDate;
if (item.contains("pubDate")) {
pubDate = item["pubDate"];
} else if (xmlMap.contains(link)) {
pubDate = xmlMap[link];
} else if (logData.contains(link)) {
pubDate = logData[link];
} else {
pubDate = getCurrentTime();
}
if (!logData.contains(link) || logData[link] != pubDate) {
logData[link] = pubDate;
}
xmlContent << " <item>\n";
xmlContent << " <title>" << name << "</title>\n";
xmlContent << " <link>" << link << "</link>\n";
xmlContent << " <description>" << desc << "</description>\n";
xmlContent << " <pubDate>" << pubDate << "</pubDate>\n";
xmlContent << " </item>\n";
}
std::vector<std::string> keysToRemove;
for (auto it = logData.begin(); it != logData.end(); ++it) {
const std::string& link = it.key();
if (jsonLinks.find(link) == jsonLinks.end()) {
keysToRemove.push_back(link);
}
}
for (const auto& link : keysToRemove) {
logData.erase(link);
}
xmlContent << " </channel>\n";
xmlContent << "</rss>\n";
std::ofstream outputFile(xmlOutputFilename);
if (!outputFile.is_open()){
std::cerr << "无法创建文件 " << xmlOutputFilename << std::endl;
return 1;
}
outputFile << xmlContent.str();
outputFile.close();
// --- 更新的日志 ---
saveLog(logData, logFilename);
if (argc > 1 && std::strcmp(argv[1], "-c") == 0) {
std::cout << "RSS 订阅链接文件生成完毕" << xmlOutputFilename << std::endl;
} else {
#ifdef _WIN32
HWND consoleWnd = GetConsoleWindow();
if (consoleWnd != NULL) {
ShowWindow(consoleWnd, SW_HIDE);
}
MessageBoxW(NULL, L"RSS 订阅链接文件生成完毕", L"OK!", MB_OK);
#else
std::cout << "RSS 订阅链接文件生成完毕" << xmlOutputFilename << std::endl;
#endif
}
return 0;
}
站点地图生成器:
此站点地图生成器是通过读取RSS订阅文件来获取链接、链接标题、时间的.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "json.hpp"
#include <ctime>
#include <iomanip>
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#define timegm _mkgmtime
#endif
using json = nlohmann::json;
std::string convertToSitemapTime(const std::string &rssTime) {
std::tm tm = {};
std::istringstream iss(rssTime);
iss >> std::get_time(&tm, "%a, %d %b %Y %H:%M:%S GMT");
if (iss.fail()) {
std::cerr << "时间格式解析失败: " << rssTime << std::endl;
return "";
}
time_t t = timegm(&tm);
std::tm* gmt = std::gmtime(&t);
char buf[80];
std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S+00:00", gmt);
return std::string(buf);
}
std::string extractTitleFromUrl(const std::string &url) {
size_t pos = url.find_last_of('/');
if (pos == std::string::npos || pos + 1 >= url.size())
return url;
return url.substr(pos + 1);
}
int main(int argc, char* argv[]) {
std::setlocale(LC_ALL, "");
// 读取日志文件前面RSS订阅文件生成器的日志
std::string logFilename = "rss_log.json";
std::ifstream logFile(logFilename);
if (!logFile.is_open()) {
std::cerr << "无法打开日志文件: " << logFilename << std::endl;
return 1;
}
json logData;
try {
logFile >> logData;
} catch (json::parse_error &e) {
std::cerr << "日志文件解析错误: " << e.what() << std::endl;
return 1;
}
logFile.close();
// 生成 sitemap.xml
std::ofstream sitemapFile("sitemap.xml");
if (!sitemapFile.is_open()) {
std::cerr << "无法创建 sitemap.xml 文件" << std::endl;
return 1;
}
sitemapFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
sitemapFile << "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n";
for (auto it = logData.begin(); it != logData.end(); ++it) {
std::string url = it.key();
std::string rssTime = it.value();
std::string sitemapTime = convertToSitemapTime(rssTime);
std::string title = extractTitleFromUrl(url);
sitemapFile << " <url>\n";
sitemapFile << " <loc>" << url << "</loc>\n";
sitemapFile << " <lastmod>" << sitemapTime << "</lastmod>\n";
sitemapFile << " <title>" << title << "</title>\n";
sitemapFile << " </url>\n";
}
sitemapFile << "</urlset>\n";
sitemapFile.close();
if (argc > 1 && std::strcmp(argv[1], "-c") == 0) {
std::cout << "站点地图生成完毕" << std::endl;
} else {
#ifdef _WIN32
HWND consoleWnd = GetConsoleWindow();
if (consoleWnd != NULL) {
ShowWindow(consoleWnd, SW_HIDE);
}
MessageBoxW(NULL, L"站点地图生成完毕", L"OK!", MB_OK);
#else
std::cout << "站点地图生成完毕" << std::endl;
#endif
}
return 0;
}