diff --git a/frontend/src/routes/targets/+page.svelte b/frontend/src/routes/targets/+page.svelte
index fe5d2e8..2fd5e43 100644
--- a/frontend/src/routes/targets/+page.svelte
+++ b/frontend/src/routes/targets/+page.svelte
@@ -23,7 +23,7 @@
let formType = $state<'telegram' | 'webhook'>('telegram');
const defaultForm = () => ({ name: '', icon: '', bot_id: 0, chat_id: '', bot_token: '', url: '', headers: '',
max_media_to_send: 50, max_media_per_group: 10, media_delay: 500, max_asset_size: 50,
- disable_url_preview: false, send_large_photos_as_documents: false, ai_captions: false, chat_action: '' });
+ disable_url_preview: false, send_large_photos_as_documents: false, ai_captions: false, chat_action: 'typing' });
let form = $state(defaultForm());
let error = $state('');
let headersError = $state('');
@@ -55,7 +55,7 @@
max_media_to_send: c.max_media_to_send ?? 50, max_media_per_group: c.max_media_per_group ?? 10,
media_delay: c.media_delay ?? 500, max_asset_size: c.max_asset_size ?? 50,
disable_url_preview: c.disable_url_preview ?? false, send_large_photos_as_documents: c.send_large_photos_as_documents ?? false,
- ai_captions: c.ai_captions ?? false, chat_action: c.chat_action ?? '',
+ ai_captions: c.ai_captions ?? false, chat_action: c.chat_action ?? 'typing',
};
editing = tgt.id; showTelegramSettings = false; showForm = true;
if (form.bot_id) await loadBotChats();
diff --git a/frontend/src/routes/template-configs/+page.svelte b/frontend/src/routes/template-configs/+page.svelte
index 43b75a9..07778f0 100644
--- a/frontend/src/routes/template-configs/+page.svelte
+++ b/frontend/src/routes/template-configs/+page.svelte
@@ -177,7 +177,7 @@
.replace(//g, '>')
// Restore allowed tags — only http(s) URLs for to prevent javascript: XSS
- .replace(/<a href="(https?:\/\/[^&]*)">/g, '')
+ .replace(/<a href="(https?:\/\/[^"]*)">/g, '')
.replace(/<\/a>/g, '')
.replace(/<b>/g, '').replace(/<\/b>/g, '')
.replace(/<i>/g, '').replace(/<\/i>/g, '')
diff --git a/packages/core/src/notify_bridge_core/templates/defaults/en/assets_added.jinja2 b/packages/core/src/notify_bridge_core/templates/defaults/en/assets_added.jinja2
index 3fa0b59..298fcf1 100644
--- a/packages/core/src/notify_bridge_core/templates/defaults/en/assets_added.jinja2
+++ b/packages/core/src/notify_bridge_core/templates/defaults/en/assets_added.jinja2
@@ -1,12 +1,9 @@
-📷 {{ added_count }} new photo(s) added to album {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
+📷 {{ added_count }} new file(s) added to album {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
{%- if common_date %} 📅 {{ common_date }}{% endif %}
{%- if common_location %} 📍 {{ common_location }}{% endif %}
{%- if people %}
👤 {{ people | join(", ") }}
{%- endif %}
-{%- if public_url %}
-🔗 Album URL
-{%- endif %}
{%- if added_assets %}
{%- for asset in added_assets %}
• {%- if asset.type == "VIDEO" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}{{ asset.filename }}{% else %}{{ asset.filename }}{% endif %}
diff --git a/packages/core/src/notify_bridge_core/templates/defaults/en/assets_removed.jinja2 b/packages/core/src/notify_bridge_core/templates/defaults/en/assets_removed.jinja2
index 7442811..faa5441 100644
--- a/packages/core/src/notify_bridge_core/templates/defaults/en/assets_removed.jinja2
+++ b/packages/core/src/notify_bridge_core/templates/defaults/en/assets_removed.jinja2
@@ -1 +1 @@
-🗑️ {{ removed_count }} photo(s) removed from album {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
\ No newline at end of file
+🗑️ {{ removed_count }} file(s) removed from album {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
\ No newline at end of file
diff --git a/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_added.jinja2 b/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_added.jinja2
index 2b30ee0..5abafb7 100644
--- a/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_added.jinja2
+++ b/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_added.jinja2
@@ -1,12 +1,9 @@
-📷 {{ added_count }} новых фото добавлено в альбом {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
+📷 {{ added_count }} новых файл(ов) добавлено в альбом {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
{%- if common_date %} 📅 {{ common_date }}{% endif %}
{%- if common_location %} 📍 {{ common_location }}{% endif %}
{%- if people %}
👤 {{ people | join(", ") }}
{%- endif %}
-{%- if public_url %}
-🔗 Ссылка на альбом
-{%- endif %}
{%- if added_assets %}
{%- for asset in added_assets %}
• {%- if asset.type == "VIDEO" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}{{ asset.filename }}{% else %}{{ asset.filename }}{% endif %}
diff --git a/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_removed.jinja2 b/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_removed.jinja2
index b0fb33f..3c2aaf2 100644
--- a/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_removed.jinja2
+++ b/packages/core/src/notify_bridge_core/templates/defaults/ru/assets_removed.jinja2
@@ -1 +1 @@
-🗑️ {{ removed_count }} фото удалено из альбома {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
\ No newline at end of file
+🗑️ {{ removed_count }} файл(ов) удалено из альбома {% if public_url %}{{ album_name }}{% else %}"{{ album_name }}"{% endif %}.
\ No newline at end of file
diff --git a/packages/server/src/notify_bridge_server/database/models.py b/packages/server/src/notify_bridge_server/database/models.py
index 8bfb945..1b1a317 100644
--- a/packages/server/src/notify_bridge_server/database/models.py
+++ b/packages/server/src/notify_bridge_server/database/models.py
@@ -164,7 +164,7 @@ class NotificationTarget(SQLModel, table=True):
name: str
icon: str = Field(default="")
config: dict[str, Any] = Field(default_factory=dict, sa_column=Column(JSON))
- chat_action: str | None = Field(default=None) # e.g. "typing", "upload_photo"
+ chat_action: str | None = Field(default="typing") # e.g. "typing", "upload_photo"
created_at: datetime = Field(default_factory=_utcnow)
diff --git a/packages/server/src/notify_bridge_server/main.py b/packages/server/src/notify_bridge_server/main.py
index 7e7d9f5..4bd1d78 100644
--- a/packages/server/src/notify_bridge_server/main.py
+++ b/packages/server/src/notify_bridge_server/main.py
@@ -78,7 +78,7 @@ async def health():
async def _seed_default_templates():
- """Seed default templates on first startup if none exist."""
+ """Seed or update default (system-owned) templates on startup."""
from sqlmodel import func, select
from sqlmodel.ext.asyncio.session import AsyncSession
from .database.engine import get_engine
@@ -89,22 +89,36 @@ async def _seed_default_templates():
async with AsyncSession(engine) as session:
result = await session.exec(select(func.count()).select_from(TemplateConfig))
count = result.one()
- if count > 0:
- return
- for locale in ("en", "ru"):
- slots = load_default_templates(locale)
- if not slots:
- continue
- name = f"Default ({locale.upper()})"
- config = TemplateConfig(
- user_id=0,
- provider_type="immich",
- name=name,
- description=f"Default Immich templates ({locale.upper()})",
- **slots,
+ if count == 0:
+ # First startup — seed all defaults
+ for locale in ("en", "ru"):
+ slots = load_default_templates(locale)
+ if not slots:
+ continue
+ name = f"Default ({locale.upper()})"
+ config = TemplateConfig(
+ user_id=0,
+ provider_type="immich",
+ name=name,
+ description=f"Default Immich templates ({locale.upper()})",
+ **slots,
+ )
+ session.add(config)
+ else:
+ # Update existing system-owned templates from files
+ result = await session.exec(
+ select(TemplateConfig).where(TemplateConfig.user_id == 0)
)
- session.add(config)
+ system_configs = result.all()
+ for config in system_configs:
+ locale = "ru" if "(RU)" in config.name else "en"
+ slots = load_default_templates(locale)
+ if not slots:
+ continue
+ for key, value in slots.items():
+ setattr(config, key, value)
+ session.add(config)
await session.commit()