{ "name": "reading", "nodes": [ { "parameters": { "path": "/hardcover/currently-reading", "responseMode": "responseNode", "options": {} }, "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ 0, 0 ], "id": "3e611a99-cbf7-48a6-b75b-f136ac76055f", "name": "Webhook", "webhookId": "02c226fd-2d1a-450c-9941-ff438dc5c987" }, { "parameters": { "method": "POST", "url": "https://api.hardcover.app/v1/graphql", "authentication": "genericCredentialType", "genericAuthType": "httpBearerAuth", "sendQuery": true, "queryParameters": { "parameters": [ {} ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "content-type", "value": "application/json" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ { "name": "query", "value": "query GetCurrentlyReading { me { user_books(where: {status_id: {_eq: 2}}) { user_book_reads(limit: 1, order_by: {started_at: desc}) { progress } edition { title image { url } book { contributions { author { name } } } } } } }" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.3, "position": [ 288, 0 ], "id": "b2a74fcb-93a9-4a28-905f-076a51a80a98", "name": "HTTP Request", "credentials": { "httpBearerAuth": { "id": "Kmf2fBCFkuRuWWZa", "name": "Hardcover" } } }, { "parameters": { "jsCode": "// Hardcover API Response kommt als GraphQL Response\n// Die Response ist ein Array: [{ data: { me: [{ user_books: [...] }] } }]\nconst graphqlResponse = $input.all()[0].json;\n\n// Extrahiere die Daten - Response-Struktur: [{ data: { me: [{ user_books: [...] }] } }]\nconst responseData = Array.isArray(graphqlResponse) ? graphqlResponse[0] : graphqlResponse;\nconst meData = responseData?.data?.me;\nconst userBooks = (Array.isArray(meData) && meData[0]?.user_books) || meData?.user_books || [];\n\nif (!userBooks || userBooks.length === 0) {\n return {\n json: {\n currentlyReading: null\n }\n };\n}\n\n// Sortiere nach Fortschritt, falls mehrere Bücher vorhanden sind\nconst sortedBooks = userBooks.sort((a, b) => {\n const progressA = a.user_book_reads?.[0]?.progress || 0;\n const progressB = b.user_book_reads?.[0]?.progress || 0;\n return progressB - progressA; // Höchster zuerst\n});\n\n// Formatiere alle Bücher\nconst formattedBooks = sortedBooks.map(book => {\n const edition = book.edition || {};\n const bookData = edition.book || {};\n const contributions = bookData.contributions || [];\n const authors = contributions\n .filter(c => c.author && c.author.name)\n .map(c => c.author.name);\n \n const readData = book.user_book_reads?.[0] || {};\n const progress = readData.progress || 0;\n const image = edition.image?.url || null;\n\n return {\n title: edition.title || 'Unknown Title',\n authors: authors.length > 0 ? authors : ['Unknown Author'],\n image: image,\n progress: Math.round(progress) || 0, // Progress ist bereits in Prozent (z.B. 65.75)\n startedAt: readData.started_at || null,\n };\n});\n\n// Gib alle Bücher zurück\nreturn {\n json: {\n currentlyReading: formattedBooks.length > 0 ? formattedBooks : null\n }\n};" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 592, 0 ], "id": "eff96166-8be2-4ece-b338-2b4dec1ee26a", "name": "Code in JavaScript" }, { "parameters": { "options": {} }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.5, "position": [ 944, 0 ], "id": "80c59480-69db-4ecb-80f4-ddeec2be8376", "name": "Respond to Webhook" } ], "pinData": {}, "connections": { "Webhook": { "main": [ [ { "node": "HTTP Request", "type": "main", "index": 0 } ] ] }, "HTTP Request": { "main": [ [ { "node": "Code in JavaScript", "type": "main", "index": 0 } ] ] }, "Code in JavaScript": { "main": [ [ { "node": "Respond to Webhook", "type": "main", "index": 0 } ] ] } }, "active": true, "settings": { "executionOrder": "v1", "availableInMCP": false }, "versionId": "63a2c985-4b40-44ca-a40d-e7048ac5619b", "meta": { "instanceId": "cb28e4db755465d5826da179e87f69603d81f833414cc52c327be9183a217b8d" }, "id": "P2itbbCCQVa0C0HTIVGvy", "tags": [] }