Create Github Service

This commit is contained in:
Ly-sec 2025-08-12 14:11:52 +02:00
parent 049ea7c4e6
commit 663e820d26
2 changed files with 187 additions and 111 deletions

View file

@ -10,39 +10,13 @@ import qs.Widgets
ColumnLayout {
id: root
property string latestVersion: "Unknown"
property string latestVersion: Github.latestVersion
property string currentVersion: "v1.2.1" // Fallback version
property var contributors: []
property string githubDataPath: Settings.configDir + "github_data.json"
property var contributors: Github.contributors
function loadFromFile() {
const now = Date.now();
const data = githubData;
if (!data.timestamp || (now - data.timestamp > 3.6e+06)) {
console.log("[About] Cache expired or missing, fetching new data from GitHub...");
fetchFromGitHub();
return ;
}
console.log("[About] Loading cached GitHub data (age: " + Math.round((now - data.timestamp) / 60000) + " minutes)");
if (data.version)
root.latestVersion = data.version;
if (data.contributors) {
root.contributors = data.contributors;
}
}
function fetchFromGitHub() {
versionProcess.running = true;
contributorsProcess.running = true;
}
function saveData() {
githubData.timestamp = Date.now();
Qt.callLater(() => {
githubDataFile.writeAdapter();
});
Component.onCompleted: {
// Initialize the Github service
Github.init();
}
spacing: 0
@ -71,86 +45,6 @@ ColumnLayout {
}
FileView {
id: githubDataFile
path: root.githubDataPath
blockLoading: true
printErrors: true
watchChanges: true
onFileChanged: githubDataFile.reload()
onLoaded: loadFromFile()
onLoadFailed: function(error) {
console.log("GitHub data file doesn't exist yet, creating it...");
githubData.version = "Unknown";
githubData.contributors = [];
githubData.timestamp = 0;
githubDataFile.writeAdapter();
fetchFromGitHub();
}
Component.onCompleted: {
if (path)
reload();
}
JsonAdapter {
id: githubData
property string version: "Unknown"
property var contributors: []
property double timestamp: 0
}
}
Process {
id: versionProcess
command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/releases/latest"]
stdout: StdioCollector {
onStreamFinished: {
try {
const data = JSON.parse(text);
if (data.tag_name) {
const version = data.tag_name;
githubData.version = version;
root.latestVersion = version;
console.log("[About] Latest version fetched from GitHub:", version);
} else {
console.log("No tag_name in GitHub response");
}
saveData();
} catch (e) {
console.error("Failed to parse version:", e);
}
}
}
}
Process {
id: contributorsProcess
command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/contributors?per_page=100"]
stdout: StdioCollector {
onStreamFinished: {
try {
const data = JSON.parse(text);
githubData.contributors = data || [];
root.contributors = githubData.contributors;
saveData();
} catch (e) {
console.error("Failed to parse contributors:", e);
root.contributors = [];
}
}
}
}
ScrollView {
id: scrollView

182
Services/Github.qml Normal file
View file

@ -0,0 +1,182 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Services
pragma Singleton
// GitHub API logic and caching
Singleton {
id: root
property string githubDataFile: Quickshell.env("NOCTALIA_GITHUB_FILE") || (Settings.cacheDir + "github.json")
property int githubUpdateFrequency: 60 * 60 // 1 hour expressed in seconds
property var data: adapter // Used to access via Github.data.xxx.yyy
property bool isFetchingData: false
// Public properties for easy access
property string latestVersion: "Unknown"
property var contributors: []
FileView {
objectName: "githubDataFileView"
path: githubDataFile
watchChanges: true
onFileChanged: reload()
onAdapterUpdated: writeAdapter()
Component.onCompleted: function () {
reload()
}
onLoaded: function () {
loadFromCache()
}
onLoadFailed: function (error) {
if (error.toString().includes("No such file") || error === 2) {
// File doesn't exist, create it with default values
console.log("[Github] Creating new cache file...");
writeAdapter()
// Fetch data after a short delay to ensure file is created
Qt.callLater(() => {
fetchFromGitHub()
})
}
}
JsonAdapter {
id: adapter
property string version: "Unknown"
property var contributors: []
property double timestamp: 0
}
}
// --------------------------------
function init() {
// does nothing but ensure the singleton is created
// do not remove
}
// --------------------------------
function loadFromCache() {
const now = Date.now();
if (!data.timestamp || (now - data.timestamp > githubUpdateFrequency * 1000)) {
console.log("[Github] Cache expired or missing, fetching new data from GitHub...");
fetchFromGitHub();
return;
}
console.log("[Github] Loading cached GitHub data (age: " + Math.round((now - data.timestamp) / 60000) + " minutes)");
if (data.version) {
root.latestVersion = data.version;
}
if (data.contributors) {
root.contributors = data.contributors;
}
}
// --------------------------------
function fetchFromGitHub() {
if (isFetchingData) {
console.warn("[Github] GitHub data is still fetching")
return
}
isFetchingData = true
versionProcess.running = true;
contributorsProcess.running = true;
}
// --------------------------------
function saveData() {
data.timestamp = Date.now();
Qt.callLater(() => {
// Access the FileView's writeAdapter method
var fileView = root.children.find(child => child.objectName === "githubDataFileView");
if (fileView) {
fileView.writeAdapter();
}
});
}
// --------------------------------
function resetCache() {
data.version = "Unknown"
data.contributors = []
data.timestamp = 0
// Try to fetch immediately
fetchFromGitHub()
}
Process {
id: versionProcess
command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/releases/latest"]
stdout: StdioCollector {
onStreamFinished: {
try {
const response = text;
if (response && response.trim()) {
const data = JSON.parse(response);
if (data.tag_name) {
const version = data.tag_name;
root.data.version = version;
root.latestVersion = version;
console.log("[Github] Latest version fetched from GitHub:", version);
} else {
console.log("[Github] No tag_name in GitHub response");
}
} else {
console.log("[Github] Empty response from GitHub API");
}
} catch (e) {
console.error("[Github] Failed to parse version:", e);
}
// Check if both processes are done
checkAndSaveData();
}
}
}
Process {
id: contributorsProcess
command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/contributors?per_page=100"]
stdout: StdioCollector {
onStreamFinished: {
try {
const response = text;
if (response && response.trim()) {
const data = JSON.parse(response);
root.data.contributors = data || [];
root.contributors = root.data.contributors;
console.log("[Github] Contributors fetched from GitHub:", root.contributors.length);
} else {
console.log("[Github] Empty response from GitHub API for contributors");
root.data.contributors = [];
root.contributors = [];
}
} catch (e) {
console.error("[Github] Failed to parse contributors:", e);
root.data.contributors = [];
root.contributors = [];
}
// Check if both processes are done
checkAndSaveData();
}
}
}
// --------------------------------
function checkAndSaveData() {
// Only save when both processes are finished
if (!versionProcess.running && !contributorsProcess.running) {
root.isFetchingData = false;
root.saveData();
}
}
}