35photo2anime-sdcpp.json 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. {
  2. "active": false,
  3. "connections": [
  4. {
  5. "sourceNodeId": "node_1785733293322",
  6. "sourceOutput": "loop",
  7. "targetInput": "data",
  8. "targetNodeId": "node_1785733345099"
  9. },
  10. {
  11. "sourceNodeId": "node_1785733345099",
  12. "sourceOutput": "main",
  13. "targetInput": "data",
  14. "targetNodeId": "node_dedupe"
  15. },
  16. {
  17. "sourceNodeId": "node_dedupe",
  18. "sourceOutput": "main",
  19. "targetInput": "data",
  20. "targetNodeId": "node_if_new"
  21. },
  22. {
  23. "sourceNodeId": "node_1785761774374",
  24. "sourceOutput": "main",
  25. "targetInput": "data",
  26. "targetNodeId": "node_1785732919652"
  27. },
  28. {
  29. "sourceNodeId": "node_1785733004181",
  30. "sourceOutput": "main",
  31. "targetInput": "data",
  32. "targetNodeId": "node_1785732919652"
  33. },
  34. {
  35. "sourceNodeId": "node_if_new",
  36. "sourceOutput": "false",
  37. "targetInput": "data",
  38. "targetNodeId": "node_1785733293322"
  39. },
  40. {
  41. "sourceNodeId": "node_1785832349865",
  42. "sourceOutput": "main",
  43. "targetInput": "data",
  44. "targetNodeId": "node_1785733293322"
  45. },
  46. {
  47. "sourceNodeId": "node_1785909802844",
  48. "sourceOutput": "false",
  49. "targetInput": "data",
  50. "targetNodeId": "node_gen_failed"
  51. },
  52. {
  53. "sourceNodeId": "node_gen_failed",
  54. "sourceOutput": "main",
  55. "targetInput": "data",
  56. "targetNodeId": "node_1785733293322"
  57. },
  58. {
  59. "sourceNodeId": "node_1785732919652",
  60. "sourceOutput": "main",
  61. "targetInput": "input1",
  62. "targetNodeId": "node_1786088830206_58567"
  63. },
  64. {
  65. "sourceNodeId": "node_1786088853294_0",
  66. "sourceOutput": "main",
  67. "targetInput": "input2",
  68. "targetNodeId": "node_1786088830206_58567"
  69. },
  70. {
  71. "sourceNodeId": "node_1785733004181",
  72. "sourceOutput": "main",
  73. "targetInput": "data",
  74. "targetNodeId": "node_1786088853294_0"
  75. },
  76. {
  77. "sourceNodeId": "node_1785761774374",
  78. "sourceOutput": "main",
  79. "targetInput": "data",
  80. "targetNodeId": "node_1786088853294_0"
  81. },
  82. {
  83. "sourceNodeId": "node_1786088830206_58567",
  84. "sourceOutput": "main",
  85. "targetInput": "data",
  86. "targetNodeId": "node_1785733293322"
  87. },
  88. {
  89. "sourceNodeId": "node_1785733293322",
  90. "sourceOutput": "done",
  91. "targetInput": "data",
  92. "targetNodeId": "node_no_feed"
  93. },
  94. {
  95. "sourceNodeId": "node_no_feed",
  96. "sourceOutput": "true",
  97. "targetInput": "data",
  98. "targetNodeId": "node_feeds_down"
  99. },
  100. {
  101. "sourceNodeId": "node_if_new",
  102. "sourceOutput": "true",
  103. "targetInput": "data",
  104. "targetNodeId": "node_call_process"
  105. },
  106. {
  107. "sourceNodeId": "node_call_process",
  108. "sourceOutput": "main",
  109. "targetInput": "data",
  110. "targetNodeId": "node_1785909802844"
  111. },
  112. {
  113. "sourceNodeId": "node_1785909802844",
  114. "sourceOutput": "true",
  115. "targetInput": "data",
  116. "targetNodeId": "node_1785832349865"
  117. }
  118. ],
  119. "name": "35photo2anime - sdcpp",
  120. "nodes": [
  121. {
  122. "config": {
  123. "_customLabel": "Flicker",
  124. "detectNewItems": false,
  125. "maxItems": 20,
  126. "retries": 3,
  127. "retryDelayMs": 6000,
  128. "retryMaxDelayMs": 30000,
  129. "skipOnError": true,
  130. "timeout": 30000,
  131. "url": "https://api.flickr.com/services/feeds/photos_public.gne?tags=nude&format=rss2",
  132. "userAgent": "smartbotic-rss/1.0 (+https://smartbotics.ai)"
  133. },
  134. "disabled": true,
  135. "id": "node_1785732919652",
  136. "name": "35photo pro",
  137. "position": {
  138. "x": 3160,
  139. "y": 180
  140. },
  141. "type": "rss-reader"
  142. },
  143. {
  144. "config": {
  145. "label": "Execute"
  146. },
  147. "disabled": false,
  148. "id": "node_1785733004181",
  149. "name": "Click Trigger",
  150. "position": {
  151. "x": 3140,
  152. "y": 0
  153. },
  154. "type": "click-trigger"
  155. },
  156. {
  157. "config": {
  158. "continueOnError": true,
  159. "indexVariableName": "index",
  160. "inputField": "data.merged",
  161. "itemVariableName": "item",
  162. "maxIterations": 10,
  163. "outputField": "results"
  164. },
  165. "disabled": false,
  166. "id": "node_1785733293322",
  167. "name": "Loop",
  168. "position": {
  169. "x": 3300,
  170. "y": 540
  171. },
  172. "type": "loop"
  173. },
  174. {
  175. "config": {
  176. "authType": "none",
  177. "contentType": "",
  178. "downloadCollection": "nsfw_temp",
  179. "downloadTtlHours": 24,
  180. "failOnErrorStatus": true,
  181. "followRedirects": true,
  182. "method": "GET",
  183. "responseMode": "binary",
  184. "retries": 0,
  185. "retryDelayMs": 1000,
  186. "retryMaxDelayMs": 30000,
  187. "storeDownload": false,
  188. "timeout": 30000,
  189. "url": "{{data.loop.item.enclosure.url}}"
  190. },
  191. "disabled": false,
  192. "id": "node_1785733345099",
  193. "name": "Fetch Image",
  194. "position": {
  195. "x": 3280,
  196. "y": 720
  197. },
  198. "type": "http-request"
  199. },
  200. {
  201. "config": {
  202. "cronExpression": "0 * * * *",
  203. "maxConcurrent": 1,
  204. "maxRunMinutes": 0,
  205. "mode": "interval",
  206. "overlapPolicy": "skip",
  207. "pollInterval": 15,
  208. "timezone": "Europe/Budapest",
  209. "triggerName": "35photo every 5m"
  210. },
  211. "disabled": false,
  212. "id": "node_1785761774374",
  213. "name": "Schedule Trigger",
  214. "position": {
  215. "x": 3460,
  216. "y": 0
  217. },
  218. "type": "schedule-trigger"
  219. },
  220. {
  221. "config": {
  222. "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",
  223. "timeout": 30
  224. },
  225. "disabled": false,
  226. "id": "node_dedupe",
  227. "name": "Dedupe Check",
  228. "position": {
  229. "x": 3280,
  230. "y": 860
  231. },
  232. "type": "code"
  233. },
  234. {
  235. "config": {
  236. "combineWith": "and",
  237. "conditions": [
  238. {
  239. "field": "data.result.isNew",
  240. "operator": "is_true",
  241. "value": ""
  242. }
  243. ]
  244. },
  245. "disabled": false,
  246. "id": "node_if_new",
  247. "name": "Is New Image",
  248. "position": {
  249. "x": 3280,
  250. "y": 980
  251. },
  252. "type": "if-condition"
  253. },
  254. {
  255. "config": {
  256. "action": "send",
  257. "baseUrl": "https://cloud.fsociety.hu",
  258. "credentialId": "cred_c3c55bce-82b4-41ef-a061-bc679b386579",
  259. "limit": 20,
  260. "message": "Image is done.\n**Original** URL: {{$node[\"Fetch Image\"].url}}\n**NEW**:\nPost: {{$node[\"Process Image\"].result.url}}",
  261. "retries": 1,
  262. "silent": false,
  263. "skipOnError": false,
  264. "timeoutMs": 30000,
  265. "token": "REDACTED-conversation-token"
  266. },
  267. "disabled": true,
  268. "id": "node_1785832349865",
  269. "name": "Nextcloud Talk",
  270. "position": {
  271. "x": 3540,
  272. "y": 2420
  273. },
  274. "type": "nextcloud-talk"
  275. },
  276. {
  277. "config": {
  278. "_customLabel": "Did the image get made",
  279. "combineWith": "and",
  280. "conditions": [
  281. {
  282. "field": "data.result.succeeded",
  283. "operator": "is_true",
  284. "value": ""
  285. }
  286. ]
  287. },
  288. "disabled": false,
  289. "id": "node_1785909802844",
  290. "name": "IF Condition",
  291. "position": {
  292. "x": 3400,
  293. "y": 1760
  294. },
  295. "type": "if-condition"
  296. },
  297. {
  298. "config": {
  299. "action": "send",
  300. "baseUrl": "https://cloud.fsociety.hu",
  301. "credentialId": "cred_c3c55bce-82b4-41ef-a061-bc679b386579",
  302. "limit": 20,
  303. "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}}",
  304. "retries": 1,
  305. "silent": true,
  306. "skipOnError": true,
  307. "timeoutMs": 30000,
  308. "token": "REDACTED-conversation-token"
  309. },
  310. "disabled": false,
  311. "id": "node_gen_failed",
  312. "name": "Say It Failed",
  313. "position": {
  314. "x": 3280,
  315. "y": 1900
  316. },
  317. "type": "nextcloud-talk"
  318. },
  319. {
  320. "config": {
  321. "key": "enclosure.url",
  322. "mode": "combine-by-key",
  323. "path1": "items",
  324. "path2": "items"
  325. },
  326. "disabled": false,
  327. "id": "node_1786088830206_58567",
  328. "name": "Merge",
  329. "position": {
  330. "x": 3300,
  331. "y": 360
  332. },
  333. "type": "merge"
  334. },
  335. {
  336. "config": {
  337. "_customLabel": "35photo ru",
  338. "detectNewItems": false,
  339. "maxItems": 0,
  340. "retries": 3,
  341. "retryDelayMs": 6000,
  342. "retryMaxDelayMs": 30000,
  343. "skipOnError": true,
  344. "timeout": 30000,
  345. "url": "https://35photo.ru/rss/photo_new.xml",
  346. "userAgent": "smartbotic-rss/1.0 (+https://smartbotics.ai)"
  347. },
  348. "disabled": false,
  349. "id": "node_1786088853294_0",
  350. "name": "35photo ru",
  351. "position": {
  352. "x": 3460,
  353. "y": 180
  354. },
  355. "type": "rss-reader"
  356. },
  357. {
  358. "config": {
  359. "_customLabel": "Did any feed answer",
  360. "combineWith": "and",
  361. "conditions": [
  362. {
  363. "field": "{{$node[\"Merge\"].count}}",
  364. "operator": "equals",
  365. "value": "0"
  366. }
  367. ]
  368. },
  369. "disabled": false,
  370. "id": "node_no_feed",
  371. "name": "Did Any Feed Answer",
  372. "position": {
  373. "x": 3300,
  374. "y": 3240
  375. },
  376. "type": "if-condition"
  377. },
  378. {
  379. "config": {
  380. "action": "send",
  381. "baseUrl": "https://cloud.fsociety.hu",
  382. "credentialId": "cred_c3c55bce-82b4-41ef-a061-bc679b386579",
  383. "limit": 20,
  384. "message": "35photo2anime found no photos at all this run - both feeds came back empty or unreachable. Nothing was generated.",
  385. "retries": 1,
  386. "silent": true,
  387. "skipOnError": true,
  388. "timeoutMs": 30000,
  389. "token": "REDACTED-conversation-token"
  390. },
  391. "disabled": false,
  392. "id": "node_feeds_down",
  393. "name": "Say No Feed Answered",
  394. "position": {
  395. "x": 3300,
  396. "y": 3420
  397. },
  398. "type": "nextcloud-talk"
  399. },
  400. {
  401. "config": {
  402. "fields": [
  403. {
  404. "name": "file",
  405. "value": "{{$node['Fetch Image'].file}}"
  406. }
  407. ],
  408. "inputSource": "fields",
  409. "workflowId": "wf_58ed4490-dad0-4ea3-9c89-7122339dadb9"
  410. },
  411. "disabled": false,
  412. "id": "node_call_process",
  413. "name": "Process Image",
  414. "position": {
  415. "x": 3540,
  416. "y": 1200
  417. },
  418. "type": "call-workflow"
  419. }
  420. ],
  421. "settings": {
  422. "continueOnError": false,
  423. "errorWorkflowId": "wf_766fcbcb-6345-4e9c-b7f8-f219505ee45c",
  424. "storagePermissions": {
  425. "collections": {
  426. "anime_images": "read-write",
  427. "files": "read-write",
  428. "image_hashes": "read-write",
  429. "nsfw_images": "read-write",
  430. "nsfw_temp": "read-write"
  431. },
  432. "defaultAccess": "none"
  433. }
  434. }
  435. }