35photo2anime-sdcpp.json 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. {
  2. "_id": "wf_e6140002-c6b1-428c-afab-68a301591ce6",
  3. "_version": 95,
  4. "active": true,
  5. "connections": [
  6. {
  7. "sourceNodeId": "node_1785733293322",
  8. "sourceOutput": "loop",
  9. "targetInput": "data",
  10. "targetNodeId": "node_1785733345099"
  11. },
  12. {
  13. "sourceNodeId": "node_1785733345099",
  14. "sourceOutput": "main",
  15. "targetInput": "data",
  16. "targetNodeId": "node_dedupe"
  17. },
  18. {
  19. "sourceNodeId": "node_dedupe",
  20. "sourceOutput": "main",
  21. "targetInput": "data",
  22. "targetNodeId": "node_if_new"
  23. },
  24. {
  25. "sourceNodeId": "node_1785761774374",
  26. "sourceOutput": "main",
  27. "targetInput": "data",
  28. "targetNodeId": "node_1785732919652"
  29. },
  30. {
  31. "sourceNodeId": "node_1785733004181",
  32. "sourceOutput": "main",
  33. "targetInput": "data",
  34. "targetNodeId": "node_1785732919652"
  35. },
  36. {
  37. "sourceNodeId": "node_if_new",
  38. "sourceOutput": "false",
  39. "targetInput": "data",
  40. "targetNodeId": "node_1785733293322"
  41. },
  42. {
  43. "sourceNodeId": "node_1785832349865",
  44. "sourceOutput": "main",
  45. "targetInput": "data",
  46. "targetNodeId": "node_1785733293322"
  47. },
  48. {
  49. "sourceNodeId": "node_1785909802844",
  50. "sourceOutput": "false",
  51. "targetInput": "data",
  52. "targetNodeId": "node_gen_failed"
  53. },
  54. {
  55. "sourceNodeId": "node_gen_failed",
  56. "sourceOutput": "main",
  57. "targetInput": "data",
  58. "targetNodeId": "node_1785733293322"
  59. },
  60. {
  61. "sourceNodeId": "node_1785732919652",
  62. "sourceOutput": "main",
  63. "targetInput": "input1",
  64. "targetNodeId": "node_1786088830206_58567"
  65. },
  66. {
  67. "sourceNodeId": "node_1786088853294_0",
  68. "sourceOutput": "main",
  69. "targetInput": "input2",
  70. "targetNodeId": "node_1786088830206_58567"
  71. },
  72. {
  73. "sourceNodeId": "node_1785733004181",
  74. "sourceOutput": "main",
  75. "targetInput": "data",
  76. "targetNodeId": "node_1786088853294_0"
  77. },
  78. {
  79. "sourceNodeId": "node_1785761774374",
  80. "sourceOutput": "main",
  81. "targetInput": "data",
  82. "targetNodeId": "node_1786088853294_0"
  83. },
  84. {
  85. "sourceNodeId": "node_1786088830206_58567",
  86. "sourceOutput": "main",
  87. "targetInput": "data",
  88. "targetNodeId": "node_1785733293322"
  89. },
  90. {
  91. "sourceNodeId": "node_1785733293322",
  92. "sourceOutput": "done",
  93. "targetInput": "data",
  94. "targetNodeId": "node_no_feed"
  95. },
  96. {
  97. "sourceNodeId": "node_no_feed",
  98. "sourceOutput": "true",
  99. "targetInput": "data",
  100. "targetNodeId": "node_feeds_down"
  101. },
  102. {
  103. "sourceNodeId": "node_if_new",
  104. "sourceOutput": "true",
  105. "targetInput": "data",
  106. "targetNodeId": "node_call_process"
  107. },
  108. {
  109. "sourceNodeId": "node_call_process",
  110. "sourceOutput": "main",
  111. "targetInput": "data",
  112. "targetNodeId": "node_1785909802844"
  113. },
  114. {
  115. "sourceNodeId": "node_1785909802844",
  116. "sourceOutput": "true",
  117. "targetInput": "data",
  118. "targetNodeId": "node_1785832349865"
  119. }
  120. ],
  121. "consecutiveFailures": 0,
  122. "deactivatedReason": "",
  123. "description": "",
  124. "groupId": "wfg_07ea58b4-3d38-4633-b6d8-3186355c5f51",
  125. "name": "35photo2anime - sdcpp",
  126. "nodes": [
  127. {
  128. "config": {
  129. "_customLabel": "Flicker",
  130. "detectNewItems": false,
  131. "maxItems": 20,
  132. "retries": 3,
  133. "retryDelayMs": 6000,
  134. "retryMaxDelayMs": 30000,
  135. "skipOnError": true,
  136. "timeout": 30000,
  137. "url": "https://api.flickr.com/services/feeds/photos_public.gne?tags=nude&format=rss2",
  138. "userAgent": "smartbotic-rss/1.0 (+https://smartbotics.ai)"
  139. },
  140. "disabled": true,
  141. "id": "node_1785732919652",
  142. "name": "35photo pro",
  143. "position": {
  144. "x": 0,
  145. "y": 180
  146. },
  147. "type": "rss-reader"
  148. },
  149. {
  150. "config": {
  151. "label": "Execute"
  152. },
  153. "disabled": false,
  154. "id": "node_1785733004181",
  155. "name": "Click Trigger",
  156. "position": {
  157. "x": 20,
  158. "y": 0
  159. },
  160. "type": "click-trigger"
  161. },
  162. {
  163. "config": {
  164. "continueOnError": true,
  165. "indexVariableName": "index",
  166. "inputField": "data.merged",
  167. "itemVariableName": "item",
  168. "maxIterations": 10,
  169. "outputField": "results"
  170. },
  171. "disabled": false,
  172. "id": "node_1785733293322",
  173. "name": "Loop",
  174. "position": {
  175. "x": 220,
  176. "y": 560
  177. },
  178. "type": "loop"
  179. },
  180. {
  181. "config": {
  182. "authType": "none",
  183. "contentType": "",
  184. "downloadCollection": "nsfw_temp",
  185. "downloadTtlHours": 24,
  186. "failOnErrorStatus": true,
  187. "followRedirects": true,
  188. "method": "GET",
  189. "responseMode": "binary",
  190. "retries": 0,
  191. "retryDelayMs": 1000,
  192. "retryMaxDelayMs": 30000,
  193. "storeDownload": false,
  194. "timeout": 30000,
  195. "url": "{{loop.item.enclosure.url}}"
  196. },
  197. "disabled": false,
  198. "id": "node_1785733345099",
  199. "name": "Fetch Image",
  200. "position": {
  201. "x": 200,
  202. "y": 740
  203. },
  204. "type": "http-request"
  205. },
  206. {
  207. "config": {
  208. "cronExpression": "0 * * * *",
  209. "maxConcurrent": 1,
  210. "maxRunMinutes": 0,
  211. "mode": "interval",
  212. "overlapPolicy": "skip",
  213. "pollInterval": 15,
  214. "timezone": "Europe/Budapest",
  215. "triggerName": "35photo every 5m"
  216. },
  217. "disabled": false,
  218. "id": "node_1785761774374",
  219. "name": "Schedule Trigger",
  220. "position": {
  221. "x": 360,
  222. "y": 0
  223. },
  224. "type": "schedule-trigger"
  225. },
  226. {
  227. "config": {
  228. "code": "function findFetch(node, depth) {\n if (!node || typeof node !== 'object' || depth > 6) { return null; }\n if (node.file && typeof node.file.data === 'string' && node.file.data.length > 0) { return node; }\n const keys = Object.keys(node);\n for (let i = 0; i < keys.length; i++) {\n const found = findFetch(node[keys[i]], depth + 1);\n if (found) { return found; }\n }\n return null;\n}\n\nconst fetched = findFetch(input, 0);\nif (!fetched) { throw new Error('No fetched image found in input'); }\n\nconst hash = fetched.checksum || (fetched.file && fetched.file.checksum) ||\n smartbotic.utils.sha256(fetched.file.data);\nconst url = fetched.url || '';\nconst now = Date.now();\n\nconst existing = smartbotic.storage.get('image_hashes', hash);\n\nif (existing && existing.found && existing.document) {\n const doc = existing.document;\n const urls = doc.urls && typeof doc.urls.length === 'number' ? doc.urls : [];\n if (url && urls.indexOf(url) === -1) { urls.push(url); }\n\n smartbotic.storage.update('image_hashes', hash, {\n lastSeenAt: now,\n seenCount: (Number(doc.seenCount) || 1) + 1,\n urls: urls\n }, 0, true);\n\n smartbotic.log.info('Duplicate image skipped: ' + hash.substring(0, 16) + ' seen ' +\n ((Number(doc.seenCount) || 1) + 1) + ' times');\n\n return {\n isNew: false,\n checksum: hash,\n url: url,\n fileId: doc.fileId || '',\n seenCount: (Number(doc.seenCount) || 1) + 1\n };\n}\n\n// A feed can carry the same image twice in one run, so two iterations reach here\n// having both seen \"not found\". The id is the content hash, so the second insert\n// collides. Treat that as the duplicate it is rather than letting it fail the run.\n// Guarded both ways because the runtime reports a rejected insert as success\n// false, while the underlying database error can also surface as a throw.\nlet inserted = null;\nlet insertError = '';\ntry {\n inserted = smartbotic.storage.insert('image_hashes', {\n firstSeenAt: now,\n lastSeenAt: now,\n seenCount: 1,\n urls: url ? [url] : [],\n mimeType: fetched.file.mimeType || '',\n size: fetched.file.size || 0\n }, hash, 0);\n} catch (e) {\n insertError = e && e.message ? e.message : String(e);\n}\n\nif (insertError || !inserted || inserted.success === false) {\n const detail = insertError || (inserted && inserted.error) || 'unknown';\n smartbotic.log.info('Image already recorded in this run: ' + hash.substring(0, 16) + ' (' + detail + ')');\n return { isNew: false, checksum: hash, url: url, seenCount: 2 };\n}\n\nconst stored = smartbotic.storage.uploadFile(fetched.file.data, {\n name: 'source-' + hash.substring(0, 16) + '.img',\n mimeType: fetched.file.mimeType || 'image/jpeg',\n fileType: 'document',\n relatedId: hash\n});\nif (!stored.success) {\n throw new Error('Could not store the source image: ' + stored.error);\n}\n\nsmartbotic.storage.update('image_hashes', hash, { fileId: stored.id }, 0, true);\n\nreturn {\n fileId: stored.id,\n isNew: true,\n checksum: hash,\n url: url,\n seenCount: 1,\n file: fetched.file\n};\n",
  229. "timeout": 30
  230. },
  231. "disabled": false,
  232. "id": "node_dedupe",
  233. "name": "Dedupe Check",
  234. "position": {
  235. "x": 200,
  236. "y": 940
  237. },
  238. "type": "code"
  239. },
  240. {
  241. "config": {
  242. "combineWith": "and",
  243. "conditions": [
  244. {
  245. "field": "data.result.isNew",
  246. "operator": "is_true",
  247. "value": ""
  248. }
  249. ]
  250. },
  251. "disabled": false,
  252. "id": "node_if_new",
  253. "name": "Is New Image",
  254. "position": {
  255. "x": 200,
  256. "y": 1120
  257. },
  258. "type": "if-condition"
  259. },
  260. {
  261. "config": {
  262. "action": "send",
  263. "baseUrl": "https://cloud.fsociety.hu",
  264. "credentialId": "cred_c3c55bce-82b4-41ef-a061-bc679b386579",
  265. "limit": 20,
  266. "message": "Image is done.\n**Original** URL: {{$node[\"Fetch Image\"].url}}\n**NEW**:\nPost: {{$node[\"Process Image\"].result.url}}",
  267. "retries": 1,
  268. "silent": false,
  269. "skipOnError": false,
  270. "timeoutMs": 30000,
  271. "token": "REDACTED-conversation-token"
  272. },
  273. "disabled": true,
  274. "id": "node_1785832349865",
  275. "name": "Nextcloud Talk",
  276. "position": {
  277. "x": 320,
  278. "y": 1680
  279. },
  280. "type": "nextcloud-talk"
  281. },
  282. {
  283. "config": {
  284. "_customLabel": "Did the image get made",
  285. "combineWith": "and",
  286. "conditions": [
  287. {
  288. "field": "data.result.succeeded",
  289. "operator": "is_true",
  290. "value": ""
  291. }
  292. ]
  293. },
  294. "disabled": false,
  295. "id": "node_1785909802844",
  296. "name": "IF Condition",
  297. "position": {
  298. "x": 160,
  299. "y": 1480
  300. },
  301. "type": "if-condition"
  302. },
  303. {
  304. "config": {
  305. "action": "send",
  306. "baseUrl": "https://cloud.fsociety.hu",
  307. "credentialId": "cred_c3c55bce-82b4-41ef-a061-bc679b386579",
  308. "limit": 20,
  309. "message": "SD.cpp did not produce an image, moving on to the next photo.\n**Original** URL: {{$node[\"Fetch Image\"].url}}\n**Reason**: {{$node[\"Process Image\"].result.error}}",
  310. "retries": 1,
  311. "silent": true,
  312. "skipOnError": true,
  313. "timeoutMs": 30000,
  314. "token": "REDACTED-conversation-token"
  315. },
  316. "disabled": false,
  317. "id": "node_gen_failed",
  318. "name": "Say It Failed",
  319. "position": {
  320. "x": 60,
  321. "y": 1680
  322. },
  323. "type": "nextcloud-talk"
  324. },
  325. {
  326. "config": {
  327. "key": "enclosure.url",
  328. "mode": "combine-by-key",
  329. "path1": "items",
  330. "path2": "items"
  331. },
  332. "disabled": false,
  333. "id": "node_1786088830206_58567",
  334. "name": "Merge",
  335. "position": {
  336. "x": 220,
  337. "y": 380
  338. },
  339. "type": "merge"
  340. },
  341. {
  342. "config": {
  343. "_customLabel": "35photo ru",
  344. "detectNewItems": false,
  345. "maxItems": 0,
  346. "retries": 3,
  347. "retryDelayMs": 6000,
  348. "retryMaxDelayMs": 30000,
  349. "skipOnError": true,
  350. "timeout": 30000,
  351. "url": "https://35photo.ru/rss/photo_new.xml",
  352. "userAgent": "smartbotic-rss/1.0 (+https://smartbotics.ai)"
  353. },
  354. "disabled": false,
  355. "id": "node_1786088853294_0",
  356. "name": "35photo ru",
  357. "position": {
  358. "x": 340,
  359. "y": 180
  360. },
  361. "type": "rss-reader"
  362. },
  363. {
  364. "config": {
  365. "_customLabel": "Did any feed answer",
  366. "combineWith": "and",
  367. "conditions": [
  368. {
  369. "field": "{{$node[\"Merge\"].count}}",
  370. "operator": "equals",
  371. "value": "0"
  372. }
  373. ]
  374. },
  375. "disabled": false,
  376. "id": "node_no_feed",
  377. "name": "Did Any Feed Answer",
  378. "position": {
  379. "x": 160,
  380. "y": 1860
  381. },
  382. "type": "if-condition"
  383. },
  384. {
  385. "config": {
  386. "action": "send",
  387. "baseUrl": "https://cloud.fsociety.hu",
  388. "credentialId": "cred_c3c55bce-82b4-41ef-a061-bc679b386579",
  389. "limit": 20,
  390. "message": "35photo2anime found no photos at all this run - both feeds came back empty or unreachable. Nothing was generated.",
  391. "retries": 1,
  392. "silent": true,
  393. "skipOnError": true,
  394. "timeoutMs": 30000,
  395. "token": "REDACTED-conversation-token"
  396. },
  397. "disabled": false,
  398. "id": "node_feeds_down",
  399. "name": "Say No Feed Answered",
  400. "position": {
  401. "x": 180,
  402. "y": 2040
  403. },
  404. "type": "nextcloud-talk"
  405. },
  406. {
  407. "config": {
  408. "fields": [
  409. {
  410. "name": "file",
  411. "value": "{{$node['Fetch Image'].file}}"
  412. }
  413. ],
  414. "inputSource": "fields",
  415. "workflowId": "wf_58ed4490-dad0-4ea3-9c89-7122339dadb9"
  416. },
  417. "disabled": false,
  418. "id": "node_call_process",
  419. "name": "Process Image",
  420. "position": {
  421. "x": 180,
  422. "y": 1300
  423. },
  424. "type": "call-workflow"
  425. }
  426. ],
  427. "ownerId": "usr_dc798bf2-4e5b-4f86-b003-0b9184b2a528",
  428. "projectId": "prj_97b218e7-0bc1-41db-aa75-7b9263c876c0",
  429. "publishedAt": 1786513547285,
  430. "publishedBy": "admin",
  431. "publishedVersion": 94,
  432. "settings": {
  433. "continueOnError": false,
  434. "errorWorkflowId": "wf_766fcbcb-6345-4e9c-b7f8-f219505ee45c",
  435. "storagePermissions": {
  436. "collections": {
  437. "anime_images": "read-write",
  438. "files": "read-write",
  439. "image_hashes": "read-write",
  440. "nsfw_images": "read-write",
  441. "nsfw_temp": "read-write"
  442. },
  443. "defaultAccess": "none"
  444. }
  445. },
  446. "updatedAt": 1786341677586
  447. }