summaryrefslogtreecommitdiff
path: root/src/sttorrent.c
diff options
context:
space:
mode:
authorawy <awy@awy.one>2025-08-23 23:59:30 +0300
committerawy <awy@awy.one>2025-08-23 23:59:30 +0300
commit5a0107ba1e9388a3d4ade7faa06a1c94786ae3d2 (patch)
tree50938c25191f646990147158b1a4ead8c22a2028 /src/sttorrent.c
parentb3526d31b40dbdf37ea4b314c8e9aa94d39b7f8c (diff)
add sttorrent
Diffstat (limited to 'src/sttorrent.c')
-rw-r--r--src/sttorrent.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/sttorrent.c b/src/sttorrent.c
new file mode 100644
index 0000000..7a5a73c
--- /dev/null
+++ b/src/sttorrent.c
@@ -0,0 +1,169 @@
+/* Copyright (C) 2025 awy <awy@awy.one>
+
+ sttorrent is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation,
+ either version 3 of the License, or (at your option) any later version.
+
+ sttorrent is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with sttorrent. If not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <curl/curl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cjson/cJSON.h"
+
+struct MemoryStruct {
+ char *memory;
+ size_t size;
+};
+
+static size_t
+WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
+{
+ size_t realsize = size * nmemb;
+ struct MemoryStruct *mem = (struct MemoryStruct *)userp;
+
+ mem->memory = realloc(mem->memory, mem->size + realsize + 1);
+ if(mem->memory == NULL) {
+ /* out of memory! */
+ puts("not enough memory (realloc returned NULL)");
+ return 0;
+ }
+
+ memcpy(&(mem->memory[mem->size]), contents, realsize);
+ mem->size += realsize;
+ mem->memory[mem->size] = 0;
+
+ return realsize;
+}
+
+int
+get_session_id(char id[75])
+{
+ CURL* handle;
+ CURLcode res;
+ struct MemoryStruct chunk;
+
+ chunk.memory = malloc(1);
+ chunk.size = 0;
+
+ handle = curl_easy_init();
+
+ if (!handle) { return 1; }
+
+ curl_easy_setopt(handle, CURLOPT_URL, "http://localhost:9091/transmission/rpc");
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&chunk);
+ curl_easy_setopt(handle, CURLOPT_HEADERDATA, (void *)&chunk);
+
+ res = curl_easy_perform(handle);
+
+ if (res != CURLE_OK) { return 1; }
+ int nl = 0;
+ int idx = 0;
+ char buff[128] = {'\0'};
+
+ for (size_t i = 0; i < chunk.size; i++) {
+ if (nl > 3) { break; }
+ if (chunk.memory[i] == '\n') {
+ nl++;
+ }
+ if (nl == 3) {
+ buff[idx] = chunk.memory[i+1];
+ idx++;
+ }
+ }
+ /* cleanup \r\n garbage at the end of the buff*/
+ buff[strcspn(buff, "\r\n")] = 0;
+ strcpy(id, buff);
+ curl_easy_cleanup(handle);
+ if (chunk.memory)
+ free(chunk.memory);
+ return 0;
+}
+
+int
+main(void)
+{
+ char id[75];
+ CURL* handle;
+ CURLcode res;
+ cJSON *torrents;
+ int status_count[7] = {0};
+ struct MemoryStruct chunk;
+ struct curl_slist *headers = NULL;
+ const char *json = "{\"method\":\"torrent-get\",\"arguments\":{\"fields\":[\"status\", \"percentDone\"]}}";
+
+ curl_global_init(CURL_GLOBAL_ALL);
+ /* To get status from transmission we need to send
+ two CURL requests, first one to obtain session id. */
+ get_session_id(id);
+
+ chunk.memory = malloc(1);
+ chunk.size = 0;
+
+ handle = curl_easy_init();
+
+ if (!handle) { return 1; }
+
+ curl_easy_setopt(handle, CURLOPT_URL, "localhost:9091/transmission/rpc");
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&chunk);
+ headers = curl_slist_append(headers, "Content-Type: application/json");
+ headers = curl_slist_append(headers, "Accept: application/json");
+ headers = curl_slist_append(headers, id);
+ curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(handle, CURLOPT_POST, 1L);
+ curl_easy_setopt(handle, CURLOPT_POSTFIELDS, json);
+
+ res = curl_easy_perform(handle);
+
+ if (res != CURLE_OK) { return 1; }
+
+ /* JSON parsing */
+ torrents = cJSON_Parse(chunk.memory);
+
+ /* Cleanup */
+ curl_easy_cleanup(handle);
+ if (chunk.memory)
+ free(chunk.memory);
+ curl_global_cleanup();
+
+ torrents = cJSON_GetObjectItem(torrents, "arguments");
+ torrents = cJSON_GetObjectItem(torrents, "torrents");
+
+ if (cJSON_GetArraySize(torrents) == 0) { return 0; }
+
+ /* Counting statuses */
+ for (int i = 0; i < cJSON_GetArraySize(torrents); i++) {
+ cJSON *val = cJSON_GetArrayItem(torrents, i);
+ cJSON *status = cJSON_GetObjectItem(val, "status");
+ if (status) {
+ int s = status->valueint;
+ status_count[s]++;
+ }
+ }
+
+ for (int i = 0; i < 7; i++) {
+ if (status_count[i] == 0) { continue; }
+ switch (i) {
+ case 0: printf(" "); break;
+ case 3: printf("󱕱  "); break;
+ case 4: printf(" "); break;
+ case 5: printf("󱕱  "); break;
+ case 6: printf(" "); break;
+ default: break;
+ }
+ printf("%d", status_count[i]);
+ }
+
+ return 0;
+}