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