Skip to content

Commit

Permalink
refactor: release 0.0.7
Browse files Browse the repository at this point in the history
  • Loading branch information
moesnow committed Jul 18, 2023
1 parent 35c63c5 commit 95ae50d
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 173 deletions.
30 changes: 24 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
# Compiler and compilation options
# 编译器和编译选项
CC = g++
CFLAGS = -Wall -Werror -std=c++17
CFLAGS = -Wall -Werror -std=c++17 -I.
LIBS = -lcurl

# Target file name
# 目标文件名
TARGET = bing-wallpaper-macos

# Check processor architecture
# 检查处理器架构
ifeq ($(shell uname -p), arm)
CFLAGS += -I/opt/homebrew/Cellar/nlohmann-json/3.11.2/include/
CFLAGS += -I/opt/homebrew/include/
else
CFLAGS += -I/usr/local/Cellar/nlohmann-json/3.11.2/include/
CFLAGS += -I/usr/local/include/
endif

# Source file list
# 源文件列表
SRCS = bing-wallpaper-macos.cpp bing.cpp wallpaper.cpp

# Generate corresponding object file list for each source file
# 根据源文件生成对应的目标文件列表
OBJS = $(SRCS:.cpp=.o)

.PHONY: all clean

all: $(TARGET)

$(TARGET): bing-wallpaper-macos.cpp
$(CC) $(CFLAGS) $< -o $@ $(LIBS)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $^ -o $@ $(LIBS)

# Compile each source file into corresponding object file
# 编译每个源文件为对应的目标文件
%.o: %.cpp
$(CC) $(CFLAGS) -c $< -o $@

clean:
rm -f $(TARGET)
rm -f $(TARGET) $(OBJS)
229 changes: 62 additions & 167 deletions bing-wallpaper-macos.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <bing.h>
#include <curl/curl.h>
#include <wallpaper.h>

#include <filesystem>
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>

Expand All @@ -12,38 +12,28 @@ using json = nlohmann::json;
// Function declarations
void printHelp();
void printVersion();
void printUnknown(const string& arg);
string getYesterdayDate();
bool checkRunToday(const path& configpath);
bool checkNetworkConnection(const string& url);
string getJsonContent(const string& url);
string replaceAndAddPrefix(const string& url, const string& target, const string& replacement, const string& prefix);
void clearDirectory(const path& filepath);
bool downloadFile(const string& url, const path& filepath);
bool runShellCommand(const string& script);
void updateConfig(const path& configpath);
void printUnknown(const string arg);
void printSuccess(const string date);
string getDate();
json getDefaultConfig();
json getConfig(const path configpath);
bool checkNeedRun(const json configJson);
void updateConfig(const path configpath, const json jsonData);

// Constants
const string ProgramName = "bing-wallpaper-macos";
const string ProgramVersion = "0.0.6";
const string ProgramVersion = "0.0.7";
const path ProgramDir = string(getenv("HOME")) + "/.local/" + ProgramName + "/";
const string ConfigName = "config.json";
const string CheckNetworkUrl = "https://cn.bing.com";
const string WallpaperJsonUrl = CheckNetworkUrl + "/HPImageArchive.aspx?format=js&n=1&idx=0";

// Callback functions
size_t WriteCallback(void* contents, size_t size, size_t nmemb, string* data) {
size_t totalSize = size * nmemb;
data->append(static_cast<char*>(contents), totalSize);
return totalSize;
}

