syncfm-core 0.2.3__tar.gz → 0.2.5__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.
Files changed (67) hide show
  1. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/PKG-INFO +2 -4
  2. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/README.md +1 -3
  3. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/pyproject.toml +1 -1
  4. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/pyproject.toml.orig +1 -1
  5. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/sync_progress.py +2 -0
  6. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/models.py +3 -3
  7. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/sync_service.py +20 -1
  8. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/LICENSE +0 -0
  9. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/__init__.py +0 -0
  10. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/application.py +0 -0
  11. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/__init__.py +0 -0
  12. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/app.py +0 -0
  13. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/commands/__init__.py +0 -0
  14. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/commands/common.py +0 -0
  15. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/commands/discard.py +0 -0
  16. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/commands/profile.py +0 -0
  17. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/commands/resume.py +0 -0
  18. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/commands/status.py +0 -0
  19. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/commands/sync.py +0 -0
  20. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/configuration.py +0 -0
  21. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/context.py +0 -0
  22. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/dashboard.py +0 -0
  23. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/presenters.py +0 -0
  24. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/cli/verification.py +0 -0
  25. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/exceptions.py +0 -0
  26. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/__init__.py +0 -0
  27. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/network_config.py +0 -0
  28. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/retry_policy.py +0 -0
  29. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/scrobble.py +0 -0
  30. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/sync_queue_item.py +0 -0
  31. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/sync_request.py +0 -0
  32. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/sync_result.py +0 -0
  33. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/sync_session.py +0 -0
  34. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/sync_status.py +0 -0
  35. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/models/sync_verification.py +0 -0
  36. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/networks/__init__.py +0 -0
  37. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/networks/factory.py +0 -0
  38. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/networks/gnufm.py +0 -0
  39. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/networks/pylast_adapter.py +0 -0
  40. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/networks/pylast_mapper.py +0 -0
  41. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/__init__.py +0 -0
  42. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/factory.py +0 -0
  43. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/keyring_store.py +0 -0
  44. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/paths.py +0 -0
  45. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/protocols.py +0 -0
  46. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/resolver.py +0 -0
  47. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/service.py +0 -0
  48. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/profiles/toml_store.py +0 -0
  49. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/protocols/__init__.py +0 -0
  50. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/protocols/network.py +0 -0
  51. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/protocols/repositories.py +0 -0
  52. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/py.typed +0 -0
  53. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/repositories/__init__.py +0 -0
  54. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/repositories/database.py +0 -0
  55. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/repositories/queue_repository.py +0 -0
  56. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/repositories/schema.py +0 -0
  57. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/repositories/session_repository.py +0 -0
  58. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/repositories/snapshot_repository.py +0 -0
  59. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/__init__.py +0 -0
  60. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/comparison_service.py +0 -0
  61. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/metadata_service.py +0 -0
  62. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/range_resolver.py +0 -0
  63. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/recovery_service.py +0 -0
  64. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/retry_service.py +0 -0
  65. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/snapshot_service.py +0 -0
  66. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/submission_service.py +0 -0
  67. {syncfm_core-0.2.3 → syncfm_core-0.2.5}/src/syncfm_core/services/verification_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncfm-core
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Reusable synchronization engine and CLI for Last.fm, Libre.fm and GNU.fm networks.
5
5
  Keywords: lastfm,librefm,gnufm,scrobble,music
6
6
  Author: Hirad
@@ -78,9 +78,7 @@ checkout instead of an installed tool.
78
78
 
79
79
  ### 1. Create network profiles
80
80
 
81
- Create one profile for each account. Profile names must start with a lowercase
82
- letter or number and may contain lowercase letters, numbers, underscores, and
83
- hyphens.
81
+ Create one profile for each account.
84
82
 
85
83
  ```console
86
84
  syncfm profile add lastfm-main \
@@ -51,9 +51,7 @@ checkout instead of an installed tool.
51
51
 
52
52
  ### 1. Create network profiles
53
53
 
54
- Create one profile for each account. Profile names must start with a lowercase
55
- letter or number and may contain lowercase letters, numbers, underscores, and
56
- hyphens.
54
+ Create one profile for each account.
57
55
 
58
56
  ```console
