Skip to content

Commit

Permalink
Merge pull request #8 from Tastyep/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Tastyep authored Jun 5, 2020
2 parents 9b3309d + 49baa1e commit 49a2e39
Show file tree
Hide file tree
Showing 56 changed files with 796 additions and 523 deletions.
18 changes: 15 additions & 3 deletions OpenCast.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ PROJECT_NAME="OpenCast"
PROJECT_API_PORT="2020"
PROJECT_WEBAPP_PORT="8081"
LOG_DIR="log"
DOC_DIR="docs"
LOG_FILE="$PROJECT_NAME.log"
TEST_DIR="test"

Expand Down Expand Up @@ -52,7 +53,6 @@ function stop() {
# Todo hardcoded port
lsof -t -i :2020 | xargs kill >/dev/null 2>&1
lsof -t -i :8081 | xargs kill >/dev/null 2>&1
sudo killall omxplayer.bin >/dev/null 2>&1
echo "Done."
}

Expand Down Expand Up @@ -80,10 +80,22 @@ function test() {
if [ -z "$1" ]; then
run_in_env python -m unittest discover -v
else
run_in_env python -m unittest "$TEST_DIR.$1"
local selector="$1"

if [[ "$selector" != "$TEST_DIR"* ]]; then
selector="$TEST_DIR.$selector"
fi
run_in_env python -m unittest "$selector"
fi
}

function gendoc() {
cd "$DOC_DIR" || exit 1

run_in_env make html
xdg-open "build/html/index.html"
}

