@@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
description = "Automated Daily Playlist Generator for Plex Music"
|
description = "Automated Daily Playlist Generator for Plex Music"
|
||||||
authors = ["Cliff Hill <xlorep@darkhelm.org>"]
|
authors = ["Cliff Hill <xlorep@darkhelm.org>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.md"
|
readme = "README.rst"
|
||||||
homepage = "https://gitlab.com/xlorepdarkhelm/plex-playlist"
|
homepage = "https://gitlab.com/xlorepdarkhelm/plex-playlist"
|
||||||
repository = "https://gitlab.com/xlorepdarkhelm/plex-playlist"
|
repository = "https://gitlab.com/xlorepdarkhelm/plex-playlist"
|
||||||
documentation = "https://plex-playlist.readthedocs.io"
|
documentation = "https://plex-playlist.readthedocs.io"
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import datetime
|
|||||||
import functools
|
import functools
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import desert # type: ignore [import]
|
import desert
|
||||||
import marshmallow # type: ignore [import]
|
import marshmallow
|
||||||
|
|
||||||
|
|
||||||
DataSub = typing.TypeVar("DataSub")
|
DataSub = typing.TypeVar("DataSub")
|
||||||
@@ -36,6 +36,9 @@ class DataMeta(type):
|
|||||||
|
|
||||||
This provides a type definition for data to be converted to/from the
|
This provides a type definition for data to be converted to/from the
|
||||||
data class in dictionary form.
|
data class in dictionary form.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DataDict: The TypedDict for this object.
|
||||||
"""
|
"""
|
||||||
fields = {
|
fields = {
|
||||||
name: type_ if type_ is not datetime.datetime else str
|
name: type_ if type_ is not datetime.datetime else str
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ def calc_delay(times: list[float], weights: list[float]) -> None:
|
|||||||
|
|
||||||
This is based on a weighted harmonic mean of the times the processes took in
|
This is based on a weighted harmonic mean of the times the processes took in
|
||||||
the last run.
|
the last run.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
times: The list of times (as seconds) to use for the calculation.
|
||||||
|
weights: The list of weights from 0 to < 1.0 for the calculation.
|
||||||
"""
|
"""
|
||||||
with settings.modify() as s:
|
with settings.modify() as s:
|
||||||
avg_time_per_batch = utils.harmonic_mean(times, weights=weights)
|
avg_time_per_batch = utils.harmonic_mean(times, weights=weights)
|
||||||
@@ -38,6 +42,9 @@ def calc_duration(durations: list[int]) -> None:
|
|||||||
This is based on the geometric mean of the durations of every track loaded from
|
This is based on the geometric mean of the durations of every track loaded from
|
||||||
Plex. The maximum tracks to load for a day is based on the average duration calculated
|
Plex. The maximum tracks to load for a day is based on the average duration calculated
|
||||||
and the amount of time that the system was played the previous day.
|
and the amount of time that the system was played the previous day.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
durations: The list of durations (in seconds) for the calculation.
|
||||||
"""
|
"""
|
||||||
with settings.modify() as s:
|
with settings.modify() as s:
|
||||||
avg_track_duration = statistics.geometric_mean(durations)
|
avg_track_duration = statistics.geometric_mean(durations)
|
||||||
@@ -52,7 +59,7 @@ async def gen_tracks(
|
|||||||
) -> typing.AsyncGenerator[models.Track, None]:
|
) -> typing.AsyncGenerator[models.Track, None]:
|
||||||
"""Generate all Tracks from the Server, asynchronously.
|
"""Generate all Tracks from the Server, asynchronously.
|
||||||
|
|
||||||
Keyword Args:
|
Args:
|
||||||
batch_size: determines how many Tracks are pulled from the Server at a time.
|
batch_size: determines how many Tracks are pulled from the Server at a time.
|
||||||
|
|
||||||
Yields:
|
Yields:
|
||||||
|
|||||||
@@ -27,10 +27,8 @@ def harmonic_mean(
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
data: The sequence of values to calculate.
|
data: The sequence of values to calculate.
|
||||||
|
|
||||||
Keyword Args:
|
|
||||||
weights: The sequence of weights to apply to the calculation. If not
|
weights: The sequence of weights to apply to the calculation. If not
|
||||||
given it assumes all weights are 1.
|
given it assumes all weights are 1.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
float: The [weighted] harmonic mean of the data.
|
float: The [weighted] harmonic mean of the data.
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
"""Tests for validating the Settings object."""
|
"""Tests for validating the Settings object."""
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
import pytest # type: ignore [import]
|
import pytest
|
||||||
|
|
||||||
from playlist.data import settings # type: ignore [import]
|
from playlist.data import settings
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture # type: ignore [misc]
|
@pytest.fixture
|
||||||
def example_settings() -> settings.Settings:
|
def example_settings() -> settings.Settings:
|
||||||
"""Make testable Settings object."""
|
"""Make testable Settings object."""
|
||||||
return settings.Settings(
|
return settings.Settings(
|
||||||
creds=settings.CredentialSettings(baseurl="http://nowhere.huh", token="12345"),
|
creds=settings.CredentialSettings(
|
||||||
|
baseurl="http://nowhere.huh",
|
||||||
|
token="Fake Token", # noqa: S105
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture # type: ignore [misc]
|
@pytest.fixture
|
||||||
def settings_filepath(tmp_path: pathlib.Path) -> pathlib.Path:
|
def settings_filepath(tmp_path: pathlib.Path) -> pathlib.Path:
|
||||||
"""Get the path to use for the settings file."""
|
"""Get the path to use for the settings file."""
|
||||||
return tmp_path / "fake_settings.yaml"
|
return tmp_path / "fake_settings.yaml"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from playlist.data import settings # type: ignore [import]
|
|||||||
from playlist.plex import server # type: ignore [import]
|
from playlist.plex import server # type: ignore [import]
|
||||||
|
|
||||||
|
|
||||||
def test_calc_delay(mocker: pytest.fixture) -> None:
|
def test_calc_delay(mocker): # type: ignore [no-untyped-def]
|
||||||
"""Test the calc_delay function."""
|
"""Test the calc_delay function."""
|
||||||
mock_settings = mocker.patch("playlist.plex.server.settings")
|
mock_settings = mocker.patch("playlist.plex.server.settings")
|
||||||
mock_const = mocker.patch("playlist.plex.server.const")
|
mock_const = mocker.patch("playlist.plex.server.const")
|
||||||
@@ -25,7 +25,7 @@ def test_calc_delay(mocker: pytest.fixture) -> None:
|
|||||||
assert result == 100
|
assert result == 100
|
||||||
|
|
||||||
|
|
||||||
def test_calc_duration(mocker: pytest.fixture) -> None:
|
def test_calc_duration(mocker): # type: ignore [no-untyped-def]
|
||||||
"""Test the calc_duration function."""
|
"""Test the calc_duration function."""
|
||||||
mock_settings = mocker.patch("playlist.plex.server.settings")
|
mock_settings = mocker.patch("playlist.plex.server.settings")
|
||||||
durations = [100, 100, 100]
|
durations = [100, 100, 100]
|
||||||
@@ -36,8 +36,8 @@ def test_calc_duration(mocker: pytest.fixture) -> None:
|
|||||||
assert result == 2
|
assert result == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio # type: ignore [misc]
|
@pytest.mark.asyncio
|
||||||
async def test_gen_tracks(mocker: pytest.fixture) -> None:
|
async def test_gen_tracks(mocker): # type: ignore [no-untyped-def]
|
||||||
"""Test the gen_tracks asynchronous generator."""
|
"""Test the gen_tracks asynchronous generator."""
|
||||||
mock_downloader = mocker.patch(
|
mock_downloader = mocker.patch(
|
||||||
"playlist.plex.server._downloader",
|
"playlist.plex.server._downloader",
|
||||||
|
|||||||
Reference in New Issue
Block a user