// Main function
int main(int argc, char* argv[]) {
json config = getConfig(ProgramDir / ConfigName);

if (argc > 1) {
string arg(argv[1]);
if (arg == "--auto") {
if (checkRunToday(ProgramDir / ConfigName)) {
if (!checkNeedRun(config)) {
return 0;
}
} else if (arg == "--help") {
Expand All @@ -58,34 +48,23 @@ int main(int argc, char* argv[]) {
}
}

if (!checkNetworkConnection(CheckNetworkUrl)) {
if (!Bing::checkConnection(config["country_code"])) {
cerr << "Failed to connect to destination URL" << endl;
return 1;
}

string wallpaperJsonContent = getJsonContent(WallpaperJsonUrl);
json wallpaperjsonData = json::parse(wallpaperJsonContent);
string wallpaperUrl = wallpaperjsonData["images"][0]["url"];
string modifiedUrl = replaceAndAddPrefix(wallpaperUrl, "1920x1080", "UHD", "https://cn.bing.com");
string fileName = (string)wallpaperjsonData["images"][0]["startdate"] + "_" + (string)wallpaperjsonData["images"][0]["title"] + ".jpg";
path downloadedFilePath = ProgramDir / fileName;
if (downloadFile(modifiedUrl, downloadedFilePath)) {
cerr << "Failed to download wallpaper" << endl;
return 1;
}
Pictures wallpaper = Bing::getPicture(config["country_code"]);

string appleScript1 = "tell application \"System Events\" to tell every desktop to set picture to \"" + downloadedFilePath.string() + "\"";
string appleScript2 = "tell application \"System Events\" to if picture of item 1 of desktops does not contain \"" + downloadedFilePath.string() + "\" then error";
string shellCommand = "osascript -e '" + appleScript1 + "' -e '" + appleScript2 + "'";
if (runShellCommand(shellCommand)) {
cout << "\033[0m[\033[33m" << getYesterdayDate() << "\033[0m] "
<< "\033[35mWallpaper applied successfully :)" << endl;
if (Wallpaper::set(wallpaper.url, ProgramDir / wallpaper.name)) {
printSuccess(getDate());
} else {
cerr << "Failed to apply wallpaper" << endl;
return 1;
}

updateConfig(ProgramDir / ConfigName);
config["wallpaper_name"] = wallpaper.name;
config["last_update_date"] = getDate();
updateConfig(ProgramDir / ConfigName, config);

return 0;
}
Expand All @@ -103,168 +82,84 @@ void printVersion() {
cout << "Program version: " << ProgramVersion << endl;
}

void printUnknown(const string& arg) {
void printUnknown(const string arg) {
cout << ProgramName + ": option " << arg << " is unknown.\n"
<< ProgramName + ": try '" + ProgramName + " --help' for more information.\n";
}

string getYesterdayDate() {
void printSuccess(const string date) {
cout << "\033[0m[\033[33m" << date << "\033[0m] "
<< "\033[35mWallpaper applied successfully :)" << endl;
}

string getDate() {
time_t rawtime;
struct tm* timeinfo;
char buffer[9];
char buffer[11];

time(&rawtime);
timeinfo = localtime(&rawtime);
timeinfo->tm_mday--;
mktime(timeinfo);

strftime(buffer, sizeof(buffer), "%Y%m%d", timeinfo);
strftime(buffer, sizeof(buffer), "%Y/%-m/%-d", timeinfo);
return string(buffer);
}

bool checkRunToday(const path& configPath) {
json getDefaultConfig() {
json jsonData;
jsonData["last_update_date"] = "";
jsonData["wallpaper_name"] = "";
jsonData["country_code"] = "";
return jsonData;
}

json getConfig(const path configPath) {
ifstream configFile(configPath);
if (configFile.is_open()) {
try {
json configJson;
configFile >> configJson;
if (configJson.contains("last_update_date")) {
if (getYesterdayDate() == configJson["last_update_date"]) {
configFile.close();
return true;
}
if (!configJson.contains("last_update_date")) {
configJson["last_update_date"] = "";
}
if (!configJson.contains("wallpaper_name")) {
configJson["wallpaper_name"] = "";
}
if (!configJson.contains("country_code")) {
configJson["country_code"] = "";
}
return configJson;
} catch (const exception& e) {
cerr << "Error: Failed to parse config file. " << e.what() << endl;
}
}
configFile.close();
return false;
return getDefaultConfig();
}

bool checkNetworkConnection(const string& url) {
CURL* curl;
CURLcode res;
long response_code = 0;

curl_global_init(CURL_GLOBAL_DEFAULT);

curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
bool checkNeedRun(const json configJson) {
bool isDateExpired = getDate() == configJson["last_update_date"] ? false : true;

res = curl_easy_perform(curl);
if (res == CURLE_OK) {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
bool isWallpaperChange = false;
string wallpaperName = configJson["wallpaper_name"];
const vector<Screen> screens = Wallpaper::get();
for (const auto& screen : screens) {
if (screen.path.find(wallpaperName) == std::string::npos) {
isWallpaperChange = true;
break;
}

curl_easy_cleanup(curl);
}

curl_global_cleanup();

return (response_code == 200);
}

string getJsonContent(const string& url) {
CURL* curl;
CURLcode res;
string content;

curl_global_init(CURL_GLOBAL_DEFAULT);

curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &content);

res = curl_easy_perform(curl);

if (res != CURLE_OK) {
cerr << "HTTP request error: " << curl_easy_strerror(res) << endl;
}

curl_easy_cleanup(curl);
}

curl_global_cleanup();

return content;
return isDateExpired || isWallpaperChange ? true : false;
}

string replaceAndAddPrefix(const string& url, const string& target, const string& replacement, const string& prefix) {
string modifiedUrl = url;
size_t pos = 0;

while ((pos = modifiedUrl.find(target, pos)) != string::npos) {
modifiedUrl.replace(pos, target.length(), replacement);
pos += replacement.length();
}

return prefix + modifiedUrl;
}

void clearDirectory(const path& filepath) {
for (const auto& entry : directory_iterator(filepath)) {
if (entry.is_regular_file() && entry.path().extension() == ".jpg") {
remove(entry);
}
}
}

bool downloadFile(const string& url, const path& filepath) {
create_directories(filepath.parent_path());
ifstream file(filepath);
if (file.good()) {
// cout << "file exists, skip download" << endl;
return false;
} else {
clearDirectory(filepath.parent_path());
}

CURL* curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

string buffer;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);

CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
ofstream outputFile(filepath, ios::binary);
outputFile.write(buffer.c_str(), buffer.size());
outputFile.close();
} else {
cerr << "Failed to download file: " << curl_easy_strerror(res) << endl;
return true;
}
curl_easy_cleanup(curl);
} else {
cerr << "Failed to initialize libcurl" << endl;
return true;
}

return false;
}

bool runShellCommand(const string& command) {
int result = system(command.c_str());
return !result;
}

void updateConfig(const path& configPath) {
create_directories(configPath.parent_path());
json jsonData;
jsonData["last_update_date"] = getYesterdayDate();

ofstream file(configPath);
void updateConfig(const path configpath, const json jsonData) {
create_directories(configpath.parent_path());
ofstream file(configpath);
if (file.is_open()) {
file << jsonData.dump(4);
file.close();
} else {
cerr << "Failed to open file" << endl;
}
}
}
Loading

0 comments on commit 95ae50d

Please sign in to comment.