function run_in_env() {
poetry install
poetry run "$@"
Expand All @@ -93,7 +105,7 @@ function run_in_env() {
# This is likely to be done by the display manager, but not always (lightdm).
source ~/.profile

COMMANDS=("start" "stop" "restart" "update" "status" "logs" "test")
COMMANDS=("start" "stop" "restart" "update" "status" "logs" "test" "gendoc")
if element_in "$1" "${COMMANDS[@]}"; then
COMMAND="$1"
shift
Expand Down
12 changes: 8 additions & 4 deletions OpenCast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from concurrent.futures import ThreadPoolExecutor

import structlog
from vlc import Instance as VlcInstance

from .app.controller.module import ControllerModule
from .app.facade import AppFacade
Expand All @@ -15,6 +16,7 @@
from .infra.io.factory import IoFactory
from .infra.log.module import init as init_logging
from .infra.media.factory import MediaFactory
from .infra.service.factory import ServiceFactory as InfraServiceFactory


def main(argv=None):
Expand All @@ -35,14 +37,16 @@ def main(argv=None):
app_executor = ThreadPoolExecutor(max_workers=1)
app_facade = AppFacade(app_executor)

service_factory = ServiceFactory()
infra_service_factory = InfraServiceFactory()
service_factory = ServiceFactory(infra_service_factory)

repo_factory = RepoFactory()
data_facade = DataFacade(repo_factory)

downloader_executor = ThreadPoolExecutor(config["downloader.max_concurrency"])
io_factory = IoFactory(downloader_executor)
media_factory = MediaFactory()
io_factory = IoFactory()
media_factory = MediaFactory(
VlcInstance(), ThreadPoolExecutor(config["downloader.max_concurrency"])
)
infra_facade = InfraFacade(io_factory, media_factory)

ControllerModule(app_facade, infra_facade, data_facade, service_factory)
Expand Down
2 changes: 1 addition & 1 deletion OpenCast/app/command/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class QueueVideo(Command):


@command
class StopVideo(Command):
class StopPlayer(Command):
pass


Expand Down
5 changes: 5 additions & 0 deletions OpenCast/app/command/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class RetrieveVideo(Command):
output_directory: str


@command
class ParseVideo(Command):
pass


@command
class FetchVideoSubtitle(Command):
language: str
10 changes: 10 additions & 0 deletions OpenCast/app/controller/controller.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import inspect

from OpenCast.domain.service.identity import IdentityService
from OpenCast.util.naming import name_handler_method


class Controller:
Expand All @@ -11,6 +14,13 @@ def _dispatch(self, cmd_cls, component_id, *args, **kwargs):
cmd_id = IdentityService.id_command(cmd_cls, component_id)
self._cmd_dispatcher.dispatch(cmd_cls(cmd_id, component_id, *args, **kwargs))

def _observe(self, module):
classes = inspect.getmembers(module, inspect.isclass)
for _, cls in classes:
if cls.__module__ == module.__name__:
handler_name = name_handler_method(cls)
self._evt_dispatcher.observe(None, {cls: getattr(self, handler_name)})

def _start_workflow(self, workflow_cls, resource_id, *args, **kwargs):
workflow_id = IdentityService.id_workflow(workflow_cls, resource_id)
workflow = workflow_cls(workflow_id, self._app_facade, *args, **kwargs)
Expand Down
2 changes: 2 additions & 0 deletions OpenCast/app/controller/module.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .file import FileController
from .player import PlayerController
from .player_monitor import PlayerMonitController


Expand All @@ -8,3 +9,4 @@ def __init__(self, app_facade, infra_facade, data_facade, service_factory):
self._player_monitor = PlayerMonitController(
app_facade, infra_facade, data_facade, service_factory
)
self._player_controller = PlayerController(app_facade, data_facade)
33 changes: 33 additions & 0 deletions OpenCast/app/controller/player.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import structlog
from OpenCast.app.command import player as Cmd
from OpenCast.domain.service.identity import IdentityService
from OpenCast.infra.event import player as player_events

from .controller import Controller


class PlayerController(Controller):
def __init__(self, app_facade, data_facade):
super(PlayerController, self).__init__(app_facade)

self._logger = structlog.get_logger(__name__)
self._player_repo = data_facade.player_repo
self._video_repo = data_facade.video_repo

self._observe(player_events)

# Infra event handler interface implementation

def _media_end_reached(self, evt):
model = self._player_repo.get_player()
video = model.next_video()
if video is None:
self._dispatch(Cmd.StopPlayer)
else:
self._dispatch(Cmd.PlayVideo, video.id)

def _dispatch(self, cmd_cls, *args, **kwargs):
player_id = IdentityService.id_player()
return super(PlayerController, self)._dispatch(
cmd_cls, player_id, *args, **kwargs
)
18 changes: 10 additions & 8 deletions OpenCast/app/controller/player_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ class PlayerMonitController(Controller):
def __init__(self, app_facade, infra_facade, data_facade, service_factory):
super(PlayerMonitController, self).__init__(app_facade)

media_factory = infra_facade.media_factory
self._source_service = service_factory.make_source_service(
infra_facade.io_factory.make_video_downloader(app_facade.evt_dispatcher)
media_factory.make_downloader(app_facade.evt_dispatcher),
media_factory.make_video_parser(),
)
self._player_repo = data_facade.player_repo
self._video_repo = data_facade.video_repo
Expand Down Expand Up @@ -80,15 +82,15 @@ def _video(self):
if control == "pause":
self._dispatch(Cmd.ToggleVideoState)
elif control == "stop":
self._dispatch(Cmd.StopVideo)
self._dispatch(Cmd.StopPlayer)
elif control == "right":
self._dispatch(Cmd.SeekVideo, 30)
self._dispatch(Cmd.SeekVideo, Player.SHORT_TIME_STEP)
elif control == "left":
self._dispatch(Cmd.SeekVideo, -30)
self._dispatch(Cmd.SeekVideo, -Player.SHORT_TIME_STEP)
elif control == "longright":
self._dispatch(Cmd.SeekVideo, 300)
self._dispatch(Cmd.SeekVideo, Player.LONG_TIME_STEP)
elif control == "longleft":
self._dispatch(Cmd.SeekVideo, -300)
self._dispatch(Cmd.SeekVideo, -Player.LONG_TIME_STEP)
elif control == "prev":
self._dispatch(Cmd.PrevVideo)
elif control == "next":
Expand All @@ -100,9 +102,9 @@ def _video(self):

def _sound(self):
if request.query["vol"] == "more":
self._dispatcher(Cmd.ChangeVolume, Player.VOLUME_STEP)
self._dispatch(Cmd.ChangeVolume, Player.VOLUME_STEP)
else:
self._dispatcher(Cmd.ChangeVolume, -Player.VOLUME_STEP)
self._dispatch(Cmd.ChangeVolume, -Player.VOLUME_STEP)
return "1"

def _subtitle(self):
Expand Down
2 changes: 1 addition & 1 deletion OpenCast/app/service/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ def __init__(self, app_facade, infra_facade, data_facade, service_factory):
app_facade, data_facade, infra_facade.media_factory
)
self._video_service = VideoService(
app_facade, service_factory, data_facade, infra_facade.io_factory
app_facade, service_factory, data_facade, infra_facade.media_factory
)
89 changes: 33 additions & 56 deletions OpenCast/app/service/player.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,41 @@
from functools import partial

import structlog
from OpenCast.app.command import player as player_cmds
from OpenCast.app.error import CommandFailure
from OpenCast.domain.event import player as player_events
from OpenCast.config import config
from OpenCast.domain.model.player_state import PlayerState
from OpenCast.infra.event import player as infra_events

from .service import Service


class PlayerService(Service):
def __init__(self, app_facade, data_facade, media_factory):
logger = structlog.get_logger(__name__)
super(PlayerService, self).__init__(
app_facade, logger, self, player_cmds, infra_events
)
super(PlayerService, self).__init__(app_facade, logger, self, player_cmds)

self._player_repo = data_facade.player_repo
self._video_repo = data_facade.video_repo
self._player = media_factory.make_player(app_facade.evt_dispatcher)

# Infra event handler interface implementation

def _player_stopped(self, evt):
def stop_player(model):
model.stop()

def play_next(model):
video = model.next_video()
if video is not None:
self._player.play(video, model.volume)
model.play(video)

self._update(evt.id, stop_player)
if evt.id is not None:
return

self._update(evt.id, play_next)
model = self._player_model()
self._player.set_volume(model.volume)

# Command handler interface implementation

def _play_video(self, cmd):
def queue_video(model, video):
model.queue(video, with_priority=True)

video = self._video_repo.get(cmd.video_id)
self._update(cmd.id, queue_video, video)
self._queue_video_impl(cmd.id, video)
self._play_video_impl(cmd.id, video)

def _queue_video(self, cmd):
def queue_video(model):
video = self._video_repo.get(cmd.video_id)
model.queue(video)
video = self._video_repo.get(cmd.video_id)
self._queue_video_impl(cmd.id, video)

self._update(cmd.id, queue_video)
def _stop_player(self, cmd):
def stop_video(model):
model.stop()
self._player.stop()

def _stop_video(self, cmd):
self._player.stop(cmd.id)
# Model updates are done from the infra event handler
self._update(cmd.id, stop_video)

def _toggle_video_state(self, cmd):
def pause(model):
Expand Down Expand Up @@ -101,45 +78,45 @@ def _prev_video(self, cmd):
self._play_video_impl(cmd.id, prev_video)

def _toggle_subtitle(self, cmd):
def impl(model, state):
model.subtitle_state = state
def impl(model):
model.subtitle_state = not model.subtitle_state

model = self._player_model()
state = not model.subtitle_state
self._player.update_subtitle_state(state)
self._update(cmd.id, impl, state)
self._player.toggle_subtitle()
self._update(cmd.id, impl)

def _increase_subtitle_delay(self, cmd):
def impl(model):
model.subtitle_delay = model.subtitle_delay + cmd.amount
self._player.set_subtitle_delay(model.subtitle_delay)

self._player.increase_subtitle_delay()
self._update(cmd.id, impl)

def _decrease_subtitle_delay(self, cmd):
def impl(model):
model.subtitle_delay = model.subtitle_delay - cmd.amount
self._player.set_subtitle_delay(model.subtitle_delay)

self._player.increase_subtitle_delay()
self._update(cmd.id, impl)

# Private

def _play_video_impl(self, cmd_id, video):
def play_video(model, video, *_):
def impl(model):
model.play(video)

self._player.play(video, model.volume)
self._update(cmd_id, impl)
def play_video(model):
model.play(video)

self._player.play(video.id, str(video.path))
player = self._player_model()
if player.subtitle_state is True:
sub_stream = video.stream("subtitle", config["subtitle.language"])
if sub_stream is not None:
self._player.select_subtitle_stream(sub_stream.index)
self._update(cmd_id, play_video)

def _queue_video_impl(self, cmd_id, video):
def queue_video(model):
model.queue(video)

model = self._player_model()
if model.state is not PlayerState.STOPPED:
callback = partial(play_video, model, video)
self._evt_dispatcher.once(player_events.PlayerStopped, callback)
self._player.stop(cmd_id)
else:
play_video(model, video)
self._update(cmd_id, queue_video)

def _player_model(self):
return self._player_repo.get_player()
Expand Down
8 changes: 7 additions & 1 deletion OpenCast/app/service/service.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import inspect
import traceback
from functools import partial

from OpenCast.infra.data.repo.error import RepoError
Expand Down Expand Up @@ -40,7 +41,12 @@ def _dispatch_to_handler(self, cmd):
self._logger.error("Repo error", cmd=cmd, error=e)
retry_count -= 1
except Exception as e:
self._logger.error("Operation error", cmd=cmd, error=e)
self._logger.error(
"Operation error",
cmd=cmd,
error=e,
traceback=traceback.format_exc(),
)
self._abort_operation(cmd, str(e))
return

Expand Down
Loading

0 comments on commit 49a2e39

Please sign in to comment.