Productivity features, UI translations, local email translation
- Snooze (with a Snoozed folder), keyboard shortcuts with a Settings section, mail templates (Compose > More > Templates), a Subscriptions folder with bulk unsubscribe/delete, and tracker blocking with a Privacy toggle (on by default) - Own dialogs instead of browser popups; emoji picker in compose; compose windows survive a visit to Settings - Sentence completion learned from the user's sent mail (no AI) - Interface in English and Polish (one file per language, English as the fallback), picked from the browser on first run, then kept - Email translation on the server via LibreTranslate: Translate button and "Translate to...", messages in several languages translated part by part, names/addresses/emoji/file names/phone numbers kept, an animated line while translating - Antispam "Mark as spam" loads with the message, not when the menu opens Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ from arq.worker import Worker
|
||||
from app.config import get_settings
|
||||
from app.indexer.gc import sweep_job
|
||||
from app.queue import QUEUE_BULK, QUEUE_INTERACTIVE, redis_settings
|
||||
from app.snooze import wake_due_job
|
||||
from app.sync.actions import autopurge_trash_spam
|
||||
from app.sync.coordinator import SyncCoordinator
|
||||
from workers.worker import BULK_FUNCTIONS, INTERACTIVE_FUNCTIONS
|
||||
@@ -34,7 +35,9 @@ from workers.worker import BULK_FUNCTIONS, INTERACTIVE_FUNCTIONS
|
||||
# Core scheduled jobs. Daily Trash/Spam retention purge at 03:17 (off-peak, and a
|
||||
# minute that won't collide with typical top-of-hour crons); then the clean-up of
|
||||
# stored files nothing uses any more (the purge's among them) at 03:47.
|
||||
# Snoozed conversations are checked every minute (cheap: a partial index).
|
||||
_CORE_CRON_JOBS = [
|
||||
cron(wake_due_job, second=5),
|
||||
cron(autopurge_trash_spam, hour=3, minute=17),
|
||||
cron(sweep_job, hour=3, minute=47, timeout=3600),
|
||||
]
|
||||
|
||||
@@ -14,10 +14,12 @@ from typing import Any
|
||||
|
||||
from arq import func
|
||||
|
||||
from app.completion import build_index_job
|
||||
from app.indexer.attachments import dedupe_existing_job
|
||||
from app.outbox.draft_sync import push_draft_to_imap_job, remove_imap_draft_job
|
||||
from app.outbox.jobs import file_sent_copy_job, send_job
|
||||
from app.push.service import push_new_mail_job
|
||||
from app.subscriptions import backfill_list_headers_job
|
||||
from app.sync.actions import (
|
||||
ACTION_MAX_TRIES,
|
||||
delete_thread_job,
|
||||
@@ -67,4 +69,11 @@ BULK_FUNCTIONS = [
|
||||
sync_bootstrap_account,
|
||||
# Resumable (each batch is saved), so a long first run may span timeouts.
|
||||
func(dedupe_existing_job, timeout=6 * 3600),
|
||||
# Batches are saved as they go, so a run cut short resumes where it stopped.
|
||||
# No stored result: its job id (one per user) must only block a second run
|
||||
# while one is queued or running — a kept result would refuse new scans for
|
||||
# an hour after each one.
|
||||
func(backfill_list_headers_job, timeout=6 * 3600, keep_result=0),
|
||||
# Sentence completion: one per user at a time, and none kept (as above).
|
||||
func(build_index_job, timeout=1800, keep_result=0),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user