diff --git a/.config/quickshell/modules/sidebarLeft/anime/BooruResponse.qml b/.config/quickshell/modules/sidebarLeft/anime/BooruResponse.qml index 1af6c91fe..c19c8bb98 100644 --- a/.config/quickshell/modules/sidebarLeft/anime/BooruResponse.qml +++ b/.config/quickshell/modules/sidebarLeft/anime/BooruResponse.qml @@ -243,7 +243,8 @@ Rectangle { imageData: modelData rowHeight: imageRow.rowHeight imageRadius: imageRow.modelData.images.length == 1 ? 50 : Appearance.rounding.normal - manualDownload: ["danbooru", "waifu.im"].includes(root.responseData.provider) + // Download manually to reduce redundant requests or make sure downloading works + manualDownload: ["danbooru", "waifu.im", "t.alcy.cc"].includes(root.responseData.provider) previewDownloadPath: root.previewDownloadPath downloadPath: root.downloadPath nsfwPath: root.nsfwPath diff --git a/.config/quickshell/services/Booru.qml b/.config/quickshell/services/Booru.qml index 697e92069..8baebfeb6 100644 --- a/.config/quickshell/services/Booru.qml +++ b/.config/quickshell/services/Booru.qml @@ -20,7 +20,7 @@ Singleton { property var responses: [] property int runningRequests: 0 property var defaultUserAgent: ConfigOptions?.networking?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" - property var providerList: ["yandere", "konachan", "zerochan", "danbooru", "gelbooru", "waifu.im"] + property var providerList: Object.keys(providers).filter(provider => provider !== "system" && providers[provider].api) property var providers: { "system": { "name": qsTr("System") }, "yandere": { @@ -30,6 +30,7 @@ Singleton { "description": qsTr("All-rounder | Good quality, decent quantity"), "mapFunc": (response) => { return response.map(item => { + console.log(JSON.stringify(item, null, 2)) return { "id": item.id, "width": item.width, @@ -219,6 +220,60 @@ Singleton { ...response.nsfw.map(item => {return {"name": item}})] } }, + "t.alcy.cc": { + "name": "Alcy", + "url": "https://t.alcy.cc", + "api": "https://t.alcy.cc/", + "description": qsTr("Large images | God tier quality, no NSFW."), + "fixedTags": [ + { + "name": "ycy", + "count": "General" + }, + { + "name": "moez", + "count": "Moe" + }, + { + "name": "ysz", + "count": "Genshin Impact" + }, + { + "name": "fj", + "count": "Landscape" + }, + { + "name": "bd", + "count": "Girl on white background" + }, + { + "name": "xhl", + "count": "Shiggy" + }, + ], + "manualParseFunc": (responseText) => { + // Alcy just returns image links, each on a new line + const lines = responseText.trim().split('\n'); + return lines.map(line => { + return { + "id": Qt.md5(line), + // Alcy doesn't provide dimensions and images are often of god resolution + "width": 1000, + "height": 1000, + "aspect_ratio": 1, // Default aspect ratio + "tags": "[no tags]", + "rating": "s", + "is_nsfw": false, + "md5": Qt.md5(line), + "preview_url": line, + "sample_url": line, + "file_url": line, + "file_ext": line.split('.').pop(), + "source": "", + } + }); + }, + } } property var currentProvider: PersistentStates.booru.provider @@ -257,8 +312,9 @@ Singleton { function constructRequestUrl(tags, nsfw=true, limit=20, page=1) { var provider = providers[currentProvider] var baseUrl = provider.api + var url = baseUrl var tagString = tags.join(" ") - if (!nsfw && !(["zerochan", "waifu.im"].includes(currentProvider))) { + if (!nsfw && !(["zerochan", "waifu.im", "t.alcy.cc"].includes(currentProvider))) { if (currentProvider == "gelbooru") tagString += " rating:general"; else @@ -281,6 +337,12 @@ Singleton { params.push("limit=" + Math.min(limit, 30)) // Only admin can do > 30 params.push("is_nsfw=" + (nsfw ? "null" : "false")) // null is random } + else if (currentProvider === "t.alcy.cc") { + console.log(`"${tagString}"`) + url += tagString + params.push("json") + params.push("quantity=" + limit) + } else { params.push("tags=" + encodeURIComponent(tagString)) params.push("limit=" + limit) @@ -291,7 +353,6 @@ Singleton { params.push("page=" + page) } } - var url = baseUrl if (baseUrl.indexOf("?") === -1) { url += "?" + params.join("&") } else { @@ -302,7 +363,7 @@ Singleton { function makeRequest(tags, nsfw=false, limit=20, page=1) { var url = constructRequestUrl(tags, nsfw, limit, page) - // console.log("[Booru] Making request to " + url) + console.log("[Booru] Making request to " + url) const newResponse = root.booruResponseDataComponent.createObject(null, { "provider": currentProvider, @@ -317,10 +378,16 @@ Singleton { xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { try { - // console.log("[Booru] Raw response: " + xhr.responseText) - var response = JSON.parse(xhr.responseText) - response = providers[currentProvider].mapFunc(response) - // console.log("[Booru] Mapped response: " + JSON.stringify(response)) + console.log("[Booru] Raw response: " + xhr.responseText) + const provider = providers[currentProvider] + let response; + if (provider.manualParseFunc) { + response = provider.manualParseFunc(xhr.responseText) + } else { + response = JSON.parse(xhr.responseText) + response = provider.mapFunc(response) + } + console.log("[Booru] Mapped response: " + JSON.stringify(response)) newResponse.images = response newResponse.message = response.length > 0 ? "" : root.failMessage @@ -360,7 +427,10 @@ Singleton { } var provider = providers[currentProvider] - if (!provider.tagSearchTemplate) { + if (provider.fixedTags) { + root.tagSuggestion(query, provider.fixedTags) + return provider.fixedTags; + } else if (!provider.tagSearchTemplate) { return } var url = provider.tagSearchTemplate.replace("{{query}}", encodeURIComponent(query))