karaoke-gen 0.101.0__py3-none-any.whl → 0.103.1__py3-none-any.whl
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.
- backend/api/routes/audio_search.py +4 -32
- backend/api/routes/file_upload.py +18 -83
- backend/api/routes/jobs.py +2 -2
- backend/api/routes/rate_limits.py +428 -0
- backend/api/routes/users.py +79 -19
- backend/config.py +16 -0
- backend/exceptions.py +66 -0
- backend/main.py +25 -1
- backend/services/email_validation_service.py +646 -0
- backend/services/firestore_service.py +21 -0
- backend/services/job_defaults_service.py +113 -0
- backend/services/job_manager.py +41 -2
- backend/services/rate_limit_service.py +641 -0
- backend/tests/conftest.py +7 -1
- backend/tests/test_audio_search.py +12 -8
- backend/tests/test_email_validation_service.py +298 -0
- backend/tests/test_file_upload.py +8 -6
- backend/tests/test_made_for_you.py +6 -4
- backend/tests/test_rate_limit_service.py +396 -0
- backend/tests/test_rate_limits_api.py +392 -0
- backend/workers/video_worker_orchestrator.py +26 -0
- {karaoke_gen-0.101.0.dist-info → karaoke_gen-0.103.1.dist-info}/METADATA +1 -1
- {karaoke_gen-0.101.0.dist-info → karaoke_gen-0.103.1.dist-info}/RECORD +26 -18
- {karaoke_gen-0.101.0.dist-info → karaoke_gen-0.103.1.dist-info}/WHEEL +0 -0
- {karaoke_gen-0.101.0.dist-info → karaoke_gen-0.103.1.dist-info}/entry_points.txt +0 -0
- {karaoke_gen-0.101.0.dist-info → karaoke_gen-0.103.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,7 +15,7 @@ import asyncio
|
|
|
15
15
|
import logging
|
|
16
16
|
import os
|
|
17
17
|
import tempfile
|
|
18
|
-
from typing import Optional, List, Dict, Any
|
|
18
|
+
from typing import Optional, List, Dict, Any
|
|
19
19
|
|
|
20
20
|
from fastapi import APIRouter, HTTPException, BackgroundTasks, Request, Depends
|
|
21
21
|
from pydantic import BaseModel, Field, validator
|
|
@@ -34,6 +34,7 @@ from backend.services.audio_search_service import (
|
|
|
34
34
|
DownloadError,
|
|
35
35
|
)
|
|
36
36
|
from backend.services.theme_service import get_theme_service
|
|
37
|
+
from backend.services.job_defaults_service import resolve_cdg_txt_defaults
|
|
37
38
|
from backend.config import get_settings
|
|
38
39
|
from backend.version import VERSION
|
|
39
40
|
from backend.api.dependencies import require_auth
|
|
@@ -201,35 +202,6 @@ class AudioSelectResponse(BaseModel):
|
|
|
201
202
|
selected_provider: str
|
|
202
203
|
|
|
203
204
|
|
|
204
|
-
def _resolve_cdg_txt_defaults(
|
|
205
|
-
theme_id: Optional[str],
|
|
206
|
-
enable_cdg: Optional[bool],
|
|
207
|
-
enable_txt: Optional[bool]
|
|
208
|
-
) -> Tuple[bool, bool]:
|
|
209
|
-
"""
|
|
210
|
-
Resolve CDG/TXT settings based on theme and explicit settings.
|
|
211
|
-
|
|
212
|
-
When a theme is selected, CDG and TXT are enabled by default.
|
|
213
|
-
Explicit True/False values always override the default.
|
|
214
|
-
|
|
215
|
-
Args:
|
|
216
|
-
theme_id: Theme identifier (if any)
|
|
217
|
-
enable_cdg: Explicit CDG setting (None means use default)
|
|
218
|
-
enable_txt: Explicit TXT setting (None means use default)
|
|
219
|
-
|
|
220
|
-
Returns:
|
|
221
|
-
Tuple of (resolved_enable_cdg, resolved_enable_txt)
|
|
222
|
-
"""
|
|
223
|
-
# Default based on whether theme is set
|
|
224
|
-
default_enabled = theme_id is not None
|
|
225
|
-
|
|
226
|
-
# Explicit values override defaults, None uses default
|
|
227
|
-
resolved_cdg = enable_cdg if enable_cdg is not None else default_enabled
|
|
228
|
-
resolved_txt = enable_txt if enable_txt is not None else default_enabled
|
|
229
|
-
|
|
230
|
-
return resolved_cdg, resolved_txt
|
|
231
|
-
|
|
232
|
-
|
|
233
205
|
def extract_request_metadata(request: Request, created_from: str = "audio_search") -> Dict[str, Any]:
|
|
234
206
|
"""Extract metadata from request for job tracking."""
|
|
235
207
|
headers = dict(request.headers)
|
|
@@ -554,7 +526,7 @@ async def search_audio(
|
|
|
554
526
|
logger.info(f"Applying default theme: {effective_theme_id}")
|
|
555
527
|
|
|
556
528
|
# Resolve CDG/TXT defaults based on theme
|
|
557
|
-
resolved_cdg, resolved_txt =
|
|
529
|
+
resolved_cdg, resolved_txt = resolve_cdg_txt_defaults(
|
|
558
530
|
effective_theme_id, body.enable_cdg, body.enable_txt
|
|
559
531
|
)
|
|
560
532
|
|
|
@@ -597,7 +569,7 @@ async def search_audio(
|
|
|
597
569
|
# Tenant scoping
|
|
598
570
|
tenant_id=tenant_config.id if tenant_config else None,
|
|
599
571
|
)
|
|
600
|
-
job = job_manager.create_job(job_create)
|
|
572
|
+
job = job_manager.create_job(job_create, is_admin=auth_result.is_admin)
|
|
601
573
|
job_id = job.job_id
|
|
602
574
|
|
|
603
575
|
logger.info(f"Created job {job_id} for audio search: {body.artist} - {body.title}")
|
|
@@ -15,7 +15,6 @@ import json
|
|
|
15
15
|
import logging
|
|
16
16
|
import tempfile
|
|
17
17
|
import os
|
|
18
|
-
from dataclasses import dataclass
|
|
19
18
|
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, BackgroundTasks, Request, Body, Depends
|
|
20
19
|
from pathlib import Path
|
|
21
20
|
from typing import Optional, List, Dict, Any, Tuple
|
|
@@ -29,6 +28,11 @@ from backend.services.storage_service import StorageService
|
|
|
29
28
|
from backend.services.worker_service import get_worker_service
|
|
30
29
|
from backend.services.credential_manager import get_credential_manager, CredentialStatus
|
|
31
30
|
from backend.services.theme_service import get_theme_service
|
|
31
|
+
from backend.services.job_defaults_service import (
|
|
32
|
+
get_effective_distribution_settings,
|
|
33
|
+
resolve_cdg_txt_defaults,
|
|
34
|
+
EffectiveDistributionSettings,
|
|
35
|
+
)
|
|
32
36
|
from backend.config import get_settings
|
|
33
37
|
from backend.version import VERSION
|
|
34
38
|
from backend.services.metrics import metrics
|
|
@@ -264,75 +268,6 @@ async def _trigger_audio_worker_only(job_id: str) -> None:
|
|
|
264
268
|
await worker_service.trigger_audio_worker(job_id)
|
|
265
269
|
|
|
266
270
|
|
|
267
|
-
def _resolve_cdg_txt_defaults(
|
|
268
|
-
theme_id: Optional[str],
|
|
269
|
-
enable_cdg: Optional[bool],
|
|
270
|
-
enable_txt: Optional[bool]
|
|
271
|
-
) -> Tuple[bool, bool]:
|
|
272
|
-
"""
|
|
273
|
-
Resolve CDG/TXT settings based on theme and explicit settings.
|
|
274
|
-
|
|
275
|
-
When a theme is selected, CDG and TXT are enabled by default.
|
|
276
|
-
Explicit True/False values always override the default.
|
|
277
|
-
|
|
278
|
-
Args:
|
|
279
|
-
theme_id: Theme identifier (if any)
|
|
280
|
-
enable_cdg: Explicit CDG setting (None means use default)
|
|
281
|
-
enable_txt: Explicit TXT setting (None means use default)
|
|
282
|
-
|
|
283
|
-
Returns:
|
|
284
|
-
Tuple of (resolved_enable_cdg, resolved_enable_txt)
|
|
285
|
-
"""
|
|
286
|
-
# Default based on whether theme is set
|
|
287
|
-
default_enabled = theme_id is not None
|
|
288
|
-
|
|
289
|
-
# Resolve with explicit override taking precedence
|
|
290
|
-
resolved_cdg = enable_cdg if enable_cdg is not None else default_enabled
|
|
291
|
-
resolved_txt = enable_txt if enable_txt is not None else default_enabled
|
|
292
|
-
|
|
293
|
-
return resolved_cdg, resolved_txt
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
@dataclass
|
|
297
|
-
class EffectiveDistributionSettings:
|
|
298
|
-
"""Settings with defaults applied from environment variables."""
|
|
299
|
-
dropbox_path: Optional[str]
|
|
300
|
-
gdrive_folder_id: Optional[str]
|
|
301
|
-
discord_webhook_url: Optional[str]
|
|
302
|
-
brand_prefix: Optional[str]
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def _get_effective_distribution_settings(
|
|
306
|
-
dropbox_path: Optional[str] = None,
|
|
307
|
-
gdrive_folder_id: Optional[str] = None,
|
|
308
|
-
discord_webhook_url: Optional[str] = None,
|
|
309
|
-
brand_prefix: Optional[str] = None,
|
|
310
|
-
) -> EffectiveDistributionSettings:
|
|
311
|
-
"""
|
|
312
|
-
Get distribution settings with defaults applied from environment variables.
|
|
313
|
-
|
|
314
|
-
This ensures consistent handling of defaults across all job creation endpoints.
|
|
315
|
-
Each parameter, if not provided (None), falls back to the corresponding
|
|
316
|
-
environment variable configured in settings.
|
|
317
|
-
|
|
318
|
-
Args:
|
|
319
|
-
dropbox_path: Explicit Dropbox path or None for default
|
|
320
|
-
gdrive_folder_id: Explicit Google Drive folder ID or None for default
|
|
321
|
-
discord_webhook_url: Explicit Discord webhook URL or None for default
|
|
322
|
-
brand_prefix: Explicit brand prefix or None for default
|
|
323
|
-
|
|
324
|
-
Returns:
|
|
325
|
-
EffectiveDistributionSettings with defaults applied
|
|
326
|
-
"""
|
|
327
|
-
settings = get_settings()
|
|
328
|
-
return EffectiveDistributionSettings(
|
|
329
|
-
dropbox_path=dropbox_path or settings.default_dropbox_path,
|
|
330
|
-
gdrive_folder_id=gdrive_folder_id or settings.default_gdrive_folder_id,
|
|
331
|
-
discord_webhook_url=discord_webhook_url or settings.default_discord_webhook_url,
|
|
332
|
-
brand_prefix=brand_prefix or settings.default_brand_prefix,
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
|
|
336
271
|
def _prepare_theme_for_job(
|
|
337
272
|
job_id: str,
|
|
338
273
|
theme_id: str,
|
|
@@ -503,7 +438,7 @@ async def upload_and_create_job(
|
|
|
503
438
|
)
|
|
504
439
|
|
|
505
440
|
# Apply default distribution settings from environment if not provided
|
|
506
|
-
dist =
|
|
441
|
+
dist = get_effective_distribution_settings(
|
|
507
442
|
dropbox_path=dropbox_path,
|
|
508
443
|
gdrive_folder_id=gdrive_folder_id,
|
|
509
444
|
discord_webhook_url=discord_webhook_url,
|
|
@@ -581,7 +516,7 @@ async def upload_and_create_job(
|
|
|
581
516
|
logger.info(f"Applying default theme: {effective_theme_id}")
|
|
582
517
|
|
|
583
518
|
# Resolve CDG/TXT defaults based on theme
|
|
584
|
-
resolved_cdg, resolved_txt =
|
|
519
|
+
resolved_cdg, resolved_txt = resolve_cdg_txt_defaults(
|
|
585
520
|
effective_theme_id, enable_cdg, enable_txt
|
|
586
521
|
)
|
|
587
522
|
|
|
@@ -644,7 +579,7 @@ async def upload_and_create_job(
|
|
|
644
579
|
# Tenant scoping
|
|
645
580
|
tenant_id=tenant_config.id if tenant_config else None,
|
|
646
581
|
)
|
|
647
|
-
job = job_manager.create_job(job_create)
|
|
582
|
+
job = job_manager.create_job(job_create, is_admin=auth_result.is_admin)
|
|
648
583
|
job_id = job.job_id
|
|
649
584
|
|
|
650
585
|
# Record job creation metric
|
|
@@ -1077,7 +1012,7 @@ async def create_job_with_upload_urls(
|
|
|
1077
1012
|
)
|
|
1078
1013
|
|
|
1079
1014
|
# Apply default distribution settings from environment if not provided
|
|
1080
|
-
dist =
|
|
1015
|
+
dist = get_effective_distribution_settings(
|
|
1081
1016
|
dropbox_path=body.dropbox_path,
|
|
1082
1017
|
gdrive_folder_id=body.gdrive_folder_id,
|
|
1083
1018
|
discord_webhook_url=body.discord_webhook_url,
|
|
@@ -1135,7 +1070,7 @@ async def create_job_with_upload_urls(
|
|
|
1135
1070
|
logger.info(f"Applying default theme: {effective_theme_id}")
|
|
1136
1071
|
|
|
1137
1072
|
# Resolve CDG/TXT defaults based on theme
|
|
1138
|
-
resolved_cdg, resolved_txt =
|
|
1073
|
+
resolved_cdg, resolved_txt = resolve_cdg_txt_defaults(
|
|
1139
1074
|
effective_theme_id, body.enable_cdg, body.enable_txt
|
|
1140
1075
|
)
|
|
1141
1076
|
|
|
@@ -1175,7 +1110,7 @@ async def create_job_with_upload_urls(
|
|
|
1175
1110
|
# Tenant scoping
|
|
1176
1111
|
tenant_id=tenant_config.id if tenant_config else None,
|
|
1177
1112
|
)
|
|
1178
|
-
job = job_manager.create_job(job_create)
|
|
1113
|
+
job = job_manager.create_job(job_create, is_admin=auth_result.is_admin)
|
|
1179
1114
|
job_id = job.job_id
|
|
1180
1115
|
|
|
1181
1116
|
# Record job creation metric
|
|
@@ -1519,7 +1454,7 @@ async def create_job_from_url(
|
|
|
1519
1454
|
)
|
|
1520
1455
|
|
|
1521
1456
|
# Apply default distribution settings from environment if not provided
|
|
1522
|
-
dist =
|
|
1457
|
+
dist = get_effective_distribution_settings(
|
|
1523
1458
|
dropbox_path=body.dropbox_path,
|
|
1524
1459
|
gdrive_folder_id=body.gdrive_folder_id,
|
|
1525
1460
|
discord_webhook_url=body.discord_webhook_url,
|
|
@@ -1578,7 +1513,7 @@ async def create_job_from_url(
|
|
|
1578
1513
|
logger.info(f"Applying default theme: {effective_theme_id}")
|
|
1579
1514
|
|
|
1580
1515
|
# Resolve CDG/TXT defaults based on theme
|
|
1581
|
-
resolved_cdg, resolved_txt =
|
|
1516
|
+
resolved_cdg, resolved_txt = resolve_cdg_txt_defaults(
|
|
1582
1517
|
effective_theme_id, body.enable_cdg, body.enable_txt
|
|
1583
1518
|
)
|
|
1584
1519
|
|
|
@@ -1615,7 +1550,7 @@ async def create_job_from_url(
|
|
|
1615
1550
|
# Tenant scoping
|
|
1616
1551
|
tenant_id=tenant_config.id if tenant_config else None,
|
|
1617
1552
|
)
|
|
1618
|
-
job = job_manager.create_job(job_create)
|
|
1553
|
+
job = job_manager.create_job(job_create, is_admin=auth_result.is_admin)
|
|
1619
1554
|
job_id = job.job_id
|
|
1620
1555
|
|
|
1621
1556
|
# Record job creation metric
|
|
@@ -1635,7 +1570,7 @@ async def create_job_from_url(
|
|
|
1635
1570
|
update_data['youtube_description_template'] = youtube_desc
|
|
1636
1571
|
job_manager.update_job(job_id, update_data)
|
|
1637
1572
|
logger.info(f"Applied theme '{effective_theme_id}' to job {job_id}")
|
|
1638
|
-
|
|
1573
|
+
|
|
1639
1574
|
logger.info(f"Created URL-based job {job_id} for URL: {body.url}")
|
|
1640
1575
|
if artist:
|
|
1641
1576
|
logger.info(f" Artist: {artist}")
|
|
@@ -1789,7 +1724,7 @@ async def create_finalise_only_job(
|
|
|
1789
1724
|
)
|
|
1790
1725
|
|
|
1791
1726
|
# Apply default distribution settings
|
|
1792
|
-
dist =
|
|
1727
|
+
dist = get_effective_distribution_settings(
|
|
1793
1728
|
dropbox_path=body.dropbox_path,
|
|
1794
1729
|
gdrive_folder_id=body.gdrive_folder_id,
|
|
1795
1730
|
discord_webhook_url=body.discord_webhook_url,
|
|
@@ -1844,7 +1779,7 @@ async def create_finalise_only_job(
|
|
|
1844
1779
|
logger.info(f"Applying default theme: {effective_theme_id}")
|
|
1845
1780
|
|
|
1846
1781
|
# Resolve CDG/TXT defaults based on theme
|
|
1847
|
-
resolved_cdg, resolved_txt =
|
|
1782
|
+
resolved_cdg, resolved_txt = resolve_cdg_txt_defaults(
|
|
1848
1783
|
effective_theme_id, body.enable_cdg, body.enable_txt
|
|
1849
1784
|
)
|
|
1850
1785
|
|
|
@@ -1876,7 +1811,7 @@ async def create_finalise_only_job(
|
|
|
1876
1811
|
# Tenant scoping
|
|
1877
1812
|
tenant_id=tenant_config.id if tenant_config else None,
|
|
1878
1813
|
)
|
|
1879
|
-
job = job_manager.create_job(job_create)
|
|
1814
|
+
job = job_manager.create_job(job_create, is_admin=auth_result.is_admin)
|
|
1880
1815
|
job_id = job.job_id
|
|
1881
1816
|
|
|
1882
1817
|
# Record job creation metric
|
backend/api/routes/jobs.py
CHANGED
|
@@ -118,8 +118,8 @@ async def create_job(
|
|
|
118
118
|
webhook_url=request.webhook_url,
|
|
119
119
|
user_email=user_email
|
|
120
120
|
)
|
|
121
|
-
job = job_manager.create_job(job_create)
|
|
122
|
-
|
|
121
|
+
job = job_manager.create_job(job_create, is_admin=auth_result.is_admin)
|
|
122
|
+
|
|
123
123
|
# Record job creation metric
|
|
124
124
|
metrics.record_job_created(job.job_id, source="url")
|
|
125
125
|
|