From d9725003c5d1e4aa683aca9e07a83b292cd61ca1 Mon Sep 17 00:00:00 2001
From: jo <ljonas@riseup.net>
Date: Fri, 22 Jul 2022 15:41:38 +0200
Subject: [PATCH] feat(playout): integrate api-client v2 calls

---
 playout/libretime_playout/config.py          |  3 +-
 playout/libretime_playout/main.py            |  5 +-
 playout/libretime_playout/player/file.py     | 39 +++++-------
 playout/libretime_playout/player/schedule.py | 12 ++--
 playout/setup.py                             |  1 +
 playout/tests/player/schedule_test.py        | 65 +++++++++++---------
 6 files changed, 66 insertions(+), 59 deletions(-)

diff --git a/playout/libretime_playout/config.py b/playout/libretime_playout/config.py
index e3ae9b618..dac238293 100644
--- a/playout/libretime_playout/config.py
+++ b/playout/libretime_playout/config.py
@@ -1,6 +1,6 @@
 from pathlib import Path
 
-from libretime_shared.config import BaseConfig, RabbitMQConfig
+from libretime_shared.config import BaseConfig, GeneralConfig, RabbitMQConfig
 from pydantic import BaseModel
 from typing_extensions import Literal
 
@@ -23,5 +23,6 @@ class PlayoutConfig(BaseModel):
 
 
 class Config(BaseConfig):
+    general: GeneralConfig
     rabbitmq: RabbitMQConfig = RabbitMQConfig()
     playout: PlayoutConfig = PlayoutConfig()
