forked from rc/aircox
		
	cfr #121 Co-authored-by: Christophe Siraut <d@tobald.eu.org> Co-authored-by: bkfox <thomas bkfox net> Co-authored-by: Thomas Kairos <thomas@bkfox.net> Reviewed-on: rc/aircox#131 Co-authored-by: Chris Tactic <ctactic@noreply.git.radiocampus.be> Co-committed-by: Chris Tactic <ctactic@noreply.git.radiocampus.be>
		
			
				
	
	
		
			144 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
import os
 | 
						|
import tzlocal
 | 
						|
 | 
						|
from aircox.utils import to_seconds
 | 
						|
 | 
						|
from ..conf import settings
 | 
						|
from .metadata import Metadata, Request
 | 
						|
 | 
						|
 | 
						|
__all__ = (
 | 
						|
    "Source",
 | 
						|
    "PlaylistSource",
 | 
						|
    "QueueSource",
 | 
						|
)
 | 
						|
 | 
						|
local_tz = tzlocal.get_localzone()
 | 
						|
 | 
						|
 | 
						|
class Source(Metadata):
 | 
						|
    controller = None
 | 
						|
    """Parent controller."""
 | 
						|
    id = None
 | 
						|
    """Source id."""
 | 
						|
    remaining = 0.0
 | 
						|
    """Remaining time."""
 | 
						|
    status = "stopped"
 | 
						|
 | 
						|
    @property
 | 
						|
    def station(self):
 | 
						|
        return self.controller.station
 | 
						|
 | 
						|
    def __init__(self, controller=None, id=None, *args, **kwargs):
 | 
						|
        super().__init__(controller, *args, **kwargs)
 | 
						|
        self.id = id
 | 
						|
 | 
						|
    def sync(self):
 | 
						|
        """Synchronize what should be synchronized."""
 | 
						|
 | 
						|
    def fetch(self):
 | 
						|
        try:
 | 
						|
            data = self.controller.send(self.id, ".remaining")
 | 
						|
            if data:
 | 
						|
                self.remaining = float(data)
 | 
						|
        except ValueError:
 | 
						|
            self.remaining = None
 | 
						|
 | 
						|
        data = self.controller.send(f"var.get {self.id}_meta", parse_json=True)
 | 
						|
        if data:
 | 
						|
            self.validate(data if data and isinstance(data, (dict, list)) else {}, as_dict=True)
 | 
						|
 | 
						|
    def skip(self):
 | 
						|
        """Skip the current source sound."""
 | 
						|
        self.controller.send(self.id, ".skip")
 | 
						|
 | 
						|
    def restart(self):
 | 
						|
        """Restart current sound."""
 | 
						|
        # seek 10 hours back since there is not possibility to get current pos
 | 
						|
        self.seek(-216000 * 10)
 | 
						|
 | 
						|
    def seek(self, n):
 | 
						|
        """Seeks into the sound."""
 | 
						|
        self.controller.send(self.id, ".seek ", str(n))
 | 
						|
 | 
						|
 | 
						|
class PlaylistSource(Source):
 | 
						|
    """Source handling playlists (program streams)"""
 | 
						|
 | 
						|
    path = None
 | 
						|
    """Path to playlist."""
 | 
						|
    program = None
 | 
						|
    """Related program."""
 | 
						|
    playlist = None
 | 
						|
    """The playlist."""
 | 
						|
 | 
						|
    def __init__(self, controller, id=None, program=None, **kwargs):
 | 
						|
        id = program.slug.replace("-", "_") if id is None else id
 | 
						|
        self.program = program
 | 
						|
 | 
						|
        super().__init__(controller, id=id, **kwargs)
 | 
						|
        self.path = settings.get_dir(self.station, f"{self.id}.m3u")
 | 
						|
 | 
						|
    def get_sound_queryset(self):
 | 
						|
        """Get playlist's sounds queryset."""
 | 
						|
        return self.program.sound_set.broadcast()
 | 
						|
 | 
						|
    def get_playlist(self):
 | 
						|
        """Get playlist from db."""
 | 
						|
        return self.get_sound_queryset().playlist()
 | 
						|
 | 
						|
    def write_playlist(self, playlist=[]):
 | 
						|
        """Write playlist to file."""
 | 
						|
        playlist = playlist or self.get_playlist()
 | 
						|
        os.makedirs(os.path.dirname(self.path), exist_ok=True)
 | 
						|
        with open(self.path, "w") as file:
 | 
						|
            file.write("\n".join(playlist or []))
 | 
						|
 | 
						|
    def stream(self):
 | 
						|
        """Return program's stream info if any (or None) as dict."""
 | 
						|
        # used in templates
 | 
						|
        # TODO: multiple streams
 | 
						|
        stream = self.program.stream_set.all().first()
 | 
						|
        if not stream or (not stream.begin and not stream.delay):
 | 
						|
            return
 | 
						|
 | 
						|
        return {
 | 
						|
            "begin": stream.begin.strftime("%Hh%M") if stream.begin else None,
 | 
						|
            "end": stream.end.strftime("%Hh%M") if stream.end else None,
 | 
						|
            "delay": to_seconds(stream.delay) if stream.delay else 0,
 | 
						|
        }
 | 
						|
 | 
						|
    def sync(self):
 | 
						|
        playlist = self.get_playlist()
 | 
						|
        self.write_playlist(playlist)
 | 
						|
 | 
						|
 | 
						|
class QueueSource(Source):
 | 
						|
    queue = None
 | 
						|
    """Source's queue (excluded on_air request)"""
 | 
						|
 | 
						|
    @property
 | 
						|
    def requests(self):
 | 
						|
        """Queue as requests metadata."""
 | 
						|
        requests = [Request(self.controller, rid) for rid in self.queue]
 | 
						|
        for request in requests:
 | 
						|
            request.fetch()
 | 
						|
        return requests
 | 
						|
 | 
						|
    def __init__(self, *args, **kwargs):
 | 
						|
        super().__init__(*args, **kwargs)
 | 
						|
 | 
						|
    def push(self, *paths):
 | 
						|
        """Add the provided paths to source's play queue."""
 | 
						|
        for path in paths:
 | 
						|
            print(self.controller.send(f"{self.id}_queue.push {path}"))
 | 
						|
 | 
						|
    def fetch(self):
 | 
						|
        super().fetch()
 | 
						|
        queue = self.controller.send(f"{self.id}_queue.queue").strip()
 | 
						|
        if not queue:
 | 
						|
            self.queue = []
 | 
						|
            return
 | 
						|
 | 
						|
        self.queue = queue.split(" ")
 |