From 14c153733d8f83bd9e9baa770712d18d36a7ed9a Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 29 Jan 2024 14:06:15 -0500 Subject: [PATCH] listenbrainz: Add an initial ListenBrainz object I created the foundation of what I'll need for working with ListenBrainz. This includes a ListenBrainz GObject, a threading.Thread implementation that will do the actual work for communicating with ListenBrainz, and what will become a priority queue to make sure we do certain operations (such as setting the user's auth token) first. These are mostly placeholder classes right now, and future patches will expand on what they can do. Implements: #69 ("Add ListenBrainz support") Signed-off-by: Anna Schumaker --- README.md | 1 + emmental/listenbrainz/__init__.py | 19 ++++++++++++++++ emmental/listenbrainz/task.py | 6 +++++ emmental/listenbrainz/thread.py | 7 ++++++ tests/listenbrainz/test_listenbrainz.py | 30 +++++++++++++++++++++++++ tests/listenbrainz/test_task.py | 16 +++++++++++++ tests/listenbrainz/test_thread.py | 20 +++++++++++++++++ 7 files changed, 99 insertions(+) create mode 100644 emmental/listenbrainz/__init__.py create mode 100644 emmental/listenbrainz/task.py create mode 100644 emmental/listenbrainz/thread.py create mode 100644 tests/listenbrainz/test_listenbrainz.py create mode 100644 tests/listenbrainz/test_task.py create mode 100644 tests/listenbrainz/test_thread.py diff --git a/README.md b/README.md index a7c623f..075c1e2 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ other playlists run out of tracks. * Python3 * dateutil * gobject + * liblistenbrainz * musicbrainzngs * mutagen * pyxdg diff --git a/emmental/listenbrainz/__init__.py b/emmental/listenbrainz/__init__.py new file mode 100644 index 0000000..63a0898 --- /dev/null +++ b/emmental/listenbrainz/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2024 (c) Anna Schumaker. +"""Our ListenBrainz custom GObject.""" +from gi.repository import GObject +from . import thread +from . import task + + +class ListenBrainz(GObject.GObject): + """Our main ListenBrainz GObject.""" + + def __init__(self): + """Initialize the ListenBrainz GObject.""" + super().__init__() + self._queue = task.Queue() + self._thread = thread.Thread() + + def stop(self) -> None: + """Stop the ListenBrainz thread.""" + self._thread.stop() diff --git a/emmental/listenbrainz/task.py b/emmental/listenbrainz/task.py new file mode 100644 index 0000000..b4e88bd --- /dev/null +++ b/emmental/listenbrainz/task.py @@ -0,0 +1,6 @@ +# Copyright 2024 (c) Anna Schumaker. +"""Our ListenBrainz operation priority queue.""" + + +class Queue: + """A queue for prioritizing ListenBrainz operations.""" diff --git a/emmental/listenbrainz/thread.py b/emmental/listenbrainz/thread.py new file mode 100644 index 0000000..2e2745d --- /dev/null +++ b/emmental/listenbrainz/thread.py @@ -0,0 +1,7 @@ +# Copyright 2024 (c) Anna Schumaker. +"""Our ListenBrainz client thread.""" +from .. import thread + + +class Thread(thread.Thread): + """Thread for submitting listens to ListenBrainz.""" diff --git a/tests/listenbrainz/test_listenbrainz.py b/tests/listenbrainz/test_listenbrainz.py new file mode 100644 index 0000000..42d6def --- /dev/null +++ b/tests/listenbrainz/test_listenbrainz.py @@ -0,0 +1,30 @@ +# Copyright 2024 (c) Anna Schumaker. +"""Tests our custom ListenBrainz GObject.""" +import emmental.listenbrainz +import unittest +from gi.repository import GObject + + +class TestListenBrainz(unittest.TestCase): + """ListenBrainz GObject test case.""" + + def setUp(self): + """Set up common variables.""" + self.listenbrainz = emmental.listenbrainz.ListenBrainz() + + def tearDown(self): + """Clean up.""" + self.listenbrainz.stop() + + def test_init(self): + """Test that the ListenBrainz GObject was set up properly.""" + self.assertIsInstance(self.listenbrainz, GObject.GObject) + self.assertIsInstance(self.listenbrainz._queue, + emmental.listenbrainz.task.Queue) + self.assertIsInstance(self.listenbrainz._thread, + emmental.listenbrainz.thread.Thread) + + def test_stop(self): + """Test stopping the thread during shutdown.""" + self.listenbrainz.stop() + self.assertFalse(self.listenbrainz._thread.is_alive()) diff --git a/tests/listenbrainz/test_task.py b/tests/listenbrainz/test_task.py new file mode 100644 index 0000000..8bcd106 --- /dev/null +++ b/tests/listenbrainz/test_task.py @@ -0,0 +1,16 @@ +# Copyright 2024 (c) Anna Schumaker. +"""Tests our ListenBrainz priority queue.""" +import emmental.listenbrainz.task +import unittest + + +class TestTaskQueue(unittest.TestCase): + """Test the ListenBrainz queue.""" + + def setUp(self): + """Set up common variables.""" + self.queue = emmental.listenbrainz.task.Queue() + + def test_init(self): + """Test that the queue was set up properly.""" + self.assertIsNotNone(self.queue) diff --git a/tests/listenbrainz/test_thread.py b/tests/listenbrainz/test_thread.py new file mode 100644 index 0000000..446055b --- /dev/null +++ b/tests/listenbrainz/test_thread.py @@ -0,0 +1,20 @@ +# Copyright 2024 (c) Anna Schumaker. +"""Tests our ListenBrainz client thread.""" +import emmental.listenbrainz.thread +import unittest + + +class TestThread(unittest.TestCase): + """ListenBrainz Thread test case.""" + + def setUp(self): + """Set up common variables.""" + self.thread = emmental.listenbrainz.thread.Thread() + + def tearDown(self): + """Clean up.""" + self.thread.stop() + + def test_init(self): + """Test that the ListenBrainz thread was initialized properly.""" + self.assertIsInstance(self.thread, emmental.thread.Thread)