diff --git a/playout/libretime_playout/main.py b/playout/libretime_playout/main.py
index 709b20d78..9c204e4e2 100644
--- a/playout/libretime_playout/main.py
+++ b/playout/libretime_playout/main.py
@@ -129,7 +129,10 @@ def cli(log_level: str, log_filepath: Optional[Path], config_filepath: Optional[
     signal.signal(signal.SIGINT, keyboardInterruptHandler)
 
     legacy_client = LegacyClient()
-    api_client = ApiClient()
+    api_client = ApiClient(
+        base_url=config.general.public_url,
+        api_key=config.general.api_key,
+    )
     g = Global(legacy_client)
 
     while not g.selfcheck():
diff --git a/playout/libretime_playout/player/file.py b/playout/libretime_playout/player/file.py
index 499f766ff..726f9aff6 100644
--- a/playout/libretime_playout/player/file.py
+++ b/playout/libretime_playout/player/file.py
@@ -8,7 +8,7 @@ from threading import Thread
 
 from libretime_api_client.v2 import ApiClient
 from loguru import logger
-from requests.exceptions import ConnectionError, Timeout
+from requests.exceptions import ConnectionError, HTTPError, Timeout
 
 
 class PypoFile(Thread):
@@ -22,11 +22,9 @@ class PypoFile(Thread):
         """
         Copy media_item from local library directory to local cache directory.
         """
-        src = media_item["uri"]
+        file_id = media_item["id"]
         dst = media_item["dst"]
 
-        src_size = media_item["filesize"]
-
         dst_exists = True
         try:
             dst_size = os.path.getsize(dst)
@@ -43,33 +41,26 @@ class PypoFile(Thread):
             # become an issue here... This needs proper cache management.
             # https://github.com/libretime/libretime/issues/756#issuecomment-477853018
             # https://github.com/libretime/libretime/pull/845
-            logger.debug(
-                "file %s already exists in local cache as %s, skipping copying..."
-                % (src, dst)
-            )
+            logger.debug(f"found file {file_id} in cache {dst}, skipping copy...")
         else:
             do_copy = True
 
         media_item["file_ready"] = not do_copy
 
         if do_copy:
-            logger.info(f"copying from {src} to local cache {dst}")
+            logger.info(f"copying file {file_id} to cache {dst}")
             try:
                 with open(dst, "wb") as handle:
                     logger.info(media_item)
-                    response = self.api_client.services.file_download_url(
-                        id=media_item["id"]
-                    )
+                    try:
+                        response = self.api_client.download_file(file_id)
+                        for chunk in response.iter_content(chunk_size=1024):
+                            handle.write(chunk)
 
-                    if not response.ok:
-                        logger.error(response)
+                    except HTTPError as exception:
                         raise Exception(
-                            "%s - Error occurred downloading file"
-                            % response.status_code
-                        )
-
-                    for chunk in response.iter_content(chunk_size=1024):
-                        handle.write(chunk)
+                            f"could not download file {media_item['id']}"
+                        ) from exception
 
                 # make file world readable and owner writable
                 os.chmod(dst, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
@@ -82,7 +73,7 @@ class PypoFile(Thread):
 
                 media_item["file_ready"] = True
             except Exception as e:
-                logger.error(f"Could not copy from {src} to {dst}")
+                logger.error(f"could not copy file {file_id} to {dst}")
                 logger.error(e)
 
     def report_file_size_and_md5_to_api(self, file_path, file_id):
@@ -109,8 +100,10 @@ class PypoFile(Thread):
             "Could not update media file %s with file size and md5 hash:" % file_id
         )
         try:
-            payload = {"filesize": file_size, "md5": md5_hash}
-            response = self.api_client.update_file(file_id, payload)
+            self.api_client.update_file(
+                file_id,
+                json={"filesize": file_size, "md5": md5_hash},
+            )
         except (ConnectionError, Timeout):
             logger.error(error_msg)
         except Exception as e:
diff --git a/playout/libretime_playout/player/schedule.py b/playout/libretime_playout/player/schedule.py
index 01d3bd328..8ccad0ec7 100644
--- a/playout/libretime_playout/player/schedule.py
+++ b/playout/libretime_playout/player/schedule.py
@@ -25,29 +25,29 @@ def get_schedule(api_client: ApiClient):
     current_time_str = current_time.isoformat(timespec="seconds")
     end_time_str = end_time.isoformat(timespec="seconds")
 
-    schedule = api_client.services.schedule_url(
+    schedule = api_client.list_schedule(
         params={
             "ends_after": f"{current_time_str}Z",
             "ends_before": f"{end_time_str}Z",
             "overbooked": False,
             "position_status__gt": 0,
         }
-    )
+    ).json()
 
     events = {}
     for item in schedule:
         item["starts_at"] = isoparse(item["starts_at"])
         item["ends_at"] = isoparse(item["ends_at"])
 
-        show_instance = api_client.services.show_instance_url(id=item["instance_id"])
-        show = api_client.services.show_url(id=show_instance["show_id"])
+        show_instance = api_client.get_show_instance(item["instance_id"]).json()
+        show = api_client.get_show(show_instance["show_id"]).json()
 
         if item["file"]:
-            file = api_client.services.file_url(id=item["file_id"])
+            file = api_client.get_file(item["file_id"]).json()
             events.update(generate_file_events(item, file, show))
 
         elif item["stream"]:
-            webstream = api_client.services.webstream_url(id=item["stream_id"])
+            webstream = api_client.get_webstream(item["stream_id"]).json()
             events.update(generate_webstream_events(item, webstream, show))
 
     return {"media": events}
diff --git a/playout/setup.py b/playout/setup.py
index d27aac764..5cc6686b3 100644
--- a/playout/setup.py
+++ b/playout/setup.py
@@ -40,6 +40,7 @@ setup(
     extras_require={
         "dev": [
             "distro",
+            "requests-mock",
             f"libretime-api-client @ file://localhost{here.parent / 'api-client'}",
             f"libretime-shared @ file://localhost{here.parent / 'shared'}",
         ],
diff --git a/playout/tests/player/schedule_test.py b/playout/tests/player/schedule_test.py
index 688f31201..821618b98 100644
--- a/playout/tests/player/schedule_test.py
+++ b/playout/tests/player/schedule_test.py
@@ -1,10 +1,17 @@
+import pytest
+from libretime_api_client.v2 import ApiClient
+
 from libretime_playout.player.schedule import get_schedule
 
 
-class ApiClientServicesMock:
-    @staticmethod
-    def schedule_url(*args, **kwargs):
-        return [
+@pytest.fixture(name="api_client_mock")
+def _api_client_mock(requests_mock):
+    base_url = "http://localhost"
+    api_client = ApiClient(base_url=base_url, api_key="test_key")
+
+    requests_mock.get(
+        f"{base_url}/api/v2/schedule",
+        json=[
             {
                 "id": 17,
                 "starts_at": "2022-03-04T15:30:00Z",
@@ -31,23 +38,26 @@ class ApiClientServicesMock:
                 "cue_out": "00:30:00",
                 "instance_id": 3,
             },
-        ]
+        ],
+    )
 
-    @staticmethod
-    def show_instance_url(*args, **kwargs):
-        return {
+    requests_mock.get(
+        f"{base_url}/api/v2/show-instances/3",
+        json={
             "show_id": 3,
-        }
+        },
+    )
 
-    @staticmethod
-    def show_url(*args, **kwargs):
-        return {
+    requests_mock.get(
+        f"{base_url}/api/v2/shows/3",
+        json={
             "name": "Test",
-        }
+        },
+    )
 
-    @staticmethod
-    def file_url(*args, **kwargs):
-        return {
+    requests_mock.get(
+        f"{base_url}/api/v2/files/1",
+        json={
             "id": 1,
             "url": None,
             "replay_gain": "-8.77",
@@ -55,24 +65,23 @@ class ApiClientServicesMock:
             "artist_name": "Bag Raiders",
             "track_title": "Shooting Stars",
             "mime": "audio/mp3",
-        }
+        },
+    )
 
-    @staticmethod
-    def webstream_url(*args, **kwargs):
-        return {
+    requests_mock.get(
+        f"{base_url}/api/v2/webstreams/1",
+        json={
             "id": 1,
             "name": "Test",
             "url": "http://some-other-radio:8800/main.ogg",
-        }
+        },
+    )
+
+    return api_client
 
 
-class ApiClientMock:
-    services = ApiClientServicesMock()
-
-
-def test_get_schedule():
-    api_client = ApiClientMock()
-    assert get_schedule(api_client) == {
+def test_get_schedule(api_client_mock: ApiClient):
+    assert get_schedule(api_client_mock) == {
         "media": {
             "2022-03-04-15-30-00": {
                 "type": "file",