vlcsync 0.3.0__py3-none-any.whl → 0.3.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.
- vlcsync/cli.py +3 -3
- vlcsync/syncer.py +24 -9
- vlcsync/vlc.py +13 -13
- vlcsync/vlc_finder.py +2 -1
- vlcsync/vlc_state.py +4 -8
- {vlcsync-0.3.0.dist-info → vlcsync-0.3.1.dist-info}/METADATA +1 -1
- vlcsync-0.3.1.dist-info/RECORD +14 -0
- vlcsync-0.3.0.dist-info/RECORD +0 -14
- {vlcsync-0.3.0.dist-info → vlcsync-0.3.1.dist-info}/LICENSE.md +0 -0
- {vlcsync-0.3.0.dist-info → vlcsync-0.3.1.dist-info}/WHEEL +0 -0
- {vlcsync-0.3.0.dist-info → vlcsync-0.3.1.dist-info}/entry_points.txt +0 -0
vlcsync/cli.py
CHANGED
@@ -12,7 +12,7 @@ from vlcsync.vlc_finder import print_exc
|
|
12
12
|
from vlcsync.vlc_state import VlcId
|
13
13
|
|
14
14
|
# Also ref in project.toml
|
15
|
-
__version__ = "0.3.
|
15
|
+
__version__ = "0.3.1"
|
16
16
|
|
17
17
|
|
18
18
|
@click.command
|
@@ -43,7 +43,7 @@ __version__ = "0.3.0"
|
|
43
43
|
""")
|
44
44
|
def main(rc_host_list: Set[VlcId], no_local_discover, volume_sync):
|
45
45
|
"""Utility for synchronize multiple instances of VLC. Supports seek, play and pause."""
|
46
|
-
print("Vlcsync started...")
|
46
|
+
print("Vlcsync started...", flush=True)
|
47
47
|
|
48
48
|
app_config = AppConfig(rc_host_list, no_local_discover, volume_sync)
|
49
49
|
time.sleep(2) # Wait instances
|
@@ -57,4 +57,4 @@ def main(rc_host_list: Set[VlcId], no_local_discover, volume_sync):
|
|
57
57
|
sys.exit(0)
|
58
58
|
except Exception:
|
59
59
|
print_exc()
|
60
|
-
print("Exception detected. Restart sync...")
|
60
|
+
print("Exception detected. Restart sync...", flush=True)
|
vlcsync/syncer.py
CHANGED
@@ -3,11 +3,11 @@ from __future__ import annotations
|
|
3
3
|
from dataclasses import dataclass
|
4
4
|
import sys
|
5
5
|
import time
|
6
|
-
from typing import Set
|
6
|
+
from typing import Set, List
|
7
7
|
|
8
8
|
from loguru import logger
|
9
9
|
|
10
|
-
from vlcsync.vlc import VLC_IFACE_IP, VlcProcs
|
10
|
+
from vlcsync.vlc import VLC_IFACE_IP, VlcProcs, Vlc
|
11
11
|
from vlcsync.vlc_finder import LocalProcessFinderProvider, ExtraHostFinder
|
12
12
|
from vlcsync.vlc_socket import VlcConnectionError
|
13
13
|
|
@@ -30,21 +30,21 @@ class Syncer:
|
|
30
30
|
vlc_finders = set()
|
31
31
|
if not self.app_config.no_local_discovery:
|
32
32
|
vlc_finders.add(LocalProcessFinderProvider(VLC_IFACE_IP))
|
33
|
-
print(f" Discover instances on {VLC_IFACE_IP} iface...")
|
33
|
+
print(f" Discover instances on {VLC_IFACE_IP} iface...", flush=True)
|
34
34
|
else:
|
35
|
-
print(" Local discovery vlc instances DISABLED...")
|
35
|
+
print(" Local discovery vlc instances DISABLED...", flush=True)
|
36
36
|
|
37
37
|
if app_config.extra_rc_hosts:
|
38
38
|
vlc_finders.add(ExtraHostFinder(app_config.extra_rc_hosts))
|
39
39
|
for rc_host in app_config.extra_rc_hosts:
|
40
40
|
rc_host: VlcId
|
41
|
-
print(f" Manual host defined {rc_host.addr}:{rc_host.port}")
|
41
|
+
print(f" Manual host defined {rc_host.addr}:{rc_host.port}", flush=True)
|
42
42
|
else:
|
43
|
-
print(""" Manual vlc addresses ("--rc-host" args) NOT provided...""")
|
43
|
+
print(""" Manual vlc addresses ("--rc-host" args) NOT provided...""", flush=True)
|
44
44
|
|
45
45
|
if not vlc_finders:
|
46
46
|
print("\nTarget vlc instances not selected (nor autodiscover, nor manually). \n"
|
47
|
-
"""See: "vlcsync --help" for more info""")
|
47
|
+
"""See: "vlcsync --help" for more info""", flush=True)
|
48
48
|
sys.exit(1)
|
49
49
|
|
50
50
|
self.env = VlcProcs(vlc_finders)
|
@@ -69,11 +69,26 @@ class Syncer:
|
|
69
69
|
|
70
70
|
def sync_playstate(self):
|
71
71
|
for vlc_id, vlc in self.env.all_vlc.items():
|
72
|
-
is_changed, state = vlc.is_state_change()
|
72
|
+
is_changed, state, playlist_changed = vlc.is_state_change()
|
73
73
|
|
74
74
|
if is_changed:
|
75
|
-
|
75
|
+
# Workaround Save volumes.
|
76
|
+
# When playlist items changed ALSO happen volumes sync by some reason. But SHOULD NOT!
|
77
|
+
volumes: List[tuple[Vlc, int]] = []
|
78
|
+
if not self.app_config.volume_sync and playlist_changed:
|
79
|
+
volumes = [(vlc1, vlc1.volume()) for _, vlc1 in self.env.all_vlc.items()]
|
80
|
+
#
|
81
|
+
|
82
|
+
print(f"\nVlc state change detected from ({vlc_id})", flush=True)
|
76
83
|
self.env.sync_all(state, vlc)
|
84
|
+
|
85
|
+
# Restore volumes if needed
|
86
|
+
if volumes:
|
87
|
+
for vlc_next, volume in volumes:
|
88
|
+
vlc_next.set_volume(volume)
|
89
|
+
# Trying to fix endless resyncing hang
|
90
|
+
# Cannot find reproduce steps for that
|
91
|
+
time.sleep(0.5)
|
77
92
|
break
|
78
93
|
|
79
94
|
def sync_volume(self):
|
vlcsync/vlc.py
CHANGED
@@ -46,7 +46,7 @@ class Vlc:
|
|
46
46
|
def volume(self) -> Optional[int]:
|
47
47
|
vol = self.vlc_conn.cmd("volume")
|
48
48
|
if vol.strip() != '':
|
49
|
-
return int(vol)
|
49
|
+
return int(float(vol.replace(",",'.')))
|
50
50
|
else:
|
51
51
|
return None
|
52
52
|
|
@@ -79,10 +79,10 @@ class Vlc:
|
|
79
79
|
def is_state_change(self) -> (bool, State):
|
80
80
|
cur_state: State = self.cur_state()
|
81
81
|
prev_state: State = self.prev_state
|
82
|
-
|
82
|
+
full_same, playlist_same = cur_state.same(prev_state)
|
83
83
|
|
84
84
|
# Return cur_state for reduce further socket communications
|
85
|
-
return
|
85
|
+
return not full_same, cur_state, not playlist_same
|
86
86
|
|
87
87
|
def sync_to(self, new_state: State, source: Vlc):
|
88
88
|
|
@@ -195,7 +195,7 @@ class VlcProcs:
|
|
195
195
|
for vlc_id in vlc_candidates:
|
196
196
|
if vlc_id not in self._vlc_instances.keys():
|
197
197
|
if vlc := self.try_connect(vlc_id):
|
198
|
-
print(f"Found active instance {vlc_id}, with state {vlc.cur_state()}")
|
198
|
+
print(f"Found active instance {vlc_id}, with state {vlc.cur_state()}", flush=True)
|
199
199
|
self._vlc_instances[vlc_id] = vlc
|
200
200
|
|
201
201
|
logger.debug(f"Compute all_vlc (took {time.time() - start:.3f})...")
|
@@ -207,31 +207,31 @@ class VlcProcs:
|
|
207
207
|
return Vlc(vlc_id)
|
208
208
|
except Exception as e:
|
209
209
|
logger.opt(exception=True).debug("Cannot connect to {0}, cause: {1}", vlc_id, e)
|
210
|
-
print(f"Cannot connect to {vlc_id} socket, cause: {e}. Skipping. Enable debug for more info. See --help. ")
|
210
|
+
print(f"Cannot connect to {vlc_id} socket, cause: {e}. Skipping. Enable debug for more info. See --help. ", flush=True)
|
211
211
|
return None
|
212
212
|
|
213
213
|
@property
|
214
214
|
def all_vlc(self) -> dict[VlcId, Vlc]:
|
215
215
|
return self._vlc_instances.copy() # copy: for thread safe
|
216
216
|
|
217
|
-
def sync_all(self, state: State,
|
217
|
+
def sync_all(self, state: State, source_vlc: Vlc):
|
218
218
|
logger.debug(">" * 60)
|
219
|
-
logger.debug(f"Detect change to {state} from {
|
220
|
-
logger.debug(f" old --> {
|
219
|
+
logger.debug(f"Detect change to {state} from {source_vlc.vlc_id}")
|
220
|
+
logger.debug(f" old --> {source_vlc.prev_state} ")
|
221
221
|
logger.debug(f" new --> {state} ")
|
222
|
-
logger.debug(f" Time diff abs(old - new) {abs(
|
222
|
+
logger.debug(f" Time diff abs(old - new) {abs(source_vlc.prev_state.vid_start_at - state.vid_start_at)}")
|
223
223
|
logger.debug("<" * 60)
|
224
224
|
logger.debug("")
|
225
|
-
print(">>> Sync players...")
|
225
|
+
print(">>> Sync players...", flush=True)
|
226
226
|
|
227
227
|
for next_pid, next_vlc in self.all_vlc.items():
|
228
228
|
next_vlc: Vlc
|
229
|
-
print(f" Sync {next_pid} to {state}")
|
230
|
-
next_vlc.sync_to(state,
|
229
|
+
print(f" Sync {next_pid} to {state}", flush=True)
|
230
|
+
next_vlc.sync_to(state, source_vlc)
|
231
231
|
print()
|
232
232
|
|
233
233
|
def dereg(self, vlc_id: VlcId):
|
234
|
-
print(f"Detect vlc instance closed {vlc_id}")
|
234
|
+
print(f"Detect vlc instance closed {vlc_id}", flush=True)
|
235
235
|
if vlc_to_close := self._vlc_instances.pop(vlc_id, None):
|
236
236
|
vlc_to_close.close()
|
237
237
|
|
vlcsync/vlc_finder.py
CHANGED
@@ -90,11 +90,12 @@ class LocalProcessFinderProvider(IVlcListFinder):
|
|
90
90
|
|
91
91
|
def print_exc():
|
92
92
|
print("-" * 60)
|
93
|
-
print("Exception in user code: ")
|
93
|
+
print("Exception in user code: ", flush=True)
|
94
94
|
print("-" * 60)
|
95
95
|
traceback.print_exc(file=sys.stdout)
|
96
96
|
print("-" * 60)
|
97
97
|
print()
|
98
|
+
sys.stdout.flush()
|
98
99
|
|
99
100
|
|
100
101
|
class ExtraHostFinder(IVlcListFinder):
|
vlcsync/vlc_state.py
CHANGED
@@ -51,14 +51,10 @@ class State:
|
|
51
51
|
vid_start_at: float = field(repr=False)
|
52
52
|
|
53
53
|
def same(self, other: State):
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
self.pause_is_same_pos(other) or
|
59
|
-
self.both_stopped(other)
|
60
|
-
)
|
61
|
-
)
|
54
|
+
playlist_same = self.same_playlist_item(other)
|
55
|
+
full_same = (self.same_play_state(other) and playlist_same and (
|
56
|
+
self.play_in_same_pos(other) or self.pause_is_same_pos(other) or self.both_stopped(other)))
|
57
|
+
return full_same, playlist_same
|
62
58
|
|
63
59
|
def same_play_state(self, other: State):
|
64
60
|
return self.play_state == other.play_state
|
@@ -0,0 +1,14 @@
|
|
1
|
+
vlcsync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
vlcsync/cli.py,sha256=ssoMtW_DorOs0QK5-mEqm6itQQQVci86B8OA2Ed4Nw0,2005
|
3
|
+
vlcsync/cli_utils.py,sha256=hXSljymGPU5AzFr706Ea-81wxkVCYLhZY-ug-JExZ0E,883
|
4
|
+
vlcsync/main.py,sha256=An0NQ4jy3mfygwxko_UA3Sdwri9yidcUTTCP3SoyrpI,303
|
5
|
+
vlcsync/syncer.py,sha256=x9w0LWmCUtFlMFTi01q8BBos0d9fwUpOQMo0dko6n_0,3854
|
6
|
+
vlcsync/vlc.py,sha256=dBrg2TYQswhewtUveBilp0jadfMQAMRZkqgBukUK3F0,8528
|
7
|
+
vlcsync/vlc_finder.py,sha256=7BXhOeJG8lRqYJ7dbrLU3Ps8ghUPh666YkAZjNom-cw,2770
|
8
|
+
vlcsync/vlc_socket.py,sha256=WQAtNoitc49sst0oRG0bEuTkgw6a2TJXVE9iSWQaMa0,1850
|
9
|
+
vlcsync/vlc_state.py,sha256=8RpmxVS_zijqYw9rxpmnN5QwM3Sk1FmqgTxgCH3U8kU,3133
|
10
|
+
vlcsync-0.3.1.dist-info/entry_points.txt,sha256=2m_39oATnFzf5kuvlhkayyWSmW0tUefyNk9dVP4A7B0,45
|
11
|
+
vlcsync-0.3.1.dist-info/LICENSE.md,sha256=Q6ik40IpumjnuWfS1c69jnEyxAPTBV2v04DesGSgLPM,1074
|
12
|
+
vlcsync-0.3.1.dist-info/WHEEL,sha256=DA86_h4QwwzGeRoz62o1svYt5kGEXpoUTuTtwzoTb30,83
|
13
|
+
vlcsync-0.3.1.dist-info/METADATA,sha256=UWdLvYjpLAGk9KC_0pGnDrpF9dEdwZM6qs9cmrj-qrs,4258
|
14
|
+
vlcsync-0.3.1.dist-info/RECORD,,
|
vlcsync-0.3.0.dist-info/RECORD
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
vlcsync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
vlcsync/cli.py,sha256=Qqh7jM6HSeaMCos2s5Uj3e7XjG7NVlnjuNmdMk5LXv0,1981
|
3
|
-
vlcsync/cli_utils.py,sha256=hXSljymGPU5AzFr706Ea-81wxkVCYLhZY-ug-JExZ0E,883
|
4
|
-
vlcsync/main.py,sha256=An0NQ4jy3mfygwxko_UA3Sdwri9yidcUTTCP3SoyrpI,303
|
5
|
-
vlcsync/syncer.py,sha256=7fTcrPLT0qEiGKcBm8QFIwMz1csuxvwsZtHIBUgpFqM,3049
|
6
|
-
vlcsync/vlc.py,sha256=pOg8X8dz5E1vr10r47JOM_EbjLfSfriDs0FFTyePt3A,8390
|
7
|
-
vlcsync/vlc_finder.py,sha256=dfihlZ6hbA4cocQ70lQo4pYX178arEuSsHnhEbqPPOs,2735
|
8
|
-
vlcsync/vlc_socket.py,sha256=WQAtNoitc49sst0oRG0bEuTkgw6a2TJXVE9iSWQaMa0,1850
|
9
|
-
vlcsync/vlc_state.py,sha256=9ueuTCxCazsMy2z4QdwhTa39aD1leOfk8FcOOXqN9Nw,3168
|
10
|
-
vlcsync-0.3.0.dist-info/entry_points.txt,sha256=2m_39oATnFzf5kuvlhkayyWSmW0tUefyNk9dVP4A7B0,45
|
11
|
-
vlcsync-0.3.0.dist-info/LICENSE.md,sha256=Q6ik40IpumjnuWfS1c69jnEyxAPTBV2v04DesGSgLPM,1074
|
12
|
-
vlcsync-0.3.0.dist-info/WHEEL,sha256=DA86_h4QwwzGeRoz62o1svYt5kGEXpoUTuTtwzoTb30,83
|
13
|
-
vlcsync-0.3.0.dist-info/METADATA,sha256=D3IM0BPRuQBLHeI1sbjoRK5l3ZJ0_xQk8nlzJ2lrQu4,4258
|
14
|
-
vlcsync-0.3.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|