remove network sync, only single player
This commit is contained in:
parent
baa40d356e
commit
75ad983d47
1 changed files with 2 additions and 185 deletions
187
player/player.py
187
player/player.py
|
|
@ -3,7 +3,6 @@ import argparse
|
||||||
import collections
|
import collections
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import socket
|
|
||||||
import time
|
import time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
@ -58,10 +57,7 @@ class Sync(Thread):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.is_main = kwargs.get('mode', 'main') == 'main'
|
self.is_main = kwargs.get('mode', 'main') == 'main'
|
||||||
self.start_at_hour = kwargs.get("hour", False)
|
self.start_at_hour = kwargs.get("hour", False)
|
||||||
self.sock = self.init_socket()
|
|
||||||
self.main = Main()
|
self.main = Main()
|
||||||
if self.is_main:
|
|
||||||
self.socket_enable_broadcast()
|
|
||||||
|
|
||||||
if kwargs.get("music"):
|
if kwargs.get("music"):
|
||||||
music = mpv.MPV(
|
music = mpv.MPV(
|
||||||
|
|
@ -104,12 +100,7 @@ class Sync(Thread):
|
||||||
logger.error("loaded paylist: %s", self.playlist)
|
logger.error("loaded paylist: %s", self.playlist)
|
||||||
logger.debug("current playlist: %s", json.dumps(self.mpv.playlist, indent=2))
|
logger.debug("current playlist: %s", json.dumps(self.mpv.playlist, indent=2))
|
||||||
self.deviations = collections.deque(maxlen=10)
|
self.deviations = collections.deque(maxlen=10)
|
||||||
if not self.is_main:
|
if self.start_at_hour:
|
||||||
self.mpv.pause = False
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.mpv.pause = True
|
|
||||||
self.sync_to_main()
|
|
||||||
elif self.start_at_hour:
|
|
||||||
self.mpv.pause = True
|
self.mpv.pause = True
|
||||||
fmt = '%Y-%m-%d %H'
|
fmt = '%Y-%m-%d %H'
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|
@ -140,15 +131,7 @@ class Sync(Thread):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while self.active:
|
while self.active:
|
||||||
if self.is_main:
|
time.sleep(0.5)
|
||||||
time.sleep(0.5)
|
|
||||||
else:
|
|
||||||
if self.need_to_sync:
|
|
||||||
self.sync_to_main()
|
|
||||||
self.deviations = collections.deque(maxlen=10)
|
|
||||||
self.need_to_sync = False
|
|
||||||
else:
|
|
||||||
self.read_position_main()
|
|
||||||
self.reload_playlist()
|
self.reload_playlist()
|
||||||
if not self.is_paused and self._tick and abs(time.time() - self._tick) > 60:
|
if not self.is_paused and self._tick and abs(time.time() - self._tick) > 60:
|
||||||
logger.error("player is stuck")
|
logger.error("player is stuck")
|
||||||
|
|
@ -161,7 +144,6 @@ class Sync(Thread):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def q_binding(self, *args):
|
def q_binding(self, *args):
|
||||||
if self.is_keydown(args):
|
if self.is_keydown(args):
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
@ -193,25 +175,9 @@ class Sync(Thread):
|
||||||
|
|
||||||
def stop(self, *args):
|
def stop(self, *args):
|
||||||
self.active = False
|
self.active = False
|
||||||
if self.sock:
|
|
||||||
self.sock.close()
|
|
||||||
self.sock = None
|
|
||||||
|
|
||||||
def time_pos_cb(self, pos, *args, **kwargs):
|
def time_pos_cb(self, pos, *args, **kwargs):
|
||||||
self._tick = time.time()
|
self._tick = time.time()
|
||||||
if self.is_main:
|
|
||||||
self.send_position_local()
|
|
||||||
elif self.ready:
|
|
||||||
self.adjust_position()
|
|
||||||
if self._pos != self.mpv.playlist_current_pos:
|
|
||||||
self._pos = self.mpv.playlist_current_pos
|
|
||||||
self.deviations = collections.deque(maxlen=10)
|
|
||||||
self.need_to_sync = False
|
|
||||||
try:
|
|
||||||
track = self.mpv.playlist[self._pos]
|
|
||||||
logger.error("%s %s", datetime.now(), track["filename"])
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def reload_playlist(self):
|
def reload_playlist(self):
|
||||||
if not self.reload_check:
|
if not self.reload_check:
|
||||||
|
|
@ -249,155 +215,6 @@ class Sync(Thread):
|
||||||
logger.error("reloaded paylist: %s", self.playlist)
|
logger.error("reloaded paylist: %s", self.playlist)
|
||||||
logger.debug("current playlist: %s", json.dumps(self.mpv.playlist, indent=2))
|
logger.debug("current playlist: %s", json.dumps(self.mpv.playlist, indent=2))
|
||||||
|
|
||||||
def init_socket(self):
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
|
|
||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
sock.bind(("0.0.0.0", PORT))
|
|
||||||
return sock
|
|
||||||
|
|
||||||
#
|
|
||||||
# main specific
|
|
||||||
#
|
|
||||||
def socket_enable_broadcast(self):
|
|
||||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
||||||
self.sock.connect((self.destination, PORT))
|
|
||||||
|
|
||||||
def send_position_local(self):
|
|
||||||
if not self.active:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
msg = (
|
|
||||||
"%0.4f %s"
|
|
||||||
% (self.mpv.time_pos, self.mpv.playlist_current_pos)
|
|
||||||
).encode()
|
|
||||||
if CONFIG.get("sync_group"):
|
|
||||||
msg = ("%s " % CONFIG["sync_group"]).encode() + msg
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
self.sock.send(msg)
|
|
||||||
except socket.error as e:
|
|
||||||
logger.error("send failed: %s", e)
|
|
||||||
|
|
||||||
def send_playback_state(self):
|
|
||||||
state = 'pause' if self.mpv.pause else 'play'
|
|
||||||
msg = ("%s -1" % state).encode()
|
|
||||||
try:
|
|
||||||
self.sock.send(msg)
|
|
||||||
except socket.error as e:
|
|
||||||
logger.error("send failed: %s", e)
|
|
||||||
|
|
||||||
#
|
|
||||||
# follower specific
|
|
||||||
#
|
|
||||||
_last_ping = None
|
|
||||||
|
|
||||||
def read_position_main(self):
|
|
||||||
self.sock.settimeout(5)
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
data = self.sock.recvfrom(1024)[0].decode().split(" ", 1)
|
|
||||||
except socket.timeout:
|
|
||||||
if self._last_ping != "pause":
|
|
||||||
logger.error("failed to receive data from main")
|
|
||||||
return
|
|
||||||
except OSError:
|
|
||||||
logger.error("socket closed")
|
|
||||||
return
|
|
||||||
|
|
||||||
if CONFIG.get("sync_group"):
|
|
||||||
if data[0] == str(CONFIG["sync_group"]):
|
|
||||||
data = data[1].split(" ", 1)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
self._last_ping = data[0]
|
|
||||||
if data[0] == "pause":
|
|
||||||
self.is_paused = True
|
|
||||||
self.mpv.pause = True
|
|
||||||
elif data[0] == "play":
|
|
||||||
self.is_paused = False
|
|
||||||
self._tick = 0
|
|
||||||
self.mpv.pause = False
|
|
||||||
else:
|
|
||||||
self.main.time_pos = float(data[0])
|
|
||||||
self.main.playlist_current_pos = int(data[1])
|
|
||||||
|
|
||||||
def adjust_position(self):
|
|
||||||
if self.mpv.time_pos is not None:
|
|
||||||
try:
|
|
||||||
deviation = self.main.time_pos - self.mpv.time_pos
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
self.deviations.append(deviation)
|
|
||||||
median_deviation = self.median(list(self.deviations))
|
|
||||||
frames = deviation / 0.04
|
|
||||||
median_frames = median_deviation / 0.04
|
|
||||||
if abs(deviation) <= 0.04 and self.mpv.speed != 1.0:
|
|
||||||
self.mpv.speed = 1.0
|
|
||||||
logger.error(
|
|
||||||
'%0.05f back to normal speed %0.05f (%d) median %0.05f (%d) -> %s' % (self.mpv.time_pos, deviation, frames, median_deviation, median_frames, self.mpv.speed)
|
|
||||||
)
|
|
||||||
if time.time() - self.last_sync > SYNC_GRACE_TIME and abs(median_deviation) > SYNC_TOLERANCE:
|
|
||||||
if abs(median_deviation) < 1:
|
|
||||||
step = 0.02
|
|
||||||
if median_deviation > 0:
|
|
||||||
self.mpv.speed += step
|
|
||||||
else:
|
|
||||||
self.mpv.speed -= step
|
|
||||||
logger.error(
|
|
||||||
'%0.05f need to adjust speed %0.05f (%d) median %0.05f (%d) -> %s' % (self.mpv.time_pos, deviation, frames, median_deviation, median_frames, self.mpv.speed)
|
|
||||||
)
|
|
||||||
self.need_to_sync = False
|
|
||||||
self.deviations = collections.deque(maxlen=10)
|
|
||||||
self.last_sync = time.time()
|
|
||||||
elif self.mpv.time_pos > 2 and not self.need_to_sync:
|
|
||||||
logger.error(
|
|
||||||
'%0.05f need to sync %0.05f (%d) median %0.05f (%d)' % (self.mpv.time_pos, deviation, frames, median_deviation, median_frames)
|
|
||||||
)
|
|
||||||
self.need_to_sync = True
|
|
||||||
|
|
||||||
def median(self, lst):
|
|
||||||
quotient, remainder = divmod(len(lst), 2)
|
|
||||||
if remainder:
|
|
||||||
return sorted(lst)[quotient]
|
|
||||||
return float(sum(sorted(lst)[quotient - 1:quotient + 1]) / 2.0)
|
|
||||||
|
|
||||||
def sync_to_main(self):
|
|
||||||
logger.error('sync to main')
|
|
||||||
self.read_position_main()
|
|
||||||
#print(self.main.playlist_current_pos)
|
|
||||||
if self.main.playlist_current_pos != self.mpv.playlist_current_pos:
|
|
||||||
self.mpv.playlist_play_index(self.main.playlist_current_pos)
|
|
||||||
self.mpv.pause = False
|
|
||||||
self.mpv.wait_until_playing()
|
|
||||||
try:
|
|
||||||
track = self.mpv.playlist[self.mpv.playlist_current_pos]
|
|
||||||
logger.error("%s %s", datetime.now(), track["filename"])
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.mpv.pause = True
|
|
||||||
self.mpv.speed = 1
|
|
||||||
pos = self.main.time_pos + SYNC_JUMP_AHEAD
|
|
||||||
#print(pos, self.mpv.playlist_current_pos, self.mpv.time_pos)
|
|
||||||
self.mpv.seek(pos, 'absolute', 'exact')
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.read_position_main()
|
|
||||||
sync_timer = time.time() # - 10 * 0.04
|
|
||||||
deviation = self.main.time_pos - self.mpv.time_pos
|
|
||||||
while self.active:
|
|
||||||
#print(deviation, abs(deviation) - (time.time() - sync_timer))
|
|
||||||
if abs(deviation) - (time.time() - sync_timer) < 0:
|
|
||||||
self.mpv.pause = False
|
|
||||||
try:
|
|
||||||
track = self.mpv.playlist[self.mpv.playlist_current_pos]
|
|
||||||
logger.error("%s %s %s", datetime.now(), track["filename"], pos)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
break
|
|
||||||
self.last_sync = time.time()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='p_for_power player')
|
parser = argparse.ArgumentParser(description='p_for_power player')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue