@lemoncat7/dsh-partner 2.23.40 → 2.24.0-rc.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/docs/channel-activities.md +56 -0
- package/docs/compatibility-0.2.2-rc.1.md +7 -0
- package/docs/releases/2.23.41.md +9 -0
- package/docs/releases/2.23.42.md +11 -0
- package/docs/releases/2.23.43.md +13 -0
- package/docs/releases/2.23.44.md +13 -0
- package/docs/releases/2.23.45.md +11 -0
- package/docs/releases/2.23.46.md +5 -0
- package/docs/releases/2.23.47.md +5 -0
- package/docs/releases/2.23.48.md +6 -0
- package/docs/releases/2.23.49.md +6 -0
- package/docs/releases/2.23.50.md +6 -0
- package/docs/releases/2.23.51.md +5 -0
- package/docs/releases/2.23.52.md +7 -0
- package/docs/releases/2.23.53.md +5 -0
- package/docs/releases/2.23.54.md +7 -0
- package/docs/releases/2.24.0-rc.2.md +9 -0
- package/docs/releases/2.24.0-rc.3.md +6 -0
- package/docs/releases/2.24.0-rc.4.md +11 -0
- package/docs/releases/2.24.0-rc.5.md +11 -0
- package/docs/releases/2.24.0-rc.6.md +12 -0
- package/docs/releases/2.24.0-rc.9.md +5 -0
- package/lib/agent-runtime.d.ts +5 -2
- package/lib/agent-runtime.d.ts.map +1 -1
- package/lib/agent-runtime.js +204 -85
- package/lib/agent-runtime.js.map +1 -1
- package/lib/api.d.ts +1 -0
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js +69 -2
- package/lib/api.js.map +1 -1
- package/lib/attachments/reply-document.d.ts +5 -0
- package/lib/attachments/reply-document.d.ts.map +1 -1
- package/lib/attachments/reply-document.js +7 -3
- package/lib/attachments/reply-document.js.map +1 -1
- package/lib/attachments/tool.d.ts +1 -1
- package/lib/attachments/tool.d.ts.map +1 -1
- package/lib/attachments/tool.js +2 -2
- package/lib/attachments/tool.js.map +1 -1
- package/lib/channels/activity-defaults.d.ts +4 -0
- package/lib/channels/activity-defaults.d.ts.map +1 -0
- package/lib/channels/activity-defaults.js +15 -0
- package/lib/channels/activity-defaults.js.map +1 -0
- package/lib/channels/activity-registry.d.ts +37 -0
- package/lib/channels/activity-registry.d.ts.map +1 -0
- package/lib/channels/activity-registry.js +53 -0
- package/lib/channels/activity-registry.js.map +1 -0
- package/lib/channels/bilibili/activity-provider.d.ts +3 -0
- package/lib/channels/bilibili/activity-provider.d.ts.map +1 -0
- package/lib/channels/bilibili/activity-provider.js +8 -0
- package/lib/channels/bilibili/activity-provider.js.map +1 -0
- package/lib/channels/bilibili/catalog.d.ts +23 -0
- package/lib/channels/bilibili/catalog.d.ts.map +1 -0
- package/lib/channels/bilibili/catalog.js +45 -0
- package/lib/channels/bilibili/catalog.js.map +1 -0
- package/lib/channels/bilibili/media.d.ts +9 -0
- package/lib/channels/bilibili/media.d.ts.map +1 -0
- package/lib/channels/bilibili/media.js +67 -0
- package/lib/channels/bilibili/media.js.map +1 -0
- package/lib/channels/bilibili/service.d.ts +37 -0
- package/lib/channels/bilibili/service.d.ts.map +1 -0
- package/lib/channels/bilibili/service.js +138 -0
- package/lib/channels/bilibili/service.js.map +1 -0
- package/lib/channels/bilibili/tools.d.ts +6 -0
- package/lib/channels/bilibili/tools.d.ts.map +1 -0
- package/lib/channels/bilibili/tools.js +48 -0
- package/lib/channels/bilibili/tools.js.map +1 -0
- package/lib/channels/direct/message-format.js +298 -206
- package/lib/channels/direct/message-format.js.map +4 -4
- package/lib/channels/manager.d.ts +1 -0
- package/lib/channels/manager.d.ts.map +1 -1
- package/lib/channels/manager.js +48 -5
- package/lib/channels/manager.js.map +1 -1
- package/lib/channels/qq/action-catalog.js +2 -2
- package/lib/channels/qq/action-catalog.js.map +1 -1
- package/lib/channels/qq/actions.d.ts +2 -1
- package/lib/channels/qq/actions.d.ts.map +1 -1
- package/lib/channels/qq/actions.js +14 -2
- package/lib/channels/qq/actions.js.map +1 -1
- package/lib/channels/qq/activity-provider.d.ts +4 -0
- package/lib/channels/qq/activity-provider.d.ts.map +1 -0
- package/lib/channels/qq/activity-provider.js +21 -0
- package/lib/channels/qq/activity-provider.js.map +1 -0
- package/lib/channels/qq/authority.d.ts +1 -1
- package/lib/channels/qq/authority.d.ts.map +1 -1
- package/lib/channels/qq/authority.js +3 -3
- package/lib/channels/qq/authority.js.map +1 -1
- package/lib/channels/qq/connection.d.ts +5 -0
- package/lib/channels/qq/connection.d.ts.map +1 -1
- package/lib/channels/qq/connection.js +12 -2
- package/lib/channels/qq/connection.js.map +1 -1
- package/lib/channels/qq/message.d.ts.map +1 -1
- package/lib/channels/qq/message.js +11 -1
- package/lib/channels/qq/message.js.map +1 -1
- package/lib/channels/qq/reply-tool.d.ts.map +1 -1
- package/lib/channels/qq/reply-tool.js +62 -6
- package/lib/channels/qq/reply-tool.js.map +1 -1
- package/lib/channels/weixin/connect.d.ts +3 -1
- package/lib/channels/weixin/connect.d.ts.map +1 -1
- package/lib/character/activity-journal.d.ts +20 -0
- package/lib/character/activity-journal.d.ts.map +1 -0
- package/lib/character/activity-journal.js +78 -0
- package/lib/character/activity-journal.js.map +1 -0
- package/lib/character/activity-plan.d.ts +27 -0
- package/lib/character/activity-plan.d.ts.map +1 -0
- package/lib/character/activity-plan.js +47 -0
- package/lib/character/activity-plan.js.map +1 -0
- package/lib/character/activity-tool.d.ts.map +1 -1
- package/lib/character/activity-tool.js +24 -4
- package/lib/character/activity-tool.js.map +1 -1
- package/lib/character/affection-tool.js +4 -4
- package/lib/character/affection-tool.js.map +1 -1
- package/lib/character/affection.d.ts +8 -43
- package/lib/character/affection.d.ts.map +1 -1
- package/lib/character/affection.js +7 -24
- package/lib/character/affection.js.map +1 -1
- package/lib/character/background-context.d.ts +6 -0
- package/lib/character/background-context.d.ts.map +1 -0
- package/lib/character/background-context.js +29 -0
- package/lib/character/background-context.js.map +1 -0
- package/lib/character/conversation-behavior.d.ts +2 -0
- package/lib/character/conversation-behavior.d.ts.map +1 -1
- package/lib/character/conversation-behavior.js +16 -12
- package/lib/character/conversation-behavior.js.map +1 -1
- package/lib/character/domain.d.ts +10 -0
- package/lib/character/domain.d.ts.map +1 -1
- package/lib/character/domain.js +7 -0
- package/lib/character/domain.js.map +1 -1
- package/lib/character/habit-tool.d.ts +4 -0
- package/lib/character/habit-tool.d.ts.map +1 -0
- package/lib/character/habit-tool.js +31 -0
- package/lib/character/habit-tool.js.map +1 -0
- package/lib/character/habits.d.ts +38 -0
- package/lib/character/habits.d.ts.map +1 -0
- package/lib/character/habits.js +92 -0
- package/lib/character/habits.js.map +1 -0
- package/lib/character/idle-contact.d.ts +11 -4
- package/lib/character/idle-contact.d.ts.map +1 -1
- package/lib/character/idle-contact.js +28 -49
- package/lib/character/idle-contact.js.map +1 -1
- package/lib/character/interaction-review.d.ts +44 -0
- package/lib/character/interaction-review.d.ts.map +1 -0
- package/lib/character/interaction-review.js +141 -0
- package/lib/character/interaction-review.js.map +1 -0
- package/lib/character/post-reply.d.ts +1 -3
- package/lib/character/post-reply.d.ts.map +1 -1
- package/lib/character/post-reply.js +15 -18
- package/lib/character/post-reply.js.map +1 -1
- package/lib/character/prompt-projection.d.ts +1 -0
- package/lib/character/prompt-projection.d.ts.map +1 -1
- package/lib/character/prompt-projection.js +8 -1
- package/lib/character/prompt-projection.js.map +1 -1
- package/lib/character/thought-tool.d.ts +4 -0
- package/lib/character/thought-tool.d.ts.map +1 -0
- package/lib/character/thought-tool.js +99 -0
- package/lib/character/thought-tool.js.map +1 -0
- package/lib/character/thoughts.d.ts +42 -0
- package/lib/character/thoughts.d.ts.map +1 -0
- package/lib/character/thoughts.js +91 -0
- package/lib/character/thoughts.js.map +1 -0
- package/lib/chat/context-selection.d.ts.map +1 -1
- package/lib/chat/context-selection.js +5 -2
- package/lib/chat/context-selection.js.map +1 -1
- package/lib/chat/intermediate-delivery.d.ts +7 -0
- package/lib/chat/intermediate-delivery.d.ts.map +1 -0
- package/lib/chat/intermediate-delivery.js +14 -0
- package/lib/chat/intermediate-delivery.js.map +1 -0
- package/lib/chat/live-speech.d.ts +5 -2
- package/lib/chat/live-speech.d.ts.map +1 -1
- package/lib/chat/live-speech.js +39 -12
- package/lib/chat/live-speech.js.map +1 -1
- package/lib/chat/persona-delivery.d.ts +29 -0
- package/lib/chat/persona-delivery.d.ts.map +1 -0
- package/lib/chat/persona-delivery.js +129 -0
- package/lib/chat/persona-delivery.js.map +1 -0
- package/lib/chat/reply-continuity.d.ts.map +1 -1
- package/lib/chat/reply-continuity.js +12 -0
- package/lib/chat/reply-continuity.js.map +1 -1
- package/lib/chat/tools.d.ts.map +1 -1
- package/lib/chat/tools.js +41 -19
- package/lib/chat/tools.js.map +1 -1
- package/lib/chat/work-expression.d.ts +36 -0
- package/lib/chat/work-expression.d.ts.map +1 -1
- package/lib/chat/work-expression.js +80 -15
- package/lib/chat/work-expression.js.map +1 -1
- package/lib/client-api.d.ts +14 -1
- package/lib/client-api.d.ts.map +1 -1
- package/lib/client-api.js.map +1 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +9670 -13202
- package/lib/client.js.map +4 -4
- package/lib/collaboration/composition.d.ts.map +1 -1
- package/lib/collaboration/composition.js +6 -2
- package/lib/collaboration/composition.js.map +1 -1
- package/lib/collaboration/tool-discovery.d.ts.map +1 -1
- package/lib/collaboration/tool-discovery.js +12 -6
- package/lib/collaboration/tool-discovery.js.map +1 -1
- package/lib/companions/identity-tool.d.ts +1 -1
- package/lib/companions/identity-tool.d.ts.map +1 -1
- package/lib/companions/identity-tool.js +3 -4
- package/lib/companions/identity-tool.js.map +1 -1
- package/lib/companions/identity.js +4 -4
- package/lib/companions/identity.js.map +1 -1
- package/lib/companions/persona-refinement.d.ts.map +1 -1
- package/lib/companions/persona-refinement.js +1 -45
- package/lib/companions/persona-refinement.js.map +1 -1
- package/lib/compat/native-presentation.d.ts +4 -0
- package/lib/compat/native-presentation.d.ts.map +1 -0
- package/lib/compat/native-presentation.js +40 -0
- package/lib/compat/native-presentation.js.map +1 -0
- package/lib/compat/ptc-events.d.ts +2 -0
- package/lib/compat/ptc-events.d.ts.map +1 -0
- package/lib/compat/ptc-events.js +2 -0
- package/lib/compat/ptc-events.js.map +1 -0
- package/lib/compat/tool-dispatch.d.ts +4 -0
- package/lib/compat/tool-dispatch.d.ts.map +1 -0
- package/lib/compat/tool-dispatch.js +14 -0
- package/lib/compat/tool-dispatch.js.map +1 -0
- package/lib/concern-tool.d.ts.map +1 -1
- package/lib/concern-tool.js +5 -3
- package/lib/concern-tool.js.map +1 -1
- package/lib/domain.d.ts +14 -1
- package/lib/domain.d.ts.map +1 -1
- package/lib/domain.js.map +1 -1
- package/lib/execution/agent-support.d.ts.map +1 -1
- package/lib/execution/agent-support.js +3 -1
- package/lib/execution/agent-support.js.map +1 -1
- package/lib/execution/operation-tool-access.d.ts.map +1 -1
- package/lib/execution/operation-tool-access.js +2 -6
- package/lib/execution/operation-tool-access.js.map +1 -1
- package/lib/execution/reply-progress.d.ts +1 -0
- package/lib/execution/reply-progress.d.ts.map +1 -1
- package/lib/execution/service.d.ts +2 -0
- package/lib/execution/service.d.ts.map +1 -1
- package/lib/execution/service.js +7 -1
- package/lib/execution/service.js.map +1 -1
- package/lib/execution/task-preamble.js +3 -3
- package/lib/execution/task-preamble.js.map +1 -1
- package/lib/execution/work-progress-card.d.ts +10 -0
- package/lib/execution/work-progress-card.d.ts.map +1 -0
- package/lib/execution/work-progress-card.js +45 -0
- package/lib/execution/work-progress-card.js.map +1 -0
- package/lib/execution/work-progress-state.d.ts +32 -0
- package/lib/execution/work-progress-state.d.ts.map +1 -0
- package/lib/execution/work-progress-state.js +19 -0
- package/lib/execution/work-progress-state.js.map +1 -0
- package/lib/execution/work-progress.d.ts +16 -0
- package/lib/execution/work-progress.d.ts.map +1 -0
- package/lib/execution/work-progress.js +76 -0
- package/lib/execution/work-progress.js.map +1 -0
- package/lib/execution/work-tool.d.ts.map +1 -1
- package/lib/execution/work-tool.js +64 -52
- package/lib/execution/work-tool.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +12 -4
- package/lib/index.js.map +1 -1
- package/lib/memory-domain.d.ts +5 -0
- package/lib/memory-domain.d.ts.map +1 -1
- package/lib/memory-reflection.d.ts +5 -1
- package/lib/memory-reflection.d.ts.map +1 -1
- package/lib/memory-reflection.js +21 -3
- package/lib/memory-reflection.js.map +1 -1
- package/lib/memory-store.d.ts +1 -1
- package/lib/observation-loop.d.ts.map +1 -1
- package/lib/observation-loop.js +17 -3
- package/lib/observation-loop.js.map +1 -1
- package/lib/persona/context.d.ts +4 -0
- package/lib/persona/context.d.ts.map +1 -0
- package/lib/persona/context.js +12 -0
- package/lib/persona/context.js.map +1 -0
- package/lib/persona/domain.d.ts +2 -1
- package/lib/persona/domain.d.ts.map +1 -1
- package/lib/persona/domain.js +11 -3
- package/lib/persona/domain.js.map +1 -1
- package/lib/persona/service.js +2 -2
- package/lib/persona/service.js.map +1 -1
- package/lib/persona/store.js +7 -7
- package/lib/persona/store.js.map +1 -1
- package/lib/persona/types.d.ts +3 -1
- package/lib/persona/types.d.ts.map +1 -1
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +23 -0
- package/lib/store.js.map +1 -1
- package/lib/ui/affection-panel.d.ts.map +1 -1
- package/lib/ui/affection-panel.js +2 -2
- package/lib/ui/affection-panel.js.map +1 -1
- package/lib/ui/bilibili-settings.d.ts +12 -0
- package/lib/ui/bilibili-settings.d.ts.map +1 -0
- package/lib/ui/bilibili-settings.js +77 -0
- package/lib/ui/bilibili-settings.js.map +1 -0
- package/lib/ui/channels-panel.d.ts.map +1 -1
- package/lib/ui/channels-panel.js +4 -3
- package/lib/ui/channels-panel.js.map +1 -1
- package/lib/ui/character-editor.d.ts.map +1 -1
- package/lib/ui/character-editor.js +4 -2
- package/lib/ui/character-editor.js.map +1 -1
- package/lib/ui/companion-vitals.js +1 -1
- package/lib/ui/companion-vitals.js.map +1 -1
- package/lib/ui/exclusive-prompt-toggle.d.ts +5 -0
- package/lib/ui/exclusive-prompt-toggle.d.ts.map +1 -0
- package/lib/ui/exclusive-prompt-toggle.js +7 -0
- package/lib/ui/exclusive-prompt-toggle.js.map +1 -0
- package/lib/ui/habits-panel.d.ts +4 -0
- package/lib/ui/habits-panel.d.ts.map +1 -0
- package/lib/ui/habits-panel.js +30 -0
- package/lib/ui/habits-panel.js.map +1 -0
- package/lib/ui/identity-editor.js +1 -8
- package/lib/ui/identity-editor.js.map +1 -1
- package/lib/ui/idle-contact-editor.d.ts.map +1 -1
- package/lib/ui/idle-contact-editor.js +4 -1
- package/lib/ui/idle-contact-editor.js.map +1 -1
- package/lib/ui/memory/persona-view.js +1 -1
- package/lib/ui/memory/persona-view.js.map +1 -1
- package/lib/ui/push-draft.d.ts +3 -3
- package/lib/ui/qq-capability-settings.js +1 -1
- package/lib/ui/qq-capability-settings.js.map +1 -1
- package/lib/ui/thoughts-panel.d.ts +4 -0
- package/lib/ui/thoughts-panel.d.ts.map +1 -0
- package/lib/ui/thoughts-panel.js +51 -0
- package/lib/ui/thoughts-panel.js.map +1 -0
- package/lib/ui/workspace-navigation.d.ts +16 -16
- package/package.json +82 -49
- package/resources/bilibili/Dockerfile +7 -0
- package/resources/bilibili/media.py +245 -0
- package/resources/bilibili/requirements.txt +3 -0
- package/resources/bilibili/server.py +300 -0
- package/resources/bilibili/test_bridge.py +115 -0
- package/resources/bilibili/test_media.py +110 -0
- package/lib/chat/short-expression.d.ts +0 -6
- package/lib/chat/short-expression.d.ts.map +0 -1
- package/lib/chat/short-expression.js +0 -24
- package/lib/chat/short-expression.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lemoncat7/dsh-partner",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.0-rc.9",
|
|
4
4
|
"description": "Long-lived AI companions with QQ, WeChat, Matrix and Mattermost channels for DeepSeek Harness",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -24,9 +24,29 @@
|
|
|
24
24
|
"default": "./lib/client.js"
|
|
25
25
|
},
|
|
26
26
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
27
|
-
"./package.json": "./package.json"
|
|
27
|
+
"./package.json": "./package.json",
|
|
28
|
+
"./channel-activities": {
|
|
29
|
+
"types": "./lib/channels/activity-registry.d.ts",
|
|
30
|
+
"default": "./lib/channels/activity-registry.js"
|
|
31
|
+
}
|
|
28
32
|
},
|
|
29
33
|
"files": [
|
|
34
|
+
"docs/releases/2.24.0-rc.9.md",
|
|
35
|
+
"docs/releases/2.23.54.md",
|
|
36
|
+
"docs/releases/2.23.53.md",
|
|
37
|
+
"docs/releases/2.23.52.md",
|
|
38
|
+
"docs/releases/2.23.51.md",
|
|
39
|
+
"docs/releases/2.23.50.md",
|
|
40
|
+
"docs/channel-activities.md",
|
|
41
|
+
"docs/releases/2.23.49.md",
|
|
42
|
+
"docs/releases/2.23.48.md",
|
|
43
|
+
"docs/releases/2.23.47.md",
|
|
44
|
+
"docs/releases/2.23.46.md",
|
|
45
|
+
"docs/releases/2.23.45.md",
|
|
46
|
+
"docs/releases/2.23.44.md",
|
|
47
|
+
"docs/releases/2.23.43.md",
|
|
48
|
+
"docs/releases/2.23.42.md",
|
|
49
|
+
"docs/releases/2.23.41.md",
|
|
30
50
|
"docs/releases/2.23.40.md",
|
|
31
51
|
"docs/releases/2.23.39.md",
|
|
32
52
|
"docs/releases/2.23.38.md",
|
|
@@ -180,7 +200,16 @@
|
|
|
180
200
|
"docs/releases/2.23.21.md",
|
|
181
201
|
"docs/releases/2.23.22.md",
|
|
182
202
|
"docs/releases/2.23.23.md",
|
|
183
|
-
"docs/releases/2.23.24.md"
|
|
203
|
+
"docs/releases/2.23.24.md",
|
|
204
|
+
"resources/bilibili/*.py",
|
|
205
|
+
"resources/bilibili/requirements.txt",
|
|
206
|
+
"resources/bilibili/Dockerfile",
|
|
207
|
+
"docs/releases/2.24.0-rc.2.md",
|
|
208
|
+
"docs/releases/2.24.0-rc.3.md",
|
|
209
|
+
"docs/releases/2.24.0-rc.4.md",
|
|
210
|
+
"docs/releases/2.24.0-rc.5.md",
|
|
211
|
+
"docs/releases/2.24.0-rc.6.md",
|
|
212
|
+
"docs/compatibility-0.2.2-rc.1.md"
|
|
184
213
|
],
|
|
185
214
|
"dsh": {
|
|
186
215
|
"bundle": {
|
|
@@ -200,8 +229,8 @@
|
|
|
200
229
|
}
|
|
201
230
|
},
|
|
202
231
|
"engines": {
|
|
203
|
-
"node": "
|
|
204
|
-
"dsh": "
|
|
232
|
+
"node": ">=24.9.0",
|
|
233
|
+
"dsh": "=0.2.2-rc.1"
|
|
205
234
|
},
|
|
206
235
|
"scripts": {
|
|
207
236
|
"clean": "node -e \"require('node:fs').rmSync('lib', { recursive: true, force: true })\"",
|
|
@@ -212,7 +241,7 @@
|
|
|
212
241
|
"pack:verify": "node scripts/check-package.mjs"
|
|
213
242
|
},
|
|
214
243
|
"dependencies": {
|
|
215
|
-
"@deepseek-ai/schemastery": "~3.
|
|
244
|
+
"@deepseek-ai/schemastery": "~3.19.0",
|
|
216
245
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
217
246
|
"mdast-util-from-markdown": "2.0.3",
|
|
218
247
|
"mdast-util-gfm": "3.1.0",
|
|
@@ -220,50 +249,52 @@
|
|
|
220
249
|
"micromark-extension-gfm": "3.0.0"
|
|
221
250
|
},
|
|
222
251
|
"peerDependencies": {
|
|
223
|
-
"@deepseek-ai/cordis": "^4.0
|
|
224
|
-
"@deepseek-ai/dsh-agent": "^0.2.
|
|
225
|
-
"@deepseek-ai/dsh-agent-default-model": "^0.2.
|
|
226
|
-
"@deepseek-ai/dsh-agent-preset-registry": "^0.2.
|
|
227
|
-
"@deepseek-ai/dsh-attachment": "^0.2.
|
|
228
|
-
"@deepseek-ai/dsh-credentials": "^0.2.
|
|
229
|
-
"@deepseek-ai/dsh-llm": "^0.2.
|
|
230
|
-
"@deepseek-ai/dsh-scope": "^0.2.
|
|
231
|
-
"@deepseek-ai/dsh-session": "^0.2.
|
|
232
|
-
"@deepseek-ai/dsh-settings": "^0.2.
|
|
233
|
-
"@deepseek-ai/dsh-system-prompt": "^0.2.
|
|
234
|
-
"@deepseek-ai/dsh-tools": "^0.2.
|
|
235
|
-
"@deepseek-ai/dsh-user-questions": "^0.2.
|
|
236
|
-
"@deepseek-ai/dsh-workspace": "^0.2.
|
|
252
|
+
"@deepseek-ai/cordis": "^4.1.0",
|
|
253
|
+
"@deepseek-ai/dsh-agent": "^0.2.2-rc.1",
|
|
254
|
+
"@deepseek-ai/dsh-agent-default-model": "^0.2.2-rc.1",
|
|
255
|
+
"@deepseek-ai/dsh-agent-preset-registry": "^0.2.2-rc.1",
|
|
256
|
+
"@deepseek-ai/dsh-attachment": "^0.2.2-rc.1",
|
|
257
|
+
"@deepseek-ai/dsh-credentials": "^0.2.2-rc.1",
|
|
258
|
+
"@deepseek-ai/dsh-llm": "^0.2.2-rc.1",
|
|
259
|
+
"@deepseek-ai/dsh-scope": "^0.2.2-rc.1",
|
|
260
|
+
"@deepseek-ai/dsh-session": "^0.2.2-rc.1",
|
|
261
|
+
"@deepseek-ai/dsh-settings": "^0.2.2-rc.1",
|
|
262
|
+
"@deepseek-ai/dsh-system-prompt": "^0.2.2-rc.1",
|
|
263
|
+
"@deepseek-ai/dsh-tools": "^0.2.2-rc.1",
|
|
264
|
+
"@deepseek-ai/dsh-user-questions": "^0.2.2-rc.1",
|
|
265
|
+
"@deepseek-ai/dsh-workspace": "^0.2.2-rc.1",
|
|
266
|
+
"@deepseek-ai/dsh-tool-executor-native": "^0.2.2-rc.1",
|
|
267
|
+
"@deepseek-ai/dsh-tool-executor-ptc": "^0.2.2-rc.1"
|
|
237
268
|
},
|
|
238
269
|
"devDependencies": {
|
|
239
|
-
"@deepseek-ai/cordis": "~4.0
|
|
240
|
-
"@deepseek-ai/dsh-agent": "0.2.
|
|
241
|
-
"@deepseek-ai/dsh-agent-default-model": "0.2.
|
|
242
|
-
"@deepseek-ai/dsh-agent-preset-registry": "0.2.
|
|
243
|
-
"@deepseek-ai/dsh-api-remotes": "0.2.
|
|
244
|
-
"@deepseek-ai/dsh-api-session-controller": "0.2.
|
|
245
|
-
"@deepseek-ai/dsh-attachment": "0.2.
|
|
246
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.2.
|
|
247
|
-
"@deepseek-ai/dsh-client-ui-layout": "0.2.
|
|
248
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.2.
|
|
249
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.2.
|
|
250
|
-
"@deepseek-ai/dsh-client-ui-sidebar": "0.2.
|
|
251
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.2.
|
|
252
|
-
"@deepseek-ai/dsh-client-ui-theme": "0.2.
|
|
253
|
-
"@deepseek-ai/dsh-client-ui-workspace": "0.2.
|
|
254
|
-
"@deepseek-ai/dsh-credentials": "0.2.
|
|
255
|
-
"@deepseek-ai/dsh-llm": "0.2.
|
|
256
|
-
"@deepseek-ai/dsh-ptc-runtime": "0.2.
|
|
257
|
-
"@deepseek-ai/dsh-sandbox": "0.2.
|
|
258
|
-
"@deepseek-ai/dsh-sandbox-policy": "0.2.
|
|
259
|
-
"@deepseek-ai/dsh-scope": "0.2.
|
|
260
|
-
"@deepseek-ai/dsh-session": "0.2.
|
|
261
|
-
"@deepseek-ai/dsh-settings": "0.2.
|
|
262
|
-
"@deepseek-ai/dsh-system-prompt": "0.2.
|
|
263
|
-
"@deepseek-ai/dsh-tools": "0.2.
|
|
264
|
-
"@deepseek-ai/dsh-user-approval": "0.2.
|
|
265
|
-
"@deepseek-ai/dsh-user-questions": "0.2.
|
|
266
|
-
"@deepseek-ai/dsh-workspace": "0.2.
|
|
270
|
+
"@deepseek-ai/cordis": "~4.1.0",
|
|
271
|
+
"@deepseek-ai/dsh-agent": "0.2.2-rc.1",
|
|
272
|
+
"@deepseek-ai/dsh-agent-default-model": "0.2.2-rc.1",
|
|
273
|
+
"@deepseek-ai/dsh-agent-preset-registry": "0.2.2-rc.1",
|
|
274
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.2-rc.1",
|
|
275
|
+
"@deepseek-ai/dsh-api-session-controller": "0.2.2-rc.1",
|
|
276
|
+
"@deepseek-ai/dsh-attachment": "0.2.2-rc.1",
|
|
277
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.2-rc.1",
|
|
278
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.2.2-rc.1",
|
|
279
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.2-rc.1",
|
|
280
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.2-rc.1",
|
|
281
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "0.2.2-rc.1",
|
|
282
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.2-rc.1",
|
|
283
|
+
"@deepseek-ai/dsh-client-ui-theme": "0.2.2-rc.1",
|
|
284
|
+
"@deepseek-ai/dsh-client-ui-workspace": "0.2.2-rc.1",
|
|
285
|
+
"@deepseek-ai/dsh-credentials": "0.2.2-rc.1",
|
|
286
|
+
"@deepseek-ai/dsh-llm": "0.2.2-rc.1",
|
|
287
|
+
"@deepseek-ai/dsh-ptc-runtime": "0.2.2-rc.1",
|
|
288
|
+
"@deepseek-ai/dsh-sandbox": "0.2.2-rc.1",
|
|
289
|
+
"@deepseek-ai/dsh-sandbox-policy": "0.2.2-rc.1",
|
|
290
|
+
"@deepseek-ai/dsh-scope": "0.2.2-rc.1",
|
|
291
|
+
"@deepseek-ai/dsh-session": "0.2.2-rc.1",
|
|
292
|
+
"@deepseek-ai/dsh-settings": "0.2.2-rc.1",
|
|
293
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.2-rc.1",
|
|
294
|
+
"@deepseek-ai/dsh-tools": "0.2.2-rc.1",
|
|
295
|
+
"@deepseek-ai/dsh-user-approval": "0.2.2-rc.1",
|
|
296
|
+
"@deepseek-ai/dsh-user-questions": "0.2.2-rc.1",
|
|
297
|
+
"@deepseek-ai/dsh-workspace": "0.2.2-rc.1",
|
|
267
298
|
"@dimforge/rapier3d-compat": "0.20.0",
|
|
268
299
|
"@hugeicons/core-free-icons": "^4.3.5",
|
|
269
300
|
"@hugeicons/react": "^1.1.10",
|
|
@@ -276,7 +307,9 @@
|
|
|
276
307
|
"react-dom": "18.3.1",
|
|
277
308
|
"three": "0.185.1",
|
|
278
309
|
"typescript": "^5.9.3",
|
|
279
|
-
"ws": "^8.22.0"
|
|
310
|
+
"ws": "^8.22.0",
|
|
311
|
+
"@deepseek-ai/dsh-tool-executor-native": "0.2.2-rc.1",
|
|
312
|
+
"@deepseek-ai/dsh-tool-executor-ptc": "0.2.2-rc.1"
|
|
280
313
|
},
|
|
281
314
|
"publishConfig": {
|
|
282
315
|
"access": "public"
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""Staged video submission. Playback APIs only return links; no downloads."""
|
|
2
|
+
import asyncio, json, os, re, shutil, time, uuid
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from urllib.parse import urlparse
|
|
5
|
+
from aiohttp import ClientSession, ClientTimeout, ClientError, web
|
|
6
|
+
from bilibili_api import video, video_uploader, dynamic
|
|
7
|
+
from bilibili_api.utils.picture import Picture
|
|
8
|
+
from bilibili_api.utils.network import Api, get_client, BiliAPIFile
|
|
9
|
+
|
|
10
|
+
HEADERS={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36','Referer':'https://www.bilibili.com/'}
|
|
11
|
+
MAX_FILE=512*1024*1024
|
|
12
|
+
try:
|
|
13
|
+
from imageio_ffmpeg import get_ffmpeg_exe
|
|
14
|
+
FFMPEG=get_ffmpeg_exe()
|
|
15
|
+
except ImportError:
|
|
16
|
+
FFMPEG='ffmpeg'
|
|
17
|
+
|
|
18
|
+
def media_url(url):
|
|
19
|
+
p=urlparse(url)
|
|
20
|
+
if p.scheme!='https' or p.username or p.password or p.port not in (None,443) or not any((p.hostname or '').endswith('.'+h) for h in ('bilivideo.com','bilivideo.cn','hdslb.com')):
|
|
21
|
+
raise ValueError('视频来源不受支持')
|
|
22
|
+
return url
|
|
23
|
+
|
|
24
|
+
class LocalPicture(Picture):
|
|
25
|
+
def __init__(self,path):
|
|
26
|
+
from PIL import Image
|
|
27
|
+
self.path=str(path)
|
|
28
|
+
with Image.open(path) as im:
|
|
29
|
+
if im.format not in ('PNG','JPEG','WEBP') or im.width*im.height>25000000:raise ValueError('图片格式或尺寸无效')
|
|
30
|
+
self.width,self.height=im.size;self.imageType={'PNG':'png','JPEG':'jpg','WEBP':'webp'}[im.format];self.mime=im.get_format_mimetype();im.verify()
|
|
31
|
+
self.content=Path(path).read_bytes();self.size=len(self.content)//1024;self.url='file://'+str(path)
|
|
32
|
+
def _to_biliapifile(self):
|
|
33
|
+
return BiliAPIFile(path=self.path,mime_type=self.mime)
|
|
34
|
+
|
|
35
|
+
class UploadRejected(ValueError):
|
|
36
|
+
def __init__(self, phase, status, payload=None):
|
|
37
|
+
payload=payload if isinstance(payload,dict) else {}
|
|
38
|
+
code=payload.get('code');code=code if isinstance(code,int) else None
|
|
39
|
+
limited=code==601 or status==429
|
|
40
|
+
self.details={'phase':phase,'httpStatus':status,'code':code,'rateLimited':limited}
|
|
41
|
+
# Fixed descriptions prevent secrets or attacker-controlled upstream text leaking.
|
|
42
|
+
message='平台提示上传过快,请稍作休息后再继续' if limited else '平台拒绝上传请求,请核实登录状态和创作中心提示'
|
|
43
|
+
super().__init__(f'{phase}失败:HTTP {status}'+(f',业务码 {code}' if code is not None else '')+';'+message)
|
|
44
|
+
|
|
45
|
+
def checked_response(response,phase):
|
|
46
|
+
try:data=response.json()
|
|
47
|
+
except Exception:data={}
|
|
48
|
+
if response.code>=400 or data.get('OK')==0 or isinstance(data.get('code'),int) and data['code']!=0:
|
|
49
|
+
raise UploadRejected(phase,response.code,data)
|
|
50
|
+
return data
|
|
51
|
+
|
|
52
|
+
class UploadOnly(video_uploader.VideoUploader):
|
|
53
|
+
async def _preupload(self,page):
|
|
54
|
+
# SDK 17.4.2 discards the body on HTTP errors. Keep bounded diagnostic fields.
|
|
55
|
+
client=get_client()
|
|
56
|
+
resp=await client.request(method='GET',url='https://member.bilibili.com/preupload',
|
|
57
|
+
params={'profile':'ugcfx/bup','name':os.path.basename(page.path),'size':page.get_size(),'r':self.line['os'],'ssl':'0','version':'2.14.0','build':'2100400','upcdn':self.line['upcdn'],'probe_version':self.line['probe_version']},
|
|
58
|
+
cookies=await self.credential.get_buvid_cookies(),headers=HEADERS)
|
|
59
|
+
data=checked_response(resp,'预上传')
|
|
60
|
+
if data.get('OK')!=1 or not all(k in data for k in ('auth','endpoint','upos_uri','chunk_size','biz_id')):raise ValueError('预上传返回缺少上传配置,未上传素材')
|
|
61
|
+
data=self._switch_upload_endpoint(data,self.line)
|
|
62
|
+
url=media_url(self._get_upload_url(data))
|
|
63
|
+
resp=await client.request(method='POST',url=url,headers={**HEADERS,'x-upos-auth':data['auth']},params={'uploads':'','output':'json','profile':'ugcfx/bup','filesize':page.get_size(),'partsize':data['chunk_size'],'biz_id':data['biz_id']})
|
|
64
|
+
result=checked_response(resp,'初始化分片')
|
|
65
|
+
if result.get('OK')!=1 or not result.get('upload_id'):raise ValueError('分片初始化未返回任务编号')
|
|
66
|
+
data['upload_id']=result['upload_id'];return data
|
|
67
|
+
async def _submit(self, videos, cover_url=''):
|
|
68
|
+
return {'videos':videos,'cover':cover_url}
|
|
69
|
+
|
|
70
|
+
class Media:
|
|
71
|
+
def __init__(self, root, credential):
|
|
72
|
+
self.root=root/'media';self.root.mkdir(exist_ok=True);self.credential=credential
|
|
73
|
+
self.tasks={};self.limit=asyncio.Semaphore(2)
|
|
74
|
+
for path in self.root.glob('*/*/job.json'):
|
|
75
|
+
try:
|
|
76
|
+
j=json.loads(path.read_text())
|
|
77
|
+
if j['status'] in ('queued','running','submitting'):
|
|
78
|
+
j.update(status='unknown' if j['status']=='submitting' else 'interrupted',message='服务重启,任务未自动重试;若已提交投稿请在创作中心核实');self.save(path.parent,j)
|
|
79
|
+
except (ValueError,KeyError,OSError):pass
|
|
80
|
+
def directory(self,channel,jid):
|
|
81
|
+
if not re.fullmatch(r'bilibili-[A-Za-z0-9-]{1,80}',channel) or not re.fullmatch(r'[a-f0-9]{32}',jid):raise ValueError('媒体任务 ID 无效')
|
|
82
|
+
return self.root/channel/jid
|
|
83
|
+
def save(self,d,j):
|
|
84
|
+
d.mkdir(parents=True,exist_ok=True);p=d/'job.tmp';p.write_text(json.dumps(j));os.chmod(p,0o600);os.replace(p,d/'job.json')
|
|
85
|
+
def load(self,channel,jid):
|
|
86
|
+
d=self.directory(channel,jid)
|
|
87
|
+
if not (d/'job.json').exists():raise ValueError('媒体任务不存在或不属于本渠道')
|
|
88
|
+
return d,json.loads((d/'job.json').read_text())
|
|
89
|
+
def cleanup(self):
|
|
90
|
+
for p in self.root.glob('*/*/job.json'):
|
|
91
|
+
if time.time()-p.stat().st_mtime>7*86400 and p.parent.name not in self.tasks:shutil.rmtree(p.parent,ignore_errors=True)
|
|
92
|
+
size=sum(p.stat().st_size for p in self.root.glob('*/*/*') if p.is_file())
|
|
93
|
+
if size>2*1024**3:raise ValueError('视频暂存空间已满,请清理旧任务后重试')
|
|
94
|
+
def public(self,j):
|
|
95
|
+
return {k:j[k] for k in ('id','operation','status','createdAt','title','message','bvid','page','size','mimeType','published','result','uid','phase','error','retryAt','dynamic_id') if k in j}
|
|
96
|
+
def cooldown(self,channel):
|
|
97
|
+
# Channel validation also prevents arbitrary filesystem reads.
|
|
98
|
+
self.directory(channel,'0'*32)
|
|
99
|
+
p=self.root/channel/'cooldown.json'
|
|
100
|
+
if p.exists():
|
|
101
|
+
data=json.loads(p.read_text())
|
|
102
|
+
if data.get('retryAt',0)>time.time():return data
|
|
103
|
+
return {}
|
|
104
|
+
def record_failure(self,channel,j,e):
|
|
105
|
+
details=getattr(e,'details',None)
|
|
106
|
+
j.update(status='failed',published=False,message=str(e)[:250] if isinstance(e,ValueError) else '媒体操作失败('+type(e).__name__+')',phase=j.get('phase','上传素材'))
|
|
107
|
+
if details:
|
|
108
|
+
j['error']=details;j['phase']=details['phase']
|
|
109
|
+
if details.get('rateLimited'):
|
|
110
|
+
j['retryAt']=time.time()+900
|
|
111
|
+
p=self.root/channel/'cooldown.json';tmp=p.with_suffix('.tmp');tmp.write_text(json.dumps({'retryAt':j['retryAt'],'reason':'平台上传限流;十五分钟为本地保护间隔,不保证届时平台已解除限制'}));os.chmod(tmp,0o600);os.replace(tmp,p)
|
|
112
|
+
async def stage(self,request):
|
|
113
|
+
channel=request.match_info['channel'];jid=uuid.uuid4().hex;d=self.directory(channel,jid);self.cleanup()
|
|
114
|
+
d.mkdir(parents=True,exist_ok=True)
|
|
115
|
+
total=0;names=set();images=request.path.startswith('/stage-images/')
|
|
116
|
+
try:
|
|
117
|
+
reader=await request.multipart()
|
|
118
|
+
while (field:=await reader.next()) is not None:
|
|
119
|
+
if (not re.fullmatch(r'image[0-8]',field.name or '') if images else field.name not in ('video','cover')) or field.name in names:raise ValueError('只接受按顺序编号的1–9张图片' if images else '只接受一个视频和一个封面')
|
|
120
|
+
names.add(field.name);size=0
|
|
121
|
+
with (d/field.name).open('wb') as out:
|
|
122
|
+
while chunk:=await field.read_chunk(65536):
|
|
123
|
+
size+=len(chunk);total+=len(chunk)
|
|
124
|
+
if size>(MAX_FILE if field.name=='video' else 8*1024**2):raise ValueError('每张图片上限 8 MB' if images else '视频上限 512 MB,封面上限 8 MB')
|
|
125
|
+
out.write(chunk)
|
|
126
|
+
if not size:raise ValueError('媒体文件为空')
|
|
127
|
+
if images:
|
|
128
|
+
if not names or names!={f'image{i}' for i in range(len(names))}:raise ValueError('漫画图片须为连续的 1–9 张')
|
|
129
|
+
from PIL import Image
|
|
130
|
+
for name in names:
|
|
131
|
+
with Image.open(d/name) as im:
|
|
132
|
+
if im.format not in ('PNG','JPEG','WEBP') or im.width*im.height>25000000:raise ValueError('漫画图片须为 PNG/JPEG/WebP,最多2500万像素')
|
|
133
|
+
im.verify()
|
|
134
|
+
elif names!={'video','cover'}:raise ValueError('投稿需要视频与封面文件')
|
|
135
|
+
j={'id':jid,'operation':'stage','status':'staged','createdAt':time.time(),'size':total,'imageCount':len(names) if images else 0};self.save(d,j)
|
|
136
|
+
return web.json_response({'stageId':jid})
|
|
137
|
+
except BaseException:
|
|
138
|
+
shutil.rmtree(d,ignore_errors=True);raise
|
|
139
|
+
async def probe(self,path):
|
|
140
|
+
proc=await asyncio.create_subprocess_exec(FFMPEG,'-nostdin','-v','error','-protocol_whitelist','file,pipe','-format_whitelist','mov,matroska,webm,avi,flv','-i',str(path),'-map','0:v:0','-frames:v','1','-f','null','-',stdout=asyncio.subprocess.DEVNULL,stderr=asyncio.subprocess.DEVNULL)
|
|
141
|
+
try:await asyncio.wait_for(proc.wait(),20)
|
|
142
|
+
except BaseException:proc.kill();await proc.wait();raise
|
|
143
|
+
if proc.returncode:raise ValueError('文件不是可读取的视频')
|
|
144
|
+
async def start(self,channel,op,p):
|
|
145
|
+
if op not in ('upload_draft','image_dynamic'):raise ValueError('不支持的上传操作')
|
|
146
|
+
cooling=self.cooldown(channel) if op=='upload_draft' else {}
|
|
147
|
+
if cooling:raise ValueError('B站上传限流冷却中,请勿立即重试;可用 upload_health 查询建议重试时间')
|
|
148
|
+
self.cleanup()
|
|
149
|
+
if any(x[0]==channel and not x[1].done() for x in self.tasks.values()):raise ValueError('本渠道已有媒体任务,请等待完成')
|
|
150
|
+
jid=p.get('stageId')
|
|
151
|
+
d=self.directory(channel,jid)
|
|
152
|
+
cred=self.credential(channel)
|
|
153
|
+
_,old=self.load(channel,jid)
|
|
154
|
+
if old['status']!='staged':raise ValueError('素材已使用,请查询原任务')
|
|
155
|
+
if op=='image_dynamic' and (not 1<=old.get('imageCount',0)<=9 or len(p.get('text',''))>2000):raise ValueError('漫画图片暂存无效或文字过长')
|
|
156
|
+
if op=='upload_draft':
|
|
157
|
+
_,old=self.load(channel,jid)
|
|
158
|
+
if old['status']!='staged':raise ValueError('素材已使用,请查询原任务')
|
|
159
|
+
await self.probe(d/'video')
|
|
160
|
+
from PIL import Image
|
|
161
|
+
with Image.open(d/'cover') as im:
|
|
162
|
+
if im.format not in ('PNG','JPEG','WEBP') or im.width*im.height>25000000:raise ValueError('封面需为 PNG/JPEG/WebP 图片,最多 2500 万像素')
|
|
163
|
+
if not str(p.get('title','')).strip() or not p.get('tags') or not isinstance(p.get('tid'),int):raise ValueError('缺少标题、标签或分区')
|
|
164
|
+
if p.get('copyright')==2 and not p.get('source'):raise ValueError('转载投稿需要来源')
|
|
165
|
+
j={'id':jid,'operation':op,'status':'queued','createdAt':time.time(),'published':False}
|
|
166
|
+
j.update(uid=str(cred.dedeuserid))
|
|
167
|
+
if op=='upload_draft':j.update(title=p['title'])
|
|
168
|
+
else:j.update(imageCount=old['imageCount'])
|
|
169
|
+
self.save(d,j)
|
|
170
|
+
task=asyncio.create_task(self.run(channel,d,j,p,cred) if op=='upload_draft' else self.run_images(channel,d,j,p,cred));self.tasks[jid]=(channel,task)
|
|
171
|
+
task.add_done_callback(lambda _:self.tasks.pop(jid,None))
|
|
172
|
+
return self.public(j)
|
|
173
|
+
async def run(self,channel,d,j,p,cred):
|
|
174
|
+
try:
|
|
175
|
+
async with self.limit:
|
|
176
|
+
j['status']='running';j['phase']='上传素材';self.save(d,j)
|
|
177
|
+
if not await cred.check_valid():raise ValueError('上传前登录失效,请重新登录')
|
|
178
|
+
meta={'title':p['title'],'desc':p.get('description',''),'tid':p['tid'],'tag':','.join(p['tags']),'copyright':p.get('copyright',1),'source':p.get('source',''),'no_reprint':1,'desc_format_id':0}
|
|
179
|
+
uploader=UploadOnly([video_uploader.VideoUploaderPage(str(d/'video'),p['title'])],meta,cred,cover=LocalPicture(d/'cover'))
|
|
180
|
+
uploaded=await asyncio.wait_for(uploader.start(),1800)
|
|
181
|
+
if not uploaded or not uploaded.get('videos'):raise ValueError('素材上传未完成')
|
|
182
|
+
j.update(status='draft',meta=meta,uploaded=uploaded,message='素材已上传,待投稿草稿保存在伙伴服务中;尚未提交 B 站审核,不是创作中心云草稿。')
|
|
183
|
+
except asyncio.CancelledError:
|
|
184
|
+
j.update(status='interrupted',message='任务已中断,未自动重试或投稿');raise
|
|
185
|
+
except Exception as e:
|
|
186
|
+
self.record_failure(channel,j,e)
|
|
187
|
+
finally:
|
|
188
|
+
for name in ('video','cover'):(d/name).unlink(missing_ok=True)
|
|
189
|
+
self.save(d,j)
|
|
190
|
+
async def run_images(self,channel,d,j,p,cred):
|
|
191
|
+
submitting=False
|
|
192
|
+
try:
|
|
193
|
+
async with self.limit:
|
|
194
|
+
j.update(status='running',phase='上传漫画图片');self.save(d,j)
|
|
195
|
+
if not await cred.check_valid():raise ValueError('登录失效,请重新扫码')
|
|
196
|
+
pics=[]
|
|
197
|
+
for index in range(j['imageCount']):
|
|
198
|
+
picture=LocalPicture(d/f'image{index}')
|
|
199
|
+
uploaded=await asyncio.wait_for(dynamic.upload_image(picture,cred),90)
|
|
200
|
+
image_url=uploaded.get('image_url','')
|
|
201
|
+
if image_url.startswith('http://'):image_url='https://'+image_url[7:]
|
|
202
|
+
media_url(image_url)
|
|
203
|
+
pics.append({'img_src':image_url,'img_width':picture.width,'img_height':picture.height})
|
|
204
|
+
# Same request shape as bilibili-api send_dynamic; upload first so a
|
|
205
|
+
# failure before this boundary is known not to have published anything.
|
|
206
|
+
info=dynamic.BuildDynamic.empty().add_plain_text(p.get('text',''))
|
|
207
|
+
data={'dyn_req':{'content':{'contents':await info.get_contents(credential=cred)},'scene':2,'meta':{'app_meta':{'from':'create.dynamic.web','mobi_app':'web'}},'pics':pics,'attach_card':None}}
|
|
208
|
+
if str(self.credential(channel).dedeuserid)!=str(cred.dedeuserid):raise ValueError('登录账号已变化,图片动态未发布')
|
|
209
|
+
j.update(status='submitting',phase='发布图片动态');self.save(d,j);submitting=True
|
|
210
|
+
result=await asyncio.wait_for(Api(**dynamic.API['send']['instant'],credential=cred,json_body=True).update_data(**data).update_params(csrf=cred.bili_jct).result,35)
|
|
211
|
+
did=str(result.get('dyn_id_str') or result.get('dynamic_id_str') or result.get('dynamic_id') or '')
|
|
212
|
+
if not did.isdigit() or int(did)<=0:raise ValueError('动态返回缺少编号,请核实账号动态,不要重复发布')
|
|
213
|
+
j.update(status='submitted',published=True,dynamic_id=did,result={'dynamic_id':did,'url':'https://t.bilibili.com/'+did},message='图片动态已提交,实际可见状态以B站为准')
|
|
214
|
+
except BaseException as e:
|
|
215
|
+
if submitting:j.update(status='unknown',message='图片动态提交结果不明,请查看账号动态,禁止自动重发')
|
|
216
|
+
elif isinstance(e,asyncio.CancelledError):j.update(status='interrupted',message='图片上传已中断,尚未发布')
|
|
217
|
+
else:self.record_failure(channel,j,e)
|
|
218
|
+
if isinstance(e,asyncio.CancelledError):raise
|
|
219
|
+
finally:
|
|
220
|
+
for file in d.glob('image[0-8]'):file.unlink(missing_ok=True)
|
|
221
|
+
self.save(d,j)
|
|
222
|
+
|
|
223
|
+
async def publish(self,channel,p):
|
|
224
|
+
d,j=self.load(channel,p['draft_id']);cred=self.credential(channel)
|
|
225
|
+
if j.get('uid')!=str(cred.dedeuserid):raise ValueError('草稿不属于当前登录账号')
|
|
226
|
+
if j['status']!='draft':raise ValueError('草稿未就绪或已提交,请查询原任务,不重复投稿')
|
|
227
|
+
if time.time()-j['createdAt']>7*86400:raise ValueError('草稿已过期,请重新上传')
|
|
228
|
+
j['status']='submitting';self.save(d,j)
|
|
229
|
+
try:
|
|
230
|
+
meta={**j['meta'],**j['uploaded'],'csrf':cred.bili_jct}
|
|
231
|
+
r=await Api(url='https://member.bilibili.com/x/vu/web/add/v3',method='POST',verify=True,credential=cred,no_csrf=True,json_body=True).update_params(csrf=cred.bili_jct,t=time.time()*1000).update_data(**meta).result
|
|
232
|
+
if not r or not r.get('bvid'):raise ValueError('投稿返回缺少 BV 号,请在创作中心核实')
|
|
233
|
+
j.update(status='submitted',published=True,result={'bvid':r['bvid'],'aid':str(r.get('aid',''))},message='投稿已提交,实际公开状态以 B 站审核为准')
|
|
234
|
+
except BaseException:
|
|
235
|
+
j.update(status='unknown',message='投稿结果不明,请在创作中心核实,不自动重发');raise
|
|
236
|
+
finally:self.save(d,j)
|
|
237
|
+
return self.public(j)
|
|
238
|
+
async def cancel(self,channel):
|
|
239
|
+
tasks=[t for owner,t in self.tasks.values() if owner==channel]
|
|
240
|
+
for t in tasks:t.cancel()
|
|
241
|
+
await asyncio.gather(*tasks,return_exceptions=True)
|
|
242
|
+
async def close(self,app):
|
|
243
|
+
tasks=[t for _,t in self.tasks.values()]
|
|
244
|
+
for t in tasks:t.cancel()
|
|
245
|
+
await asyncio.gather(*tasks,return_exceptions=True)
|