telepost-bot 2.84.3__tar.gz → 2.84.4__tar.gz
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.
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/CHANGELOG.md +9 -0
- {telepost_bot-2.84.3/telepost_bot.egg-info → telepost_bot-2.84.4}/PKG-INFO +1 -1
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/publish.py +1 -1
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/delivery_planner.py +31 -3
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/build_info.py +1 -1
- {telepost_bot-2.84.3 → telepost_bot-2.84.4/telepost_bot.egg-info}/PKG-INFO +1 -1
- telepost_bot-2.84.4/tests/test_delivery_planner.py +210 -0
- telepost_bot-2.84.3/tests/test_delivery_planner.py +0 -112
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/LICENSE +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/MANIFEST.in +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/README.en.md +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/README.md +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/config/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/config/fly-telepost-policy.example.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/config/review_policy.md +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/config/settings.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/config.ini.example +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/database/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/database/db_manager.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/api_commands.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/automation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/botconfig.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/callback_handlers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/channel_listener.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/command_handlers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/conversation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/error_handler.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/index_handlers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/mode_selection.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/moderation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/preview_handlers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/reaction_stats.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/recovery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/review.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/schedule_status.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/search_handlers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/stats_handlers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/handlers/upload.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/main.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/mcp_server/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/mcp_server/review_client.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/mcp_server/server.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/models/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/models/state.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/SOURCES.sha256 +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/error-mapping.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/ackresult.candidate_search.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/capabilities.pixivflow.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/event.job.expired.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/event.job.succeeded.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/eventpage.candidate_search.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.cancelled.candidate_search.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.failed.no_candidate.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.queued.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.running.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.succeeded.candidate_search.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/jobpage.candidate_search.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/task.candidate_search.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/task.candidate_search.target_only.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/protocol.schema.json +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/pyproject.toml +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/run.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/services/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/services/review_service.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/setup.cfg +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/api/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/admin_ops.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/automation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/editorial.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/hot.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/novel_fallback_card.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/novel_preview.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/pixivflow_jobs.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/post_media.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/posts.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/publication.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/reaction_backfill.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/recovery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/refetch.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/rerender.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/resubmit.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/review_queue.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/submitter_notify.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/application/telepress_provider.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/automation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/delivery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/editorial.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/errors.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/hot.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/media.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/navigation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/novel_preview.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/packing.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/presentation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/presentation_policy.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/refetch_state.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/review.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/review_chat.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/domain/submission.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/miniapp/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/miniapp/auth.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/miniapp/rbac.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/miniapp/role_bindings.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/miniapp/session.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/observability/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/observability/audit.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/observability/cli.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/observability/doctor.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/observability/errors.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/observability/redact.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/automation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/columns.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/editorial.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/inbox.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/ledger.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/media_assets.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/moderation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/novel_preview.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/posts.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/protocol_events.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/recovery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/refetch.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/reviews.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/storage/sqlite/submitter_notifications.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/callback_feedback.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/capture.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/discussion.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/executor.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/gateway.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/legacy_runner.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/planner.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/preparation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/registry.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/delivery/sender.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/inbox_worker.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/review_expiry.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/review_keyboard.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/review_media.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost/telegram/review_stager.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost_bot.egg-info/SOURCES.txt +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost_bot.egg-info/dependency_links.txt +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost_bot.egg-info/entry_points.txt +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost_bot.egg-info/requires.txt +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/telepost_bot.egg-info/top_level.txt +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_admin_api.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_anonymous.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_api_commands.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_api_server.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_api_version.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_architecture_application.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_architecture_core.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_automation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_backfill_attribution.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_blacklist.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_bot_language.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_bot_token_logging.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_botconfig.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_boundary.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_callback_contract.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_caption_mentions.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_compatibility.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_config_encoding.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_console_encoding.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_conversation_flow.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_data_class_cleanup.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_database.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_database_first_start.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_database_operations.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_discussion_uncertainty.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_disposition.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_doctor.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_editorial.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_file_validator.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_fly_deploy_contract.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_frozen_support.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_handlers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_heat_calculator.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_helper_functions.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_hot_domain.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_identity_provenance.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_install_scripts.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_integration.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_legacy_delivery_port_navigation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_logic_flow.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_logical_submissions.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_maintenance_jobs.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_manager_notifications.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_media_decision_audit.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_media_delivery_pipeline.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_media_domain.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_media_preparation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_media_proxy_delivery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_menu_shortcut_single_reply.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_messages.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_miniapp_api.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_miniapp_auth.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_miniapp_content.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_miniapp_entries.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_miniapp_history.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_miniapp_rbac.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_mixed_media_integrity.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_moderation_and_admin_ux.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_navigation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_no_owner_probe.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_novel_cover_preview.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_novel_delivery_semantics.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_novel_preview.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_observability.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_observability_lifecycle.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_online_reading_root_button.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_packing_ssot.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_polling_server.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_preview_pagination.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_production_handler_graph.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_protocol_contract.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_publication_presentation.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_publish_idempotency.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_publish_regressions.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_publish_reply.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_reaction_backfill.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_reaction_stats.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_recovery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_refetch.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_refetch_card_state.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_refetch_events.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_refetch_job_lifecycle.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_refetch_reason_normalization.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_refetch_replacement.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_remote_fetch_fallback.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_rerender.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_resubmit.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_album_payload.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_card_recovery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_chat_contract.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_consistency.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_expiry_recovery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_http_mcp.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_media_lifecycle.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_review_service.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_robustness.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_run_dispatcher.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_run_mode.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_run_supervisor.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_schedule_outcomes.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_search_disabled_hint.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_search_recovery.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_security.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_security_headers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_session_database_handles.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_shutdown.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_streaming_uploads.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_submission_timeout_idempotency.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_telegram_golden_messages.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_telegram_media_cache.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_update_inbox.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_upload.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_user_friendly_messages.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_webhook_payload_admission.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_webhook_ready.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_webhook_router.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_webhook_secret.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_webhook_secret_logging.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_webhook_static.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/tests/test_work_id_wire.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/ui/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/ui/i18n.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/ui/keyboards.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/ui/locales/en/LC_MESSAGES/telepost.mo +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/ui/locales/en/LC_MESSAGES/telepost.po +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/ui/messages.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/api_server.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/api_tokens.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/blacklist.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/cache.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/config_wizard.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/console.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/database.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/file_validator.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/heat_calculator.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/helper_functions.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/index_manager.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/logging_config.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/maintenance_jobs.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/polling_server.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/run_mode.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/runtime_policy.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/schedule_watchdog.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/search_engine.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/security_headers.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/submission.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/utils/webhook_server.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/webapp/__init__.py +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/webapp/dist/assets/2d82b92e720462f8dd3b-Bh4Fahcw.svg +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/webapp/dist/assets/index-CLfkW8eZ.css +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/webapp/dist/assets/index-CfjBQN_e.js +0 -0
- {telepost_bot-2.84.3 → telepost_bot-2.84.4}/webapp/dist/index.html +0 -0
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
> 发布说明面向普通用户:写「对用户有什么改变」,不写内部实现细节(模块名、函数名、配置键);
|
|
9
9
|
> 技术细节放进代码注释或 `docs/`。每个 Release 的正文由本文件对应版本段自动生成。
|
|
10
10
|
|
|
11
|
+
## [2.84.4](https://github.com/redtidev1918/TelePost/compare/v2.84.3...v2.84.4) (2026-10-24)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* drop chain asset refs that belong to a different work ([f277843](https://github.com/redtidev1918/TelePost/commit/f2778430929694219321c49864ec10e6bd31e16e))
|
|
17
|
+
* keep staged media kind when chain assets downgrade to photo ([d6ae2d1](https://github.com/redtidev1918/TelePost/commit/d6ae2d1c3c316278c2364d98966802ebac841b39))
|
|
18
|
+
* plan replacement publications with the real staged media type ([59f0af9](https://github.com/redtidev1918/TelePost/commit/59f0af92b76c959ea653111674933db3a603e94f))
|
|
19
|
+
|
|
11
20
|
## [2.84.3](https://github.com/redtidev1918/TelePost/compare/v2.84.2...v2.84.3) (2026-10-24)
|
|
12
21
|
|
|
13
22
|
|
|
@@ -745,7 +745,7 @@ async def publish_from_file_ids(bot, media, documents, *, tags="", title="",
|
|
|
745
745
|
assets = [MediaAsset.coerce(a) for a in (media_assets or [])]
|
|
746
746
|
|
|
747
747
|
if assets:
|
|
748
|
-
plan = plan_review_media(media, assets, documents=documents)
|
|
748
|
+
plan = plan_review_media(media, assets, documents=documents, work_id=pid)
|
|
749
749
|
items = plan.to_media_items(spoiler=spoiler)
|
|
750
750
|
else:
|
|
751
751
|
items = _items_from_dicts([
|
|
@@ -111,6 +111,23 @@ def _asset_kind_to_media_kind(asset_kind: str) -> str:
|
|
|
111
111
|
return str(asset_kind).strip().lower()
|
|
112
112
|
|
|
113
113
|
|
|
114
|
+
def _asset_belongs_to_other_work(asset_id: str, work_id: str) -> bool:
|
|
115
|
+
"""True only for a ``pixiv:<work_id>:...`` ref whose work is NOT this one.
|
|
116
|
+
|
|
117
|
+
Unparseable / non-pixiv asset ids stay (conservative): filtering them would
|
|
118
|
+
silently drop legitimate uploads. A chain's refs are replaced per
|
|
119
|
+
submission, but a refetch replacement that arrives without its own asset
|
|
120
|
+
manifest leaves the SUPERSEDED work's refs on the chain — publishing must
|
|
121
|
+
never ship another work's pictures as this submission's content (review
|
|
122
|
+
208: a 4-page illustration refetch-replaced by a ugoira).
|
|
123
|
+
"""
|
|
124
|
+
parts = str(asset_id or "").split(":")
|
|
125
|
+
if len(parts) < 3 or parts[0] != "pixiv":
|
|
126
|
+
return False
|
|
127
|
+
ref_work = parts[1].strip()
|
|
128
|
+
return bool(ref_work) and bool(work_id) and ref_work != work_id
|
|
129
|
+
|
|
130
|
+
|
|
114
131
|
def _overall_strategy(entries: List[MediaPlanEntry]) -> str:
|
|
115
132
|
if not entries:
|
|
116
133
|
return "empty"
|
|
@@ -126,7 +143,8 @@ def _overall_strategy(entries: List[MediaPlanEntry]) -> str:
|
|
|
126
143
|
|
|
127
144
|
def plan_review_media(media: List[Dict[str, Any]],
|
|
128
145
|
media_assets: List[Dict[str, Any]],
|
|
129
|
-
*, documents: Optional[List[Dict[str, Any]]] = None
|
|
146
|
+
*, documents: Optional[List[Dict[str, Any]]] = None,
|
|
147
|
+
work_id: str = "") -> MediaDeliveryPlan:
|
|
130
148
|
"""Build a delivery plan from a review's local media + canonical asset refs.
|
|
131
149
|
|
|
132
150
|
``media`` / ``documents`` mirror the raw ``pending_reviews`` JSON arrays
|
|
@@ -137,8 +155,14 @@ def plan_review_media(media: List[Dict[str, Any]],
|
|
|
137
155
|
Positional pairing (same index) is used because PixivFlow manifests are
|
|
138
156
|
ordered and match the Telegram file list order; a mismatch can ONLY fall
|
|
139
157
|
back to ``remote_url`` and never produces a bogus file_id.
|
|
158
|
+
|
|
159
|
+
``work_id`` drops chain refs that provably belong to a DIFFERENT pixiv
|
|
160
|
+
work (a refetch replacement may leave the superseded work's refs behind).
|
|
140
161
|
"""
|
|
141
162
|
assets = [MediaAsset.coerce(a) for a in (media_assets or [])]
|
|
163
|
+
if work_id:
|
|
164
|
+
assets = [a for a in assets
|
|
165
|
+
if not _asset_belongs_to_other_work(a.asset_id, work_id)]
|
|
142
166
|
media_items = list(media or [])
|
|
143
167
|
document_items = list(documents or [])
|
|
144
168
|
local_items = media_items + document_items
|
|
@@ -182,8 +206,10 @@ def plan_review_media(media: List[Dict[str, Any]],
|
|
|
182
206
|
else:
|
|
183
207
|
local = local_items[index] if index < len(local_items) else None
|
|
184
208
|
# The indexed local item is authoritative for presentation: a Telegram
|
|
185
|
-
# TXT document must never be sent as a photo,
|
|
186
|
-
#
|
|
209
|
+
# TXT document must never be sent as a photo, and a staged animation /
|
|
210
|
+
# video / audio file_id must keep its real Telegram type even when the
|
|
211
|
+
# canonical asset ref (or a stale refetch-chain ref) says kind=image
|
|
212
|
+
# (review 208: sendPhoto on an animation file_id is a certain reject).
|
|
187
213
|
local_kind = (
|
|
188
214
|
str(local.get("type") or local.get("kind") or "")
|
|
189
215
|
.strip().lower().replace("-", "_")
|
|
@@ -198,6 +224,8 @@ def plan_review_media(media: List[Dict[str, Any]],
|
|
|
198
224
|
)
|
|
199
225
|
if is_document:
|
|
200
226
|
kind = MediaKind.DOCUMENT.value
|
|
227
|
+
elif local_kind:
|
|
228
|
+
kind = _asset_kind_to_media_kind(local_kind)
|
|
201
229
|
else:
|
|
202
230
|
kind = MediaKind.PHOTO.value
|
|
203
231
|
local_file_id = (str(local.get("file_id") or "").strip()
|
|
@@ -8,7 +8,7 @@ to the entry points; when present it overrides these committed defaults.
|
|
|
8
8
|
# Bumped automatically by release-please (extra-files in
|
|
9
9
|
# release-please-config.json). Release bundles and images override it at build
|
|
10
10
|
# time with the exact version/commit; this constant is the local-dev fallback.
|
|
11
|
-
RELEASE_VERSION = "2.84.
|
|
11
|
+
RELEASE_VERSION = "2.84.4" # x-release-please-version
|
|
12
12
|
RELEASE_COMMIT = "dev"
|
|
13
13
|
BUILD_DATE = "dev"
|
|
14
14
|
SERVICE = "telepost"
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""Step 11 DeliveryPlanner: TelePost decides how to deliver review media."""
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from telepost.application.delivery_planner import (
|
|
5
|
+
STRATEGY_FILE_ID,
|
|
6
|
+
STRATEGY_REMOTE_URL,
|
|
7
|
+
plan_review_media,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestPlanReviewMedia:
|
|
12
|
+
def test_no_assets_uses_local_file_ids(self):
|
|
13
|
+
plan = plan_review_media(
|
|
14
|
+
[{"type": "photo", "file_id": "AAA"}],
|
|
15
|
+
[],
|
|
16
|
+
)
|
|
17
|
+
assert plan.strategy == STRATEGY_FILE_ID
|
|
18
|
+
assert len(plan.entries) == 1
|
|
19
|
+
assert plan.entries[0].strategy == STRATEGY_FILE_ID
|
|
20
|
+
assert plan.entries[0].file_id == "AAA"
|
|
21
|
+
|
|
22
|
+
def test_asset_with_file_id_prefers_zero_reupload(self):
|
|
23
|
+
plan = plan_review_media(
|
|
24
|
+
[{"type": "photo", "file_id": "AAA"}],
|
|
25
|
+
[{"asset_id": "pixiv-1", "kind": "image",
|
|
26
|
+
"source_url": "https://i.pximg.net/1.jpg"}],
|
|
27
|
+
)
|
|
28
|
+
assert plan.strategy == STRATEGY_FILE_ID
|
|
29
|
+
assert plan.entries[0].strategy == STRATEGY_FILE_ID
|
|
30
|
+
assert plan.entries[0].asset_id == "pixiv-1"
|
|
31
|
+
|
|
32
|
+
def test_asset_without_file_id_falls_back_to_remote_url(self):
|
|
33
|
+
plan = plan_review_media(
|
|
34
|
+
[],
|
|
35
|
+
[{"asset_id": "pixiv-1", "kind": "image",
|
|
36
|
+
"source_url": "https://proxy.example/pixiv/1.jpg"}],
|
|
37
|
+
)
|
|
38
|
+
assert plan.strategy == STRATEGY_REMOTE_URL
|
|
39
|
+
assert plan.entries[0].strategy == STRATEGY_REMOTE_URL
|
|
40
|
+
assert plan.entries[0].source_url == "https://proxy.example/pixiv/1.jpg"
|
|
41
|
+
|
|
42
|
+
def test_mixed_plan(self):
|
|
43
|
+
plan = plan_review_media(
|
|
44
|
+
[{"type": "photo", "file_id": "AAA"}],
|
|
45
|
+
[
|
|
46
|
+
{"asset_id": "a1", "kind": "image", "source_url": "https://x/a"},
|
|
47
|
+
{"asset_id": "a2", "kind": "image", "source_url": "https://x/b"},
|
|
48
|
+
],
|
|
49
|
+
)
|
|
50
|
+
assert plan.strategy == "mixed"
|
|
51
|
+
strategies = [e.strategy for e in plan.entries]
|
|
52
|
+
assert strategies == [STRATEGY_FILE_ID, STRATEGY_REMOTE_URL]
|
|
53
|
+
|
|
54
|
+
def test_stale_chain_asset_never_downgrades_local_animation_to_photo(self):
|
|
55
|
+
"""Regression (review 208): a refetch replacement staged an animation
|
|
56
|
+
file_id while the chain's media_asset_refs still declared the OLD
|
|
57
|
+
multi-page work as kind=image. The indexed local item is authoritative:
|
|
58
|
+
sendPhoto on an animation file_id is a certain Telegram reject."""
|
|
59
|
+
plan = plan_review_media(
|
|
60
|
+
[{"type": "animation", "file_id": "UGOIRA_FID"}],
|
|
61
|
+
[
|
|
62
|
+
{"asset_id": "pixiv:1:illust:page-1", "kind": "image",
|
|
63
|
+
"source_url": "https://x/1"},
|
|
64
|
+
{"asset_id": "pixiv:1:illust:page-2", "kind": "image",
|
|
65
|
+
"source_url": "https://x/2"},
|
|
66
|
+
],
|
|
67
|
+
)
|
|
68
|
+
assert plan.entries[0].kind == "animation"
|
|
69
|
+
assert plan.entries[0].strategy == STRATEGY_FILE_ID
|
|
70
|
+
assert plan.entries[0].file_id == "UGOIRA_FID"
|
|
71
|
+
# The asset-only tail keeps the documented remote fallback.
|
|
72
|
+
assert plan.entries[1].kind == "photo"
|
|
73
|
+
assert plan.entries[1].strategy == STRATEGY_REMOTE_URL
|
|
74
|
+
|
|
75
|
+
def test_local_video_and_audio_keep_their_kind_with_image_assets(self):
|
|
76
|
+
plan = plan_review_media(
|
|
77
|
+
[
|
|
78
|
+
{"type": "video", "file_id": "VID"},
|
|
79
|
+
{"type": "audio", "file_id": "AUD"},
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
{"asset_id": "a1", "kind": "image", "source_url": "https://x/1"},
|
|
83
|
+
{"asset_id": "a2", "kind": "image", "source_url": "https://x/2"},
|
|
84
|
+
],
|
|
85
|
+
)
|
|
86
|
+
assert [e.kind for e in plan.entries] == ["video", "audio"]
|
|
87
|
+
assert all(e.file_id for e in plan.entries)
|
|
88
|
+
|
|
89
|
+
def test_foreign_work_refs_are_dropped_from_the_plan(self):
|
|
90
|
+
"""Regression (review 208): a ugoira refetch-replaced a 4-page
|
|
91
|
+
illustration; the chain kept the OLD work's pixiv refs. With work_id
|
|
92
|
+
the plan must contain ONLY this work's staged animation — never the
|
|
93
|
+
superseded work's pages as remote photos."""
|
|
94
|
+
plan = plan_review_media(
|
|
95
|
+
[{"type": "animation", "file_id": "UGOIRA_FID"}],
|
|
96
|
+
[
|
|
97
|
+
{"asset_id": "pixiv:151182115:illust:page-1", "kind": "image",
|
|
98
|
+
"source_url": "https://x/1"},
|
|
99
|
+
{"asset_id": "pixiv:151182115:illust:page-2", "kind": "image",
|
|
100
|
+
"source_url": "https://x/2"},
|
|
101
|
+
{"asset_id": "pixiv:151182115:illust:page-3", "kind": "image",
|
|
102
|
+
"source_url": "https://x/3"},
|
|
103
|
+
{"asset_id": "pixiv:151182115:illust:page-4", "kind": "image",
|
|
104
|
+
"source_url": "https://x/4"},
|
|
105
|
+
],
|
|
106
|
+
work_id="151190970",
|
|
107
|
+
)
|
|
108
|
+
assert len(plan.entries) == 1
|
|
109
|
+
entry = plan.entries[0]
|
|
110
|
+
assert entry.kind == "animation"
|
|
111
|
+
assert entry.strategy == STRATEGY_FILE_ID
|
|
112
|
+
assert entry.file_id == "UGOIRA_FID"
|
|
113
|
+
|
|
114
|
+
def test_same_work_and_non_pixiv_refs_survive_the_filter(self):
|
|
115
|
+
plan = plan_review_media(
|
|
116
|
+
[{"type": "document", "file_id": "TXT"}],
|
|
117
|
+
[
|
|
118
|
+
{"asset_id": "pixiv:29430449:novelcover", "kind": "image",
|
|
119
|
+
"source_url": "https://x/cover"},
|
|
120
|
+
{"asset_id": "uploadedimage:abc", "kind": "image",
|
|
121
|
+
"source_url": "https://x/up"},
|
|
122
|
+
{"asset_id": "pixiv:29430449:illust:page-1", "kind": "image",
|
|
123
|
+
"source_url": "https://x/1"},
|
|
124
|
+
],
|
|
125
|
+
work_id="29430449",
|
|
126
|
+
)
|
|
127
|
+
kinds = [e.kind for e in plan.entries]
|
|
128
|
+
# same-work cover + upload pair first, TXT document keeps its slot.
|
|
129
|
+
assert "photo" in kinds and "document" in kinds
|
|
130
|
+
assert not any(e.asset_id and e.asset_id.startswith("pixiv:999") for e in plan.entries)
|
|
131
|
+
|
|
132
|
+
def test_no_work_id_keeps_legacy_unfiltered_behavior(self):
|
|
133
|
+
plan = plan_review_media(
|
|
134
|
+
[{"type": "animation", "file_id": "UGOIRA_FID"}],
|
|
135
|
+
[
|
|
136
|
+
{"asset_id": "pixiv:151182115:illust:page-1", "kind": "image",
|
|
137
|
+
"source_url": "https://x/1"},
|
|
138
|
+
{"asset_id": "pixiv:151182115:illust:page-2", "kind": "image",
|
|
139
|
+
"source_url": "https://x/2"},
|
|
140
|
+
],
|
|
141
|
+
)
|
|
142
|
+
assert [e.kind for e in plan.entries] == ["animation", "photo"]
|
|
143
|
+
assert plan.entries[1].strategy == STRATEGY_REMOTE_URL
|
|
144
|
+
|
|
145
|
+
def test_local_photo_stays_photo_with_image_asset(self):
|
|
146
|
+
plan = plan_review_media(
|
|
147
|
+
[{"type": "photo", "file_id": "AAA"}],
|
|
148
|
+
[{"asset_id": "a1", "kind": "image", "source_url": "https://x/a"}],
|
|
149
|
+
)
|
|
150
|
+
assert plan.entries[0].kind == "photo"
|
|
151
|
+
|
|
152
|
+
def test_indexed_document_is_not_photo(self):
|
|
153
|
+
"""Regression: novel cover assets + indexed TXT file_id."""
|
|
154
|
+
plan = plan_review_media(
|
|
155
|
+
[],
|
|
156
|
+
[
|
|
157
|
+
{"asset_id": "a1", "kind": "image",
|
|
158
|
+
"source_url": "https://x/a"},
|
|
159
|
+
{"asset_id": "txt", "kind": "image",
|
|
160
|
+
"source_url": "https://x/txt"},
|
|
161
|
+
],
|
|
162
|
+
documents=[{"file_id": "DDD", "filename": "novel.txt"}],
|
|
163
|
+
)
|
|
164
|
+
assert [e.kind for e in plan.entries] == ["photo", "document"]
|
|
165
|
+
assert plan.strategy == "mixed"
|
|
166
|
+
items = plan.to_media_items()
|
|
167
|
+
assert items[0].kind.value == "photo"
|
|
168
|
+
assert items[1].kind.value == "document"
|
|
169
|
+
assert items[1].telegram_file_id == "DDD"
|
|
170
|
+
|
|
171
|
+
def test_single_cover_asset_pairs_with_indexed_txt_document(self):
|
|
172
|
+
"""Regression: a novel with one cover asset and one TXT must not plan
|
|
173
|
+
the TXT as a photo; that made novel_images_preview_only remove every
|
|
174
|
+
item and the publication failed with "delivery returned no messages"."""
|
|
175
|
+
plan = plan_review_media(
|
|
176
|
+
[],
|
|
177
|
+
[{"asset_id": "cover", "kind": "image",
|
|
178
|
+
"source_url": "https://i.pximg.net/cover.png"}],
|
|
179
|
+
documents=[{"file_id": "TXT_FILE_ID", "filename": "novel.txt"}],
|
|
180
|
+
)
|
|
181
|
+
assert [e.kind for e in plan.entries] == ["document"]
|
|
182
|
+
assert [e.strategy for e in plan.entries] == [STRATEGY_FILE_ID]
|
|
183
|
+
assert plan.entries[0].file_id == "TXT_FILE_ID"
|
|
184
|
+
assert plan.entries[0].filename == "novel.txt"
|
|
185
|
+
|
|
186
|
+
def test_leftover_document_keeps_file_id(self):
|
|
187
|
+
plan = plan_review_media(
|
|
188
|
+
[{"type": "photo", "file_id": "AAA"}],
|
|
189
|
+
[{"asset_id": "a1", "kind": "image", "source_url": "https://x/a"}],
|
|
190
|
+
documents=[{"file_id": "DDD", "filename": "novel.txt"}],
|
|
191
|
+
)
|
|
192
|
+
assert [e.kind for e in plan.entries] == ["photo", "document"]
|
|
193
|
+
assert [e.strategy for e in plan.entries] == [STRATEGY_FILE_ID, STRATEGY_FILE_ID]
|
|
194
|
+
assert plan.entries[1].file_id == "DDD"
|
|
195
|
+
|
|
196
|
+
def test_empty_plan(self):
|
|
197
|
+
plan = plan_review_media([], [])
|
|
198
|
+
assert plan.strategy == "empty"
|
|
199
|
+
assert plan.to_media_items() == []
|
|
200
|
+
|
|
201
|
+
def test_to_media_items(self):
|
|
202
|
+
plan = plan_review_media(
|
|
203
|
+
[],
|
|
204
|
+
[{"asset_id": "a1", "kind": "image",
|
|
205
|
+
"source_url": "https://proxy.example/pixiv/1.jpg"}],
|
|
206
|
+
)
|
|
207
|
+
items = plan.to_media_items()
|
|
208
|
+
assert len(items) == 1
|
|
209
|
+
assert items[0].source.url == "https://proxy.example/pixiv/1.jpg"
|
|
210
|
+
assert items[0].telegram_file_id is None
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"""Step 11 DeliveryPlanner: TelePost decides how to deliver review media."""
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
|
-
from telepost.application.delivery_planner import (
|
|
5
|
-
STRATEGY_FILE_ID,
|
|
6
|
-
STRATEGY_REMOTE_URL,
|
|
7
|
-
plan_review_media,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class TestPlanReviewMedia:
|
|
12
|
-
def test_no_assets_uses_local_file_ids(self):
|
|
13
|
-
plan = plan_review_media(
|
|
14
|
-
[{"type": "photo", "file_id": "AAA"}],
|
|
15
|
-
[],
|
|
16
|
-
)
|
|
17
|
-
assert plan.strategy == STRATEGY_FILE_ID
|
|
18
|
-
assert len(plan.entries) == 1
|
|
19
|
-
assert plan.entries[0].strategy == STRATEGY_FILE_ID
|
|
20
|
-
assert plan.entries[0].file_id == "AAA"
|
|
21
|
-
|
|
22
|
-
def test_asset_with_file_id_prefers_zero_reupload(self):
|
|
23
|
-
plan = plan_review_media(
|
|
24
|
-
[{"type": "photo", "file_id": "AAA"}],
|
|
25
|
-
[{"asset_id": "pixiv-1", "kind": "image",
|
|
26
|
-
"source_url": "https://i.pximg.net/1.jpg"}],
|
|
27
|
-
)
|
|
28
|
-
assert plan.strategy == STRATEGY_FILE_ID
|
|
29
|
-
assert plan.entries[0].strategy == STRATEGY_FILE_ID
|
|
30
|
-
assert plan.entries[0].asset_id == "pixiv-1"
|
|
31
|
-
|
|
32
|
-
def test_asset_without_file_id_falls_back_to_remote_url(self):
|
|
33
|
-
plan = plan_review_media(
|
|
34
|
-
[],
|
|
35
|
-
[{"asset_id": "pixiv-1", "kind": "image",
|
|
36
|
-
"source_url": "https://proxy.example/pixiv/1.jpg"}],
|
|
37
|
-
)
|
|
38
|
-
assert plan.strategy == STRATEGY_REMOTE_URL
|
|
39
|
-
assert plan.entries[0].strategy == STRATEGY_REMOTE_URL
|
|
40
|
-
assert plan.entries[0].source_url == "https://proxy.example/pixiv/1.jpg"
|
|
41
|
-
|
|
42
|
-
def test_mixed_plan(self):
|
|
43
|
-
plan = plan_review_media(
|
|
44
|
-
[{"type": "photo", "file_id": "AAA"}],
|
|
45
|
-
[
|
|
46
|
-
{"asset_id": "a1", "kind": "image", "source_url": "https://x/a"},
|
|
47
|
-
{"asset_id": "a2", "kind": "image", "source_url": "https://x/b"},
|
|
48
|
-
],
|
|
49
|
-
)
|
|
50
|
-
assert plan.strategy == "mixed"
|
|
51
|
-
strategies = [e.strategy for e in plan.entries]
|
|
52
|
-
assert strategies == [STRATEGY_FILE_ID, STRATEGY_REMOTE_URL]
|
|
53
|
-
|
|
54
|
-
def test_indexed_document_is_not_photo(self):
|
|
55
|
-
"""Regression: novel cover assets + indexed TXT file_id."""
|
|
56
|
-
plan = plan_review_media(
|
|
57
|
-
[],
|
|
58
|
-
[
|
|
59
|
-
{"asset_id": "a1", "kind": "image",
|
|
60
|
-
"source_url": "https://x/a"},
|
|
61
|
-
{"asset_id": "txt", "kind": "image",
|
|
62
|
-
"source_url": "https://x/txt"},
|
|
63
|
-
],
|
|
64
|
-
documents=[{"file_id": "DDD", "filename": "novel.txt"}],
|
|
65
|
-
)
|
|
66
|
-
assert [e.kind for e in plan.entries] == ["photo", "document"]
|
|
67
|
-
assert plan.strategy == "mixed"
|
|
68
|
-
items = plan.to_media_items()
|
|
69
|
-
assert items[0].kind.value == "photo"
|
|
70
|
-
assert items[1].kind.value == "document"
|
|
71
|
-
assert items[1].telegram_file_id == "DDD"
|
|
72
|
-
|
|
73
|
-
def test_single_cover_asset_pairs_with_indexed_txt_document(self):
|
|
74
|
-
"""Regression: a novel with one cover asset and one TXT must not plan
|
|
75
|
-
the TXT as a photo; that made novel_images_preview_only remove every
|
|
76
|
-
item and the publication failed with "delivery returned no messages"."""
|
|
77
|
-
plan = plan_review_media(
|
|
78
|
-
[],
|
|
79
|
-
[{"asset_id": "cover", "kind": "image",
|
|
80
|
-
"source_url": "https://i.pximg.net/cover.png"}],
|
|
81
|
-
documents=[{"file_id": "TXT_FILE_ID", "filename": "novel.txt"}],
|
|
82
|
-
)
|
|
83
|
-
assert [e.kind for e in plan.entries] == ["document"]
|
|
84
|
-
assert [e.strategy for e in plan.entries] == [STRATEGY_FILE_ID]
|
|
85
|
-
assert plan.entries[0].file_id == "TXT_FILE_ID"
|
|
86
|
-
assert plan.entries[0].filename == "novel.txt"
|
|
87
|
-
|
|
88
|
-
def test_leftover_document_keeps_file_id(self):
|
|
89
|
-
plan = plan_review_media(
|
|
90
|
-
[{"type": "photo", "file_id": "AAA"}],
|
|
91
|
-
[{"asset_id": "a1", "kind": "image", "source_url": "https://x/a"}],
|
|
92
|
-
documents=[{"file_id": "DDD", "filename": "novel.txt"}],
|
|
93
|
-
)
|
|
94
|
-
assert [e.kind for e in plan.entries] == ["photo", "document"]
|
|
95
|
-
assert [e.strategy for e in plan.entries] == [STRATEGY_FILE_ID, STRATEGY_FILE_ID]
|
|
96
|
-
assert plan.entries[1].file_id == "DDD"
|
|
97
|
-
|
|
98
|
-
def test_empty_plan(self):
|
|
99
|
-
plan = plan_review_media([], [])
|
|
100
|
-
assert plan.strategy == "empty"
|
|
101
|
-
assert plan.to_media_items() == []
|
|
102
|
-
|
|
103
|
-
def test_to_media_items(self):
|
|
104
|
-
plan = plan_review_media(
|
|
105
|
-
[],
|
|
106
|
-
[{"asset_id": "a1", "kind": "image",
|
|
107
|
-
"source_url": "https://proxy.example/pixiv/1.jpg"}],
|
|
108
|
-
)
|
|
109
|
-
items = plan.to_media_items()
|
|
110
|
-
assert len(items) == 1
|
|
111
|
-
assert items[0].source.url == "https://proxy.example/pixiv/1.jpg"
|
|
112
|
-
assert items[0].telegram_file_id is None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/ackresult.candidate_search.json
RENAMED
|
File without changes
|
{telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/capabilities.pixivflow.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/eventpage.candidate_search.json
RENAMED
|
File without changes
|
{telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.cancelled.candidate_search.json
RENAMED
|
File without changes
|
{telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.failed.no_candidate.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/job.succeeded.candidate_search.json
RENAMED
|
File without changes
|
{telepost_bot-2.84.3 → telepost_bot-2.84.4}/protocol/v1/fixtures/jobpage.candidate_search.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|