59
57
  syncfm profile add lastfm-main \
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "syncfm-core"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "Reusable synchronization engine and CLI for Last.fm, Libre.fm and GNU.fm networks."
5
5
  readme = "README.md"
6
6
  license = "GPL-3.0-or-later"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "syncfm-core"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "Reusable synchronization engine and CLI for Last.fm, Libre.fm and GNU.fm networks."
5
5
  readme = "README.md"
6
6
  license = "GPL-3.0-or-later"
@@ -4,6 +4,7 @@ from collections.abc import Callable
4
4
  from dataclasses import dataclass
5
5
 
6
6
  from syncfm_core.models.scrobble import Scrobble
7
+ from syncfm_core.models.sync_request import SyncRange
7
8
  from syncfm_core.models.sync_session import SyncPhase
8
9
 
9
10
 
@@ -17,6 +18,7 @@ class SyncProgress:
17
18
  current_scrobble: Scrobble | None = None
18
19
  current_scrobble_completed: bool = False
19
20
  current_scrobble_failed: bool = False
21
+ sync_range: SyncRange | None = None
20
22
 
21
23
  def __post_init__(self) -> None:
22
24
  """Validate progress values."""
@@ -7,7 +7,7 @@ from enum import StrEnum
7
7
  from syncfm_core.exceptions import ConfigurationError
8
8
  from syncfm_core.models.network_config import NetworkType
9
9
 
10
- _PROFILE_NAME_PATTERN = re.compile(r"^[a-z0-9][a-z0-9_-]*$")
10
+ _PROFILE_NAME_PATTERN = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]*$")
11
11
 
12
12
 
13
13
  class SecretStorage(StrEnum):
@@ -85,8 +85,8 @@ class NetworkProfile:
85
85
  """Validate profile configuration."""
86
86
  if not _PROFILE_NAME_PATTERN.fullmatch(self.name):
87
87
  raise ConfigurationError(
88
- "Profile name must start with a lowercase letter or number "
89
- "and contain only lowercase letters, numbers, underscores and hyphens."
88
+ "Profile name must start with a letter or number and may only contain "
89
+ "letters, numbers, underscores (_), hyphens (-), dashes (-), and dots (.)."
90
90
  )
91
91
  if not self.username.strip():
92
92
  raise ConfigurationError("A profile username must be provided.")
@@ -87,6 +87,10 @@ class SyncService:
87
87
  """
88
88
  self._validate_profile_pair(source_profile, target_profile)
89
89
  sync_range = self._range_resolver.resolve(request, target)
90
+ self._report_phase(
91
+ SyncPhase.CREATED,
92
+ sync_range=sync_range,
93
+ )
90
94
  session = self._create_session(
91
95
  source,
92
96
  target,
@@ -130,6 +134,16 @@ class SyncService:
130
134
  """
131
135
  session = self.get_session(session_id)
132
136
  self._validate_resume_networks(session, source, target)
137
+
138
+ sync_range = SyncRange(
139
+ start_timestamp=session.start_timestamp,
140
+ end_timestamp=session.end_timestamp,
141
+ )
142
+ self._report_phase(
143
+ session.phase,
144
+ sync_range=sync_range,
145
+ )
146
+
133
147
  self._record_resume_profiles(
134
148
  session,
135
149
  source_profile,
@@ -289,7 +303,11 @@ class SyncService:
289
303
  self._session_repository.update_phase(session_id, phase)
290
304
  self._report_phase(phase)
291
305
 
292
- def _report_phase(self, phase: SyncPhase) -> None:
306
+ def _report_phase(
307
+ self,
308
+ phase: SyncPhase,
309
+ sync_range: SyncRange | None = None,
310
+ ) -> None:
293
311
  """Report a synchronization phase to the frontend."""
294
312
  if self._progress_callback is not None:
295
313
  self._progress_callback(
@@ -297,6 +315,7 @@ class SyncService:
297
315
  phase=phase,
298
316
  completed=0,
299
317
  total=0,
318
+ sync_range=sync_range,
300
319
  )
301
320
  )
302
321
 
File without changes