Repository: nwithan8/dizqueTV-python (language: python)

Issue:
Compatible with PlexAPI 4.11?
I've install PlexAPI 4.11 and get an incompatibility error with dizqueTV 1.5.0.4. Is this version still compatible or will dizqueTV-python require an update?


Discussion / hints:

Fix patch:
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..59b2008
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,77 @@
+PYTHON_BINARY := python3
+VIRTUAL_ENV := venv
+VIRTUAL_BIN := $(VIRTUAL_ENV)/bin
+PROJECT_NAME := dizqueTV
+TEST_DIR := tests
+
+## help - Display help about make targets for this Makefile
+help:
+	@cat Makefile | grep '^## ' --color=never | cut -c4- | sed -e "`printf 's/ - /\t- /;'`" | column -s "`printf '\t'`" -t
+
+## build - Builds the project in preparation for release
+build:
+	$(VIRTUAL_BIN)/python setup.py sdist bdist_wheel
+
+## clean - Remove the virtual environment and clear out .pyc files
+clean:
+	rm -rf $(VIRTUAL_ENV) dist/ build/ *.egg-info/ .pytest_cache .mypy_cache
+	find . -name '*.pyc' -delete
+
+## coverage - Test the project and generate an HTML coverage report
+coverage:
+	$(VIRTUAL_BIN)/pytest --cov=$(PROJECT_NAME) --cov-branch --cov-report=html --cov-report=term-missing
+
+## black - Runs the Black Python formatter against the project
+black:
+	$(VIRTUAL_BIN)/black $(PROJECT_NAME)/ $(TEST_DIR)/
+
+## black-check - Checks if the project is formatted correctly against the Black rules
+black-check:
+	$(VIRTUAL_BIN)/black $(PROJECT_NAME)/ $(TEST_DIR)/ --check
+
+## format - Runs all formatting tools against the project
+format: black isort
+
+## format-check - Checks if the project is formatted correctly against all formatting rules
+format-check: black-check isort-check lint mypy
+
+## install - Install the project locally
+install:
+	$(PYTHON_BINARY) -m venv $(VIRTUAL_ENV)
+	$(VIRTUAL_BIN)/pip install -r requirements.txt
+	$(VIRTUAL_BIN)/pip install -r dev_requirements.txt
+
+## isort - Sorts imports throughout the project
+isort:
+	$(VIRTUAL_BIN)/isort $(PROJECT_NAME)/ $(TEST_DIR)/
+
+## isort-check - Checks that imports throughout the project are sorted correctly
+isort-check:
+	$(VIRTUAL_BIN)/isort $(PROJECT_NAME)/ $(TEST_DIR)/ --check-only
+
+## lint - Lint the project
+lint:
+	$(VIRTUAL_BIN)/flake8 $(PROJECT_NAME)/ $(TEST_DIR)/
+
+## mypy - Run mypy type checking on the project
+mypy:
+	$(VIRTUAL_BIN)/mypy $(PROJECT_NAME)/ $(TEST_DIR)/
+
+## publish - Publish the project to PyPI
+publish:
+	$(VIRTUAL_BIN)/twine upload dist/*
+
+## release - Cuts a release for the project on GitHub (requires GitHub CLI)
+# tag = The associated tag title of the release
+release:
+	gh release create ${tag} dist/*
+
+## scan - Scans the project for security issues with Bandit
+scan:
+	$(VIRTUAL_BIN)/bandit -r $(PROJECT_NAME)
+
+## test - Test the project
+test:
+	$(VIRTUAL_BIN)/pytest
+
+.PHONY: help build clean coverage black black-check format format-check install isort isort-check lint mypy publish release scan test
\ No newline at end of file
diff --git a/dev_requirements.txt b/dev_requirements.txt
new file mode 100644
index 0000000..a3ca3a5
--- /dev/null
+++ b/dev_requirements.txt
@@ -0,0 +1,8 @@
+black
+flake8
+isort
+pytest-cov==3.*
+pytest==7.*
+types-requests
+types-urllib3
+python-dotenv
\ No newline at end of file
diff --git a/dizqueTV/__init__.py b/dizqueTV/__init__.py
index 14ba838..51ba41d 100644
--- a/dizqueTV/__init__.py
+++ b/dizqueTV/__init__.py
@@ -1,5 +1,9 @@
-from dizqueTV.dizquetv import API, convert_plex_item_to_filler_item, convert_plex_item_to_program, \
-    convert_plex_server_to_dizque_plex_server, make_time_slot_from_dizque_program
-from dizqueTV.plex_utils import PlexUtils
+from dizqueTV.dizquetv import (API, convert_plex_item_to_filler_item,
+                               convert_plex_item_to_program,
+                               convert_plex_server_to_dizque_plex_server,
+                               make_time_slot_from_dizque_program)
 from dizqueTV.models import PlexServer
-from ._info import __author__, __version__, __license__, __copyright__, __author_email__
+from dizqueTV.plex_utils import PlexUtils
+
+from ._info import (__author__, __author_email__, __copyright__, __license__,
+                    __version__)
diff --git a/dizqueTV/_analytics.py b/dizqueTV/_analytics.py
index 040829b..a70825b 100644
--- a/dizqueTV/_analytics.py
+++ b/dizqueTV/_analytics.py
@@ -20,12 +20,14 @@ def _generate_uuid(random=False):
 
 def _verify_params(params_needed, **included_params):
     for needed_param in params_needed:
-        if needed_param not in included_params.keys() or included_params.get(needed_param):
+        if needed_param not in included_params.keys() or included_params.get(
+            needed_param
+        ):
             return False
     return True
 
 
-def _string_size(string: str, max_size: int, encoding: str = 'utf-8'):
+def _string_size(string: str, max_size: int, encoding: str = "utf-8"):
     return len(string.encode(encoding)) <= max_size
 
 
@@ -36,12 +38,11 @@ def _make_url(params_dict):
 
 
 class GoogleAnalytics:
-    def __init__(self,
-                 analytics_id: str,
-                 anonymous_ip: bool = False,
-                 do_not_track: bool = False):
+    def __init__(
+        self, analytics_id: str, anonymous_ip: bool = False, do_not_track: bool = False
+    ):
         self.analytics_id = analytics_id
-        self.version = '1'
+        self.version = "1"
         self.anonymize_ip = anonymous_ip
         self.do_not_track = do_not_track
 
@@ -54,82 +55,88 @@ def _send(self, final_params):
             return True
         return False
 
-    def exception(self,
-                  exception_description: str,
-                  is_fatal: bool = False,
-                  user_id: str = None,
-                  anonymize_ip: bool = False,
-                  random_uuid_if_needed: bool = False):
+    def exception(
+        self,
+        exception_description: str,
+        is_fatal: bool = False,
+        user_id: str = None,
+        anonymize_ip: bool = False,
+        random_uuid_if_needed: bool = False,
+    ):
         if self.do_not_track:
             return True
         if not user_id:
             user_id = str(_generate_uuid(random=random_uuid_if_needed))
         final_params = {
-            'v': self.version,
-            'tid': self.analytics_id,
-            't': 'exception',
-            'cid': user_id,
-            'exf': 0
+            "v": self.version,
+            "tid": self.analytics_id,
+            "t": "exception",
+            "cid": user_id,
+            "exf": 0,
         }
         if not _string_size(string=exception_description, max_size=150):
             return False
         else:
-            final_params['exd'] = exception_description
+            final_params["exd"] = exception_description
         if is_fatal:
-            final_params['exf'] = 1
+            final_params["exf"] = 1
         if anonymize_ip or self.anonymize_ip:
-            final_params['aip'] = 0
+            final_params["aip"] = 0
         return self._send(final_params=final_params)
 
-    def event(self,
-              event_category: str,
-              event_action: str,
-              event_label: str = None,
-              event_value: int = None,
-              user_id: str = None,
-              anonymize_ip: bool = False,
-              random_uuid_if_needed: bool = False):
+    def event(
+        self,
+        event_category: str,
+        event_action: str,
+        event_label: str = None,
+        event_value: int = None,
+        user_id: str = None,
+        anonymize_ip: bool = False,
+        random_uuid_if_needed: bool = False,
+    ):
         if self.do_not_track:
             return True
         if not user_id:
             user_id = str(_generate_uuid(random=random_uuid_if_needed))
         final_params = {
-            'v': self.version,
-            'tid': self.analytics_id,
-            't': 'event',
-            'cid': user_id
+            "v": self.version,
+            "tid": self.analytics_id,
+            "t": "event",
+            "cid": user_id,
         }
         if anonymize_ip or self.anonymize_ip:
-            final_params['aip'] = 0
-        final_params['ec'] = event_category
-        final_params['ea'] = event_action
+            final_params["aip"] = 0
+        final_params["ec"] = event_category
+        final_params["ea"] = event_action
         if event_label:
-            final_params['el'] = event_label
+            final_params["el"] = event_label
         if event_value:
-            final_params['ev'] = event_value
+            final_params["ev"] = event_value
         return self._send(final_params=final_params)
 
-    def pageview(self,
-                 visited_page: str,
-                 page_title: str = None,
-                 user_id: str = None,
-                 anonymize_ip: bool = False,
-                 random_uuid_if_needed: bool = False):
+    def pageview(
+        self,
+        visited_page: str,
+        page_title: str = None,
+        user_id: str = None,
+        anonymize_ip: bool = False,
+        random_uuid_if_needed: bool = False,
+    ):
         if self.do_not_track:
             return True
         if not user_id:
             user_id = str(_generate_uuid(random=random_uuid_if_needed))
         final_params = {
-            'v': self.version,
-            'tid': self.analytics_id,
-            't': 'pageview',
-            'cid': user_id
+            "v": self.version,
+            "tid": self.analytics_id,
+            "t": "pageview",
+            "cid": user_id,
         }
         if anonymize_ip or self.anonymize_ip:
-            final_params['aip'] = 0
-        if not visited_page.startswith('/'):
+            final_params["aip"] = 0
+        if not visited_page.startswith("/"):
             visited_page = f"/{visited_page}"
-        final_params['dl'] = visited_page
+        final_params["dl"] = visited_page
         if page_title:
-            final_params['dt'] = page_title
+            final_params["dt"] = page_title
         return self._send(final_params=final_params)
diff --git a/dizqueTV/_info.py b/dizqueTV/_info.py
index d4bab54..dbdbc3d 100644
--- a/dizqueTV/_info.py
+++ b/dizqueTV/_info.py
@@ -1,24 +1,24 @@
-__version__ = 'VERSIONADDEDBYGITHUB'
+__version__ = "VERSIONADDEDBYGITHUB"
 
 __title__ = "dizqueTV"
-__author__ = 'Nate Harris'
-__author_email__ = 'n8gr8gbln@gmail.com'
+__author__ = "Nate Harris"
+__author_email__ = "n8gr8gbln@gmail.com"
 __copyright__ = "Copyright © YEARADDEDBYGITHUB - Nate Harris"
-__license__ = 'GNU General Public License v3 (GPLv3)'
+__license__ = "GNU General Public License v3 (GPLv3)"
 __docs__ = "https://dizquetv.readthedocs.io/en/latest"
 __description__ = "Interact with a dizqueTV instance's API"
 __keywords__ = [
-    'dizqueTV',
-    'Plex',
-    'Jellyfin',
-    'Emby',
-    'media',
-    'API',
-    'server',
-    'interaction',
-    'TV',
-    'television',
-    'streaming'
+    "dizqueTV",
+    "Plex",
+    "Jellyfin",
+    "Emby",
+    "media",
+    "API",
+    "server",
+    "interaction",
+    "TV",
+    "television",
+    "streaming",
 ]
 
 __analytics_id__ = "UA-174268200-3"
diff --git a/dizqueTV/advanced.py b/dizqueTV/advanced.py
index ffa0c73..623f49a 100644
--- a/dizqueTV/advanced.py
+++ b/dizqueTV/advanced.py
@@ -19,7 +19,7 @@ def get_ffmpeg_urls_raw(self, channel_number: int) -> str:
         if channel_number not in self._dizque_instance.channel_numbers:
             raise Exception(f"Channel {channel_number} does not exist.")
         url = f"{self._dizque_instance.url}/playlist?channel={channel_number}"
-        response = requests.get(url=url, log='info')
+        response = requests.get(url=url, log="info")
         if not response:
             return ""
         return response.text
diff --git a/dizqueTV/dizquetv.py b/dizqueTV/dizquetv.py
index e98574c..d78ea2c 100644
--- a/dizqueTV/dizquetv.py
+++ b/dizqueTV/dizquetv.py
@@ -1,8 +1,7 @@
 import json
 import logging
-from concurrent.futures import ThreadPoolExecutor
 from datetime import datetime
-from typing import List, Union, Dict
+from typing import Dict, List, Union
 from xml.etree import ElementTree
 
 import m3u8
@@ -10,25 +9,32 @@
 from objectrest import Response
 from plexapi.audio import Track
 from plexapi.server import PlexServer as PServer
-from plexapi.video import Video, Movie, Episode
+from plexapi.video import Episode, Movie, Video
 
 import dizqueTV.dizquetv_requests as requests
 import dizqueTV.helpers as helpers
 from dizqueTV._analytics import GoogleAnalytics
 from dizqueTV._info import __analytics_id__ as analytics_id
 from dizqueTV.advanced import Advanced
-from dizqueTV.exceptions import MissingParametersError, ChannelCreationError, ItemCreationError, GeneralException
-from dizqueTV.models import Channel, TimeSlot, TimeSlotItem, Schedule, CustomShow, CustomShowDetails, CustomShowItem, \
-    FillerList, UploadImageResponse, Guide, FillerItem, Program, Redirect, PlexServer, XMLTVSettings, PlexSettings, \
-    FFMPEGSettings, HDHomeRunSettings, ServerDetails
-from dizqueTV.models.templates import PLEX_SERVER_SETTINGS_TEMPLATE, CHANNEL_SETTINGS_TEMPLATE, \
-    CHANNEL_SETTINGS_DEFAULT, \
-    FILLER_LIST_SETTINGS_TEMPLATE, WATERMARK_SETTINGS_DEFAULT, CUSTOM_SHOW_TEMPLATE
-
-
-def make_time_slot_from_dizque_program(program: Union[Program, Redirect],
-                                       time: str,
-                                       order: str) -> Union[TimeSlot, None]:
+from dizqueTV.exceptions import (ChannelCreationError, GeneralException,
+                                 ItemCreationError, MissingParametersError)
+from dizqueTV.models import (Channel, CustomShow, CustomShowDetails,
+                             CustomShowItem, FFMPEGSettings, FillerItem,
+                             FillerList, Guide, HDHomeRunSettings, PlexServer,
+                             PlexSettings, Program, Redirect, Schedule,
+                             ServerDetails, TimeSlot, TimeSlotItem,
+                             UploadImageResponse, XMLTVSettings)
+from dizqueTV.models.templates import (CHANNEL_SETTINGS_DEFAULT,
+                                       CHANNEL_SETTINGS_TEMPLATE,
+                                       CUSTOM_SHOW_TEMPLATE,
+                                       FILLER_LIST_SETTINGS_TEMPLATE,
+                                       PLEX_SERVER_SETTINGS_TEMPLATE,
+                                       WATERMARK_SETTINGS_DEFAULT)
+
+
+def make_time_slot_from_dizque_program(
+    program: Union[Program, Redirect], time: str, order: str
+) -> Union[TimeSlot, None]:
     """
     Convert a DizqueTV Program or Redirect into a TimeSlot object for use in scheduling
 
@@ -41,22 +47,26 @@ def make_time_slot_from_dizque_program(program: Union[Program, Redirect],
     :return: TimeSlot object
     :rtype: TimeSlot
     """
-    if program.type == 'redirect':
-        item = TimeSlotItem(item_type='redirect', item_value=program.channel)
+    if program.type == "redirect":
+        item = TimeSlotItem(item_type="redirect", item_value=program.channel)
     elif program.showTitle:
-        if program.type == 'movie':
-            item = TimeSlotItem(item_type='movie', item_value=program.showTitle)
+        if program.type == "movie":
+            item = TimeSlotItem(item_type="movie", item_value=program.showTitle)
         else:
-            item = TimeSlotItem(item_type='tv', item_value=program.showTitle)
+            item = TimeSlotItem(item_type="tv", item_value=program.showTitle)
     else:
         return None
-    data = {'time': helpers.convert_24_time_to_milliseconds_past_midnight(time_string=time),
-            'showId': item.showId,
-            'order': order}
+    data = {
+        "time": helpers.convert_24_time_to_milliseconds_past_midnight(time_string=time),
+        "showId": item.showId,
+        "order": order,
+    }
     return TimeSlot(data=data, program=item)
 
 
-def convert_program_to_custom_show_item(program: Program, dizque_instance) -> CustomShowItem:
+def convert_program_to_custom_show_item(
+    program: Program, dizque_instance
+) -> CustomShowItem:
     """
     Convert a dizqueTV Program to a dizqueTV CustomShowItem (add durationStr and commercials)
 
@@ -68,12 +78,16 @@ def convert_program_to_custom_show_item(program: Program, dizque_instance) -> Cu
     :rtype: CustomShowItem
     """
     program_data = program._data
-    program_data['durationStr'] = helpers.duration_to_string(milliseconds=program_data['duration'])
-    program_data['commercials'] = []
+    program_data["durationStr"] = helpers.duration_to_string(
+        milliseconds=program_data["duration"]
+    )
+    program_data["commercials"] = []
     return CustomShowItem(data=program_data, dizque_instance=dizque_instance, order=-1)
 
 
-def convert_custom_show_to_programs(custom_show: CustomShow, dizque_instance) -> List[Program]:
+def convert_custom_show_to_programs(
+    custom_show: CustomShow, dizque_instance
+) -> List[Program]:
     """
     Convert a CustomShow into a list of Program objects
 
@@ -87,15 +101,18 @@ def convert_custom_show_to_programs(custom_show: CustomShow, dizque_instance) ->
     programs = []
     for program in custom_show.content:
         data = program._data
-        data['customShowId'] = custom_show.id
-        data['customShowName'] = custom_show.name
-        data['customOrder'] = program.order
-        programs.append(Program(data=data, dizque_instance=dizque_instance, channel_instance=None))
+        data["customShowId"] = custom_show.id
+        data["customShowName"] = custom_show.name
+        data["customOrder"] = program.order
+        programs.append(
+            Program(data=data, dizque_instance=dizque_instance, channel_instance=None)
+        )
     return programs
 
 
-def convert_plex_item_to_program(plex_item: Union[Video, Movie, Episode, Track],
-                                 plex_server: PServer) -> Program:
+def convert_plex_item_to_program(
+    plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer
+) -> Program:
     """
     Convert a PlexAPI Video, Movie, Episode or Track object into a Program
 
@@ -106,12 +123,15 @@ def convert_plex_item_to_program(plex_item: Union[Video, Movie, Episode, Track],
     :return: Program object
     :rtype: Program
     """
-    data = helpers._make_program_dict_from_plex_item(plex_item=plex_item, plex_server=plex_server)
+    data = helpers._make_program_dict_from_plex_item(
+        plex_item=plex_item, plex_server=plex_server
+    )
     return Program(data=data, dizque_instance=None, channel_instance=None)
 
 
-def convert_plex_item_to_filler_item(plex_item: Union[Video, Movie, Episode, Track],
-                                     plex_server: PServer) -> FillerItem:
+def convert_plex_item_to_filler_item(
+    plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer
+) -> FillerItem:
     """
     Convert a PlexAPI Video, Movie, Episode or Track object into a FillerItem
 
@@ -122,7 +142,9 @@ def convert_plex_item_to_filler_item(plex_item: Union[Video, Movie, Episode, Tra
     :return: Program object
     :rtype: Program
     """
-    data = helpers._make_filler_dict_from_plex_item(plex_item=plex_item, plex_server=plex_server)
+    data = helpers._make_filler_dict_from_plex_item(
+        plex_item=plex_item, plex_server=plex_server
+    )
     return FillerItem(data=data, dizque_instance=None, filler_list_instance=None)
 
 
@@ -187,15 +209,19 @@ def expand_custom_show_items(programs: List, dizque_instance) -> List:
 
     :param programs: List of programs (i.e. Program, Movie, Video, Track, CustomShow)
     :type programs: list
+    :param dizque_instance: DizqueTV API instance
+    :type dizque_instance: API
     :return: list of all programs (including custom show programs)
     :rtype: list
     """
     all_items = []
     for item in programs:
-        if not helpers._object_has_attribute(obj=item, attribute_name='customShowTag'):
+        if not helpers._object_has_attribute(obj=item, attribute_name="customShowTag"):
             all_items.append(item)
         else:
-            programs = convert_custom_show_to_programs(custom_show=item, dizque_instance=dizque_instance)
+            programs = convert_custom_show_to_programs(
+                custom_show=item, dizque_instance=dizque_instance
+            )
             all_items.extend(programs)
     return all_items
 
@@ -210,22 +236,37 @@ def fill_in_watermark_settings(handle_errors: bool = True, **kwargs) -> dict:
     :return: A complete and valid watermark dict
     :rtype: dict
     """
-    final_dict = helpers._combine_settings_add_new(new_settings_dict=kwargs,
-                                                   default_dict=WATERMARK_SETTINGS_DEFAULT)
-    if handle_errors and final_dict['enabled'] is True:
-        if not (0 < final_dict['width'] <= 100):
-            raise GeneralException("Watermark width must greater than 0 and less than 100")
-        if not (final_dict['width'] + final_dict['horizontalMargin'] <= 100):
-            raise GeneralException("Watermark width + horizontalMargin must not be greater than 100")
-        if not (final_dict['verticalMargin'] <= 100):
-            raise GeneralException("Watermark verticalMargin must not be greater than 100")
-        if not (final_dict['duration'] and final_dict['duration'] >= 0):
-            raise GeneralException("Must include a watermark duration. Use 0 for a permanent watermark.")
+    final_dict = helpers._combine_settings_add_new(
+        new_settings_dict=kwargs, default_dict=WATERMARK_SETTINGS_DEFAULT
+    )
+    if handle_errors and final_dict["enabled"] is True:
+        if not (0 < final_dict["width"] <= 100):
+            raise GeneralException(
+                "Watermark width must greater than 0 and less than 100"
+            )
+        if not (final_dict["width"] + final_dict["horizontalMargin"] <= 100):
+            raise GeneralException(
+                "Watermark width + horizontalMargin must not be greater than 100"
+            )
+        if not (final_dict["verticalMargin"] <= 100):
+            raise GeneralException(
+                "Watermark verticalMargin must not be greater than 100"
+            )
+        if not (final_dict["duration"] and final_dict["duration"] >= 0):
+            raise GeneralException(
+                "Must include a watermark duration. Use 0 for a permanent watermark."
+            )
     return final_dict
 
 
 class API:
-    def __init__(self, url: str, verbose: bool = False, allow_analytics: bool = True, anonymous_analytics: bool = True):
+    def __init__(
+        self,
+        url: str,
+        verbose: bool = False,
+        allow_analytics: bool = True,
+        anonymous_analytics: bool = True,
+    ):
         """
         Interact with dizqueTV's API
 
@@ -238,65 +279,90 @@ def __init__(self, url: str, verbose: bool = False, allow_analytics: bool = True
         :param anonymous_analytics: Make Google Analytics anonymous (see disclaimer)
         :type anonymous_analytics: bool
         """
-        self.url = url.rstrip('/')
+        self.url = url.rstrip("/")
         self.verbose = verbose
         self.advanced = Advanced(dizque_instance=self)
-        self.analytics = GoogleAnalytics(analytics_id=analytics_id,
-                                         anonymous_ip=anonymous_analytics,
-                                         do_not_track=not allow_analytics)
-        logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',
-                            level=(logging.INFO if verbose else logging.ERROR))
+        self.analytics = GoogleAnalytics(
+            analytics_id=analytics_id,
+            anonymous_ip=anonymous_analytics,
+            do_not_track=not allow_analytics,
+        )
+        logging.basicConfig(
+            format="%(asctime)s %(levelname)s:%(message)s",
+            level=(logging.INFO if verbose else logging.ERROR),
+        )
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.url})"
 
-    def _get(self, endpoint: str, params: dict = None, headers: dict = None, timeout: int = 2) -> Union[Response, None]:
-        if not endpoint.startswith('/'):
+    def _get(
+        self, endpoint: str, params: dict = None, headers: dict = None, timeout: int = 2
+    ) -> Union[Response, None]:
+        if not endpoint.startswith("/"):
             endpoint = f"/{endpoint}"
         url = f"{self.url}/api{endpoint}"
-        return requests.get(url=url,
-                            params=params,
-                            headers=headers,
-                            timeout=timeout,
-                            log='info')
-
-    def _post(self, endpoint: str, params: dict = None, headers: dict = None, data: dict = None, files: dict = None,
-              timeout: int = 2) -> Union[Response, None]:
-        if not endpoint.startswith('/'):
+        return requests.get(
+            url=url, params=params, headers=headers, timeout=timeout, log="info"
+        )
+
+    def _post(
+        self,
+        endpoint: str,
+        params: dict = None,
+        headers: dict = None,
+        data: dict = None,
+        files: dict = None,
+        timeout: int = 2,
+    ) -> Union[Response, None]:
+        if not endpoint.startswith("/"):
             endpoint = f"/{endpoint}"
         url = f"{self.url}/api{endpoint}"
-        return requests.post(url=url,
-                             params=params,
-                             data=data,
-                             files=files,
-                             headers=headers,
-                             timeout=timeout,
-                             log='info')
-
-    def _put(self, endpoint: str, params: dict = None, headers: dict = None, data: dict = None, timeout: int = 2) -> \
-            Union[Response, None]:
-        if not endpoint.startswith('/'):
+        return requests.post(
+            url=url,
+            params=params,
+            data=data,
+            files=files,
+            headers=headers,
+            timeout=timeout,
+            log="info",
+        )
+
+    def _put(
+        self,
+        endpoint: str,
+        params: dict = None,
+        headers: dict = None,
+        data: dict = None,
+        timeout: int = 2,
+    ) -> Union[Response, None]:
+        if not endpoint.startswith("/"):
             endpoint = f"/{endpoint}"
         url = f"{self.url}/api{endpoint}"
-        return requests.put(url=url,
-                            params=params,
-                            data=data,
-                            headers=headers,
-                            timeout=timeout,
-                            log='info')
-
-    def _delete(self, endpoint: str, params: dict = None, data: dict = None, timeout: int = 2) -> Union[Response, None]:
-        if not endpoint.startswith('/'):
+        return requests.put(
+            url=url,
+            params=params,
+            data=data,
+            headers=headers,
+            timeout=timeout,
+            log="info",
+        )
+
+    def _delete(
+        self, endpoint: str, params: dict = None, data: dict = None, timeout: int = 2
+    ) -> Union[Response, None]:
+        if not endpoint.startswith("/"):
             endpoint = f"/{endpoint}"
         url = f"{self.url}/api{endpoint}"
-        return requests.delete(url=url,
-                               params=params,
-                               data=data,
-                               timeout=timeout,
-                               log='info')
-
-    def _get_json(self, endpoint: str, params: dict = None, headers: dict = None, timeout: int = 2) -> json:
-        response = self._get(endpoint=endpoint, params=params, headers=headers, timeout=timeout)
+        return requests.delete(
+            url=url, params=params, data=data, timeout=timeout, log="info"
+        )
+
+    def _get_json(
+        self, endpoint: str, params: dict = None, headers: dict = None, timeout: int = 2
+    ) -> Union[dict, list, str]:
+        response = self._get(
+            endpoint=endpoint, params=params, headers=headers, timeout=timeout
+        )
         if response:
             return response.json()
         return {}
@@ -309,7 +375,7 @@ def dizquetv_server_details(self) -> ServerDetails:
         :return: ServerDetails object
         :rtype: ServerDetails
         """
-        json_data = self._get_json(endpoint='/version')
+        json_data = self._get_json(endpoint="/version")
         return ServerDetails(data=json_data, dizque_instance=self)
 
     # Versions
@@ -352,7 +418,7 @@ def plex_servers(self) -> List[PlexServer]:
         :return: List of PlexServer objects
         :rtype: List[PlexServer]
         """
-        json_data = self._get_json(endpoint='/plex-servers')
+        json_data = self._get_json(endpoint="/plex-servers")
         return [PlexServer(data=server, dizque_instance=self) for server in json_data]
 
     def plex_server_status(self, server_name: str) -> bool:
@@ -364,7 +430,7 @@ def plex_server_status(self, server_name: str) -> bool:
         :return: True if active, False if not active
         :rtype: bool
         """
-        if self._post(endpoint='/plex-servers/status', data={'name': server_name}):
+        if self._post(endpoint="/plex-servers/status", data={"name": server_name}):
             return True
         return False
 
@@ -376,7 +442,9 @@ def plex_server_foreign_status(self, server_name: str) -> bool:
         :return: True if active, False if not active
         :rtype: bool
         """
-        if self._post(endpoint='/plex-servers/foreignstatus', data={'name': server_name}):
+        if self._post(
+            endpoint="/plex-servers/foreignstatus", data={"name": server_name}
+        ):
             return True
         return False
 
@@ -402,14 +470,17 @@ def add_plex_server(self, **kwargs) -> Union[PlexServer, None]:
         :return: PlexServer object or None
         :rtype: PlexServer
         """
-        if helpers._settings_are_complete(new_settings_dict=kwargs,
-                                          template_settings_dict=PLEX_SERVER_SETTINGS_TEMPLATE,
-                                          ignore_keys=['_id', 'id']) \
-                and self._put(endpoint='/plex-servers', data=kwargs):
-            return self.get_plex_server(server_name=kwargs['name'])
+        if helpers._settings_are_complete(
+            new_settings_dict=kwargs,
+            template_settings_dict=PLEX_SERVER_SETTINGS_TEMPLATE,
+            ignore_keys=["_id", "id"],
+        ) and self._put(endpoint="/plex-servers", data=kwargs):
+            return self.get_plex_server(server_name=kwargs["name"])
         return None
 
-    def add_plex_server_from_plexapi(self, plex_server: PServer) -> Union[PlexServer, None]:
+    def add_plex_server_from_plexapi(
+        self, plex_server: PServer
+    ) -> Union[PlexServer, None]:
         """
         Convert and add a plexapi.PlexServer as a Plex Media Server to dizqueTV
 
@@ -427,12 +498,12 @@ def add_plex_server_from_plexapi(self, plex_server: PServer) -> Union[PlexServer
             else:
                 index_available = True
         server_settings = {
-            'name': plex_server.friendlyName,
-            'uri': helpers.get_plex_indirect_uri(plex_server=plex_server),
-            'accessToken': helpers.get_plex_access_token(plex_server=plex_server),
-            'index': index,
-            'arChannels': True,
-            'arGuide': True
+            "name": plex_server.friendlyName,
+            "uri": helpers.get_plex_indirect_uri(plex_server=plex_server),
+            "accessToken": helpers.get_plex_access_token(plex_server=plex_server),
+            "index": index,
+            "arChannels": True,
+            "arGuide": True,
         }
         return self.add_plex_server(**server_settings)
 
@@ -448,8 +519,10 @@ def update_plex_server(self, server_name: str, **kwargs) -> bool:
         """
         server = self.get_plex_server(server_name=server_name)
         if server:
-            new_settings = helpers._combine_settings(new_settings_dict=kwargs, default_dict=server._data)
-            if self._post(endpoint='/plex-servers', data=new_settings):
+            new_settings = helpers._combine_settings(
+                new_settings_dict=kwargs, default_dict=server._data
+            )
+            if self._post(endpoint="/plex-servers", data=new_settings):
                 return True
         return False
 
@@ -462,7 +535,7 @@ def delete_plex_server(self, server_name: str) -> bool:
         :return: True if successful, False if unsuccessful
         :rtype: bool
         """
-        if self._delete(endpoint='/plex-servers', data={'name': server_name}):
+        if self._delete(endpoint="/plex-servers", data={"name": server_name}):
             return True
         return False
 
@@ -470,7 +543,7 @@ def delete_plex_server(self, server_name: str) -> bool:
 
     def _get_channel_data(self, channel_number: int) -> Union[Dict, None]:
         # large JSON may take longer, so bigger timeout
-        return self._get_json(endpoint=f'/channel/{channel_number}', timeout=5)
+        return self._get_json(endpoint=f"/channel/{channel_number}", timeout=5)
 
     @property
     def channels(self) -> List[Channel]:
@@ -484,8 +557,11 @@ def channels(self) -> List[Channel]:
         numbers = self.channel_numbers
         channels = []
 
-        channels_json_data = helpers._multithread(func=self._get_channel_data, elements=numbers,
-                                                  element_param_name="channel_number")
+        channels_json_data = helpers._multithread(
+            func=self._get_channel_data,
+            elements=numbers,
+            element_param_name="channel_number",
+        )
 
         for json_data in channels_json_data:
             if json_data:
@@ -493,7 +569,9 @@ def channels(self) -> List[Channel]:
 
         return channels
 
-    def get_channel(self, channel_number: int = None, channel_name: str = None) -> Union[Channel, None]:
+    def get_channel(
+        self, channel_number: int = None, channel_name: str = None
+    ) -> Union[Channel, None]:
         """
         Get a specific dizqueTV channel by number or name
 
@@ -505,9 +583,11 @@ def get_channel(self, channel_number: int = None, channel_name: str = None) -> U
         :rtype: Channel
         """
         if not channel_number and not channel_name:
-            raise MissingParametersError("Must include either 'channel_number' or 'channel_name'")
+            raise MissingParametersError(
+                "Must include either 'channel_number' or 'channel_name'"
+            )
         if channel_number:
-            channel_data = self._get_json(endpoint=f'/channel/{channel_number}')
+            channel_data = self._get_json(endpoint=f"/channel/{channel_number}")
             if channel_data:
                 return Channel(data=channel_data, dizque_instance=self)
         if channel_name:
@@ -525,16 +605,18 @@ def get_channel_info(self, channel_number: int) -> json:
         :return: JSON data with channel name, number and icon path
         :rtype: dict
         """
-        return self._get_json(endpoint=f'/channel/description/{channel_number}')
+        return self._get_json(endpoint=f"/channel/description/{channel_number}")
 
     def get_channel_without_programs(self, channel_number: int) -> Union[Channel, None]:
-        channel_data = self._get_json(endpoint=f'/channel/programless/{channel_number}')
+        channel_data = self._get_json(endpoint=f"/channel/programless/{channel_number}")
         if channel_data:
             return Channel(data=channel_data, dizque_instance=self)
         return None
 
-    def get_channel_programs(self, channel_number: int) -> List[Union[Program, CustomShow]]:
-        channel_data = self._get_json(endpoint=f'/channel/programs/{channel_number}')
+    def get_channel_programs(
+        self, channel_number: int
+    ) -> List[Union[Program, CustomShow]]:
+        channel_data = self._get_json(endpoint=f"/channel/programs/{channel_number}")
         if channel_data:
             channel = Channel(data=channel_data, dizque_instance=self)
             if channel:
@@ -549,7 +631,7 @@ def channel_numbers(self) -> List[int]:
         :return: List of channel numbers
         :rtype: List[int]
         """
-        data = self._get_json(endpoint='/channelNumbers')
+        data = self._get_json(endpoint="/channelNumbers")
         if data:
             return data
         return []
@@ -572,7 +654,10 @@ def highest_channel_number(self) -> int:
         :return: Int number of the highest active channel
         :rtype: int
         """
-        return max(self.channel_numbers)
+        numbers = self.channel_numbers
+        if numbers:
+            return max(numbers)
+        return 0
 
     @property
     def lowest_channel_number(self) -> int:
@@ -592,11 +677,15 @@ def lowest_available_channel_number(self) -> int:
         :return: Int number of the lowest available channel
         :rtype: int
         """
-        possible = range(1, self.highest_channel_number + 2)  # between 1 and highest_channel_number + 1
+        possible = range(
+            1, self.highest_channel_number + 2
+        )  # between 1 and highest_channel_number + 1
         # find the lowest number of the differences in the sets
         return min(set(possible) - set(self.channel_numbers))
 
-    def _fill_in_default_channel_settings(self, settings_dict: dict, handle_errors: bool = False) -> dict:
+    def _fill_in_default_channel_settings(
+        self, settings_dict: dict, handle_errors: bool = False
+    ) -> dict:
         """
         Set some dynamic default values, such as channel number, start time and image URLs
 
@@ -607,40 +696,50 @@ def _fill_in_default_channel_settings(self, settings_dict: dict, handle_errors:
         :return: Dictionary of settings with defaults filled in
         :rtype: dict
         """
-        if not settings_dict.get('programs'):  # empty or doesn't exist
+        if not settings_dict.get("programs"):  # empty or doesn't exist
             if handle_errors:
-                settings_dict['programs'] = [{
-                    "duration": 600000,
-                    "isOffline": True
-                }]
+                settings_dict["programs"] = [{"duration": 600000, "isOffline": True}]
             else:
-                raise ChannelCreationError("You must include at least one program when creating a channel.")
-        if settings_dict.get('number') in self.channel_numbers:
+                raise ChannelCreationError(
+                    "You must include at least one program when creating a channel."
+                )
+        if settings_dict.get("number") in self.channel_numbers:
             if handle_errors:
-                settings_dict.pop('number')  # remove 'number' key, will be caught down below
+                settings_dict.pop(
+                    "number"
+                )  # remove 'number' key, will be caught down below
             else:
-                raise ChannelCreationError(f"Channel #{settings_dict.get('number')} already exists.")
-        if not settings_dict.get('number'):
-            settings_dict['number'] = max(self.channel_numbers) + 1
-        if not settings_dict.get('name'):
-            settings_dict['name'] = f"Channel {settings_dict['number']}"
-        if not settings_dict.get('startTime'):
-            settings_dict['startTime'] = helpers.get_nearest_30_minute_mark()
-        if not settings_dict.get('icon'):
-            settings_dict['icon'] = f"{self.url}/images/dizquetv.png"
-        if not settings_dict.get('offlinePicture'):
-            settings_dict['offlinePicture'] = f"{self.url}/images/generic-offline-screen.png"
+                raise ChannelCreationError(
+                    f"Channel #{settings_dict.get('number')} already exists."
+                )
+        if not settings_dict.get("number"):
+            settings_dict["number"] = max(self.channel_numbers) + 1
+        if not settings_dict.get("name"):
+            settings_dict["name"] = f"Channel {settings_dict['number']}"
+        if not settings_dict.get("startTime"):
+            settings_dict["startTime"] = helpers.get_nearest_30_minute_mark()
+        if not settings_dict.get("icon"):
+            settings_dict["icon"] = f"{self.url}/images/dizquetv.png"
+        if not settings_dict.get("offlinePicture"):
+            settings_dict[
+                "offlinePicture"
+            ] = f"{self.url}/images/generic-offline-screen.png"
         # override duration regardless of user input
-        settings_dict['duration'] = sum(program['duration'] for program in settings_dict['programs'])
-        settings_dict['watermark'] = fill_in_watermark_settings(**settings_dict)
-        return helpers._combine_settings_add_new(new_settings_dict=settings_dict,
-                                                 default_dict=CHANNEL_SETTINGS_DEFAULT)
-
-    def add_channel(self,
-                    programs: List[Union[Program, Redirect, Video, Movie, Episode, Track]] = [],
-                    plex_server: PServer = None,
-                    handle_errors: bool = True,
-                    **kwargs) -> Union[Channel, None]:
+        settings_dict["duration"] = sum(
+            program["duration"] for program in settings_dict["programs"]
+        )
+        settings_dict["watermark"] = fill_in_watermark_settings(**settings_dict)
+        return helpers._combine_settings_add_new(
+            new_settings_dict=settings_dict, default_dict=CHANNEL_SETTINGS_DEFAULT
+        )
+
+    def add_channel(
+        self,
+        programs: List[Union[Program, Redirect, Video, Movie, Episode, Track]] = None,
+        plex_server: PServer = None,
+        handle_errors: bool = True,
+        **kwargs,
+    ) -> Union[Channel, None]:
         """
         Add a channel to dizqueTV
 
@@ -654,24 +753,35 @@ def add_channel(self,
         :return: new Channel object or None
         :rtype: Channel
         """
-        kwargs['programs'] = []
+        kwargs["programs"] = []
+        programs = programs or []
         for item in programs:
             if type(item) in [Program, Redirect]:
-                kwargs['programs'].append(item._data)
+                kwargs["programs"].append(item._data)
             else:
                 if not plex_server:
-                    raise ItemCreationError("You must include a plex_server if you are adding PlexAPI Videos, "
-                                            "Movies, Episodes or Tracks as programs")
-                kwargs['programs'].append(
-                    convert_plex_item_to_program(plex_item=item, plex_server=plex_server)._data)
-        if kwargs.get('iconPosition'):
-            kwargs['iconPosition'] = helpers.convert_icon_position(position_text=kwargs['iconPosition'])
-        kwargs = self._fill_in_default_channel_settings(settings_dict=kwargs, handle_errors=handle_errors)
-        if helpers._settings_are_complete(new_settings_dict=kwargs,
-                                          template_settings_dict=CHANNEL_SETTINGS_TEMPLATE,
-                                          ignore_keys=['_id', 'id']) \
-                and self._put(endpoint="/channel", data=kwargs):
-            return self.get_channel(channel_number=kwargs['number'])
+                    raise ItemCreationError(
+                        "You must include a plex_server if you are adding PlexAPI Videos, "
+                        "Movies, Episodes or Tracks as programs"
+                    )
+                kwargs["programs"].append(
+                    convert_plex_item_to_program(
+                        plex_item=item, plex_server=plex_server
+                    )._data
+                )
+        if kwargs.get("iconPosition"):
+            kwargs["iconPosition"] = helpers.convert_icon_position(
+                position_text=kwargs["iconPosition"]
+            )
+        kwargs = self._fill_in_default_channel_settings(
+            settings_dict=kwargs, handle_errors=handle_errors
+        )
+        if helpers._settings_are_complete(
+            new_settings_dict=kwargs,
+            template_settings_dict=CHANNEL_SETTINGS_TEMPLATE,
+            ignore_keys=["_id", "id"],
+        ) and self._put(endpoint="/channel", data=kwargs):
+            return self.get_channel(channel_number=kwargs["number"])
         return None
 
     def update_channel(self, channel_number: int, **kwargs) -> bool:
@@ -686,9 +796,13 @@ def update_channel(self, channel_number: int, **kwargs) -> bool:
         """
         channel = self.get_channel(channel_number=channel_number)
         if channel:
-            if kwargs.get('iconPosition'):
-                kwargs['iconPosition'] = helpers.convert_icon_position(position_text=kwargs['iconPosition'])
-            new_settings = helpers._combine_settings_add_new(new_settings_dict=kwargs, default_dict=channel._data)
+            if kwargs.get("iconPosition"):
+                kwargs["iconPosition"] = helpers.convert_icon_position(
+                    position_text=kwargs["iconPosition"]
+                )
+            new_settings = helpers._combine_settings_add_new(
+                new_settings_dict=kwargs, default_dict=channel._data
+            )
             if self._post(endpoint="/channel", data=new_settings):
                 return True
         return False
@@ -702,11 +816,16 @@ def delete_channel(self, channel_number: int) -> bool:
         :return: True if successful, False if unsuccessful
         :rtype: bool
         """
-        if self._delete(endpoint="/channel", data={'number': channel_number}):
+        if self._delete(endpoint="/channel", data={"number": channel_number}):
             return True
         return False
 
-    def _make_schedule(self, channel: Channel, schedule: Schedule = None, schedule_settings: dict = None) -> bool:
+    def _make_schedule(
+        self,
+        channel: Channel,
+        schedule: Schedule = None,
+        schedule_settings: dict = None,
+    ) -> bool:
         """
         Add or update a schedule to a Channel
 
@@ -719,26 +838,34 @@ def _make_schedule(self, channel: Channel, schedule: Schedule = None, schedule_s
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        data = {'programs': []}
+        data = {"programs": []}
         if schedule:
-            data['schedule'] = (schedule._data
-                                if helpers._object_has_attribute(obj=schedule, attribute_name="_data")
-                                else {})
+            data["schedule"] = (
+                schedule._data
+                if helpers._object_has_attribute(obj=schedule, attribute_name="_data")
+                else {}
+            )
         else:
-            data['schedule'] = schedule_settings
+            data["schedule"] = schedule_settings
         for item in channel.programs:
             if type(item) in [Program, Redirect]:
-                data['programs'].append(item._data)
-        res = self._post(endpoint='/channel-tools/time-slots', data=data)
+                data["programs"].append(item._data)
+        res = self._post(endpoint="/channel-tools/time-slots", data=data)
         if res:
             schedule_json = res.json()
-            return channel.update(programs=schedule_json['programs'],
-                                  startTime=schedule_json['startTime'],
-                                  scheduleBackup=data['schedule'])
+            return channel.update(
+                programs=schedule_json["programs"],
+                startTime=schedule_json["startTime"],
+                scheduleBackup=data["schedule"],
+            )
         return False
 
-    def _make_random_schedule(self, channel: Channel, schedule: Schedule = None,
-                              schedule_settings: dict = None) -> bool:
+    def _make_random_schedule(
+        self,
+        channel: Channel,
+        schedule: Schedule = None,
+        schedule_settings: dict = None,
+    ) -> bool:
         """
         Add or update a random schedule to a Channel
 
@@ -751,22 +878,26 @@ def _make_random_schedule(self, channel: Channel, schedule: Schedule = None,
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        data = {'programs': []}
+        data = {"programs": []}
         if schedule:
-            data['schedule'] = (schedule._data
-                                if helpers._object_has_attribute(obj=schedule, attribute_name="_data")
-                                else {})
+            data["schedule"] = (
+                schedule._data
+                if helpers._object_has_attribute(obj=schedule, attribute_name="_data")
+                else {}
+            )
         else:
-            data['schedule'] = schedule_settings
+            data["schedule"] = schedule_settings
         for item in channel.programs:
             if type(item) in [Program, Redirect]:
-                data['programs'].append(item._data)
-        res = self._post(endpoint='/channel-tools/random-slots', data=data)
+                data["programs"].append(item._data)
+        res = self._post(endpoint="/channel-tools/random-slots", data=data)
         if res:
             schedule_json = res.json()
-            return channel.update(programs=schedule_json['programs'],
-                                  startTime=schedule_json['startTime'],
-                                  scheduleBackup=data['schedule'])
+            return channel.update(
+                programs=schedule_json["programs"],
+                startTime=schedule_json["startTime"],
+                scheduleBackup=data["schedule"],
+            )
         return False
 
     # FillerItem List Settings
@@ -778,8 +909,13 @@ def filler_lists(self) -> List[FillerList]:
         :return: List of FillerList objects
         :rtype: List[FillerList]
         """
-        json_data = self._get_json(endpoint='/fillers', timeout=5)  # large JSON may take longer, so bigger timeout
-        return [FillerList(data=filler_list, dizque_instance=self) for filler_list in json_data]
+        json_data = self._get_json(
+            endpoint="/fillers", timeout=5
+        )  # large JSON may take longer, so bigger timeout
+        return [
+            FillerList(data=filler_list, dizque_instance=self)
+            for filler_list in json_data
+        ]
 
     def get_filler_list(self, filler_list_id: str) -> Union[FillerList, None]:
         """
@@ -790,7 +926,7 @@ def get_filler_list(self, filler_list_id: str) -> Union[FillerList, None]:
         :return: FillerList object
         :rtype: FillerList
         """
-        filler_list_data = self._get_json(endpoint=f'/filler/{filler_list_id}')
+        filler_list_data = self._get_json(endpoint=f"/filler/{filler_list_id}")
         if filler_list_data:
             return FillerList(data=filler_list_data, dizque_instance=self)
         return None
@@ -818,7 +954,7 @@ def get_filler_list_info(self, filler_list_id: str) -> json:
         :return: JSON data with filler list name, content and id
         :rtype: dict
         """
-        return self._get_json(endpoint=f'/filler/{filler_list_id}')
+        return self._get_json(endpoint=f"/filler/{filler_list_id}")
 
     def get_filler_list_channels(self, filler_list_id: str) -> List[Channel]:
         """
@@ -829,10 +965,15 @@ def get_filler_list_channels(self, filler_list_id: str) -> List[Channel]:
         :return: List of Channel objects
         :rtype: List[Channel]
         """
-        channel_data = self._get_json(endpoint=f'/filler/{filler_list_id}/channels')
-        return [self.get_channel(channel_number=channel.get('number')) for channel in channel_data]
+        channel_data = self._get_json(endpoint=f"/filler/{filler_list_id}/channels")
+        return [
+            self.get_channel(channel_number=channel.get("number"))
+            for channel in channel_data
+        ]
 
-    def _fill_in_default_filler_list_settings(self, settings_dict: dict, handle_errors: bool = False) -> dict:
+    def _fill_in_default_filler_list_settings(
+        self, settings_dict: dict, handle_errors: bool = False
+    ) -> dict:
         """
         Set some dynamic default values, such as filler list name
 
@@ -843,23 +984,26 @@ def _fill_in_default_filler_list_settings(self, settings_dict: dict, handle_erro
         :return: Dictionary of settings with defaults filled in
         :rtype: dict
         """
-        if not settings_dict.get('content'):  # empty or doesn't exist
+        if not settings_dict.get("content"):  # empty or doesn't exist
             if handle_errors:
-                settings_dict['content'] = [{
-                    "duration": 600000,
-                    "isOffline": True
-                }]
+                settings_dict["content"] = [{"duration": 600000, "isOffline": True}]
             else:
-                raise ChannelCreationError("You must include at least one program when creating a filler list.")
-        if 'name' not in settings_dict.keys():
-            settings_dict['name'] = f"New List {len(self.filler_lists) + 1}"
-        return helpers._combine_settings(new_settings_dict=settings_dict, default_dict=CHANNEL_SETTINGS_DEFAULT)
-
-    def add_filler_list(self,
-                        content: List[Union[Program, Video, Movie, Episode, Track]],
-                        plex_server: PServer = None,
-                        handle_errors: bool = False,
-                        **kwargs) -> Union[FillerList, None]:
+                raise ChannelCreationError(
+                    "You must include at least one program when creating a filler list."
+                )
+        if "name" not in settings_dict.keys():
+            settings_dict["name"] = f"New List {len(self.filler_lists) + 1}"
+        return helpers._combine_settings(
+            new_settings_dict=settings_dict, default_dict=CHANNEL_SETTINGS_DEFAULT
+        )
+
+    def add_filler_list(
+        self,
+        content: List[Union[Program, Video, Movie, Episode, Track]],
+        plex_server: PServer = None,
+        handle_errors: bool = False,
+        **kwargs,
+    ) -> Union[FillerList, None]:
         """
         Add a filler list to dizqueTV
         Must include at least one program to create
@@ -874,23 +1018,32 @@ def add_filler_list(self,
         :return: new FillerList object or None
         :rtype: FillerList
         """
-        kwargs['content'] = []
+        kwargs["content"] = []
         for item in content:
             if type(item) == FillerItem:
-                kwargs['content'].append(item)
+                kwargs["content"].append(item)
             else:
                 if not plex_server:
-                    raise ItemCreationError("You must include a plex_server if you are adding PlexAPI Videos, "
-                                            "Movies, Episodes or Tracks as programs")
-                kwargs['content'].append(
-                    convert_plex_item_to_filler_item(plex_item=item, plex_server=plex_server)._data)
-        kwargs = self._fill_in_default_filler_list_settings(settings_dict=kwargs, handle_errors=handle_errors)
-        if helpers._settings_are_complete(new_settings_dict=kwargs,
-                                          template_settings_dict=FILLER_LIST_SETTINGS_TEMPLATE,
-                                          ignore_keys=['_id', 'id']):
+                    raise ItemCreationError(
+                        "You must include a plex_server if you are adding PlexAPI Videos, "
+                        "Movies, Episodes or Tracks as programs"
+                    )
+                kwargs["content"].append(
+                    convert_plex_item_to_filler_item(
+                        plex_item=item, plex_server=plex_server
+                    )._data
+                )
+        kwargs = self._fill_in_default_filler_list_settings(
+            settings_dict=kwargs, handle_errors=handle_errors
+        )
+        if helpers._settings_are_complete(
+            new_settings_dict=kwargs,
+            template_settings_dict=FILLER_LIST_SETTINGS_TEMPLATE,
+            ignore_keys=["_id", "id"],
+        ):
             response = self._put(endpoint="/filler", data=kwargs)
             if response:
-                return self.get_filler_list(filler_list_id=response.json()['id'])
+                return self.get_filler_list(filler_list_id=response.json()["id"])
         return None
 
     def update_filler_list(self, filler_list_id: str, **kwargs) -> bool:
@@ -905,7 +1058,9 @@ def update_filler_list(self, filler_list_id: str, **kwargs) -> bool:
         """
         filler_list = self.get_filler_list(filler_list_id=filler_list_id)
         if filler_list:
-            new_settings = helpers._combine_settings(new_settings_dict=kwargs, default_dict=filler_list._data)
+            new_settings = helpers._combine_settings(
+                new_settings_dict=kwargs, default_dict=filler_list._data
+            )
             if self._post(endpoint=f"/filler/{filler_list_id}", data=new_settings):
                 return True
         return False
@@ -932,7 +1087,9 @@ def custom_shows(self) -> List[CustomShow]:
         :return: List of CustomShow objects
         :rtype: List[CustomShow]
         """
-        json_data = self._get_json(endpoint='/shows', timeout=5)  # large JSON may take longer, so bigger timeout
+        json_data = self._get_json(
+            endpoint="/shows", timeout=5
+        )  # large JSON may take longer, so bigger timeout
         return [CustomShow(data=show, dizque_instance=self) for show in json_data]
 
     def get_custom_show(self, custom_show_id: str) -> Union[CustomShow, None]:
@@ -949,7 +1106,9 @@ def get_custom_show(self, custom_show_id: str) -> Union[CustomShow, None]:
                 return custom_show
         return None
 
-    def get_custom_show_details(self, custom_show_id: str) -> Union[CustomShowDetails, None]:
+    def get_custom_show_details(
+        self, custom_show_id: str
+    ) -> Union[CustomShowDetails, None]:
         """
         Get the details of a custom show
 
@@ -958,30 +1117,42 @@ def get_custom_show_details(self, custom_show_id: str) -> Union[CustomShowDetail
         :return: CustomShowDetails object or None
         :rtype: CustomShowDetails
         """
-        json_data = self._get_json(endpoint=f'/show/{custom_show_id}')
+        json_data = self._get_json(endpoint=f"/show/{custom_show_id}")
         if json_data:
             return CustomShowDetails(data=json_data, dizque_instance=self)
         return None
 
-    def add_custom_show(self,
-                        name: str,
-                        content: List[Union[Program, Video, Movie, Episode, Track]],
-                        plex_server: PServer = None) -> Union[CustomShow, None]:
-        kwargs = {'name': name, 'content': []}
+    def add_custom_show(
+        self,
+        name: str,
+        content: List[Union[Program, Video, Movie, Episode, Track]],
+        plex_server: PServer = None,
+    ) -> Union[CustomShow, None]:
+        kwargs = {"name": name, "content": []}
         for item in content:
             if type(item) == Program:
-                custom_show_item = convert_program_to_custom_show_item(program=item, dizque_instance=self)
+                custom_show_item = convert_program_to_custom_show_item(
+                    program=item, dizque_instance=self
+                )
             else:
                 if not plex_server:
-                    raise ItemCreationError("You must include a plex_server if you are adding PlexAPI Videos, "
-                                            "Movies, Episodes or Tracks as programs")
-                program = convert_plex_item_to_program(plex_item=item, plex_server=plex_server)
-                custom_show_item = convert_program_to_custom_show_item(program=program, dizque_instance=self)
-            kwargs['content'].append(custom_show_item._full_data)
-        if helpers._settings_are_complete(new_settings_dict=kwargs, template_settings_dict=CUSTOM_SHOW_TEMPLATE):
-            response = self._put(endpoint='/show', data=kwargs)
+                    raise ItemCreationError(
+                        "You must include a plex_server if you are adding PlexAPI Videos, "
+                        "Movies, Episodes or Tracks as programs"
+                    )
+                program = convert_plex_item_to_program(
+                    plex_item=item, plex_server=plex_server
+                )
+                custom_show_item = convert_program_to_custom_show_item(
+                    program=program, dizque_instance=self
+                )
+            kwargs["content"].append(custom_show_item._full_data)
+        if helpers._settings_are_complete(
+            new_settings_dict=kwargs, template_settings_dict=CUSTOM_SHOW_TEMPLATE
+        ):
+            response = self._put(endpoint="/show", data=kwargs)
             if response:
-                return self.get_custom_show(custom_show_id=response.json()['id'])
+                return self.get_custom_show(custom_show_id=response.json()["id"])
         return None
 
     def update_custom_show(self, custom_show_id: str, **kwargs) -> bool:
@@ -996,7 +1167,9 @@ def update_custom_show(self, custom_show_id: str, **kwargs) -> bool:
         """
         custom_show = self.get_custom_show(custom_show_id=custom_show_id)
         if custom_show:
-            new_settings = helpers._combine_settings_add_new(new_settings_dict=kwargs, default_dict=custom_show._data)
+            new_settings = helpers._combine_settings_add_new(
+                new_settings_dict=kwargs, default_dict=custom_show._data
+            )
             if self._post(endpoint=f"/show/{custom_show_id}", data=new_settings):
                 return True
         return False
@@ -1026,8 +1199,8 @@ def upload_image(self, image_file_path: str) -> Union[UploadImageResponse, None]
         """
         if not helpers.file_exists(image_file_path):
             raise GeneralException("Invalid image_file_path provided.")
-        file_data = {'image': helpers.read_file_bytes(file_path=image_file_path)}
-        res = self._post(endpoint=f"/upload/image", files=file_data)
+        file_data = {"image": helpers.read_file_bytes(file_path=image_file_path)}
+        res = self._post(endpoint="/upload/image", files=file_data)
         if not res:
             return None
         return UploadImageResponse(data=res.json())
@@ -1041,7 +1214,7 @@ def ffmpeg_settings(self) -> Union[FFMPEGSettings, None]:
         :return: FFMPEGSettings object or None
         :rtype: FFMPEGSettings
         """
-        json_data = self._get_json(endpoint='/ffmpeg-settings')
+        json_data = self._get_json(endpoint="/ffmpeg-settings")
         if json_data:
             return FFMPEGSettings(data=json_data, dizque_instance=self)
         return None
@@ -1054,8 +1227,10 @@ def update_ffmpeg_settings(self, **kwargs) -> bool:
         :return: True if successful, False if unsuccessful
         :rtype: bool
         """
-        new_settings = helpers._combine_settings(new_settings_dict=kwargs, default_dict=self.ffmpeg_settings._data)
-        if self._put(endpoint='/ffmpeg-settings', data=new_settings):
+        new_settings = helpers._combine_settings(
+            new_settings_dict=kwargs, default_dict=self.ffmpeg_settings._data
+        )
+        if self._put(endpoint="/ffmpeg-settings", data=new_settings):
             return True
         return False
 
@@ -1067,7 +1242,7 @@ def reset_ffmpeg_settings(self) -> bool:
         :rtype: bool
         """
         old_settings = self.ffmpeg_settings._data
-        if self._post(endpoint='/ffmpeg-settings', data={'_id': old_settings['_id']}):
+        if self._post(endpoint="/ffmpeg-settings", data={"_id": old_settings["_id"]}):
             return True
         return False
 
@@ -1080,7 +1255,7 @@ def plex_settings(self) -> Union[PlexSettings, None]:
         :return: PlexSettings object or None
         :rtype: PlexSettings
         """
-        json_data = self._get_json(endpoint='/plex-settings')
+        json_data = self._get_json(endpoint="/plex-settings")
         if json_data:
             return PlexSettings(data=json_data, dizque_instance=self)
         return None
@@ -1093,8 +1268,10 @@ def update_plex_settings(self, **kwargs) -> bool:
         :return: True if successful, False if unsuccessful
         :rtype: bool
         """
-        new_settings = helpers._combine_settings(new_settings_dict=kwargs, default_dict=self.plex_settings._data)
-        if self._put(endpoint='/plex-settings', data=new_settings):
+        new_settings = helpers._combine_settings(
+            new_settings_dict=kwargs, default_dict=self.plex_settings._data
+        )
+        if self._put(endpoint="/plex-settings", data=new_settings):
             return True
         return False
 
@@ -1106,7 +1283,7 @@ def reset_plex_settings(self) -> bool:
         :rtype: bool
         """
         old_settings = self.plex_settings._data
-        if self._post(endpoint='/plex-settings', data={'_id': old_settings['_id']}):
+        if self._post(endpoint="/plex-settings", data={"_id": old_settings["_id"]}):
             return True
         return False
 
@@ -1119,7 +1296,7 @@ def last_xmltv_refresh(self) -> str:
         :return: Timestamp of last refresh
         :rtype: str
         """
-        return self._get_json(endpoint='/xmltv-last-refresh')
+        return self._get_json(endpoint="/xmltv-last-refresh")
 
     # XMLTV Settings
     @property
@@ -1130,7 +1307,7 @@ def xmltv_settings(self) -> Union[XMLTVSettings, None]:
         :return: XMLTVSettings object or None
         :rtype: XMLTVSettings
         """
-        json_data = self._get_json(endpoint='/xmltv-settings')
+        json_data = self._get_json(endpoint="/xmltv-settings")
         if json_data:
             return XMLTVSettings(data=json_data, dizque_instance=self)
         return None
@@ -1143,8 +1320,10 @@ def update_xmltv_settings(self, **kwargs) -> bool:
         :return: True if successful, False if unsuccessful
         :rtype: bool
         """
-        new_settings = helpers._combine_settings(new_settings_dict=kwargs, default_dict=self.xmltv_settings._data)
-        if self._put(endpoint='/xmltv-settings', data=new_settings):
+        new_settings = helpers._combine_settings(
+            new_settings_dict=kwargs, default_dict=self.xmltv_settings._data
+        )
+        if self._put(endpoint="/xmltv-settings", data=new_settings):
             return True
         return False
 
@@ -1156,7 +1335,7 @@ def reset_xmltv_settings(self) -> bool:
         :rtype: bool
         """
         old_settings = self.xmltv_settings._data
-        if self._post(endpoint='/xmltv-settings', data={'_id': old_settings['_id']}):
+        if self._post(endpoint="/xmltv-settings", data={"_id": old_settings["_id"]}):
             return True
         return False
 
@@ -1169,7 +1348,7 @@ def hdhr_settings(self) -> Union[HDHomeRunSettings, None]:
         :return: HDHomeRunSettings object or None
         :rtype: HDHomeRunSettings
         """
-        json_data = self._get_json(endpoint='/hdhr-settings')
+        json_data = self._get_json(endpoint="/hdhr-settings")
         if json_data:
             return HDHomeRunSettings(data=json_data, dizque_instance=self)
         return None
@@ -1182,8 +1361,10 @@ def update_hdhr_settings(self, **kwargs) -> bool:
         :return: True if successful, False if unsuccessful
         :rtype: bool
         """
-        new_settings = helpers._combine_settings(new_settings_dict=kwargs, default_dict=self.hdhr_settings._data)
-        if self._put(endpoint='/hdhr-settings', data=new_settings):
+        new_settings = helpers._combine_settings(
+            new_settings_dict=kwargs, default_dict=self.hdhr_settings._data
+        )
+        if self._put(endpoint="/hdhr-settings", data=new_settings):
             return True
         return False
 
@@ -1195,7 +1376,7 @@ def reset_hdhr_settings(self) -> bool:
         :rtype: bool
         """
         old_settings = self.hdhr_settings._data
-        if self._post(endpoint='/hdhr-settings', data={'_id': old_settings['_id']}):
+        if self._post(endpoint="/hdhr-settings", data={"_id": old_settings["_id"]}):
             return True
         return False
 
@@ -1219,41 +1400,41 @@ def xmltv_xml(self) -> Union[ElementTree.Element, None]:
         :rtype: ElementTree.Element
         """
         self.refresh_xml()
-        response = self._get(endpoint='/xmltv.xml')
+        response = self._get(endpoint="/xmltv.xml")
         if response:
             return ElementTree.fromstring(response.content)
         return None
 
     @property
-    def m3u(self) -> m3u8:
+    def m3u(self) -> m3u8.model.M3U8:
         """
         Get dizqueTV's m3u playlist
         Without m3u8, this method currently produces an error.
 
         :return: m3u8 object
-        :rtype: m3u8
+        :rtype: m3u8.model.M3U8
         """
         return m3u8.load(f"{self.url}/api/channels.m3u")
 
     @property
-    def hls_m3u(self) -> m3u8:
+    def hls_m3u(self) -> m3u8.model.M3U8:
         """
         Get dizqueTV's hls.m3u playlist
         Without m3u8, this method currently produces an error.
 
         :return: m3u8 object
-        :rtype: m3u8
+        :rtype: m3u8.model.M3U8
         """
         return m3u8.load(f"{self.url}/api/hls.m3u")
 
-    def get_channel_m3u(self, channel_number: int) -> m3u8:
+    def get_channel_m3u(self, channel_number: int) -> m3u8.model.M3U8:
         """
         Get a channel-specific m3u playlist
 
         :param channel_number: Number of channel to get M3U playlist
         :type channel_number: int
         :return: m3u8 object
-        :rtype: m3u8
+        :rtype: m3u8.model.M3U8
         """
         if channel_number not in self.channel_numbers:
             raise Exception(f"Channel {channel_number} does not exist.")
@@ -1274,7 +1455,7 @@ def get_stream_url(self, channel_number: int, audio_only: bool = False) -> str:
             raise Exception(f"Channel {channel_number} does not exist.")
         url = f"{self.url}/stream?channel={channel_number}"
         if audio_only:
-            url += f"&audiOnly=true"
+            url += "&audiOnly=true"
         return url
 
     def get_video_url(self, channel_number: int) -> str:
@@ -1312,7 +1493,7 @@ def guide(self) -> Guide:
         :return: dizqueTV.Guide object
         :rtype: Guide
         """
-        json_data = self._get_json(endpoint='/guide/debug')
+        json_data = self._get_json(endpoint="/guide/debug")
         return Guide(data=json_data, dizque_instance=self)
 
     @property
@@ -1323,9 +1504,9 @@ def last_guide_update(self) -> Union[datetime, None]:
         :return: datetime.datetime object
         :rtype: datetime
         """
-        data = self._get_json(endpoint='/guide/status')
-        if data and data.get('lastUpdate'):
-            return helpers.string_to_datetime(date_string=data['lastUpdate'])
+        data = self._get_json(endpoint="/guide/status")
+        if data and data.get("lastUpdate"):
+            return helpers.string_to_datetime(date_string=data["lastUpdate"])
         return None
 
     @property
@@ -1336,9 +1517,9 @@ def guide_channel_numbers(self) -> List[str]:
         :return: List of strings (not ints)
         :rtype: List[str]
         """
-        data = self._get_json(endpoint='/guide/status')
-        if data and data.get('channelNumbers'):
-            return data['channelNumbers']
+        data = self._get_json(endpoint="/guide/status")
+        if data and data.get("channelNumbers"):
+            return data["channelNumbers"]
         return []
 
     @property
@@ -1349,11 +1530,12 @@ def guide_lineup_json(self) -> json:
         :return: JSON data
         :rtype: dict
         """
-        return self._get_json(endpoint='/guide/debug')
+        return self._get_json(endpoint="/guide/debug")
 
     # Other Functions
-    def convert_plex_item_to_program(self, plex_item: Union[Video, Movie, Episode, Track],
-                                     plex_server: PServer) -> Program:
+    def convert_plex_item_to_program(
+        self, plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer
+    ) -> Program:
         """
         Convert a PlexAPI Video, Movie, Episode or Track object into a Program
 
@@ -1364,10 +1546,13 @@ def convert_plex_item_to_program(self, plex_item: Union[Video, Movie, Episode, T
         :return: Program object
         :rtype: Program
         """
-        return convert_plex_item_to_program(plex_item=plex_item, plex_server=plex_server)
+        return convert_plex_item_to_program(
+            plex_item=plex_item, plex_server=plex_server
+        )
 
-    def convert_plex_item_to_filler_item(self, plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer) -> \
-            FillerItem:
+    def convert_plex_item_to_filler_item(
+        self, plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer
+    ) -> FillerItem:
         """
         Convert a PlexAPI Video, Movie, Episode or Track object into a FillerItem
 
@@ -1378,7 +1563,9 @@ def convert_plex_item_to_filler_item(self, plex_item: Union[Video, Movie, Episod
         :return: Program object
         :rtype: Program
         """
-        return convert_plex_item_to_filler_item(plex_item=plex_item, plex_server=plex_server)
+        return convert_plex_item_to_filler_item(
+            plex_item=plex_item, plex_server=plex_server
+        )
 
     def convert_program_to_custom_show_item(self, program: Program) -> CustomShowItem:
         """
@@ -1389,7 +1576,9 @@ def convert_program_to_custom_show_item(self, program: Program) -> CustomShowIte
         :return: CustomShowItem
         :rtype: CustomShowItem
         """
-        return convert_program_to_custom_show_item(program=program, dizque_instance=self)
+        return convert_program_to_custom_show_item(
+            program=program, dizque_instance=self
+        )
 
     def expand_custom_show_items(self, programs: List) -> List:
         """
@@ -1402,37 +1591,51 @@ def expand_custom_show_items(self, programs: List) -> List:
         """
         return expand_custom_show_items(programs=programs, dizque_instance=self)
 
-    def create_custom_show_with_programs(self, custom_show_programs: list) -> CustomShow:
+    def create_custom_show_with_programs(
+        self, custom_show_programs: list
+    ) -> CustomShow:
         custom_show_data = {
-            'name': custom_show_programs[0]['customShowName'],
-            'id': custom_show_programs[0]['customShowId'],
-            'content': custom_show_programs
+            "name": custom_show_programs[0]["customShowName"],
+            "id": custom_show_programs[0]["customShowId"],
+            "content": custom_show_programs,
         }
         return CustomShow(data=custom_show_data, dizque_instance=self)
 
-    def parse_custom_shows_and_non_custom_shows(self, items: list, non_custom_show_type, **kwargs):
+    def parse_custom_shows_and_non_custom_shows(
+        self, items: list, non_custom_show_type, **kwargs
+    ):
         custom_show_programs = []
         current_custom_show_id = None
         parsing_custom_show = False
         final_items = []
         for item in items:
-            if item.get('customShowId'):  # came across an item that belongs to a custom show
+            if item.get(
+                "customShowId"
+            ):  # came across an item that belongs to a custom show
                 if not current_custom_show_id:  # initialize the first custom show
-                    current_custom_show_id = item.get('customShowId')
-                if item.get('customShowId') == current_custom_show_id:  # item belongs to the same custom show
+                    current_custom_show_id = item.get("customShowId")
+                if (
+                    item.get("customShowId") == current_custom_show_id
+                ):  # item belongs to the same custom show
                     custom_show_programs.append(item)
                 else:  # item belong to a new custom show
                     # create and save the old custom show
-                    custom_show = self.create_custom_show_with_programs(custom_show_programs=custom_show_programs)
+                    custom_show = self.create_custom_show_with_programs(
+                        custom_show_programs=custom_show_programs
+                    )
                     final_items.append(custom_show)
                     # start storing the new custom show
-                    current_custom_show_id = item.get('customShowId')
+                    current_custom_show_id = item.get("customShowId")
                     custom_show_programs = [item]
                 parsing_custom_show = True
             else:  # came across an item that does not belong to a custom show
-                if parsing_custom_show:  # was tracking a custom show, have reached the end
+                if (
+                    parsing_custom_show
+                ):  # was tracking a custom show, have reached the end
                     # create and save a custom show with the items we collected
-                    custom_show = self.create_custom_show_with_programs(custom_show_programs=custom_show_programs)
+                    custom_show = self.create_custom_show_with_programs(
+                        custom_show_programs=custom_show_programs
+                    )
                     final_items.append(custom_show)
                     # reset for capturing the next custom show
                     parsing_custom_show = False
@@ -1441,15 +1644,19 @@ def parse_custom_shows_and_non_custom_shows(self, items: list, non_custom_show_t
                     final_items.append(non_custom_show_type(data=item, **kwargs))
         # build final custom show if needed
         if custom_show_programs:
-            custom_show = self.create_custom_show_with_programs(custom_show_programs=custom_show_programs)
+            custom_show = self.create_custom_show_with_programs(
+                custom_show_programs=custom_show_programs
+            )
             final_items.append(custom_show)
         return final_items
 
-    def add_programs_to_channels(self,
-                                 programs: List[Union[Program, CustomShow, Video, Movie, Episode, Track]],
-                                 channels: List[Channel] = None,
-                                 channel_numbers: List[int] = None,
-                                 plex_server: PServer = None) -> bool:
+    def add_programs_to_channels(
+        self,
+        programs: List[Union[Program, CustomShow, Video, Movie, Episode, Track]],
+        channels: List[Channel] = None,
+        channel_numbers: List[int] = None,
+        plex_server: PServer = None,
+    ) -> bool:
         """
         Add multiple programs to multiple channels
 
@@ -1466,7 +1673,8 @@ def add_programs_to_channels(self,
         """
         if not channels and not channel_numbers:
             raise MissingParametersError(
-                "Please include either a list of Channel objects or a list of channel numbers.")
+                "Please include either a list of Channel objects or a list of channel numbers."
+            )
         if channel_numbers:
             channels = []
             for number in channel_numbers:
@@ -1476,10 +1684,12 @@ def add_programs_to_channels(self,
                 return False
         return True
 
-    def add_filler_lists_to_channels(self,
-                                     filler_lists: List[FillerList],
-                                     channels: List[Channel] = None,
-                                     channel_numbers: List[int] = None) -> bool:
+    def add_filler_lists_to_channels(
+        self,
+        filler_lists: List[FillerList],
+        channels: List[Channel] = None,
+        channel_numbers: List[int] = None,
+    ) -> bool:
         """
         Add multiple filler lists to multiple channels
 
@@ -1494,7 +1704,8 @@ def add_filler_lists_to_channels(self,
         """
         if not channels and not channel_numbers:
             raise MissingParametersError(
-                "Please include either a list of Channel objects or a list of channel numbers.")
+                "Please include either a list of Channel objects or a list of channel numbers."
+            )
         if channel_numbers:
             channels = []
             for number in channel_numbers:
diff --git a/dizqueTV/dizquetv_logging.py b/dizqueTV/dizquetv_logging.py
index 0832408..44e386a 100644
--- a/dizqueTV/dizquetv_logging.py
+++ b/dizqueTV/dizquetv_logging.py
@@ -13,11 +13,7 @@ def warning(message):
     logging.warning(msg=message)
 
 
-level_map = {
-    'info': info,
-    'error': error,
-    'warning': warning
-}
+level_map = {"info": info, "error": error, "warning": warning}
 
 
 def log(message: str, level: str = "info") -> None:
@@ -30,5 +26,5 @@ def log(message: str, level: str = "info") -> None:
     :rtype: None
     """
     if level not in level_map.keys():
-        level = 'info'
+        level = "info"
     level_map[level](message)
diff --git a/dizqueTV/dizquetv_requests.py b/dizqueTV/dizquetv_requests.py
index 57a8c16..b9da5fd 100644
--- a/dizqueTV/dizquetv_requests.py
+++ b/dizqueTV/dizquetv_requests.py
@@ -6,11 +6,13 @@
 import dizqueTV.dizquetv_logging as logs
 
 
-def get(url: str,
-        params: dict = None,
-        headers: dict = None,
-        timeout: int = 2,
-        log: str = None) -> Union[objectrest.Response, None]:
+def get(
+    url: str,
+    params: dict = None,
+    headers: dict = None,
+    timeout: int = 2,
+    log: str = None,
+) -> Union[objectrest.Response, None]:
     if params:
         url += f"?{urlencode(params)}"
     try:
@@ -23,32 +25,38 @@ def get(url: str,
         return None
 
 
-def post(url: str,
-         params: dict = None,
-         headers: dict = None,
-         data: dict = None,
-         files: dict = None,
-         timeout: int = 2,
-         log: str = None) -> Union[objectrest.Response, None]:
+def post(
+    url: str,
+    params: dict = None,
+    headers: dict = None,
+    data: dict = None,
+    files: dict = None,
+    timeout: int = 2,
+    log: str = None,
+) -> Union[objectrest.Response, None]:
     if params:
         url += f"?{urlencode(params)}"
     try:
-        res = objectrest.post(url=url, json=data, files=files, headers=headers, timeout=timeout)
+        res = objectrest.post(
+            url=url, json=data, files=files, headers=headers, timeout=timeout
+        )
         if log:
             logs.log(message=f"POST {url}, Body: {data}", level=log)
             logs.log(message=f"Response: {res}", level=("error" if not res else log))
         return res
         # use json= rather than data= to convert single-quoted dict to double-quoted JSON
-    except objectrest.exceptions.Timeout as e:
+    except objectrest.exceptions.Timeout:
         return None
 
 
-def put(url: str,
-        params: dict = None,
-        headers: dict = None,
-        data: dict = None,
-        timeout: int = 2,
-        log: str = None) -> Union[objectrest.Response, None]:
+def put(
+    url: str,
+    params: dict = None,
+    headers: dict = None,
+    data: dict = None,
+    timeout: int = 2,
+    log: str = None,
+) -> Union[objectrest.Response, None]:
     if params:
         url += f"?{urlencode(params)}"
     try:
@@ -62,12 +70,14 @@ def put(url: str,
         return None
 
 
-def delete(url: str,
-           params: dict = None,
-           headers: dict = None,
-           data: dict = None,
-           timeout: int = 2,
-           log: str = None) -> Union[objectrest.Response, None]:
+def delete(
+    url: str,
+    params: dict = None,
+    headers: dict = None,
+    data: dict = None,
+    timeout: int = 2,
+    log: str = None,
+) -> Union[objectrest.Response, None]:
     if params:
         url += f"?{urlencode(params)}"
     try:
diff --git a/dizqueTV/exceptions.py b/dizqueTV/exceptions.py
index 877056d..f782a89 100644
--- a/dizqueTV/exceptions.py
+++ b/dizqueTV/exceptions.py
@@ -14,15 +14,15 @@ def _platform_info(dtv_api):
     return f"os:{platform.system()}|pyv:{platform.python_version()}|libv:{version}|softv:{dtv_api.dizquetv_version}"
 
 
-def _send_error_to_analytics(dtv_api,
-                             analytics: GA.GoogleAnalytics,
-                             function_name: str,
-                             random_uuid: bool = True):
-    analytics.exception(exception_description=f"{function_name}|{_platform_info(dtv_api=dtv_api)}",
-                        is_fatal=False,
-                        anonymize_ip=analytics.anonymize_ip,
-                        random_uuid_if_needed=(random_uuid if random_uuid else analytics.anonymize_ip)
-                        )
+def _send_error_to_analytics(
+    dtv_api, analytics: GA.GoogleAnalytics, function_name: str, random_uuid: bool = True
+):
+    analytics.exception(
+        exception_description=f"{function_name}|{_platform_info(dtv_api=dtv_api)}",
+        is_fatal=False,
+        anonymize_ip=analytics.anonymize_ip,
+        random_uuid_if_needed=(random_uuid if random_uuid else analytics.anonymize_ip),
+    )
 
 
 class IncludeFunctionName(Exception):
@@ -33,51 +33,48 @@ def __init__(self, message: str, errored_function: str = None):
 
 
 class ReportedException(IncludeFunctionName):
-    def __init__(self,
-                 message: str,
-                 send_analytics: bool = True,
-                 dtv_api_object=None,
-                 analytics: GA.GoogleAnalytics = None):
+    def __init__(
+        self,
+        message: str,
+        send_analytics: bool = True,
+        dtv_api_object=None,
+        analytics: GA.GoogleAnalytics = None,
+    ):
         errored_function = str(_errored_func)
         if send_analytics:
-            _send_error_to_analytics(dtv_api=dtv_api_object,
-                                     analytics=analytics,
-                                     function_name=errored_function)
-        super().__init__(message,
-                         errored_function=errored_function)
+            _send_error_to_analytics(
+                dtv_api=dtv_api_object,
+                analytics=analytics,
+                function_name=errored_function,
+            )
+        super().__init__(message, errored_function=errored_function)
 
 
 class GeneralException(IncludeFunctionName):
-    def __init__(self,
-                 message: str):
+    def __init__(self, message: str):
         super().__init__(message)
 
 
 class MissingSettingsError(IncludeFunctionName):
-    def __init__(self,
-                 message: str):
+    def __init__(self, message: str):
         super().__init__(f"The provided settings are incomplete. {message}")
 
 
 class MissingParametersError(IncludeFunctionName):
-    def __init__(self,
-                 message: str):
+    def __init__(self, message: str):
         super().__init__(message)
 
 
 class NotRemoteObjectError(IncludeFunctionName):
-    def __init__(self,
-                 object_type: str):
+    def __init__(self, object_type: str):
         super().__init__(f"Local {object_type} object does not exist on dizqueTV.")
 
 
 class ItemCreationError(IncludeFunctionName):
-    def __init__(self,
-                 message: str):
+    def __init__(self, message: str):
         super().__init__(message)
 
 
 class ChannelCreationError(IncludeFunctionName):
-    def __init__(self,
-                 message: str):
+    def __init__(self, message: str):
         super().__init__(message)
diff --git a/dizqueTV/helpers.py b/dizqueTV/helpers.py
index 8f23888..3a911fa 100644
--- a/dizqueTV/helpers.py
+++ b/dizqueTV/helpers.py
@@ -2,25 +2,27 @@
 import json
 import os
 import random
-from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
+from concurrent.futures import ALL_COMPLETED, ThreadPoolExecutor, wait
 from datetime import datetime, timedelta
-from typing import List, Union, Tuple
+from typing import List, Tuple, Union
 
 import numpy.random as numpy_random
 from plexapi.audio import Track
 from plexapi.server import PlexServer as PServer
-from plexapi.video import Video, Movie, Episode
+from plexapi.video import Episode, Movie, Video
 
 import dizqueTV.dizquetv_requests as requests
 from dizqueTV.exceptions import MissingSettingsError
-from dizqueTV.models.media import Program, Redirect, FillerItem
+from dizqueTV.models.media import FillerItem, Program, Redirect
 
 _access_tokens = {}
 _uris = {}
 
 
 # Internal Helpers
-def _multithread(func, elements: List, element_param_name: str, thread_count: int = 20, **kwargs) -> List:
+def _multithread(
+    func, elements: List, element_param_name: str, thread_count: int = 20, **kwargs
+) -> List:
     """
     Multithread a function for elements in a list
 
@@ -49,9 +51,9 @@ def _multithread(func, elements: List, element_param_name: str, thread_count: in
     return [t.result() for t in thread_list]
 
 
-def _combine_settings_add_new(new_settings_dict: dict,
-                              default_dict: dict,
-                              ignore_keys: List = None) -> dict:
+def _combine_settings_add_new(
+    new_settings_dict: dict, default_dict: dict, ignore_keys: List = None
+) -> dict:
     """
     Build a complete dictionary for new settings, using old settings as a base
     Add new keys to template.
@@ -76,9 +78,9 @@ def _combine_settings_add_new(new_settings_dict: dict,
     return default_dict
 
 
-def _combine_settings(new_settings_dict: dict,
-                      default_dict: dict,
-                      ignore_keys: List = None) -> dict:
+def _combine_settings(
+    new_settings_dict: dict, default_dict: dict, ignore_keys: List = None
+) -> dict:
     """
     Build a complete dictionary for new settings, using old settings as a base
     Do not add new keys to template.
@@ -105,10 +107,12 @@ def _combine_settings(new_settings_dict: dict,
     return default_dict
 
 
-def _combine_settings_enforce_types(new_settings_dict: dict,
-                                    default_dict: dict,
-                                    template_dict: dict,
-                                    ignore_keys: List = None) -> dict:
+def _combine_settings_enforce_types(
+    new_settings_dict: dict,
+    default_dict: dict,
+    template_dict: dict,
+    ignore_keys: List = None,
+) -> dict:
     """
     Build a complete dictionary for new settings, using old settings as a base
     Do not add new keys to template
@@ -158,7 +162,9 @@ def _filter_dictionary(new_dictionary: dict, template_dict: dict) -> dict:
     return final_dict
 
 
-def _settings_are_complete(new_settings_dict: dict, template_settings_dict: json, ignore_keys: List = None) -> bool:
+def _settings_are_complete(
+    new_settings_dict: dict, template_settings_dict: json, ignore_keys: List = None
+) -> bool:
     """
     Check that all elements from the settings template are present in the new settings
 
@@ -195,15 +201,15 @@ def convert_icon_position(position_text: str) -> str:
     if type(position_text) == int:
         return str(position_text)
     position_text = position_text.lower()
-    if 'top' in position_text:
-        if 'left' in position_text:
-            return '0'
-        if 'right' in position_text:
-            return '1'
-    if 'bottom' in position_text:
-        if 'left' in position_text:
-            return '2'
-    return '3'
+    if "top" in position_text:
+        if "left" in position_text:
+            return "0"
+        if "right" in position_text:
+            return "1"
+    if "bottom" in position_text:
+        if "left" in position_text:
+            return "2"
+    return "3"
 
 
 def file_exists(file_path: str) -> bool:
@@ -227,7 +233,7 @@ def read_file_bytes(file_path: str):
     :return:
     :rtype:
     """
-    return open(file_path, 'rb')
+    return open(file_path, "rb")
 
 
 def _object_has_attribute(obj: object, attribute_name: str) -> bool:
@@ -247,7 +253,9 @@ def _object_has_attribute(obj: object, attribute_name: str) -> bool:
     return False
 
 
-def _make_program_dict_from_plex_item(plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer) -> dict:
+def _make_program_dict_from_plex_item(
+    plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer
+) -> dict:
     """
     Build a dictionary for a Program using a PlexAPI Video, Movie, Episode or Track object
 
@@ -263,37 +271,58 @@ def _make_program_dict_from_plex_item(plex_item: Union[Video, Movie, Episode, Tr
     plex_uri = get_plex_indirect_uri(plex_server=plex_server)
     plex_token = get_plex_access_token(plex_server=plex_server)
     data = {
-        'title': plex_item.title,
-        'key': plex_item.key,
-        'ratingKey': str(plex_item.ratingKey),
-        'icon': f"{plex_uri}{plex_item.thumb}?X-Plex-Token={plex_token}",
-        'type': item_type,
-        'duration': (plex_item.duration if (hasattr(plex_item, 'duration') and plex_item.duration) else 0),
-        'summary': plex_item.summary,
-        'rating': "" if plex_item.type == 'track' else plex_item.contentRating,
-        'date': (remove_time_from_date(plex_item.originallyAvailableAt)
-                 if (hasattr(plex_item, 'originallyAvailableAt') and plex_item.originallyAvailableAt)
-                 else '1900-01-01'),
-        'year': (get_year_from_date(plex_item.originallyAvailableAt)
-                 if (hasattr(plex_item, 'originallyAvailableAt') and plex_item.originallyAvailableAt)
-                 else '1900'),
-        'plexFile': plex_media_item_part.key,
-        'file': plex_media_item_part.file,
-        'showTitle': (plex_item.title if item_type == 'movie' else plex_item.grandparentTitle),
-        'episode': (1 if item_type == 'movie' else int(plex_item.index)),
-        'season': (1 if item_type == 'movie' else int(plex_item.parentIndex)),
-        'serverKey': plex_server.friendlyName
+        "title": plex_item.title,
+        "key": plex_item.key,
+        "ratingKey": str(plex_item.ratingKey),
+        "icon": f"{plex_uri}{plex_item.thumb}?X-Plex-Token={plex_token}",
+        "type": item_type,
+        "duration": (
+            plex_item.duration
+            if (hasattr(plex_item, "duration") and plex_item.duration)
+            else 0
+        ),
+        "summary": plex_item.summary,
+        "rating": "" if plex_item.type == "track" else plex_item.contentRating,
+        "date": (
+            remove_time_from_date(plex_item.originallyAvailableAt)
+            if (
+                hasattr(plex_item, "originallyAvailableAt")
+                and plex_item.originallyAvailableAt
+            )
+            else "1900-01-01"
+        ),
+        "year": (
+            get_year_from_date(plex_item.originallyAvailableAt)
+            if (
+                hasattr(plex_item, "originallyAvailableAt")
+                and plex_item.originallyAvailableAt
+            )
+            else "1900"
+        ),
+        "plexFile": plex_media_item_part.key,
+        "file": plex_media_item_part.file,
+        "showTitle": (
+            plex_item.title if item_type == "movie" else plex_item.grandparentTitle
+        ),
+        "episode": (1 if item_type == "movie" else int(plex_item.index)),
+        "season": (1 if item_type == "movie" else int(plex_item.parentIndex)),
+        "serverKey": plex_server.friendlyName,
     }
-    if plex_item.type == 'episode':
-        data['episodeIcon'] = f"{plex_uri}{plex_item.thumb}?X-Plex-Token={plex_token}"
+    if plex_item.type == "episode":
+        data["episodeIcon"] = f"{plex_uri}{plex_item.thumb}?X-Plex-Token={plex_token}"
         data[
-            'seasonIcon'] = f"{plex_uri}{plex_item.parentThumb if plex_item.parentThumb else plex_item.grandparentThumb}?X-Plex-Token={plex_token}"
-        data['showIcon'] = f"{plex_uri}{plex_item.grandparentThumb}?X-Plex-Token={plex_token}"
-        data['icon'] = data['showIcon']
+            "seasonIcon"
+        ] = f"{plex_uri}{plex_item.parentThumb if plex_item.parentThumb else plex_item.grandparentThumb}?X-Plex-Token={plex_token}"
+        data[
+            "showIcon"
+        ] = f"{plex_uri}{plex_item.grandparentThumb}?X-Plex-Token={plex_token}"
+        data["icon"] = data["showIcon"]
     return data
 
 
-def _make_filler_dict_from_plex_item(plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer) -> dict:
+def _make_filler_dict_from_plex_item(
+    plex_item: Union[Video, Movie, Episode, Track], plex_server: PServer
+) -> dict:
     """
     Build a dictionary for a FillerItem using a PlexAPI Video, Movie, Episode or Track object
 
@@ -307,36 +336,54 @@ def _make_filler_dict_from_plex_item(plex_item: Union[Video, Movie, Episode, Tra
     item_type = plex_item.type
     plex_media_item_part = plex_item.media[0].parts[0]
     data = {
-        'title': plex_item.title,
-        'key': plex_item.key,
-        'ratingKey': str(plex_item.ratingKey),
-        'icon': plex_item.thumb,
-        'type': item_type,
-        'duration': (plex_item.duration if (hasattr(plex_item, 'duration') and plex_item.duration) else 0),
-        'summary': plex_item.summary,
-        'date': (remove_time_from_date(plex_item.originallyAvailableAt)
-                 if (hasattr(plex_item, 'originallyAvailableAt') and plex_item.originallyAvailableAt)
-                 else '1900-01-01'),
-        'year': (get_year_from_date(plex_item.originallyAvailableAt)
-                 if (hasattr(plex_item, 'originallyAvailableAt') and plex_item.originallyAvailableAt)
-                 else '1900-01-01'),
-        'plexFile': plex_media_item_part.key,
-        'file': plex_media_item_part.file,
-        'showTitle': (plex_item.title if item_type == 'movie' else plex_item.grandparentTitle),
-        'episode': (1 if item_type == 'movie' else int(plex_item.index)),
-        'season': (1 if item_type == 'movie' else int(plex_item.parentIndex)),
-        'serverKey': plex_server.friendlyName
+        "title": plex_item.title,
+        "key": plex_item.key,
+        "ratingKey": str(plex_item.ratingKey),
+        "icon": plex_item.thumb,
+        "type": item_type,
+        "duration": (
+            plex_item.duration
+            if (hasattr(plex_item, "duration") and plex_item.duration)
+            else 0
+        ),
+        "summary": plex_item.summary,
+        "date": (
+            remove_time_from_date(plex_item.originallyAvailableAt)
+            if (
+                hasattr(plex_item, "originallyAvailableAt")
+                and plex_item.originallyAvailableAt
+            )
+            else "1900-01-01"
+        ),
+        "year": (
+            get_year_from_date(plex_item.originallyAvailableAt)
+            if (
+                hasattr(plex_item, "originallyAvailableAt")
+                and plex_item.originallyAvailableAt
+            )
+            else "1900-01-01"
+        ),
+        "plexFile": plex_media_item_part.key,
+        "file": plex_media_item_part.file,
+        "showTitle": (
+            plex_item.title if item_type == "movie" else plex_item.grandparentTitle
+        ),
+        "episode": (1 if item_type == "movie" else int(plex_item.index)),
+        "season": (1 if item_type == "movie" else int(plex_item.parentIndex)),
+        "serverKey": plex_server.friendlyName,
     }
-    if plex_item.type == 'episode':
-        data['episodeIcon'] = plex_item.thumb
-        data['seasonIcon'] = plex_item.parentThumb
-        data['showIcon'] = plex_item.grandparentThumb
+    if plex_item.type == "episode":
+        data["episodeIcon"] = plex_item.thumb
+        data["seasonIcon"] = plex_item.parentThumb
+        data["showIcon"] = plex_item.grandparentThumb
     return data
 
 
-def _make_server_dict_from_plex_server(plex_server: PServer,
-                                       auto_reload_channels: bool = False,
-                                       auto_reload_guide: bool = True) -> dict:
+def _make_server_dict_from_plex_server(
+    plex_server: PServer,
+    auto_reload_channels: bool = False,
+    auto_reload_guide: bool = True,
+) -> dict:
     """
     Build a dictionary for a PlexServer using a PlexAPI server
 
@@ -350,11 +397,11 @@ def _make_server_dict_from_plex_server(plex_server: PServer,
     :rtype: dict
     """
     data = {
-        'name': plex_server.friendlyName,
-        'uri': get_plex_indirect_uri(plex_server=plex_server),
-        'accessToken': get_plex_access_token(plex_server=plex_server),
-        'arChannels': auto_reload_channels,
-        'arGuide': auto_reload_guide
+        "name": plex_server.friendlyName,
+        "uri": get_plex_indirect_uri(plex_server=plex_server),
+        "accessToken": get_plex_access_token(plex_server=plex_server),
+        "arChannels": auto_reload_channels,
+        "arGuide": auto_reload_guide,
     }
     return data
 
@@ -391,8 +438,14 @@ def get_items_of_type(item_type: str, items: List) -> List:
     :return: list of items with 'type' = X
     :rtype: list
     """
-    return [item for item in items if
-            (_object_has_attribute(obj=item, attribute_name='type') and item.type == item_type)]
+    return [
+        item
+        for item in items
+        if (
+            _object_has_attribute(obj=item, attribute_name="type")
+            and item.type == item_type
+        )
+    ]
 
 
 def get_items_of_not_type(item_type: str, items: List) -> List:
@@ -406,8 +459,14 @@ def get_items_of_not_type(item_type: str, items: List) -> List:
     :return: list of items without 'type' = X
     :rtype: list
     """
-    return [item for item in items if
-            (_object_has_attribute(obj=item, attribute_name='type') and item.type != item_type)]
+    return [
+        item
+        for item in items
+        if (
+            _object_has_attribute(obj=item, attribute_name="type")
+            and item.type != item_type
+        )
+    ]
 
 
 def get_non_shows(media_items: List) -> List:
@@ -419,9 +478,20 @@ def get_non_shows(media_items: List) -> List:
     :return: list of non-show MediaItem objects
     :rtype: list
     """
-    return [item for item in media_items if
-            ((_object_has_attribute(obj=item, attribute_name='type') and item.type != 'episode') or
-             (_object_has_attribute(obj=item, attribute_name='season') and not item.season))]
+    return [
+        item
+        for item in media_items
+        if (
+            (
+                _object_has_attribute(obj=item, attribute_name="type")
+                and item.type != "episode"
+            )
+            or (
+                _object_has_attribute(obj=item, attribute_name="season")
+                and not item.season
+            )
+        )
+    ]
 
 
 def make_show_dict(media_items: List) -> dict:
@@ -436,7 +506,11 @@ def make_show_dict(media_items: List) -> dict:
     """
     show_dict = {}
     for item in media_items:
-        if _object_has_attribute(obj=item, attribute_name='type') and item.type == 'episode' and item.episode:
+        if (
+            _object_has_attribute(obj=item, attribute_name="type")
+            and item.type == "episode"
+            and item.episode
+        ):
             if item.showTitle in show_dict.keys():
                 if item.season in show_dict[item.showTitle].keys():
                     show_dict[item.showTitle][item.season][item.episode] = item
@@ -460,13 +534,21 @@ def order_show_dict(show_dict: dict) -> dict:
     for show_name, seasons in show_dict.items():
         episode_ordered_dict[show_name] = {}
         for season_number, episodes in seasons.items():
-            ordered_episodes = {episode_number: episode for episode_number, episode in
-                                sorted(episodes.items(), key=lambda item: item[0])}
+            ordered_episodes = {
+                episode_number: episode
+                for episode_number, episode in sorted(
+                    episodes.items(), key=lambda item: item[0]
+                )
+            }
             episode_ordered_dict[show_name][season_number] = ordered_episodes
     season_ordered_dict = {}
     for show_name, seasons in episode_ordered_dict.items():
-        ordered_seasons = {season_number: episodes for season_number, episodes in
-                           sorted(seasons.items(), key=lambda item: item[0])}
+        ordered_seasons = {
+            season_number: episodes
+            for season_number, episodes in sorted(
+                seasons.items(), key=lambda item: item[0]
+            )
+        }
         season_ordered_dict[show_name] = ordered_seasons
     return season_ordered_dict
 
@@ -482,14 +564,21 @@ def add_durations_to_show_dict(show_dict: dict) -> dict:
     """
     sorted_shows = {}
     for show_name, seasons in show_dict.items():
-        sorted_shows[show_name] = {'seasons': {}, 'duration': 0}
+        sorted_shows[show_name] = {"seasons": {}, "duration": 0}
         for season_number, episodes in seasons.items():
-            sorted_shows[show_name]['seasons'][season_number] = {'episodes': {}, 'duration': 0}
+            sorted_shows[show_name]["seasons"][season_number] = {
+                "episodes": {},
+                "duration": 0,
+            }
             for episode_number, episode in episodes.items():
-                episode_dict = {'episode': episode, 'duration': episode.duration}
-                sorted_shows[show_name]['seasons'][season_number]['episodes'][episode_number] = episode_dict
-                sorted_shows[show_name]['seasons'][season_number]['duration'] += episode.duration
-                sorted_shows[show_name]['duration'] += episode.duration
+                episode_dict = {"episode": episode, "duration": episode.duration}
+                sorted_shows[show_name]["seasons"][season_number]["episodes"][
+                    episode_number
+                ] = episode_dict
+                sorted_shows[show_name]["seasons"][season_number][
+                    "duration"
+                ] += episode.duration
+                sorted_shows[show_name]["duration"] += episode.duration
     return sorted_shows
 
 
@@ -504,14 +593,14 @@ def condense_show_dict(show_dict: dict) -> dict:
     :return: dict object with all episodes arranged by show-episode
     :rtype: dict
     """
-    sorted_shows = {'count': 0, 'shows': {}}
+    sorted_shows = {"count": 0, "shows": {}}
     for show_name, seasons in show_dict.items():
-        sorted_shows['shows'][show_name] = {'episodes': [], 'count': 0}
+        sorted_shows["shows"][show_name] = {"episodes": [], "count": 0}
         for season_number, episodes in seasons.items():
             for episode_number, episode in episodes.items():
-                sorted_shows['shows'][show_name]['episodes'].append(episode)
-                sorted_shows['shows'][show_name]['count'] += 1
-                sorted_shows['count'] += 1
+                sorted_shows["shows"][show_name]["episodes"].append(episode)
+                sorted_shows["shows"][show_name]["count"] += 1
+                sorted_shows["count"] += 1
     return sorted_shows
 
 
@@ -544,7 +633,9 @@ def get_year_from_date(date_string: Union[datetime, str]) -> int:
     return int(date_string.strftime("%Y"))
 
 
-def string_to_datetime(date_string: str, template: str = "%Y-%m-%dT%H:%M:%S") -> datetime:
+def string_to_datetime(
+    date_string: str, template: str = "%Y-%m-%dT%H:%M:%S"
+) -> datetime:
     """
     Convert a datetime string to a datetime.datetime object
 
@@ -555,12 +646,14 @@ def string_to_datetime(date_string: str, template: str = "%Y-%m-%dT%H:%M:%S") ->
     :return: datetime.datetime object
     :rtype: datetime.datetime
     """
-    if date_string.endswith('Z'):
+    if date_string.endswith("Z"):
         date_string = date_string[:-5]
     return datetime.strptime(date_string, template)
 
 
-def datetime_to_string(datetime_object: datetime, template: str = "%Y-%m-%dT%H:%M:%S.000Z") -> str:
+def datetime_to_string(
+    datetime_object: datetime, template: str = "%Y-%m-%dT%H:%M:%S.000Z"
+) -> str:
     """
     Convert a datetime.datetime object to a string
 
@@ -585,7 +678,7 @@ def string_to_time(time_string: str, template: str = "%H:%M:%S") -> datetime:
     :return: datetime.datetime object
     :rtype: datetime.datetime
     """
-    if time_string.endswith('Z'):
+    if time_string.endswith("Z"):
         time_string = time_string[:-5]
     return datetime.strptime(time_string, template)
 
@@ -642,13 +735,15 @@ def hours_difference_in_timezone() -> int:
     return int((datetime.utcnow() - datetime.now()).total_seconds() / 60 / 60)
 
 
-def shift_time(starting_time: datetime,
-               seconds: int = 0,
-               minutes: int = 0,
-               hours: int = 0,
-               days: int = 0,
-               months: int = 0,
-               years: int = 0) -> datetime:
+def shift_time(
+    starting_time: datetime,
+    seconds: int = 0,
+    minutes: int = 0,
+    hours: int = 0,
+    days: int = 0,
+    months: int = 0,
+    years: int = 0,
+) -> datetime:
     """
     Shift a time forward or backwards
 
@@ -670,7 +765,9 @@ def shift_time(starting_time: datetime,
     :rtype: datetime.datetime
     """
     days = days + (30 * months) + (365 * years)
-    return starting_time + timedelta(seconds=seconds, minutes=minutes, hours=hours, days=days)
+    return starting_time + timedelta(
+        seconds=seconds, minutes=minutes, hours=hours, days=days
+    )
 
 
 def get_nearest_30_minute_mark() -> str:
@@ -697,14 +794,16 @@ def convert_24_time_to_milliseconds_past_midnight(time_string: str) -> int:
     :return: int of milliseconds since midnight
     :rtype: int
     """
-    hour_minute_second = time_string.split(':')
+    hour_minute_second = time_string.split(":")
     if len(hour_minute_second) < 2 or len(hour_minute_second) > 4:
         raise Exception("Time string must be in two-digit format hour:minute:second")
     if len(hour_minute_second) == 2:
         time_string += ":00"
     time_in_datetime = string_to_time(time_string=time_string)
     midnight = string_to_time(time_string="00:00:00")
-    return get_milliseconds_between_two_datetimes(start_datetime=midnight, end_datetime=time_in_datetime)
+    return get_milliseconds_between_two_datetimes(
+        start_datetime=midnight, end_datetime=time_in_datetime
+    )
 
 
 def get_milliseconds_between_two_hours(start_hour: int, end_hour: int) -> int:
@@ -726,7 +825,9 @@ def get_milliseconds_between_two_hours(start_hour: int, end_hour: int) -> int:
     return int((end_date - start_date).total_seconds()) * 1000
 
 
-def get_milliseconds_between_two_datetimes(start_datetime: datetime, end_datetime: datetime) -> int:
+def get_milliseconds_between_two_datetimes(
+    start_datetime: datetime, end_datetime: datetime
+) -> int:
     """
     Get how many milliseconds between two datetime.datetime objects
 
@@ -740,7 +841,9 @@ def get_milliseconds_between_two_datetimes(start_datetime: datetime, end_datetim
     return int((end_datetime - start_datetime).total_seconds()) * 1000
 
 
-def get_needed_flex_time(item_time_milliseconds: int, allowed_minutes_time_frame: int) -> int:
+def get_needed_flex_time(
+    item_time_milliseconds: int, allowed_minutes_time_frame: int
+) -> int:
     """
     Get how many milliseconds needed to stretch an item's runtime to a specific interval length
 
@@ -751,17 +854,24 @@ def get_needed_flex_time(item_time_milliseconds: int, allowed_minutes_time_frame
     :return: int of milliseconds needed to stretch item
     :rtype: int
     """
-    minute_start = (30 if datetime.utcnow().minute >= 30 else 0)
+    minute_start = 30 if datetime.utcnow().minute >= 30 else 0
 
-    allowed_milliseconds_time_frame = (allowed_minutes_time_frame + (minute_start % allowed_minutes_time_frame)) * \
-                                      60 * 1000
-    remainder = allowed_milliseconds_time_frame - (item_time_milliseconds % allowed_milliseconds_time_frame)
+    allowed_milliseconds_time_frame = (
+        (allowed_minutes_time_frame + (minute_start % allowed_minutes_time_frame))
+        * 60
+        * 1000
+    )
+    remainder = allowed_milliseconds_time_frame - (
+        item_time_milliseconds % allowed_milliseconds_time_frame
+    )
     if remainder == allowed_milliseconds_time_frame:
         return 0
     return remainder
 
 
-def get_plex_indirect_uri(plex_server: PServer, force_update: bool = False) -> Union[str, None]:
+def get_plex_indirect_uri(
+    plex_server: PServer, force_update: bool = False
+) -> Union[str, None]:
     """
     Get the indirect URI (ex. http://192.168.1.1-xxxxxxxxxxxxxxxx.plex.direct) for a Plex server
 
@@ -775,24 +885,28 @@ def get_plex_indirect_uri(plex_server: PServer, force_update: bool = False) -> U
     if _uris.get(plex_server.friendlyName) and not force_update:
         return _uris[plex_server.friendlyName]
     headers = {
-        'Accept': 'application/json',
-        'X-Plex-Product': 'dizqueTV-Python',
-        'X-Plex-Version': 'Plex OAuth',
-        'X-Plex-Client-Identifier': 'dizqueTV-Python',
-        'X-Plex-Model': 'Plex OAuth',
-        'X-Plex-Token': plex_server._token
+        "Accept": "application/json",
+        "X-Plex-Product": "dizqueTV-Python",
+        "X-Plex-Version": "Plex OAuth",
+        "X-Plex-Client-Identifier": "dizqueTV-Python",
+        "X-Plex-Model": "Plex OAuth",
+        "X-Plex-Token": plex_server._token,
     }
-    response = requests.get(url="https://plex.tv/api/v2/resources?includeHttps=1", headers=headers)
+    response = requests.get(
+        url="https://plex.tv/api/v2/resources?includeHttps=1", headers=headers
+    )
     if response:
         json_data = response.json()
         for server in json_data:
-            if server['name'] == plex_server.friendlyName:
-                _uris[plex_server.friendlyName] = server['connections'][0]['uri']
-                return server['connections'][0]['uri']
+            if server["name"] == plex_server.friendlyName:
+                _uris[plex_server.friendlyName] = server["connections"][0]["uri"]
+                return server["connections"][0]["uri"]
     return None
 
 
-def get_plex_access_token(plex_server: PServer, force_update: bool = False) -> Union[str, None]:
+def get_plex_access_token(
+    plex_server: PServer, force_update: bool = False
+) -> Union[str, None]:
     """
     Get the access token for a Plex server
 
@@ -806,19 +920,21 @@ def get_plex_access_token(plex_server: PServer, force_update: bool = False) -> U
     if not force_update:
         return plex_server._token
     headers = {
-        'Accept': 'application/json',
-        'X-Plex-Product': 'dizqueTV-Python',
-        'X-Plex-Version': 'Plex OAuth',
-        'X-Plex-Client-Identifier': 'dizqueTV-Python',
-        'X-Plex-Model': 'Plex OAuth',
-        'X-Plex-Token': plex_server._token
+        "Accept": "application/json",
+        "X-Plex-Product": "dizqueTV-Python",
+        "X-Plex-Version": "Plex OAuth",
+        "X-Plex-Client-Identifier": "dizqueTV-Python",
+        "X-Plex-Model": "Plex OAuth",
+        "X-Plex-Token": plex_server._token,
     }
-    response = requests.get(url="https://plex.tv/api/v2/resources?includeHttps=1", headers=headers)
+    response = requests.get(
+        url="https://plex.tv/api/v2/resources?includeHttps=1", headers=headers
+    )
     if response:
         json_data = response.json()
         for server in json_data:
-            if server['name'] == plex_server.friendlyName:
-                return server['accessToken']
+            if server["name"] == plex_server.friendlyName:
+                return server["accessToken"]
     return None
 
 
@@ -969,7 +1085,9 @@ def remove_duplicates_by_attribute(items: List, attribute_name: str) -> List:
     return filtered
 
 
-def sort_media_alphabetically(media_items: List[Union[Program, FillerItem]]) -> List[Union[Program, FillerItem]]:
+def sort_media_alphabetically(
+    media_items: List[Union[Program, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Sort media items alphabetically.
     Note: Shows will be grouped and sorted by series title, but episodes may be out of order.
@@ -980,14 +1098,20 @@ def sort_media_alphabetically(media_items: List[Union[Program, FillerItem]]) ->
     :return: List of Program and FillerItem objects
     :rtype: List[Union[Program, FillerItem]]
     """
-    items_with_titles, items_without_titles = _separate_with_and_without(items=media_items,
-                                                                         attribute_name='title')
-    sorted_items = sorted(items_with_titles, key=lambda x: (x.showTitle if x.type == 'episode' else x.title))
+    items_with_titles, items_without_titles = _separate_with_and_without(
+        items=media_items, attribute_name="title"
+    )
+    sorted_items = sorted(
+        items_with_titles,
+        key=lambda x: (x.showTitle if x.type == "episode" else x.title),
+    )
     sorted_items.extend(items_without_titles)
     return sorted_items
 
 
-def sort_media_by_release_date(media_items: List[Union[Program, FillerItem]]) -> List[Union[Program, FillerItem]]:
+def sort_media_by_release_date(
+    media_items: List[Union[Program, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Sort media items by release date.
     Note: Items without release dates are appended (alphabetically) at the end of the list
@@ -997,9 +1121,12 @@ def sort_media_by_release_date(media_items: List[Union[Program, FillerItem]]) ->
     :return: List of Program and FillerItem objects
     :rtype: List[Union[Program, FillerItem]]
     """
-    items_with_dates, items_without_dates = _separate_with_and_without(items=media_items,
-                                                                       attribute_name='date')
-    sorted_items = sorted(items_with_dates, key=lambda x: datetime.strptime(x.date, "%Y-%m-%d"))
+    items_with_dates, items_without_dates = _separate_with_and_without(
+        items=media_items, attribute_name="date"
+    )
+    sorted_items = sorted(
+        items_with_dates, key=lambda x: datetime.strptime(x.date, "%Y-%m-%d")
+    )
     sorted_items.extend(sort_media_alphabetically(media_items=items_without_dates))
     return sorted_items
 
@@ -1017,15 +1144,21 @@ def _sort_shows_by_season_order(shows_dict: dict) -> List[Union[Program, FillerI
     sorted_list = []
     sorted_shows = sorted(shows_dict.items(), key=lambda show_name: show_name)
     for show in sorted_shows:
-        sorted_seasons = sorted(show[1].items(), key=lambda season_number: season_number)
+        sorted_seasons = sorted(
+            show[1].items(), key=lambda season_number: season_number
+        )
         for season in sorted_seasons:
-            sorted_episodes = sorted(season[1].items(), key=lambda episode_number: episode_number)
+            sorted_episodes = sorted(
+                season[1].items(), key=lambda episode_number: episode_number
+            )
             for item in sorted_episodes:
                 sorted_list.append(item[1])
     return sorted_list
 
 
-def sort_media_by_season_order(media_items: List[Union[Program, FillerItem]]) -> List[Union[Program, FillerItem]]:
+def sort_media_by_season_order(
+    media_items: List[Union[Program, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Sort media items by season order.
     Note: Series are ordered alphabetically, movies appended (alphabetically) at the end of the list.
@@ -1043,7 +1176,9 @@ def sort_media_by_season_order(media_items: List[Union[Program, FillerItem]]) ->
     return sorted_all
 
 
-def sort_media_by_duration(media_items: List[Union[Program, FillerItem]]) -> List[Union[Program, FillerItem]]:
+def sort_media_by_duration(
+    media_items: List[Union[Program, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Sort media by duration.
     Note: Automatically removes redirect items
@@ -1053,15 +1188,22 @@ def sort_media_by_duration(media_items: List[Union[Program, FillerItem]]) -> Lis
     :return: List of Program and FillerItem objects
     :rtype: List[Union[Program, FillerList]]
     """
-    non_redirects = [item for item in media_items if
-                     (_object_has_attribute(obj=item, attribute_name='duration')
-                      and _object_has_attribute(obj=item, attribute_name='type')
-                      and item.type != 'redirect')]
+    non_redirects = [
+        item
+        for item in media_items
+        if (
+            _object_has_attribute(obj=item, attribute_name="duration")
+            and _object_has_attribute(obj=item, attribute_name="type")
+            and item.type != "redirect"
+        )
+    ]
     sorted_media = sorted(non_redirects, key=lambda x: x.duration)
     return sorted_media
 
 
-def sort_media_randomly(media_items: List[Union[Program, FillerItem]]) -> List[Union[Program, FillerItem]]:
+def sort_media_randomly(
+    media_items: List[Union[Program, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Sort media randomly.
 
@@ -1074,7 +1216,9 @@ def sort_media_randomly(media_items: List[Union[Program, FillerItem]]) -> List[U
     return media_items
 
 
-def sort_media_cyclical_shuffle(media_items: List[Union[Program, FillerItem]]) -> List[Union[Program, FillerItem]]:
+def sort_media_cyclical_shuffle(
+    media_items: List[Union[Program, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Sort media cyclically.
     Note: Automatically removes FillerItem objects
@@ -1103,24 +1247,29 @@ def sort_media_cyclical_shuffle(media_items: List[Union[Program, FillerItem]]) -
         show_list[index] = show_cyclical_order
         index_list.append(index)
         index += 1
-    show_list['remaining_episode_count'] = total_episode_count
+    show_list["remaining_episode_count"] = total_episode_count
     final_list = []
     while len(final_list) != total_item_count:
         categories_and_sizes = {
-            'show': show_list['remaining_episode_count'],
-            'non_show': len(non_shows)
+            "show": show_list["remaining_episode_count"],
+            "non_show": len(non_shows),
         }
-        if 'non_show' in categories_and_sizes.keys() and len(non_shows) == 0:
-            del categories_and_sizes['non_show']
-        if 'show' in categories_and_sizes.keys() and show_list['remaining_episode_count'] == 0:
-            del categories_and_sizes['show']
+        if "non_show" in categories_and_sizes.keys() and len(non_shows) == 0:
+            del categories_and_sizes["non_show"]
+        if (
+            "show" in categories_and_sizes.keys()
+            and show_list["remaining_episode_count"] == 0
+        ):
+            del categories_and_sizes["show"]
         if not categories_and_sizes:
             break
-        show_or_non_show = weighted_choice_by_sizes_dict(items_and_sizes=categories_and_sizes)
-        if show_or_non_show == 'show':
+        show_or_non_show = weighted_choice_by_sizes_dict(
+            items_and_sizes=categories_and_sizes
+        )
+        if show_or_non_show == "show":
             random_index = random_choice(items=index_list)  # failure 1
             new_item = show_list[random_index].pop(0)
-            show_list['remaining_episode_count'] -= 1
+            show_list["remaining_episode_count"] -= 1
             final_list.append(new_item)
             if len(show_list[random_index]) == 0:
                 index_list.remove(random_index)
@@ -1130,9 +1279,11 @@ def sort_media_cyclical_shuffle(media_items: List[Union[Program, FillerItem]]) -
     return final_list
 
 
-def sort_media_block_shuffle(media_items: List[Union[Program, FillerItem]],
-                             block_length: int = 1,
-                             randomize: bool = False) -> List[Union[Program, FillerItem]]:
+def sort_media_block_shuffle(
+    media_items: List[Union[Program, FillerItem]],
+    block_length: int = 1,
+    randomize: bool = False,
+) -> List[Union[Program, FillerItem]]:
     """
     Sort media with block shuffle.
     Default: Items are alternated one at a time, alphabetically
@@ -1152,30 +1303,35 @@ def sort_media_block_shuffle(media_items: List[Union[Program, FillerItem]],
     ordered_show_dict = order_show_dict(show_dict=show_dict)
     condensed_show_dict = condense_show_dict(show_dict=ordered_show_dict)
     final_show_list = []
-    target_length = condensed_show_dict['count']
+    target_length = condensed_show_dict["count"]
     if randomize:
         while len(final_show_list) < target_length:
-            random_show_name = random.choice(list(condensed_show_dict['shows'].keys()))
+            random_show_name = random.choice(list(condensed_show_dict["shows"].keys()))
             for _ in range(0, random.randint(1, block_length)):
-                if len(condensed_show_dict['shows'][random_show_name]['episodes']) > 0:
-                    final_show_list.append(condensed_show_dict['shows'][random_show_name]['episodes'].pop(0))
+                if len(condensed_show_dict["shows"][random_show_name]["episodes"]) > 0:
+                    final_show_list.append(
+                        condensed_show_dict["shows"][random_show_name]["episodes"].pop(
+                            0
+                        )
+                    )
                 else:
-                    del condensed_show_dict['shows'][random_show_name]
+                    del condensed_show_dict["shows"][random_show_name]
                     break
     else:
         while len(final_show_list) < target_length:
-            for show_name, data in condensed_show_dict['shows'].items():
+            for show_name, data in condensed_show_dict["shows"].items():
                 for _ in range(0, block_length):
-                    if len(data['episodes']) > 0:
-                        final_show_list.append(data['episodes'].pop(0))
+                    if len(data["episodes"]) > 0:
+                        final_show_list.append(data["episodes"].pop(0))
                     else:
                         break
     final_list = final_show_list + non_shows
     return final_list
 
 
-def balance_shows(media_items: List[Union[Program, FillerItem]], margin_of_correction: float = 0.1) -> \
-        List[Union[Program, FillerItem]]:
+def balance_shows(
+    media_items: List[Union[Program, FillerItem]], margin_of_correction: float = 0.1
+) -> List[Union[Program, FillerItem]]:
     """
     Balance weights of the shows. Movies are untouched.
 
@@ -1189,26 +1345,32 @@ def balance_shows(media_items: List[Union[Program, FillerItem]], margin_of_corre
     non_shows = get_non_shows(media_items=media_items)
     show_dict = make_show_dict(media_items=media_items)
     ordered_show_dict = order_show_dict(show_dict=show_dict)
-    ordered_show_dict_with_durations = add_durations_to_show_dict(show_dict=ordered_show_dict)
+    ordered_show_dict_with_durations = add_durations_to_show_dict(
+        show_dict=ordered_show_dict
+    )
     show_durations = []
     for show_name in ordered_show_dict_with_durations.keys():
-        show_durations.append(ordered_show_dict_with_durations[show_name]['duration'])
+        show_durations.append(ordered_show_dict_with_durations[show_name]["duration"])
     shortest_show_length = min(show_durations)
     margin = 1 + margin_of_correction
     final_shows = []
     for show_name, show_data in ordered_show_dict_with_durations.items():
         show_running_duration = 0
         continue_with_show = True
-        for season_number, season_data in show_data['seasons'].items():
+        for season_number, season_data in show_data["seasons"].items():
             if not continue_with_show:
                 break
-            for episode_number, episode_data in season_data['episodes'].items():
+            for episode_number, episode_data in season_data["episodes"].items():
                 if not continue_with_show:
                     break
-                potential_show_duration = show_running_duration + episode_data['duration']
-                if (float(potential_show_duration) / float(shortest_show_length)) <= margin:
-                    final_shows.append(episode_data['episode'])
-                    show_running_duration += episode_data['duration']
+                potential_show_duration = (
+                    show_running_duration + episode_data["duration"]
+                )
+                if (
+                    float(potential_show_duration) / float(shortest_show_length)
+                ) <= margin:
+                    final_shows.append(episode_data["episode"])
+                    show_running_duration += episode_data["duration"]
                 else:
                     continue_with_show = False
     sorted_movies = sort_media_alphabetically(media_items=non_shows)
@@ -1216,7 +1378,9 @@ def balance_shows(media_items: List[Union[Program, FillerItem]], margin_of_corre
     return sorted_all
 
 
-def remove_non_programs(media_items: List[Union[Program, Redirect, FillerItem]]) -> List[Union[Program, FillerItem]]:
+def remove_non_programs(
+    media_items: List[Union[Program, Redirect, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Remove all non-programs from list of media items.
 
@@ -1225,13 +1389,19 @@ def remove_non_programs(media_items: List[Union[Program, Redirect, FillerItem]])
     :return: List of Program and FillerItem objects
     :rtype: List[Union[Program, FillerList]]
     """
-    return [item for item in media_items if
-            (_object_has_attribute(obj=item, attribute_name='type')
-             and item.type != 'redirect')]
+    return [
+        item
+        for item in media_items
+        if (
+            _object_has_attribute(obj=item, attribute_name="type")
+            and item.type != "redirect"
+        )
+    ]
 
 
-def remove_duplicate_media_items(media_items: List[Union[Program, Redirect, FillerItem]]) -> \
-        List[Union[Program, FillerItem]]:
+def remove_duplicate_media_items(
+    media_items: List[Union[Program, Redirect, FillerItem]]
+) -> List[Union[Program, FillerItem]]:
     """
     Remove duplicate items from list of media items.
     Check by ratingKey.
@@ -1243,11 +1413,14 @@ def remove_duplicate_media_items(media_items: List[Union[Program, Redirect, Fill
     :rtype: List[Union[Program, FillerList]]
     """
     non_redirects = remove_non_programs(media_items=media_items)
-    return remove_duplicates_by_attribute(items=non_redirects, attribute_name='ratingKey')
+    return remove_duplicates_by_attribute(
+        items=non_redirects, attribute_name="ratingKey"
+    )
 
 
-def _get_first_x_minutes_of_programs(programs: List[Union[Program, Redirect, FillerItem]],
-                                     minutes: int) -> Tuple[List[Union[Program, Redirect, FillerItem]], int]:
+def _get_first_x_minutes_of_programs(
+    programs: List[Union[Program, Redirect, FillerItem]], minutes: int
+) -> Tuple[List[Union[Program, Redirect, FillerItem]], int]:
     """
     Keep building a list of programs in order until a duration limit is met.
 
@@ -1270,10 +1443,13 @@ def _get_first_x_minutes_of_programs(programs: List[Union[Program, Redirect, Fil
     return programs_to_return, running_total
 
 
-def _get_first_x_minutes_of_programs_return_unused(programs: List[Union[Program, Redirect, FillerItem]],
-                                                   minutes: int) -> Tuple[List[Union[Program, Redirect, FillerItem]],
-                                                                          int,
-                                                                          List[Union[Program, Redirect, FillerItem]]]:
+def _get_first_x_minutes_of_programs_return_unused(
+    programs: List[Union[Program, Redirect, FillerItem]], minutes: int
+) -> Tuple[
+    List[Union[Program, Redirect, FillerItem]],
+    int,
+    List[Union[Program, Redirect, FillerItem]],
+]:
     """
     Keep building a list of programs in order until a duration limit is met.
 
diff --git a/dizqueTV/models/__init__.py b/dizqueTV/models/__init__.py
index 752f807..e3420e7 100644
--- a/dizqueTV/models/__init__.py
+++ b/dizqueTV/models/__init__.py
@@ -1,8 +1,11 @@
-from dizqueTV.models.channels import Channel, TimeSlot, TimeSlotItem, Schedule
-from dizqueTV.models.custom_show import CustomShow, CustomShowDetails, CustomShowItem
+from dizqueTV.models.channels import Channel, Schedule, TimeSlot, TimeSlotItem
+from dizqueTV.models.custom_show import (CustomShow, CustomShowDetails,
+                                         CustomShowItem)
 from dizqueTV.models.fillers import FillerList
 from dizqueTV.models.general import UploadImageResponse
 from dizqueTV.models.guide import Guide
 from dizqueTV.models.media import FillerItem, Program, Redirect
 from dizqueTV.models.plex_server import PlexServer
-from dizqueTV.models.settings import XMLTVSettings, PlexSettings, FFMPEGSettings, HDHomeRunSettings, ServerDetails
+from dizqueTV.models.settings import (FFMPEGSettings, HDHomeRunSettings,
+                                      PlexSettings, ServerDetails,
+                                      XMLTVSettings)
diff --git a/dizqueTV/models/channels.py b/dizqueTV/models/channels.py
index 15dc706..7d7824f 100644
--- a/dizqueTV/models/channels.py
+++ b/dizqueTV/models/channels.py
@@ -5,36 +5,41 @@
 from plexapi.collection import Collection
 from plexapi.playlist import Playlist
 from plexapi.server import PlexServer as PServer
-from plexapi.video import Video, Movie, Episode
+from plexapi.video import Episode, Movie, Video
 
 import dizqueTV.helpers as helpers
 from dizqueTV import decorators
-from dizqueTV.exceptions import MissingParametersError, GeneralException
+from dizqueTV.exceptions import GeneralException, MissingParametersError
 from dizqueTV.models.base import BaseAPIObject, BaseObject
 from dizqueTV.models.custom_show import CustomShow, CustomShowItem
 from dizqueTV.models.fillers import FillerList
-from dizqueTV.models.media import Redirect, Program, FillerItem
-from dizqueTV.models.templates import MOVIE_PROGRAM_TEMPLATE, EPISODE_PROGRAM_TEMPLATE, TRACK_PROGRAM_TEMPLATE, \
-    REDIRECT_PROGRAM_TEMPLATE, FILLER_LIST_CHANNEL_TEMPLATE, \
-    CHANNEL_FFMPEG_SETTINGS_DEFAULT, SCHEDULE_SETTINGS_DEFAULT, TIME_SLOT_SETTINGS_TEMPLATE, SCHEDULE_SETTINGS_TEMPLATE, \
-    RANDOM_SCHEDULE_SETTINGS_TEMPLATE, RANDOM_SCHEDULE_SETTINGS_DEFAULT
+from dizqueTV.models.media import FillerItem, Program, Redirect
+from dizqueTV.models.templates import (CHANNEL_FFMPEG_SETTINGS_DEFAULT,
+                                       EPISODE_PROGRAM_TEMPLATE,
+                                       FILLER_LIST_CHANNEL_TEMPLATE,
+                                       MOVIE_PROGRAM_TEMPLATE,
+                                       RANDOM_SCHEDULE_SETTINGS_DEFAULT,
+                                       RANDOM_SCHEDULE_SETTINGS_TEMPLATE,
+                                       REDIRECT_PROGRAM_TEMPLATE,
+                                       SCHEDULE_SETTINGS_DEFAULT,
+                                       SCHEDULE_SETTINGS_TEMPLATE,
+                                       TIME_SLOT_SETTINGS_TEMPLATE,
+                                       TRACK_PROGRAM_TEMPLATE)
 
 
 class ChannelFFMPEGSettings(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance, channel_instance):
         super().__init__(data, dizque_instance)
         self._channel_instance = channel_instance
-        self.targetResolution = data.get('targetResolution')
-        self.videoBitrate = data.get('videoBitrate')
-        self.videoBufSize = data.get('videoBufSize')
+        self.targetResolution = data.get("targetResolution")
+        self.videoBitrate = data.get("videoBitrate")
+        self.videoBufSize = data.get("videoBufSize")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({(self.targetResolution if self.targetResolution else 'Default')})"
 
     @decorators.check_for_dizque_instance
-    def update(self,
-               use_global_settings: bool = False,
-               **kwargs) -> bool:
+    def update(self, use_global_settings: bool = False, **kwargs) -> bool:
         """
         Edit this channel's FFMPEG settings on dizqueTV
         Automatically refreshes associated Channel object
@@ -48,10 +53,12 @@ def update(self,
         if use_global_settings:
             new_settings = CHANNEL_FFMPEG_SETTINGS_DEFAULT
         else:
-            new_settings = helpers._combine_settings(new_settings_dict=kwargs,
-                                                     default_dict=self._data)
-        if self._dizque_instance.update_channel(channel_number=self._channel_instance.number,
-                                                transcoding=new_settings):
+            new_settings = helpers._combine_settings(
+                new_settings_dict=kwargs, default_dict=self._data
+            )
+        if self._dizque_instance.update_channel(
+            channel_number=self._channel_instance.number, transcoding=new_settings
+        ):
             self._channel_instance.refresh()
             del self
             return True
@@ -62,11 +69,11 @@ class ChannelOnDemandSettings(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance, channel_instance):
         super().__init__(data, dizque_instance)
         self._channel_instance = channel_instance
-        self.isOnDemand = data.get('isOnDemand')
-        self.modulo = data.get('modulo')
-        self.paused = data.get('paused')
-        self.firstProgramModulo = data.get('firstProgramModulo')
-        self.playedOffset = data.get('playedOffset')
+        self.isOnDemand = data.get("isOnDemand")
+        self.modulo = data.get("modulo")
+        self.paused = data.get("paused")
+        self.firstProgramModulo = data.get("firstProgramModulo")
+        self.playedOffset = data.get("playedOffset")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({('On Demand' if self.isOnDemand else 'Not On Demand')})"
@@ -82,11 +89,15 @@ def update(self, **kwargs) -> bool:
         :return: True if successful, False if unsuccessful (Channel reloads in-place, ChannelFFMPEGSettings object is destroyed)
         :rtype: bool
         """
-        new_settings = helpers._combine_settings(new_settings_dict=kwargs, default_dict=self._data)
-        new_settings['firstProgramModulo'] = (self._channel_instance.startTime_datetime.timestamp() * 1000) % \
-                                             new_settings['modulo']
-        if self._dizque_instance.update_channel(channel_number=self._channel_instance.number,
-                                                onDemand=new_settings):
+        new_settings = helpers._combine_settings(
+            new_settings_dict=kwargs, default_dict=self._data
+        )
+        new_settings["firstProgramModulo"] = (
+            self._channel_instance.startTime_datetime.timestamp() * 1000
+        ) % new_settings["modulo"]
+        if self._dizque_instance.update_channel(
+            channel_number=self._channel_instance.number, onDemand=new_settings
+        ):
             self._channel_instance.refresh()
             del self
             return True
@@ -97,22 +108,21 @@ class Watermark(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance, channel_instance):
         super().__init__(data, dizque_instance)
         self._channel_instance = channel_instance
-        self.enabled = data.get('enabled')
-        self.width = data.get('width')
-        self.verticalMargin = data.get('verticalMargin')
-        self.horizontalMargin = data.get('horizontalMargin')
-        self.duration = data.get('duration')
-        self.fixedSize = data.get('fixedSize')
-        self.position = data.get('position')
-        self.url = data.get('url')
-        self.animated = data.get('animated')
+        self.enabled = data.get("enabled")
+        self.width = data.get("width")
+        self.verticalMargin = data.get("verticalMargin")
+        self.horizontalMargin = data.get("horizontalMargin")
+        self.duration = data.get("duration")
+        self.fixedSize = data.get("fixedSize")
+        self.position = data.get("position")
+        self.url = data.get("url")
+        self.animated = data.get("animated")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.enabled}:{(self.url if self.url else 'Empty URL')})"
 
     @decorators.check_for_dizque_instance
-    def update(self,
-               **kwargs) -> bool:
+    def update(self, **kwargs) -> bool:
         """
         Edit this Watermark on dizqueTV
         Automatically refreshes associated Channel object
@@ -122,8 +132,9 @@ def update(self,
         :rtype: bool
         """
         new_watermark_dict = self._dizque_instance.fill_in_watermark_settings(**kwargs)
-        if self._dizque_instance.update_channel(channel_number=self._channel_instance.number,
-                                                watermark=new_watermark_dict):
+        if self._dizque_instance.update_channel(
+            channel_number=self._channel_instance.number, watermark=new_watermark_dict
+        ):
             self._channel_instance.refresh()
             del self
             return True
@@ -131,9 +142,7 @@ def update(self,
 
 
 class TimeSlotItem:
-    def __init__(self,
-                 item_type: str,
-                 item_value: str = ""):
+    def __init__(self, item_type: str, item_value: str = ""):
         self.showId = f"{item_type}.{item_value}"
 
     def __repr__(self):
@@ -141,11 +150,13 @@ def __repr__(self):
 
 
 class TimeSlot(BaseObject):
-    def __init__(self, data: dict, program: TimeSlotItem = None, schedule_instance=None):
+    def __init__(
+        self, data: dict, program: TimeSlotItem = None, schedule_instance=None
+    ):
         super().__init__(data)
-        self.time = data.get('time')
-        self.showId = (program.showId if program else data.get('showId'))
-        self.order = data.get('order')
+        self.time = data.get("time")
+        self.showId = program.showId if program else data.get("showId")
+        self.order = data.get("order")
         self._schedule_instance = schedule_instance
 
     def __repr__(self):
@@ -155,15 +166,20 @@ def edit(self, time_string: str = None, **kwargs) -> bool:
         """
         Edit this TimeSlot object
 
-        :param time_string: time in readable 24-hour format (ex. 00:00:00 = 12:00:00 A.M., 05:15:00 = 5:15 A.M., 20:08:12 = 8:08:12 P.M.) (Optional if time=<milliseconds_since_midnight> not included in kwargs)
+        :param time_string: time in readable 24-hour format
+        (ex. 00:00:00 = 12:00:00 A.M., 05:15:00 = 5:15 A.M., 20:08:12 = 8:08:12 P.M.)
+        (Optional if time=<milliseconds_since_midnight> not included in kwargs)
         :type time_string: str, optional
         :param kwargs: Keyword arguments for the edited time slot (time, showId and order)
-        :return: True if successful, False if unsuccessful (Channel reloads in-place, this TimeSlot and its parent Schedule object are destroyed)
+        :return: True if successful, False if unsuccessful
+        (Channel reloads in-place, this TimeSlot and its parent Schedule object are destroyed)
         :rtype: bool
         """
         if not self._schedule_instance:
             return False
-        return self._schedule_instance.edit_time_slot(time_slot=self, time_string=time_string, **kwargs)
+        return self._schedule_instance.edit_time_slot(
+            time_slot=self, time_string=time_string, **kwargs
+        )
 
     def delete(self) -> bool:
         """
@@ -181,21 +197,23 @@ class Schedule(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance, channel_instance):
         super().__init__(data, dizque_instance)
         self._channel_instance = channel_instance
-        self.lateness = data.get('lateness')
-        self.maxDays = data.get('maxDays')
-        self.slots = [TimeSlot(data=slot, schedule_instance=self) for slot in data.get('slots', [])]
-        self.pad = data.get('pad')
-        self.timeZoneOffset = data.get('timeZoneOffset')
-        self.padStyle = data.get('padStyle')
-        self.randomDistribution = data.get('randomDistribution')
-        self.flexPreference = data.get('flexPreference')
+        self.lateness = data.get("lateness")
+        self.maxDays = data.get("maxDays")
+        self.slots = [
+            TimeSlot(data=slot, schedule_instance=self)
+            for slot in data.get("slots", [])
+        ]
+        self.pad = data.get("pad")
+        self.timeZoneOffset = data.get("timeZoneOffset")
+        self.padStyle = data.get("padStyle")
+        self.randomDistribution = data.get("randomDistribution")
+        self.flexPreference = data.get("flexPreference")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.maxDays} Days:{len(self.slots)} TimeSlots>"
 
     @decorators.check_for_dizque_instance
-    def update(self,
-               **kwargs):
+    def update(self, **kwargs):
         """
         Edit this Schedule on dizqueTV
         Automatically refreshes associated Channel object
@@ -204,16 +222,15 @@ def update(self,
         :return: True if successful, False if unsuccessful (Channel reloads in-place, this Schedule object is destroyed)
         :rtype: bool
         """
-        new_settings = helpers._combine_settings_add_new(new_settings_dict=kwargs,
-                                                         default_dict=(self._data
-                                                                       if self._data else SCHEDULE_SETTINGS_DEFAULT)
-                                                         )
+        new_settings = helpers._combine_settings_add_new(
+            new_settings_dict=kwargs,
+            default_dict=(self._data if self._data else SCHEDULE_SETTINGS_DEFAULT),
+        )
         return self._channel_instance.update_schedule(**new_settings)
 
-    def add_time_slot(self,
-                      time_slot: TimeSlot = None,
-                      time_string: str = None,
-                      **kwargs) -> bool:
+    def add_time_slot(
+        self, time_slot: TimeSlot = None, time_string: str = None, **kwargs
+    ) -> bool:
         """
         Add a time slot to this Schedule
 
@@ -229,24 +246,35 @@ def add_time_slot(self,
             kwargs = time_slot._data
         else:
             if time_string:
-                kwargs['time'] = helpers.convert_24_time_to_milliseconds_past_midnight(time_string=time_string)
-            new_settings_filtered = helpers._filter_dictionary(new_dictionary=kwargs,
-                                                               template_dict=TIME_SLOT_SETTINGS_TEMPLATE)
-            if not helpers._settings_are_complete(new_settings_dict=new_settings_filtered,
-                                                  template_settings_dict=TIME_SLOT_SETTINGS_TEMPLATE):
+                kwargs["time"] = helpers.convert_24_time_to_milliseconds_past_midnight(
+                    time_string=time_string
+                )
+            new_settings_filtered = helpers._filter_dictionary(
+                new_dictionary=kwargs, template_dict=TIME_SLOT_SETTINGS_TEMPLATE
+            )
+            if not helpers._settings_are_complete(
+                new_settings_dict=new_settings_filtered,
+                template_settings_dict=TIME_SLOT_SETTINGS_TEMPLATE,
+            ):
                 raise GeneralException("Missing settings required to make a time slot.")
 
             kwargs = new_settings_filtered
-        if kwargs['showId'] not in [item.showId for item in self._channel_instance.scheduledableItems]:
-            raise GeneralException(f"Program {kwargs['showId']} cannot be added to a time slot. "
-                                   f"Please make sure the program is added to the channel first.")
-        slots = self._data.get('slots', [])
-        if kwargs['time'] in [slot['time'] for slot in slots]:
+        if kwargs["showId"] not in [
+            item.showId for item in self._channel_instance.scheduledableItems
+        ]:
+            raise GeneralException(
+                f"Program {kwargs['showId']} cannot be added to a time slot. "
+                f"Please make sure the program is added to the channel first."
+            )
+        slots = self._data.get("slots", [])
+        if kwargs["time"] in [slot["time"] for slot in slots]:
             raise GeneralException(f"Time slot {kwargs['time']} is already filled.")
         slots.append(kwargs)
         return self.update(slots=slots)
 
-    def edit_time_slot(self, time_slot: TimeSlot, time_string: str = None, **kwargs) -> bool:
+    def edit_time_slot(
+        self, time_slot: TimeSlot, time_string: str = None, **kwargs
+    ) -> bool:
         """
         Edit a time slot from this Schedule
 
@@ -259,14 +287,18 @@ def edit_time_slot(self, time_slot: TimeSlot, time_string: str = None, **kwargs)
         :rtype: bool
         """
         if time_string:
-            kwargs['time'] = helpers.convert_24_time_to_milliseconds_past_midnight(time_string=time_string)
-        current_slots = self._data.get('slots', [])
+            kwargs["time"] = helpers.convert_24_time_to_milliseconds_past_midnight(
+                time_string=time_string
+            )
+        current_slots = self._data.get("slots", [])
         new_slots = []
         for slot in current_slots:
-            if slot['time'] != time_slot.time:
+            if slot["time"] != time_slot.time:
                 new_slots.append(slot)
             else:
-                new_slot_data = helpers._combine_settings(new_settings_dict=kwargs, default_dict=slot)
+                new_slot_data = helpers._combine_settings(
+                    new_settings_dict=kwargs, default_dict=slot
+                )
                 new_slots.append(new_slot_data)
         return self.update(slots=new_slots)
 
@@ -280,7 +312,7 @@ def delete_time_slot(self, time_slot: TimeSlot) -> bool:
         :return: True if successful, False if unsuccessful (Channel reloads in-place, this Schedule object is destroyed)
         :rtype: bool
         """
-        slots = self._data.get('slots', [])
+        slots = self._data.get("slots", [])
         try:
             slots.remove(time_slot._data)
             return self.update(slots=slots)
@@ -303,35 +335,60 @@ def delete(self) -> bool:
 class Channel(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance, plex_server: PServer = None):
         super().__init__(data, dizque_instance)
-        self._program_data = data.get('programs')
-        self._fillerCollections_data = data.get('fillerCollections')
-        self.fillerRepeatCooldown = data.get('fillerRepeatCooldown')
-        self.startTime = data.get('startTime')
-        self.offlinePicture = data.get('offlinePicture')
-        self.offlineSoundtrack = data.get('offlineSoundtrack')
-        self.offlineMode = data.get('offlineMode')
-        self.number = data.get('number')
-        self.name = data.get('name')
-        self.duration = data.get('duration')
-        self.stealth = data.get('stealth')
-        self._id = data.get('_id')
-        self.fallback = [FillerItem(data=filler_data,
-                                    dizque_instance=dizque_instance, filler_list_instance=None)
-                         for filler_data in data.get('fallback')]
-        self.watermark = Watermark(data=data.get('watermark'),
-                                   dizque_instance=dizque_instance,
-                                   channel_instance=self) if data.get('watermark') else None
-        self.transcoding = ChannelFFMPEGSettings(data=data.get('transcoding'),
-                                                 dizque_instance=dizque_instance,
-                                                 channel_instance=self) if data.get('transcoding') else None
-        self.onDemand = ChannelOnDemandSettings(data=data.get('onDemand'),
-                                                dizque_instance=dizque_instance,
-                                                channel_instance=self) if data.get('onDemand') else None
+        self._program_data = data.get("programs")
+        self._fillerCollections_data = data.get("fillerCollections")
+        self.fillerRepeatCooldown = data.get("fillerRepeatCooldown")
+        self.startTime = data.get("startTime")
+        self.offlinePicture = data.get("offlinePicture")
+        self.offlineSoundtrack = data.get("offlineSoundtrack")
+        self.offlineMode = data.get("offlineMode")
+        self.number = data.get("number")
+        self.name = data.get("name")
+        self.duration = data.get("duration")
+        self.stealth = data.get("stealth")
+        self._id = data.get("_id")
+        self.fallback = [
+            FillerItem(
+                data=filler_data,
+                dizque_instance=dizque_instance,
+                filler_list_instance=None,
+            )
+            for filler_data in data.get("fallback")
+        ]
+        self.watermark = (
+            Watermark(
+                data=data.get("watermark"),
+                dizque_instance=dizque_instance,
+                channel_instance=self,
+            )
+            if data.get("watermark")
+            else None
+        )
+        self.transcoding = (
+            ChannelFFMPEGSettings(
+                data=data.get("transcoding"),
+                dizque_instance=dizque_instance,
+                channel_instance=self,
+            )
+            if data.get("transcoding")
+            else None
+        )
+        self.onDemand = (
+            ChannelOnDemandSettings(
+                data=data.get("onDemand"),
+                dizque_instance=dizque_instance,
+                channel_instance=self,
+            )
+            if data.get("onDemand")
+            else None
+        )
         self.schedule = None
-        if data.get('scheduleBackup'):
-            self.schedule = Schedule(data=data.get('scheduleBackup'),
-                                     dizque_instance=dizque_instance,
-                                     channel_instance=self)
+        if data.get("scheduleBackup"):
+            self.schedule = Schedule(
+                data=data.get("scheduleBackup"),
+                dizque_instance=dizque_instance,
+                channel_instance=self,
+            )
         self.plex_server = plex_server
         self.scheduledableItems = self._get_schedulable_items()
 
@@ -352,16 +409,24 @@ def _get_schedulable_items(self) -> List[TimeSlotItem]:
         used_titles = []
         schedulable_items = []
         for program in self.programs:
-            if program.type == 'customShow':  # custom shows not schedulable at this time
+            if (
+                program.type == "customShow"
+            ):  # custom shows not schedulable at this time
                 pass
-            elif program.type == 'redirect' and program.channel not in used_titles:
-                schedulable_items.append(TimeSlotItem(item_type='redirect', item_value=program.channel))
+            elif program.type == "redirect" and program.channel not in used_titles:
+                schedulable_items.append(
+                    TimeSlotItem(item_type="redirect", item_value=program.channel)
+                )
                 used_titles.append(program.channel)
             elif program.showTitle and program.showTitle not in used_titles:
-                if program.type == 'movie':
-                    schedulable_items.append(TimeSlotItem(item_type='movie', item_value=program.showTitle))
+                if program.type == "movie":
+                    schedulable_items.append(
+                        TimeSlotItem(item_type="movie", item_value=program.showTitle)
+                    )
                 else:
-                    schedulable_items.append(TimeSlotItem(item_type='tv', item_value=program.showTitle))
+                    schedulable_items.append(
+                        TimeSlotItem(item_type="tv", item_value=program.showTitle)
+                    )
                 used_titles.append(program.showTitle)
         return schedulable_items
 
@@ -376,15 +441,17 @@ def programs(self) -> List[Union[Program, CustomShow]]:
         :return: List of Program and CustomShow objects
         :rtype: List[Union[Program, CustomShow]]
         """
-        return self._dizque_instance.parse_custom_shows_and_non_custom_shows(items=self._program_data,
-                                                                             non_custom_show_type=Program,
-                                                                             dizque_instance=self._dizque_instance,
-                                                                             channel_instance=self)
+        return self._dizque_instance.parse_custom_shows_and_non_custom_shows(
+            items=self._program_data,
+            non_custom_show_type=Program,
+            dizque_instance=self._dizque_instance,
+            channel_instance=self,
+        )
 
     @decorators.check_for_dizque_instance
-    def get_program(self,
-                    program_title: str = None,
-                    redirect_channel_number: int = None) -> Union[Program, None]:
+    def get_program(
+        self, program_title: str = None, redirect_channel_number: int = None
+    ) -> Union[Program, None]:
         """
         Get a specific program on this channel
 
@@ -396,10 +463,13 @@ def get_program(self,
         :rtype: Program
         """
         if not program_title and not redirect_channel_number:
-            raise MissingParametersError("Please include either a program_title or a redirect_channel_number.")
+            raise MissingParametersError(
+                "Please include either a program_title or a redirect_channel_number."
+            )
         for program in self.programs:
-            if (program_title and program.title == program_title) \
-                    or (redirect_channel_number and redirect_channel_number == program.channel):
+            if (program_title and program.title == program_title) or (
+                redirect_channel_number and redirect_channel_number == program.channel
+            ):
                 return program
         return None
 
@@ -411,12 +481,13 @@ def filler_lists(self) -> List[FillerList]:
         :return: List of FillerList objects
         :rtype: List[FillerList]
         """
-        return [FillerList(data=filler_list, dizque_instance=self._dizque_instance)
-                for filler_list in self._fillerCollections_data]
+        return [
+            FillerList(data=filler_list, dizque_instance=self._dizque_instance)
+            for filler_list in self._fillerCollections_data
+        ]
 
     @decorators.check_for_dizque_instance
-    def get_filler_list(self,
-                        filler_list_title: str) -> Union[FillerList, None]:
+    def get_filler_list(self, filler_list_title: str) -> Union[FillerList, None]:
         """
         Get a specific filler list on this channel
 
@@ -446,8 +517,7 @@ def refresh(self):
             del temp_channel
 
     @decorators.check_for_dizque_instance
-    def update(self,
-               **kwargs) -> bool:
+    def update(self, **kwargs) -> bool:
         """
         Edit this Channel on dizqueTV
         Automatically refreshes current Channel object
@@ -462,8 +532,7 @@ def update(self,
         return False
 
     @decorators.check_for_dizque_instance
-    def edit(self,
-             **kwargs) -> bool:
+    def edit(self, **kwargs) -> bool:
         """
         Alias for channels.update()
 
@@ -474,11 +543,13 @@ def edit(self,
         return self.update(**kwargs)
 
     @decorators.check_for_dizque_instance
-    def add_program(self,
-                    plex_item: Union[Video, Movie, Episode, Track] = None,
-                    plex_server: PServer = None,
-                    program: Union[Program, CustomShow] = None,
-                    **kwargs) -> bool:
+    def add_program(
+        self,
+        plex_item: Union[Video, Movie, Episode, Track] = None,
+        plex_server: PServer = None,
+        program: Union[Program, CustomShow] = None,
+        **kwargs,
+    ) -> bool:
         """
         Add a program to this channel
 
@@ -493,13 +564,14 @@ def add_program(self,
         :rtype: bool
         """
         if not plex_item and not program and not kwargs:
-            raise MissingParametersError("Please include either a program, a plex_item/plex_server combo, or kwargs")
+            raise MissingParametersError(
+                "Please include either a program, a plex_item/plex_server combo, or kwargs"
+            )
         if plex_item and (plex_server or self.plex_server):
-            temp_program = self._dizque_instance.convert_plex_item_to_program(plex_item=plex_item,
-                                                                              plex_server=(
-                                                                                  plex_server if plex_server
-                                                                                  else self.plex_server)
-                                                                              )
+            temp_program = self._dizque_instance.convert_plex_item_to_program(
+                plex_item=plex_item,
+                plex_server=(plex_server if plex_server else self.plex_server),
+            )
             kwargs = temp_program._data
         elif program:
             if type(program) == CustomShow:
@@ -508,27 +580,31 @@ def add_program(self,
             else:
                 kwargs = program._data
         template = MOVIE_PROGRAM_TEMPLATE
-        if kwargs['type'] == 'episode':
+        if kwargs["type"] == "episode":
             template = EPISODE_PROGRAM_TEMPLATE
-        elif kwargs['type'] == 'track':
+        elif kwargs["type"] == "track":
             template = TRACK_PROGRAM_TEMPLATE
-        elif kwargs['type'] == 'redirect':
+        elif kwargs["type"] == "redirect":
             template = REDIRECT_PROGRAM_TEMPLATE
-        if helpers._settings_are_complete(new_settings_dict=kwargs,
-                                          template_settings_dict=template,
-                                          ignore_keys=['_id', 'id']):
+        if helpers._settings_are_complete(
+            new_settings_dict=kwargs,
+            template_settings_dict=template,
+            ignore_keys=["_id", "id"],
+        ):
             channel_data = self._data
-            if not channel_data['duration']:
-                channel_data['duration'] = 0
-            channel_data['programs'].append(kwargs)
-            channel_data['duration'] += kwargs.get('duration', 0)
+            if not channel_data["duration"]:
+                channel_data["duration"] = 0
+            channel_data["programs"].append(kwargs)
+            channel_data["duration"] += kwargs.get("duration", 0)
             return self.update(**channel_data)
         return False
 
     @decorators.check_for_dizque_instance
-    def add_programs(self,
-                     programs: List[Union[Program, CustomShow, Video, Movie, Episode, Track]],
-                     plex_server: PServer = None) -> bool:
+    def add_programs(
+        self,
+        programs: List[Union[Program, CustomShow, Video, Movie, Episode, Track]],
+        plex_server: PServer = None,
+    ) -> bool:
         """
         Add multiple programs to this channel
 
@@ -541,28 +617,29 @@ def add_programs(self,
         """
         channel_data = self._data
         if not programs:
-            raise GeneralException("You must provide at least one program to add to the channel.")
+            raise GeneralException(
+                "You must provide at least one program to add to the channel."
+            )
 
         programs = self._dizque_instance.expand_custom_show_items(programs=programs)
 
         for program in programs:
             if type(program) not in [Program, Redirect, CustomShowItem]:
                 if not plex_server and not self.plex_server:
-                    raise MissingParametersError("Please include a plex_server if you are adding PlexAPI Video, "
-                                                 "Movie, Episode or Track items.")
-                program = self._dizque_instance.convert_plex_item_to_program(plex_item=program,
-                                                                             plex_server=(
-                                                                                 plex_server if plex_server
-                                                                                 else self.plex_server)
-                                                                             )
-            channel_data['programs'].append(program._data)
-            channel_data['duration'] += program.duration
+                    raise MissingParametersError(
+                        "Please include a plex_server if you are adding PlexAPI Video, "
+                        "Movie, Episode or Track items."
+                    )
+                program = self._dizque_instance.convert_plex_item_to_program(
+                    plex_item=program,
+                    plex_server=(plex_server if plex_server else self.plex_server),
+                )
+            channel_data["programs"].append(program._data)
+            channel_data["duration"] += program.duration
         return self.update(**channel_data)
 
     @decorators.check_for_dizque_instance
-    def add_collection(self,
-                       collection: Collection,
-                       plex_server: PServer) -> bool:
+    def add_collection(self, collection: Collection, plex_server: PServer) -> bool:
         """
         Add a collection to this channel
 
@@ -574,7 +651,9 @@ def add_collection(self,
         :rtype: bool
         """
         if not collection:
-            raise MissingParametersError("You must provide a collection to add to the channel.")
+            raise MissingParametersError(
+                "You must provide a collection to add to the channel."
+            )
         items = collection.items()
         final_items = []
         for item in items:
@@ -585,9 +664,7 @@ def add_collection(self,
         return self.add_programs(programs=final_items, plex_server=plex_server)
 
     @decorators.check_for_dizque_instance
-    def add_playlist(self,
-                     playlist: Playlist,
-                     plex_server: PServer) -> bool:
+    def add_playlist(self, playlist: Playlist, plex_server: PServer) -> bool:
         """
         Add a playlist to this channel
 
@@ -599,7 +676,9 @@ def add_playlist(self,
         :rtype: bool
         """
         if not playlist:
-            raise MissingParametersError("You must provide a playlist to add to the channel.")
+            raise MissingParametersError(
+                "You must provide a playlist to add to the channel."
+            )
         items = playlist.items()
         final_items = []
         for item in items:
@@ -610,9 +689,7 @@ def add_playlist(self,
         return self.add_programs(programs=final_items, plex_server=plex_server)
 
     @decorators.check_for_dizque_instance
-    def update_program(self,
-                       program: Program,
-                       **kwargs) -> bool:
+    def update_program(self, program: Program, **kwargs) -> bool:
         """
         Update a program from this channel
 
@@ -623,20 +700,22 @@ def update_program(self,
         :rtype: bool
         """
         channel_data = self._data
-        for a_program in channel_data['programs']:
-            if (program.type == 'redirect' and a_program['type'] == 'redirect') \
-                    or (a_program['title'] == program.title):
-                if kwargs.get('duration'):
-                    channel_data['duration'] -= a_program['duration']
-                    channel_data['duration'] += kwargs['duration']
-                new_data = helpers._combine_settings(new_settings_dict=kwargs, default_dict=a_program)
+        for a_program in channel_data["programs"]:
+            if (program.type == "redirect" and a_program["type"] == "redirect") or (
+                a_program["title"] == program.title
+            ):
+                if kwargs.get("duration"):
+                    channel_data["duration"] -= a_program["duration"]
+                    channel_data["duration"] += kwargs["duration"]
+                new_data = helpers._combine_settings(
+                    new_settings_dict=kwargs, default_dict=a_program
+                )
                 a_program.update(new_data)
                 return self.update(**channel_data)
         return False
 
     @decorators.check_for_dizque_instance
-    def delete_program(self,
-                       program: Program) -> bool:
+    def delete_program(self, program: Program) -> bool:
         """
         Delete a program from this channel
 
@@ -646,18 +725,17 @@ def delete_program(self,
         :rtype: bool
         """
         channel_data = self._data
-        for a_program in channel_data['programs']:
-            if (program.type == 'redirect' and a_program['type'] == 'redirect') \
-                    or (a_program['title'] == program.title):
-                channel_data['duration'] -= a_program['duration']
-                channel_data['programs'].remove(a_program)
+        for a_program in channel_data["programs"]:
+            if (program.type == "redirect" and a_program["type"] == "redirect") or (
+                a_program["title"] == program.title
+            ):
+                channel_data["duration"] -= a_program["duration"]
+                channel_data["programs"].remove(a_program)
                 return self.update(**channel_data)
         return False
 
     @decorators.check_for_dizque_instance
-    def delete_show(self,
-                    show_name: str,
-                    season_number: int = None) -> bool:
+    def delete_show(self, show_name: str, season_number: int = None) -> bool:
         """
         Delete all episodes of a specific show
 
@@ -672,7 +750,7 @@ def delete_show(self,
         programs_to_add = []
         for program in all_programs:
             # collect everything that's not an episode
-            if program.type != 'episode':
+            if program.type != "episode":
                 programs_to_add.append(program)
             else:
                 # collect everything that's not the targeted show
@@ -689,10 +767,12 @@ def delete_show(self,
         return False
 
     @decorators.check_for_dizque_instance
-    def add_x_number_of_show_episodes(self,
-                                      number_of_episodes: int,
-                                      list_of_episodes: List[Union[Program, Episode]],
-                                      plex_server: PServer = None) -> bool:
+    def add_x_number_of_show_episodes(
+        self,
+        number_of_episodes: int,
+        list_of_episodes: List[Union[Program, Episode]],
+        plex_server: PServer = None,
+    ) -> bool:
         """
         Add the first X number of items from a list of programs to a dizqueTV channel
 
@@ -709,23 +789,28 @@ def add_x_number_of_show_episodes(self,
         for i in range(0, number_of_episodes):
             if not type(list_of_episodes[i]) == Program:
                 if not plex_server and not self.plex_server:
-                    raise MissingParametersError("Please include a plex_server if you are adding PlexAPI Video "
-                                                 "or Episode items.")
-                list_of_episodes[i] = self._dizque_instance.convert_plex_item_to_program(plex_item=list_of_episodes[i],
-                                                                                         plex_server=(
-                                                                                             plex_server if plex_server
-                                                                                             else self.plex_server)
-                                                                                         )
-            channel_data['programs'].append(list_of_episodes[i]._data)
-            channel_data['duration'] += list_of_episodes[i].duration
+                    raise MissingParametersError(
+                        "Please include a plex_server if you are adding PlexAPI Video "
+                        "or Episode items."
+                    )
+                list_of_episodes[
+                    i
+                ] = self._dizque_instance.convert_plex_item_to_program(
+                    plex_item=list_of_episodes[i],
+                    plex_server=(plex_server if plex_server else self.plex_server),
+                )
+            channel_data["programs"].append(list_of_episodes[i]._data)
+            channel_data["duration"] += list_of_episodes[i].duration
         return self.update(**channel_data)
 
     @decorators.check_for_dizque_instance
-    def add_x_duration_of_show_episodes(self,
-                                        duration_in_milliseconds: int,
-                                        list_of_episodes: List[Union[Program, Episode]],
-                                        plex_server: PServer = None,
-                                        allow_overtime: bool = False) -> bool:
+    def add_x_duration_of_show_episodes(
+        self,
+        duration_in_milliseconds: int,
+        list_of_episodes: List[Union[Program, Episode]],
+        plex_server: PServer = None,
+        allow_overtime: bool = False,
+    ) -> bool:
         """
         Add an X duration of items from a list of programs to a dizqueTV channel
 
@@ -735,7 +820,8 @@ def add_x_duration_of_show_episodes(self,
         :type list_of_episodes: List[Union[Program, plexapi.video.Episode]]
         :param plex_server: plexapi.server.PlexServer, needed if adding plexapi.media.Episode objects
         :type plex_server: plexapi.server.PlexServer, optional
-        :param allow_overtime: Allow adding one more episode, even if total time would go over. Otherwise, don't add any more if total time would exceed duration_in_milliseconds (default: False)
+        :param allow_overtime: Allow adding one more episode, even if total time would go over.
+        Otherwise, don't add any more if total time would exceed duration_in_milliseconds (default: False)
         :type allow_overtime: bool, optional
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
@@ -746,23 +832,27 @@ def add_x_duration_of_show_episodes(self,
         while total_runtime < duration_in_milliseconds:
             if not type(list_of_episodes[list_index]) == Program:
                 if not plex_server and not self.plex_server:
-                    raise MissingParametersError("Please include a plex_server if you are adding PlexAPI Video "
-                                                 "or Episode items.")
-                list_of_episodes[list_index] = \
-                    self._dizque_instance.convert_plex_item_to_program(plex_item=list_of_episodes[list_index],
-                                                                       plex_server=(
-                                                                           plex_server if plex_server
-                                                                           else self.plex_server)
-                                                                       )
-            if (total_runtime + list_of_episodes[list_index].duration) > duration_in_milliseconds:
+                    raise MissingParametersError(
+                        "Please include a plex_server if you are adding PlexAPI Video "
+                        "or Episode items."
+                    )
+                list_of_episodes[
+                    list_index
+                ] = self._dizque_instance.convert_plex_item_to_program(
+                    plex_item=list_of_episodes[list_index],
+                    plex_server=(plex_server if plex_server else self.plex_server),
+                )
+            if (
+                total_runtime + list_of_episodes[list_index].duration
+            ) > duration_in_milliseconds:
                 if allow_overtime:
-                    channel_data['programs'].append(list_of_episodes[list_index]._data)
-                    channel_data['duration'] += list_of_episodes[list_index].duration
+                    channel_data["programs"].append(list_of_episodes[list_index]._data)
+                    channel_data["duration"] += list_of_episodes[list_index].duration
                 else:
                     pass
             else:
-                channel_data['programs'].append(list_of_episodes[list_index]._data)
-                channel_data['duration'] += list_of_episodes[list_index].duration
+                channel_data["programs"].append(list_of_episodes[list_index]._data)
+                channel_data["duration"] += list_of_episodes[list_index].duration
             total_runtime += list_of_episodes[list_index].duration
             list_index += 1
         return self.update(**channel_data)
@@ -776,8 +866,8 @@ def delete_all_programs(self) -> bool:
         :rtype: bool
         """
         channel_data = self._data
-        channel_data['duration'] -= sum(program.duration for program in self.programs)
-        channel_data['programs'] = []
+        channel_data["duration"] -= sum(program.duration for program in self.programs)
+        channel_data["programs"] = []
         return self.update(**channel_data)
 
     @decorators.check_for_dizque_instance
@@ -790,18 +880,20 @@ def _delete_all_offline_times(self) -> bool:
         """
         programs_to_add = []
         for program in self.programs:
-            if not program.isOffline or program.type == 'redirect':
+            if not program.isOffline or program.type == "redirect":
                 programs_to_add.append(program)
         if programs_to_add and self.delete_all_programs():
             return self.add_programs(programs=programs_to_add)
         return False
 
     @decorators.check_for_dizque_instance
-    def add_filler_list(self,
-                        filler_list: FillerList = None,
-                        filler_list_id: str = None,
-                        weight: int = 300,
-                        cooldown: int = 0) -> bool:
+    def add_filler_list(
+        self,
+        filler_list: FillerList = None,
+        filler_list_id: str = None,
+        weight: int = 300,
+        cooldown: int = 0,
+    ) -> bool:
         """
         Add a filler list to this channel
 
@@ -817,27 +909,31 @@ def add_filler_list(self,
         :rtype: bool
         """
         if not filler_list and not filler_list_id:
-            raise MissingParametersError("Please include either a FillerList object or kwargs")
+            raise MissingParametersError(
+                "Please include either a FillerList object or kwargs"
+            )
         if filler_list:
             filler_list_id = filler_list.id
         new_settings_dict = {
-            'id': filler_list_id,
-            'weight': weight,
-            'cooldown': cooldown
+            "id": filler_list_id,
+            "weight": weight,
+            "cooldown": cooldown,
         }
-        if helpers._settings_are_complete(new_settings_dict=new_settings_dict,
-                                          template_settings_dict=FILLER_LIST_CHANNEL_TEMPLATE,
-                                          ignore_keys=['_id', 'id']):
+        if helpers._settings_are_complete(
+            new_settings_dict=new_settings_dict,
+            template_settings_dict=FILLER_LIST_CHANNEL_TEMPLATE,
+            ignore_keys=["_id", "id"],
+        ):
             channel_data = self._data
-            channel_data['fillerCollections'].append(new_settings_dict)
+            channel_data["fillerCollections"].append(new_settings_dict)
             # filler_list_data['duration'] += kwargs['duration']
             return self.update(**channel_data)
         return False
 
     @decorators.check_for_dizque_instance
-    def delete_filler_list(self,
-                           filler_list: FillerList = None,
-                           filler_list_id: str = None) -> bool:
+    def delete_filler_list(
+        self, filler_list: FillerList = None, filler_list_id: str = None
+    ) -> bool:
         """
         Delete a program from this channel
 
@@ -849,13 +945,15 @@ def delete_filler_list(self,
         :rtype: bool
         """
         if not filler_list and not filler_list_id:
-            raise GeneralException("You must include either a filler_list or a filler_list_id.")
+            raise GeneralException(
+                "You must include either a filler_list or a filler_list_id."
+            )
         if filler_list:
             filler_list_id = filler_list.id
         channel_data = self._data
-        for a_list in channel_data['fillerCollections']:
-            if filler_list_id == a_list.get('id'):
-                channel_data['fillerCollections'].remove(a_list)
+        for a_list in channel_data["fillerCollections"]:
+            if filler_list_id == a_list.get("id"):
+                channel_data["fillerCollections"].remove(a_list)
                 return self.update(**channel_data)
         return False
 
@@ -868,7 +966,7 @@ def delete_all_filler_lists(self) -> bool:
         :rtype: bool
         """
         channel_data = self._data
-        channel_data['fillerCollections'] = []
+        channel_data["fillerCollections"] = []
         return self.update(**channel_data)
 
     # Schedule
@@ -884,13 +982,19 @@ def add_schedule(self, time_slots: List[TimeSlot], **kwargs) -> bool:
         :rtype: bool
         """
         for slot in time_slots:
-            kwargs['slots'].append(slot._data)
-        schedule_settings = helpers._combine_settings_enforce_types(new_settings_dict=kwargs,
-                                                                    default_dict=SCHEDULE_SETTINGS_DEFAULT,
-                                                                    template_dict=SCHEDULE_SETTINGS_TEMPLATE)
-        if helpers._settings_are_complete(new_settings_dict=schedule_settings,
-                                          template_settings_dict=SCHEDULE_SETTINGS_TEMPLATE):
-            schedule = Schedule(data=schedule_settings, dizque_instance=None, channel_instance=self)
+            kwargs["slots"].append(slot._data)
+        schedule_settings = helpers._combine_settings_enforce_types(
+            new_settings_dict=kwargs,
+            default_dict=SCHEDULE_SETTINGS_DEFAULT,
+            template_dict=SCHEDULE_SETTINGS_TEMPLATE,
+        )
+        if helpers._settings_are_complete(
+            new_settings_dict=schedule_settings,
+            template_settings_dict=SCHEDULE_SETTINGS_TEMPLATE,
+        ):
+            schedule = Schedule(
+                data=schedule_settings, dizque_instance=None, channel_instance=self
+            )
             return self._dizque_instance._make_schedule(channel=self, schedule=schedule)
         return False
 
@@ -906,14 +1010,22 @@ def add_random_schedule(self, time_slots: List[TimeSlot], **kwargs) -> bool:
         :rtype: bool
         """
         for slot in time_slots:
-            kwargs['slots'].append(slot._data)
-        schedule_settings = helpers._combine_settings_enforce_types(new_settings_dict=kwargs,
-                                                                    default_dict=RANDOM_SCHEDULE_SETTINGS_DEFAULT,
-                                                                    template_dict=RANDOM_SCHEDULE_SETTINGS_TEMPLATE)
-        if helpers._settings_are_complete(new_settings_dict=schedule_settings,
-                                          template_settings_dict=RANDOM_SCHEDULE_SETTINGS_TEMPLATE):
-            schedule = Schedule(data=schedule_settings, dizque_instance=None, channel_instance=self)
-            return self._dizque_instance._make_random_schedule(channel=self, schedule=schedule)
+            kwargs["slots"].append(slot._data)
+        schedule_settings = helpers._combine_settings_enforce_types(
+            new_settings_dict=kwargs,
+            default_dict=RANDOM_SCHEDULE_SETTINGS_DEFAULT,
+            template_dict=RANDOM_SCHEDULE_SETTINGS_TEMPLATE,
+        )
+        if helpers._settings_are_complete(
+            new_settings_dict=schedule_settings,
+            template_settings_dict=RANDOM_SCHEDULE_SETTINGS_TEMPLATE,
+        ):
+            schedule = Schedule(
+                data=schedule_settings, dizque_instance=None, channel_instance=self
+            )
+            return self._dizque_instance._make_random_schedule(
+                channel=self, schedule=schedule
+            )
         return False
 
     @decorators.check_for_dizque_instance
@@ -921,11 +1033,12 @@ def update_schedule(self, **kwargs) -> bool:
         """
         Update the schedule for this channel
 
-        :param kwargs: keyword arguments for schedule settings (slots data included if needed) (include random=true to use random time slots)
+        :param kwargs: keyword arguments for schedule settings (slots data included if needed)
+        (include random=true to use random time slots)
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        if kwargs.get('random', False):
+        if kwargs.get("random", False):
             return self.add_random_schedule(time_slots=[], **kwargs)
         return self.add_schedule(time_slots=[], **kwargs)
 
@@ -1024,9 +1137,7 @@ def cyclical_shuffle(self) -> bool:
         return False
 
     @decorators.check_for_dizque_instance
-    def block_shuffle(self,
-                      block_length: int,
-                      randomize: bool = False) -> bool:
+    def block_shuffle(self, block_length: int, randomize: bool = False) -> bool:
         """
         Sort TV shows on this channel cyclically
 
@@ -1037,16 +1148,15 @@ def block_shuffle(self,
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        sorted_programs = helpers.sort_media_block_shuffle(media_items=self.programs,
-                                                           block_length=block_length,
-                                                           randomize=randomize)
+        sorted_programs = helpers.sort_media_block_shuffle(
+            media_items=self.programs, block_length=block_length, randomize=randomize
+        )
         if sorted_programs and self.delete_all_programs():
             return self.add_programs(programs=sorted_programs)
         return False
 
     @decorators.check_for_dizque_instance
-    def replicate(self,
-                  how_many_times: int) -> bool:
+    def replicate(self, how_many_times: int) -> bool:
         """
         Replicate/repeat the channel lineup x number of times
         Items will remain in the same order.
@@ -1067,8 +1177,7 @@ def replicate(self,
         return False
 
     @decorators.check_for_dizque_instance
-    def replicate_and_shuffle(self,
-                              how_many_times: int) -> bool:
+    def replicate_and_shuffle(self, how_many_times: int) -> bool:
         """
         Replicate/repeat the channel lineup, shuffled, x number of times
         Items will be shuffled in each repeat group.
@@ -1099,7 +1208,9 @@ def remove_duplicate_programs(self) -> bool:
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        sorted_programs = helpers.remove_duplicate_media_items(media_items=self.programs)
+        sorted_programs = helpers.remove_duplicate_media_items(
+            media_items=self.programs
+        )
         if sorted_programs and self.delete_all_programs():
             return self.add_programs(programs=sorted_programs)
         return False
@@ -1112,7 +1223,9 @@ def remove_duplicate_redirects(self) -> bool:
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        sorted_programs = helpers.remove_duplicates_by_attribute(items=self.programs, attribute_name='channel')
+        sorted_programs = helpers.remove_duplicates_by_attribute(
+            items=self.programs, attribute_name="channel"
+        )
         if sorted_programs and self.delete_all_programs():
             return self.add_programs(programs=sorted_programs)
         return False
@@ -1127,7 +1240,10 @@ def remove_redirects(self) -> bool:
         """
         non_redirects = []
         for item in self.programs:
-            if not helpers._object_has_attribute(obj=item, attribute_name='type') or item.type != 'redirect':
+            if (
+                not helpers._object_has_attribute(obj=item, attribute_name="type")
+                or item.type != "redirect"
+            ):
                 non_redirects.append(item)
         if non_redirects and self.delete_all_programs():
             return self.add_programs(programs=non_redirects)
@@ -1142,23 +1258,34 @@ def remove_specials(self) -> bool:
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        non_redirects = [item for item in self.programs if
-                         (helpers._object_has_attribute(obj=item, attribute_name='type')
-                          and item.type != 'redirect')]
-        non_specials = [item for item in non_redirects if
-                        (helpers._object_has_attribute(obj=item, attribute_name='season')
-                         and item.season != 0)]
+        non_redirects = [
+            item
+            for item in self.programs
+            if (
+                helpers._object_has_attribute(obj=item, attribute_name="type")
+                and item.type != "redirect"
+            )
+        ]
+        non_specials = [
+            item
+            for item in non_redirects
+            if (
+                helpers._object_has_attribute(obj=item, attribute_name="season")
+                and item.season != 0
+            )
+        ]
         if non_specials and self.delete_all_programs():
             return self.add_programs(programs=non_specials)
         return False
 
     @decorators.check_for_dizque_instance
-    def pad_times(self,
-                  start_every_x_minutes: int) -> bool:
+    def pad_times(self, start_every_x_minutes: int) -> bool:
         """
         Add padding between programs on a channel, so programs start at specific intervals
 
-        :param start_every_x_minutes: Programs start every X minutes past the hour (ex. 10 for :00, :10, :20, :30, :40 & :50; 15 for :00, :15, :30 & :45; 20 for :00, :20 & :40; 30 for :00 & :30; 60 or 0 for :00)
+        :param start_every_x_minutes: Programs start every X minutes past the hour
+        (ex. 10 for :00, :10, :20, :30, :40 & :50; 15 for :00, :15,
+        :30 & :45; 20 for :00, :20 & :40; 30 for :00 & :30; 60 or 0 for :00)
         :type start_every_x_minutes: int
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
@@ -1166,22 +1293,27 @@ def pad_times(self,
         programs_and_pads = []
         if self._delete_all_offline_times():
             for program in self.programs:
-                filler_time_needed = helpers.get_needed_flex_time(item_time_milliseconds=program.duration,
-                                                                  allowed_minutes_time_frame=start_every_x_minutes)
+                filler_time_needed = helpers.get_needed_flex_time(
+                    item_time_milliseconds=program.duration,
+                    allowed_minutes_time_frame=start_every_x_minutes,
+                )
                 programs_and_pads.append(program)
                 if filler_time_needed > 0:
-                    programs_and_pads.append(Program(data={'duration': filler_time_needed, 'isOffline': True},
-                                                     dizque_instance=self._dizque_instance,
-                                                     channel_instance=self))
+                    programs_and_pads.append(
+                        Program(
+                            data={"duration": filler_time_needed, "isOffline": True},
+                            dizque_instance=self._dizque_instance,
+                            channel_instance=self,
+                        )
+                    )
             if programs_and_pads and self.delete_all_programs():
                 return self.add_programs(programs=programs_and_pads)
         return False
 
     @decorators.check_for_dizque_instance
-    def add_reruns(self,
-                   start_time: datetime,
-                   length_hours: int,
-                   times_to_repeat: int) -> bool:
+    def add_reruns(
+        self, start_time: datetime, length_hours: int, times_to_repeat: int
+    ) -> bool:
         """
         Add a block of reruns to a dizqueTV channel
 
@@ -1198,13 +1330,18 @@ def add_reruns(self,
             raise GeneralException("You cannot use a start time in the future.")
         start_time = start_time.strftime("%Y-%m-%dT%H:%M:%S.000Z")
         self.remove_duplicate_programs()
-        programs_to_add, running_time = helpers._get_first_x_minutes_of_programs(programs=self.programs,
-                                                                                 minutes=length_hours * 60)
+        programs_to_add, running_time = helpers._get_first_x_minutes_of_programs(
+            programs=self.programs, minutes=length_hours * 60
+        )
         if running_time < (length_hours * 60 * 60 * 1000):
             time_needed = (length_hours * 60 * 60 * 1000) - running_time
-            programs_to_add.append(Program(data={'duration': time_needed, 'isOffline': True},
-                                           dizque_instance=self._dizque_instance,
-                                           channel_instance=self))
+            programs_to_add.append(
+                Program(
+                    data={"duration": time_needed, "isOffline": True},
+                    dizque_instance=self._dizque_instance,
+                    channel_instance=self,
+                )
+            )
         final_programs_to_add = []
         for _ in range(0, times_to_repeat):
             for program in programs_to_add:
@@ -1215,10 +1352,9 @@ def add_reruns(self,
         return False
 
     @decorators.check_for_dizque_instance
-    def add_channel_at_night(self,
-                             night_channel_number: int,
-                             start_hour: int,
-                             end_hour: int) -> bool:
+    def add_channel_at_night(
+        self, night_channel_number: int, start_hour: int, end_hour: int
+    ) -> bool:
         """
         Add a Channel at Night to a dizqueTV channel
 
@@ -1239,33 +1375,53 @@ def add_channel_at_night(self,
             raise GeneralException("You cannot add a 24-hour Channel at Night.")
         if night_channel_number not in self._dizque_instance.channel_numbers:
             raise GeneralException(f"Channel #{night_channel_number} does not exist.")
-        length_of_night_block = helpers.get_milliseconds_between_two_hours(start_hour=start_hour, end_hour=end_hour)
+        length_of_night_block = helpers.get_milliseconds_between_two_hours(
+            start_hour=start_hour, end_hour=end_hour
+        )
         length_of_regular_block = (24 * 60 * 60 * 1000) - length_of_night_block
-        new_channel_start_time = datetime.now().replace(hour=end_hour, minute=0, second=0, microsecond=0)
+        new_channel_start_time = datetime.now().replace(
+            hour=end_hour, minute=0, second=0, microsecond=0
+        )
         if end_hour > datetime.now().hour:
             new_channel_start_time = new_channel_start_time - timedelta(days=1)
-        new_channel_start_time = new_channel_start_time + timedelta(hours=helpers.hours_difference_in_timezone())
-        new_channel_start_time = new_channel_start_time.strftime("%Y-%m-%dT%H:%M:%S.000Z")
+        new_channel_start_time = new_channel_start_time + timedelta(
+            hours=helpers.hours_difference_in_timezone()
+        )
+        new_channel_start_time = new_channel_start_time.strftime(
+            "%Y-%m-%dT%H:%M:%S.000Z"
+        )
         final_programs_to_add = []
         programs_left = self.programs
         while programs_left:  # loop until you get done with all the programs
-            programs_to_add, total_running_time, programs_left = \
-                helpers._get_first_x_minutes_of_programs_return_unused(programs=programs_left,
-                                                                       minutes=int(
-                                                                           length_of_regular_block / 1000 / 60)
-                                                                       )
+            (
+                programs_to_add,
+                total_running_time,
+                programs_left,
+            ) = helpers._get_first_x_minutes_of_programs_return_unused(
+                programs=programs_left, minutes=int(length_of_regular_block / 1000 / 60)
+            )
             if total_running_time < length_of_regular_block:
                 # add flex time between last item and night channel
                 time_needed = length_of_regular_block - total_running_time
-                programs_to_add.append(Program(data={'duration': time_needed, 'isOffline': True},
-                                               dizque_instance=self._dizque_instance,
-                                               channel_instance=self))
-            programs_to_add.append(Redirect(data={'duration': length_of_night_block,
-                                                  'isOffline': True,
-                                                  'channel': night_channel_number,
-                                                  'type': 'redirect'},
-                                            dizque_instance=self._dizque_instance,
-                                            channel_instance=self))
+                programs_to_add.append(
+                    Program(
+                        data={"duration": time_needed, "isOffline": True},
+                        dizque_instance=self._dizque_instance,
+                        channel_instance=self,
+                    )
+                )
+            programs_to_add.append(
+                Redirect(
+                    data={
+                        "duration": length_of_night_block,
+                        "isOffline": True,
+                        "channel": night_channel_number,
+                        "type": "redirect",
+                    },
+                    dizque_instance=self._dizque_instance,
+                    channel_instance=self,
+                )
+            )
             for program in programs_to_add:
                 final_programs_to_add.append(program)
 
@@ -1275,10 +1431,9 @@ def add_channel_at_night(self,
         return False
 
     @decorators.check_for_dizque_instance
-    def add_channel_at_night_alt(self,
-                                 night_channel_number: int,
-                                 start_hour: int,
-                                 end_hour: int) -> bool:
+    def add_channel_at_night_alt(
+        self, night_channel_number: int, start_hour: int, end_hour: int
+    ) -> bool:
         """
         Add a Channel at Night to a dizqueTV channel
 
@@ -1297,77 +1452,122 @@ def add_channel_at_night_alt(self,
             raise GeneralException("end_hour must be between 0 and 23.")
         if night_channel_number not in self._dizque_instance.channel_numbers:
             raise GeneralException(f"Channel #{night_channel_number} does not exist.")
-        length_of_night_block = helpers.get_milliseconds_between_two_hours(start_hour=start_hour, end_hour=end_hour)
+        length_of_night_block = helpers.get_milliseconds_between_two_hours(
+            start_hour=start_hour, end_hour=end_hour
+        )
         if length_of_night_block == 0:
             raise GeneralException("You cannot add a 24-hour Channel at Night.")
         length_of_regular_block = (24 * 60 * 60 * 1000) - length_of_night_block
-        channel_start_time_datetime = helpers.string_to_datetime(date_string=self.startTime)
+        channel_start_time_datetime = helpers.string_to_datetime(
+            date_string=self.startTime
+        )
         time_until_night_block_start = helpers.get_milliseconds_between_two_datetimes(
-            start_datetime=helpers.adjust_datetime_for_timezone(channel_start_time_datetime),
-            end_datetime=datetime.now().replace(hour=start_hour,
-                                                minute=0,
-                                                second=0,
-                                                microsecond=0)
+            start_datetime=helpers.adjust_datetime_for_timezone(
+                channel_start_time_datetime
+            ),
+            end_datetime=datetime.now().replace(
+                hour=start_hour, minute=0, second=0, microsecond=0
+            ),
         )
         final_programs_to_add = []
         all_programs = self.programs
         programs_to_add, total_running_time = helpers._get_first_x_minutes_of_programs(
-            programs=all_programs,
-            minutes=int(
-                time_until_night_block_start / 1000 / 60)
+            programs=all_programs, minutes=int(time_until_night_block_start / 1000 / 60)
         )
-        if len(programs_to_add) == len(all_programs):  # all programs can play before night channel even starts
-            if total_running_time < time_until_night_block_start:  # add flex time between last item and night channel
+        if len(programs_to_add) == len(
+            all_programs
+        ):  # all programs can play before night channel even starts
+            if (
+                total_running_time < time_until_night_block_start
+            ):  # add flex time between last item and night channel
                 time_needed = time_until_night_block_start - total_running_time
-                programs_to_add.append(Program(data={'duration': time_needed, 'isOffline': True},
-                                               dizque_instance=self._dizque_instance,
-                                               channel_instance=self))
+                programs_to_add.append(
+                    Program(
+                        data={"duration": time_needed, "isOffline": True},
+                        dizque_instance=self._dizque_instance,
+                        channel_instance=self,
+                    )
+                )
             # add the night channel
-            programs_to_add.append(Redirect(data={'duration': length_of_night_block,
-                                                  'isOffline': True,
-                                                  'channel': night_channel_number,
-                                                  'type': 'redirect'},
-                                            dizque_instance=self._dizque_instance,
-                                            channel_instance=self))
+            programs_to_add.append(
+                Redirect(
+                    data={
+                        "duration": length_of_night_block,
+                        "isOffline": True,
+                        "channel": night_channel_number,
+                        "type": "redirect",
+                    },
+                    dizque_instance=self._dizque_instance,
+                    channel_instance=self,
+                )
+            )
             final_programs_to_add = programs_to_add
         else:  # need to interlace programs and night channels
             programs_left = all_programs
-            programs_to_add, total_running_time, programs_left = \
-                helpers._get_first_x_minutes_of_programs_return_unused(programs=programs_left,
-                                                                       minutes=int(
-                                                                           time_until_night_block_start / 1000 / 60)
-                                                                       )
-            if total_running_time < time_until_night_block_start:  # add flex time between last item and night channel
+            (
+                programs_to_add,
+                total_running_time,
+                programs_left,
+            ) = helpers._get_first_x_minutes_of_programs_return_unused(
+                programs=programs_left,
+                minutes=int(time_until_night_block_start / 1000 / 60),
+            )
+            if (
+                total_running_time < time_until_night_block_start
+            ):  # add flex time between last item and night channel
                 time_needed = time_until_night_block_start - total_running_time
-                programs_to_add.append(Program(data={'duration': time_needed, 'isOffline': True},
-                                               dizque_instance=self._dizque_instance,
-                                               channel_instance=self))
+                programs_to_add.append(
+                    Program(
+                        data={"duration": time_needed, "isOffline": True},
+                        dizque_instance=self._dizque_instance,
+                        channel_instance=self,
+                    )
+                )
             # add the night channel
-            programs_to_add.append(Redirect(data={'duration': length_of_night_block,
-                                                  'isOffline': True,
-                                                  'channel': night_channel_number,
-                                                  'type': 'redirect'},
-                                            dizque_instance=self._dizque_instance,
-                                            channel_instance=self))
+            programs_to_add.append(
+                Redirect(
+                    data={
+                        "duration": length_of_night_block,
+                        "isOffline": True,
+                        "channel": night_channel_number,
+                        "type": "redirect",
+                    },
+                    dizque_instance=self._dizque_instance,
+                    channel_instance=self,
+                )
+            )
             final_programs_to_add = programs_to_add
             while programs_left:  # loop until you get done with all the programs
-                programs_to_add, total_running_time, programs_left = \
-                    helpers._get_first_x_minutes_of_programs_return_unused(programs=programs_left,
-                                                                           minutes=int(
-                                                                               length_of_regular_block / 1000 / 60)
-                                                                           )
+                (
+                    programs_to_add,
+                    total_running_time,
+                    programs_left,
+                ) = helpers._get_first_x_minutes_of_programs_return_unused(
+                    programs=programs_left,
+                    minutes=int(length_of_regular_block / 1000 / 60),
+                )
                 if total_running_time < length_of_regular_block:
                     # add flex time between last item and night channel
                     time_needed = length_of_regular_block - total_running_time
-                    programs_to_add.append(Program(data={'duration': time_needed, 'isOffline': True},
-                                                   dizque_instance=self._dizque_instance,
-                                                   channel_instance=self))
-                programs_to_add.append(Redirect(data={'duration': length_of_night_block,
-                                                      'isOffline': True,
-                                                      'channel': night_channel_number,
-                                                      'type': 'redirect'},
-                                                dizque_instance=self._dizque_instance,
-                                                channel_instance=self))
+                    programs_to_add.append(
+                        Program(
+                            data={"duration": time_needed, "isOffline": True},
+                            dizque_instance=self._dizque_instance,
+                            channel_instance=self,
+                        )
+                    )
+                programs_to_add.append(
+                    Redirect(
+                        data={
+                            "duration": length_of_night_block,
+                            "isOffline": True,
+                            "channel": night_channel_number,
+                            "type": "redirect",
+                        },
+                        dizque_instance=self._dizque_instance,
+                        channel_instance=self,
+                    )
+                )
                 for program in programs_to_add:
                     final_programs_to_add.append(program)
         if final_programs_to_add and self.delete_all_programs():
@@ -1375,8 +1575,7 @@ def add_channel_at_night_alt(self,
         return False
 
     @decorators.check_for_dizque_instance
-    def balance_programs(self,
-                         margin_of_error: float = 0.1) -> bool:
+    def balance_programs(self, margin_of_error: float = 0.1) -> bool:
         """
         Balance shows to the shortest show length. Movies unaffected.
 
@@ -1385,19 +1584,23 @@ def balance_programs(self,
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        sorted_programs = helpers.balance_shows(media_items=self.programs, margin_of_correction=margin_of_error)
+        sorted_programs = helpers.balance_shows(
+            media_items=self.programs, margin_of_correction=margin_of_error
+        )
         if sorted_programs and self.delete_all_programs():
             return self.add_programs(programs=sorted_programs)
         return False
 
     @decorators.check_for_dizque_instance
-    def fast_forward(self,
-                     seconds: int = 0,
-                     minutes: int = 0,
-                     hours: int = 0,
-                     days: int = 0,
-                     months: int = 0,
-                     years: int = 0) -> bool:
+    def fast_forward(
+        self,
+        seconds: int = 0,
+        minutes: int = 0,
+        hours: int = 0,
+        days: int = 0,
+        months: int = 0,
+        years: int = 0,
+    ) -> bool:
         """
         Fast forward the channel start time by an amount of time
 
@@ -1417,26 +1620,32 @@ def fast_forward(self,
         :rtype: bool
         """
         current_start_time = helpers.string_to_datetime(date_string=self.startTime)
-        shifted_start_time = helpers.shift_time(starting_time=current_start_time,
-                                                seconds=seconds,
-                                                minutes=minutes,
-                                                hours=hours,
-                                                days=days,
-                                                months=months,
-                                                years=years)
-        shifted_start_time = helpers.datetime_to_string(datetime_object=shifted_start_time)
+        shifted_start_time = helpers.shift_time(
+            starting_time=current_start_time,
+            seconds=seconds,
+            minutes=minutes,
+            hours=hours,
+            days=days,
+            months=months,
+            years=years,
+        )
+        shifted_start_time = helpers.datetime_to_string(
+            datetime_object=shifted_start_time
+        )
         if self.update(startTime=shifted_start_time):
             return True
         return False
 
     @decorators.check_for_dizque_instance
-    def rewind(self,
-               seconds: int = 0,
-               minutes: int = 0,
-               hours: int = 0,
-               days: int = 0,
-               months: int = 0,
-               years: int = 0) -> bool:
+    def rewind(
+        self,
+        seconds: int = 0,
+        minutes: int = 0,
+        hours: int = 0,
+        days: int = 0,
+        months: int = 0,
+        years: int = 0,
+    ) -> bool:
         """
         Fast forward the channel start time by an amount of time
 
@@ -1455,12 +1664,14 @@ def rewind(self,
         :return: True if successful, False if unsuccessful (Channel reloads in-place)
         :rtype: bool
         """
-        return self.fast_forward(seconds=seconds * -1,
-                                 minutes=minutes * -1,
-                                 hours=hours * -1,
-                                 days=days * -1,
-                                 months=months * -1,
-                                 years=years * -1)
+        return self.fast_forward(
+            seconds=seconds * -1,
+            minutes=minutes * -1,
+            hours=hours * -1,
+            days=days * -1,
+            months=months * -1,
+            years=years * -1,
+        )
 
     # Delete
     @decorators.check_for_dizque_instance
diff --git a/dizqueTV/models/custom_show.py b/dizqueTV/models/custom_show.py
index 45cf7d9..8d996d9 100644
--- a/dizqueTV/models/custom_show.py
+++ b/dizqueTV/models/custom_show.py
@@ -1,11 +1,11 @@
-from typing import Union, List
+from typing import List, Union
 
 from plexapi.audio import Track
 from plexapi.server import PlexServer as PServer
-from plexapi.video import Video, Movie, Episode
+from plexapi.video import Episode, Movie, Video
 
 from dizqueTV import decorators, helpers
-from dizqueTV.exceptions import MissingParametersError, ItemCreationError
+from dizqueTV.exceptions import ItemCreationError, MissingParametersError
 from dizqueTV.models.base import BaseAPIObject
 from dizqueTV.models.media import Program
 
@@ -15,7 +15,7 @@ def __init__(self, data: dict, dizque_instance, order: int):
         super().__init__(data, dizque_instance, None)
         self._full_data = data
         self.order = order
-        self.durationStr = data.get('durationStr')
+        self.durationStr = data.get("durationStr")
         self._commercials = []
 
     def __repr__(self):
@@ -30,8 +30,8 @@ def _data(self):
         :rtype: dict
         """
         data = self._full_data
-        data.pop('durationStr', None)
-        data.pop('commercials', None)
+        data.pop("durationStr", None)
+        data.pop("commercials", None)
         return data
 
     @property
@@ -50,8 +50,8 @@ def commercials(self) -> List:
 class CustomShowDetails(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.name = data.get('name')
-        self.id = data.get('id')
+        self.name = data.get("name")
+        self.id = data.get("id")
         self._content = []
 
     def __repr__(self):
@@ -67,8 +67,12 @@ def content(self) -> List[CustomShowItem]:
         """
         if not self._content:
             order = 0
-            for item in self._data.get('content', []):
-                self._content.append(CustomShowItem(data=item, dizque_instance=self._dizque_instance, order=order))
+            for item in self._data.get("content", []):
+                self._content.append(
+                    CustomShowItem(
+                        data=item, dizque_instance=self._dizque_instance, order=order
+                    )
+                )
                 order += 1
         return self._content
 
@@ -78,9 +82,9 @@ class CustomShow(BaseAPIObject):
 
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.id = data.get('id')
-        self.name = data.get('name')
-        self.count = data.get('count')
+        self.id = data.get("id")
+        self.name = data.get("name")
+        self.count = data.get("count")
         self.type = "customShow"
         self.customShowTag = "customShow"
         self._details = None
@@ -97,7 +101,9 @@ def details(self) -> Union[CustomShowDetails, None]:
         :rtype: CustomShowDetails
         """
         if not self._details:
-            self._details = self._dizque_instance.get_custom_show_details(custom_show_id=self.id)
+            self._details = self._dizque_instance.get_custom_show_details(
+                custom_show_id=self.id
+            )
         return self._details
 
     @property
@@ -144,8 +150,7 @@ def update(self, **kwargs) -> bool:
         return False
 
     @decorators.check_for_dizque_instance
-    def edit(self,
-             **kwargs) -> bool:
+    def edit(self, **kwargs) -> bool:
         """
         Alias for custom_show.update()
 
@@ -156,10 +161,12 @@ def edit(self,
         return self.update(**kwargs)
 
     @decorators.check_for_dizque_instance
-    def add_program(self,
-                    plex_item: Union[Video, Movie, Episode, Track] = None,
-                    plex_server: PServer = None,
-                    program: Union[Program, CustomShowItem] = None):
+    def add_program(
+        self,
+        plex_item: Union[Video, Movie, Episode, Track] = None,
+        plex_server: PServer = None,
+        program: Union[Program, CustomShowItem] = None,
+    ):
         """
         Add a program to this custom show
 
@@ -175,27 +182,45 @@ def add_program(self,
         custom_show_data = self._data
 
         if not plex_item and not program:
-            raise MissingParametersError("Please include either a program, a plex_item/plex_server combo, or kwargs")
+            raise MissingParametersError(
+                "Please include either a program, a plex_item/plex_server combo, or kwargs"
+            )
         if plex_item:
             if not plex_server:
-                raise ItemCreationError("You must include a plex_server if you are adding PlexAPI Videos, "
-                                        "Movies, Episodes or Tracks as programs")
-            program = self._dizque_instance.convert_plex_item_to_program(plex_item=plex_item, plex_server=plex_server)
-            custom_show_item = self._dizque_instance.convert_program_to_custom_show_item(program=program)
+                raise ItemCreationError(
+                    "You must include a plex_server if you are adding PlexAPI Videos, "
+                    "Movies, Episodes or Tracks as programs"
+                )
+            program = self._dizque_instance.convert_plex_item_to_program(
+                plex_item=plex_item, plex_server=plex_server
+            )
+            custom_show_item = (
+                self._dizque_instance.convert_program_to_custom_show_item(
+                    program=program
+                )
+            )
         elif type(program) != CustomShowItem:
-            custom_show_item = self._dizque_instance.convert_program_to_custom_show_item(program=program)
+            custom_show_item = (
+                self._dizque_instance.convert_program_to_custom_show_item(
+                    program=program
+                )
+            )
         else:
             custom_show_item = program
-        custom_show_data['content'].append(custom_show_item._full_data)
-        custom_show_data['count'] = len(custom_show_data['content'])
-        if custom_show_data.get('duration'):
-            custom_show_data['duration'] += custom_show_item.duration
+        custom_show_data["content"].append(custom_show_item._full_data)
+        custom_show_data["count"] = len(custom_show_data["content"])
+        if custom_show_data.get("duration"):
+            custom_show_data["duration"] += custom_show_item.duration
         return self.update(**custom_show_data)
 
     @decorators.check_for_dizque_instance
-    def add_programs(self,
-                     programs: List[Union[Program, CustomShowItem, Video, Movie, Episode, Track]] = None,
-                     plex_server: PServer = None):
+    def add_programs(
+        self,
+        programs: List[
+            Union[Program, CustomShowItem, Video, Movie, Episode, Track]
+        ] = None,
+        plex_server: PServer = None,
+    ):
         """
         Add multiple programs to this custom show
 
@@ -212,19 +237,30 @@ def add_programs(self,
         for program in programs:
             if type(program) not in [Program, CustomShowItem]:
                 if not plex_server:
-                    raise MissingParametersError("Please include a plex_server if you are adding PlexAPI Video, "
-                                                 "Movie, Episode or Track items.")
-                temp_program = self._dizque_instance.convert_plex_item_to_program(plex_item=program,
-                                                                                  plex_server=plex_server)
-                custom_show_item = self._dizque_instance.convert_program_to_custom_show_item(program=temp_program)
+                    raise MissingParametersError(
+                        "Please include a plex_server if you are adding PlexAPI Video, "
+                        "Movie, Episode or Track items."
+                    )
+                temp_program = self._dizque_instance.convert_plex_item_to_program(
+                    plex_item=program, plex_server=plex_server
+                )
+                custom_show_item = (
+                    self._dizque_instance.convert_program_to_custom_show_item(
+                        program=temp_program
+                    )
+                )
             elif type(program) != CustomShowItem:
-                custom_show_item = self._dizque_instance.convert_program_to_custom_show_item(program=program)
+                custom_show_item = (
+                    self._dizque_instance.convert_program_to_custom_show_item(
+                        program=program
+                    )
+                )
             else:
                 custom_show_item = program
-            custom_show_data['content'].append(custom_show_item._full_data)
-            custom_show_data['count'] = len(custom_show_data['content'])
-            if custom_show_data.get('duration'):
-                custom_show_data['duration'] += custom_show_item.duration
+            custom_show_data["content"].append(custom_show_item._full_data)
+            custom_show_data["count"] = len(custom_show_data["content"])
+            if custom_show_data.get("duration"):
+                custom_show_data["duration"] += custom_show_item.duration
         return self.update(**custom_show_data)
 
     @decorators.check_for_dizque_instance
@@ -238,11 +274,11 @@ def delete_program(self, program: Union[Program, CustomShowItem]) -> bool:
         :rtype: bool
         """
         custom_show_data = self._data
-        for a_program in custom_show_data['content']:
-            if a_program['title'] == program.title:
-                if custom_show_data.get('duration'):
-                    custom_show_data['duration'] -= a_program['duration']
-                custom_show_data['content'].remove(a_program)
+        for a_program in custom_show_data["content"]:
+            if a_program["title"] == program.title:
+                if custom_show_data.get("duration"):
+                    custom_show_data["duration"] -= a_program["duration"]
+                custom_show_data["content"].remove(a_program)
                 return self.update(**custom_show_data)
         return False
 
@@ -255,9 +291,11 @@ def delete_all_programs(self) -> bool:
         :rtype: bool
         """
         custom_show_data = self._data
-        if custom_show_data.get('duration'):
-            custom_show_data['duration'] -= sum(program.duration for program in self.content)
-        custom_show_data['content'] = []
+        if custom_show_data.get("duration"):
+            custom_show_data["duration"] -= sum(
+                program.duration for program in self.content
+            )
+        custom_show_data["content"] = []
         return self.update(**custom_show_data)
 
     # Sort FillerItem
diff --git a/dizqueTV/models/fillers.py b/dizqueTV/models/fillers.py
index c70b9fa..e221b8e 100755
--- a/dizqueTV/models/fillers.py
+++ b/dizqueTV/models/fillers.py
@@ -2,7 +2,7 @@
 
 from plexapi.audio import Track
 from plexapi.server import PlexServer as PServer
-from plexapi.video import Video, Movie, Episode
+from plexapi.video import Episode, Movie, Video
 
 import dizqueTV.helpers as helpers
 from dizqueTV import decorators
@@ -16,10 +16,10 @@
 class FillerList(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.id = data.get('id')
-        self.name = data.get('name')
-        self.count = data.get('count')
-        self._filler_data = data.get('content')
+        self.id = data.get("id")
+        self.name = data.get("name")
+        self.count = data.get("count")
+        self._filler_data = data.get("content")
         if not self.count and self._filler_data:
             self.count = len(self._filler_data)
 
@@ -63,10 +63,12 @@ def content(self) -> List[Union[FillerItem, CustomShow]]:
         """
         if not self._filler_data:
             self.refresh()
-        return self._dizque_instance.parse_custom_shows_and_non_custom_shows(items=self._filler_data,
-                                                                             non_custom_show_type=FillerItem,
-                                                                             dizque_instance=self._dizque_instance,
-                                                                             filler_list_instance=self)
+        return self._dizque_instance.parse_custom_shows_and_non_custom_shows(
+            items=self._filler_data,
+            non_custom_show_type=FillerItem,
+            dizque_instance=self._dizque_instance,
+            filler_list_instance=self,
+        )
 
     @property
     @decorators.check_for_dizque_instance
@@ -96,8 +98,7 @@ def update(self, **kwargs) -> bool:
         return False
 
     @decorators.check_for_dizque_instance
-    def get_filler_item(self,
-                        filler_item_title: str) -> Union[FillerItem, None]:
+    def get_filler_item(self, filler_item_title: str) -> Union[FillerItem, None]:
         """
         Get a specific program on this channel
 
@@ -112,11 +113,13 @@ def get_filler_item(self,
         return None
 
     @decorators.check_for_dizque_instance
-    def add_filler(self,
-                   plex_item: Union[Video, Movie, Episode, Track] = None,
-                   plex_server: PServer = None,
-                   filler: FillerItem = None,
-                   **kwargs) -> bool:
+    def add_filler(
+        self,
+        plex_item: Union[Video, Movie, Episode, Track] = None,
+        plex_server: PServer = None,
+        filler: FillerItem = None,
+        **kwargs
+    ) -> bool:
         """
         Add a filler item to this filler list
 
@@ -131,30 +134,37 @@ def add_filler(self,
         :rtype: bool
         """
         if not plex_item and not filler and not kwargs:
-            raise MissingParametersError("Please include either a program, a plex_item/plex_server combo, or kwargs")
+            raise MissingParametersError(
+                "Please include either a program, a plex_item/plex_server combo, or kwargs"
+            )
         if plex_item and plex_server:
-            temp_filler = self._dizque_instance.convert_plex_item_to_filler(plex_item=plex_item,
-                                                                            plex_server=plex_server)
+            temp_filler = self._dizque_instance.convert_plex_item_to_filler(
+                plex_item=plex_item, plex_server=plex_server
+            )
             kwargs = temp_filler._data
         if filler:
             if type(filler) == CustomShow:
                 # pass CustomShow handling to add_programs, since multiple programs need to be added
                 return self.add_fillers(fillers=[filler])
             kwargs = filler._data
-        if helpers._settings_are_complete(new_settings_dict=kwargs,
-                                          template_settings_dict=FILLER_ITEM_TEMPLATE,
-                                          ignore_keys=['_id', 'id']):
+        if helpers._settings_are_complete(
+            new_settings_dict=kwargs,
+            template_settings_dict=FILLER_ITEM_TEMPLATE,
+            ignore_keys=["_id", "id"],
+        ):
             filler_list_data = self._data
-            filler_list_data['content'].append(kwargs)
-            if filler_list_data.get('duration'):
-                filler_list_data['duration'] += kwargs['duration']
+            filler_list_data["content"].append(kwargs)
+            if filler_list_data.get("duration"):
+                filler_list_data["duration"] += kwargs["duration"]
             return self.update(**filler_list_data)
         return False
 
     @decorators.check_for_dizque_instance
-    def add_fillers(self,
-                    fillers: List[Union[FillerItem, CustomShow, Video, Movie, Episode, Track]],
-                    plex_server: PServer = None) -> bool:
+    def add_fillers(
+        self,
+        fillers: List[Union[FillerItem, CustomShow, Video, Movie, Episode, Track]],
+        plex_server: PServer = None,
+    ) -> bool:
         """
         Add multiple programs to this channel
 
@@ -167,17 +177,23 @@ def add_fillers(self,
         """
         filler_list_data = self._data
 
-        fillers = self._dizque_instance.expand_custom_show_items(programs=fillers, dizque_instance=self)
+        fillers = self._dizque_instance.expand_custom_show_items(
+            programs=fillers, dizque_instance=self
+        )
 
         for filler in fillers:
             if type(filler) not in [FillerItem, CustomShowItem]:
                 if not plex_server:
-                    raise MissingParametersError("Please include a plex_server if you are adding PlexAPI Video, "
-                                                 "Movie, Episode or Track items.")
-                filler = self._dizque_instance.convert_plex_item_to_filler(plex_item=filler, plex_server=plex_server)
-            filler_list_data['content'].append(filler._data)
-            if filler_list_data.get('duration'):
-                filler_list_data['duration'] += filler.duration
+                    raise MissingParametersError(
+                        "Please include a plex_server if you are adding PlexAPI Video, "
+                        "Movie, Episode or Track items."
+                    )
+                filler = self._dizque_instance.convert_plex_item_to_filler(
+                    plex_item=filler, plex_server=plex_server
+                )
+            filler_list_data["content"].append(filler._data)
+            if filler_list_data.get("duration"):
+                filler_list_data["duration"] += filler.duration
         return self.update(**filler_list_data)
 
     @decorators.check_for_dizque_instance
@@ -192,12 +208,14 @@ def update_filler(self, filler: FillerItem, **kwargs) -> bool:
         :rtype: bool
         """
         filler_list_data = self._data
-        for a_filler in filler_list_data['content']:
-            if a_filler['title'] == filler.title:
-                if kwargs.get('duration'):
-                    filler_list_data['duration'] -= a_filler['duration']
-                    filler_list_data['duration'] += kwargs['duration']
-                new_data = helpers._combine_settings(new_settings_dict=kwargs, default_dict=a_filler)
+        for a_filler in filler_list_data["content"]:
+            if a_filler["title"] == filler.title:
+                if kwargs.get("duration"):
+                    filler_list_data["duration"] -= a_filler["duration"]
+                    filler_list_data["duration"] += kwargs["duration"]
+                new_data = helpers._combine_settings(
+                    new_settings_dict=kwargs, default_dict=a_filler
+                )
                 a_filler.update(new_data)
                 return self.update(**filler_list_data)
         return False
@@ -213,11 +231,11 @@ def delete_filler(self, filler: FillerItem) -> bool:
         :rtype: bool
         """
         filler_list_data = self._data
-        for a_filler in filler_list_data['content']:
-            if a_filler['title'] == filler.title:
-                if filler_list_data.get('duration'):
-                    filler_list_data['duration'] -= a_filler['duration']
-                filler_list_data['content'].remove(a_filler)
+        for a_filler in filler_list_data["content"]:
+            if a_filler["title"] == filler.title:
+                if filler_list_data.get("duration"):
+                    filler_list_data["duration"] -= a_filler["duration"]
+                filler_list_data["content"].remove(a_filler)
                 return self.update(**filler_list_data)
         return False
 
@@ -230,9 +248,11 @@ def delete_all_fillers(self) -> bool:
         :rtype: bool
         """
         filler_list_data = self._data
-        if filler_list_data.get('duration'):
-            filler_list_data['duration'] -= sum(filler.duration for filler in self.content)
-        filler_list_data['content'] = []
+        if filler_list_data.get("duration"):
+            filler_list_data["duration"] -= sum(
+                filler.duration for filler in self.content
+            )
+        filler_list_data["content"] = []
         return self.update(**filler_list_data)
 
     # Sort FillerItem
diff --git a/dizqueTV/models/general.py b/dizqueTV/models/general.py
index 5c8cee2..00dca8c 100644
--- a/dizqueTV/models/general.py
+++ b/dizqueTV/models/general.py
@@ -4,7 +4,7 @@
 class UploadImageResponse(BaseObject):
     def __init__(self, data: dict):
         super().__init__(data)
-        self.name = data.get('name')
-        self.mimetype = data.get('mimetype')
-        self.size = data.get('size')
-        self.fileUrl = data.get('fileUrl')
+        self.name = data.get("name")
+        self.mimetype = data.get("mimetype")
+        self.size = data.get("size")
+        self.fileUrl = data.get("fileUrl")
diff --git a/dizqueTV/models/guide.py b/dizqueTV/models/guide.py
index 5e94427..4859ebd 100644
--- a/dizqueTV/models/guide.py
+++ b/dizqueTV/models/guide.py
@@ -1,20 +1,20 @@
 from datetime import datetime
-from typing import Union, List
+from typing import List, Union
 
 import dizqueTV.helpers as helpers
-from dizqueTV.models.base import BaseObject, BaseAPIObject
+from dizqueTV.models.base import BaseAPIObject, BaseObject
 
 
 class GuideProgram(BaseObject):
     def __init__(self, data):
         super().__init__(data)
-        self.start = data.get('start')
-        self.stop = data.get('stop')
-        self.summary = data.get('summary')
-        self.date = data.get('date')
-        self.rating = data.get('rating')
-        self.icon = data.get('icon')
-        self.title = data.get('title')
+        self.start = data.get("start")
+        self.stop = data.get("stop")
+        self.summary = data.get("summary")
+        self.date = data.get("date")
+        self.rating = data.get("rating")
+        self.icon = data.get("icon")
+        self.title = data.get("title")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.title})"
@@ -23,9 +23,9 @@ def __repr__(self):
 class GuideChannel(BaseAPIObject):
     def __init__(self, data, programs, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.name = data.get('name')
-        self.icon = data.get('icon')
-        self.number = data.get('number')
+        self.name = data.get("name")
+        self.icon = data.get("icon")
+        self.number = data.get("number")
         self.programs = programs
 
     def __repr__(self):
@@ -43,12 +43,17 @@ def get_lineup(self, from_date: datetime, to_date: datetime) -> List[GuideProgra
         :rtype: list[GuideProgram]
         """
         params = {
-            'dateFrom': helpers.datetime_to_string(datetime_object=from_date),
-            'dateTo': helpers.datetime_to_string(datetime_object=to_date)
+            "dateFrom": helpers.datetime_to_string(datetime_object=from_date),
+            "dateTo": helpers.datetime_to_string(datetime_object=to_date),
         }
-        json_data = self._dizque_instance._get_json(endpoint=f'/guide/channels/{self.number}', params=params)
-        if json_data.get('programs'):
-            return [GuideProgram(data=program_data) for program_data in json_data['programs']]
+        json_data = self._dizque_instance._get_json(
+            endpoint=f"/guide/channels/{self.number}", params=params
+        )
+        if json_data.get("programs"):
+            return [
+                GuideProgram(data=program_data)
+                for program_data in json_data["programs"]
+            ]
         return []
 
 
@@ -69,8 +74,14 @@ def _create_channels_and_programs(self) -> List[GuideChannel]:
         """
         channels = []
         for channel_number, data in self._data.items():
-            programs = [GuideProgram(data=program_data) for program_data in data['programs']]
-            channel = GuideChannel(data=data['channel'], programs=programs, dizque_instance=self._dizque_instance)
+            programs = [
+                GuideProgram(data=program_data) for program_data in data["programs"]
+            ]
+            channel = GuideChannel(
+                data=data["channel"],
+                programs=programs,
+                dizque_instance=self._dizque_instance,
+            )
             channels.append(channel)
         return channels
 
@@ -82,7 +93,7 @@ def last_update(self) -> Union[datetime, None]:
         :return: datetime.datetime object
         :rtype: datetime.datetime
         """
-        data = self._dizque_instance._get_json(endpoint='/guide/status')
-        if data and data.get('lastUpdate'):
-            return helpers.string_to_datetime(date_string=data['lastUpdate'])
+        data = self._dizque_instance._get_json(endpoint="/guide/status")
+        if data and data.get("lastUpdate"):
+            return helpers.string_to_datetime(date_string=data["lastUpdate"])
         return None
diff --git a/dizqueTV/models/media.py b/dizqueTV/models/media.py
index 40781ce..58240d7 100644
--- a/dizqueTV/models/media.py
+++ b/dizqueTV/models/media.py
@@ -6,9 +6,9 @@
 class BaseMediaItem(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance, channel_instance=None):
         super().__init__(data, dizque_instance)
-        self.type = data.get('type')
-        self.isOffline = data.get('isOffline')
-        self.duration = data.get('duration')
+        self.type = data.get("type")
+        self.isOffline = data.get("isOffline")
+        self.duration = data.get("duration")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.type})"
@@ -16,25 +16,29 @@ def __repr__(self):
 
 class MediaItem(BaseMediaItem):
     def __init__(self, data: dict, dizque_instance, channel_instance=None):
-        super().__init__(data=data, dizque_instance=dizque_instance, channel_instance=channel_instance)
-        self.title = data.get('title')
-        self.key = data.get('key')
-        self.ratingKey = data.get('ratingKey')
-        self.duration = data.get('duration')
-        self.icon = data.get('icon')
-        self.summary = data.get('summary')
-        self.date = data.get('date')
-        self.year = data.get('year')
-        self.plexFile = data.get('plexFile')
-        self.file = data.get('file')
-        self.showTitle = data.get('showTitle')
-        self.episode = data.get('episode')
-        self.season = data.get('season')
-        self.serverKey = data.get('serverKey')
-
-        self.showIcon = data.get('showIcon')
-        self.episodeIcon = data.get('episodeIcon')
-        self.seasonIcon = data.get('seasonIcon')
+        super().__init__(
+            data=data,
+            dizque_instance=dizque_instance,
+            channel_instance=channel_instance,
+        )
+        self.title = data.get("title")
+        self.key = data.get("key")
+        self.ratingKey = data.get("ratingKey")
+        self.duration = data.get("duration")
+        self.icon = data.get("icon")
+        self.summary = data.get("summary")
+        self.date = data.get("date")
+        self.year = data.get("year")
+        self.plexFile = data.get("plexFile")
+        self.file = data.get("file")
+        self.showTitle = data.get("showTitle")
+        self.episode = data.get("episode")
+        self.season = data.get("season")
+        self.serverKey = data.get("serverKey")
+
+        self.showIcon = data.get("showIcon")
+        self.episodeIcon = data.get("episodeIcon")
+        self.seasonIcon = data.get("seasonIcon")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.title})"
@@ -44,7 +48,7 @@ class Redirect(BaseMediaItem):
     def __init__(self, data: dict, dizque_instance, channel_instance):
         super().__init__(data=data, dizque_instance=dizque_instance)
         self._channel_instance = channel_instance
-        self.channel = data.get('channel')
+        self.channel = data.get("channel")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.channel})"
@@ -52,14 +56,23 @@ def __repr__(self):
 
 class Program(MediaItem, Redirect):
     def __init__(self, data: dict, dizque_instance, channel_instance):
-        super().__init__(data=data, dizque_instance=dizque_instance, channel_instance=channel_instance)
-        self.rating = data.get('rating')
+        super().__init__(
+            data=data,
+            dizque_instance=dizque_instance,
+            channel_instance=channel_instance,
+        )
+        self.rating = data.get("rating")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.title})"
 
     @decorators.check_for_dizque_instance
-    def refresh(self, data: dict = None, program_title: str = None, redirect_channel_number: int = None):
+    def refresh(
+        self,
+        data: dict = None,
+        program_title: str = None,
+        redirect_channel_number: int = None,
+    ):
         """
         Reload current Program object
         Use to update data
@@ -68,18 +81,25 @@ def refresh(self, data: dict = None, program_title: str = None, redirect_channel
         """
         if not data and not program_title and not redirect_channel_number:
             raise MissingParametersError(
-                "Please include either a JSON array, program_title or a redirect_channel_number.")
+                "Please include either a JSON array, program_title or a redirect_channel_number."
+            )
         if program_title or redirect_channel_number:
-            temp_program = self._channel_instance.get_program(program_title=program_title,
-                                                              redirect_channel_number=redirect_channel_number)
+            temp_program = self._channel_instance.get_program(
+                program_title=program_title,
+                redirect_channel_number=redirect_channel_number,
+            )
             if not temp_program:
                 raise Exception("Could not find program.")
             else:
                 data = temp_program._data
-                self._channel_instance = temp_program._channel_instance,
+                self._channel_instance = (temp_program._channel_instance,)
                 self._dizque_instance = temp_program._dizque_instance
                 del temp_program
-        self.__init__(data=data, channel_instance=self._channel_instance, dizque_instance=self._dizque_instance)
+        self.__init__(
+            data=data,
+            channel_instance=self._channel_instance,
+            dizque_instance=self._dizque_instance,
+        )
 
     @decorators.check_for_dizque_instance
     def update(self, **kwargs) -> bool:
@@ -120,17 +140,24 @@ def refresh(self, data: dict = None, filler_item_title: str = None):
         """
         if not data and not filler_item_title:
             raise MissingParametersError(
-                "Please include either a JSON array or a filler_item_title.")
+                "Please include either a JSON array or a filler_item_title."
+            )
         if filler_item_title:
-            temp_item = self._filler_list_instance.get_filler_item(filler_item_title=filler_item_title)
+            temp_item = self._filler_list_instance.get_filler_item(
+                filler_item_title=filler_item_title
+            )
             if not temp_item:
                 raise Exception("Could not find filler item.")
             else:
                 data = temp_item._data
-                self._filler_list_instance = temp_item._filler_list_instance,
+                self._filler_list_instance = (temp_item._filler_list_instance,)
                 self._dizque_instance = temp_item._dizque_instance
                 del temp_item
-        self.__init__(data=data, filler_list_instance=self._filler_list_instance, dizque_instance=self._dizque_instance)
+        self.__init__(
+            data=data,
+            filler_list_instance=self._filler_list_instance,
+            dizque_instance=self._dizque_instance,
+        )
 
     @decorators.check_for_dizque_instance
     def update(self, **kwargs) -> bool:
diff --git a/dizqueTV/models/plex_server.py b/dizqueTV/models/plex_server.py
index 8d22515..e2ec5d5 100644
--- a/dizqueTV/models/plex_server.py
+++ b/dizqueTV/models/plex_server.py
@@ -5,13 +5,13 @@
 class PlexServer(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.name = data.get('name')
-        self.uri = data.get('uri')
-        self.accessToken = data.get('accessToken')
-        self.index = data.get('index')
-        self.arChannels = data.get('arChannels')
-        self.arGuide = data.get('arGuide')
-        self._id = data.get('_id')
+        self.name = data.get("name")
+        self.uri = data.get("uri")
+        self.accessToken = data.get("accessToken")
+        self.index = data.get("index")
+        self.arChannels = data.get("arChannels")
+        self.arGuide = data.get("arGuide")
+        self._id = data.get("_id")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.name})"
@@ -63,7 +63,9 @@ def update(self, **kwargs) -> bool:
         :rtype: bool
         """
         if self._dizque_instance:
-            if self._dizque_instance.update_plex_server(server_name=self.name, **kwargs):
+            if self._dizque_instance.update_plex_server(
+                server_name=self.name, **kwargs
+            ):
                 self.refresh()
                 return True
         return False
diff --git a/dizqueTV/models/settings.py b/dizqueTV/models/settings.py
index 0b8466a..b7ae9ec 100644
--- a/dizqueTV/models/settings.py
+++ b/dizqueTV/models/settings.py
@@ -5,9 +5,9 @@
 class ServerDetails(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.server_version = data.get('dizquetv')
-        self.ffmpeg_version = data.get('ffmpeg')
-        self.nodejs_version = data.get('nodejs')
+        self.server_version = data.get("dizquetv")
+        self.ffmpeg_version = data.get("ffmpeg")
+        self.nodejs_version = data.get("nodejs")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self.server_version})"
@@ -30,10 +30,10 @@ def reload(self):
 class XMLTVSettings(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.cache = data.get('cache')
-        self.refresh = data.get('refresh')
-        self.file = data.get('file')
-        self._id = data.get('_id')
+        self.cache = data.get("cache")
+        self.refresh = data.get("refresh")
+        self.file = data.get("file")
+        self._id = data.get("_id")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self._id})"
@@ -85,9 +85,9 @@ def reset(self) -> bool:
 class HDHomeRunSettings(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.tunerCount = data.get('tunerCount')
-        self.autoDiscovery = data.get('autoDiscovery')
-        self._id = data.get('_id')
+        self.tunerCount = data.get("tunerCount")
+        self.autoDiscovery = data.get("autoDiscovery")
+        self._id = data.get("_id")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self._id})"
@@ -139,31 +139,31 @@ def reset(self) -> bool:
 class FFMPEGSettings(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.configVersion = data.get('configVersion')
-        self.ffmpegPath = data.get('ffmpegPath')
-        self.threads = data.get('threads')
-        self.concatMuxDelay = data.get('concatMuxDelay')
-        self.logFfmpeg = data.get('logFfmpeg')
-        self.enableFFMPEGTranscoding = data.get('enableFFMPEGTranscoding')
-        self.audioVolumePercent = data.get('audioVolumePercent')
-        self.videoEncoder = data.get('videoEncoder')
-        self.audioEncoder = data.get('audioEncoder')
-        self.targetResolution = data.get('targetResolution')
-        self.videoBitrate = data.get('videoBitrate')
-        self.videoBufSize = data.get('videoBufSize')
-        self.audioBitrate = data.get('audioBitrate')
-        self.audioBufSize = data.get('audioBufSize')
-        self.audioSampleRate = data.get('audioSampleRate')
-        self.audioChannels = data.get('audioChannels')
-        self.errorScreen = data.get('errorScreen')
-        self.errorAudio = data.get('errorAudio')
-        self.normalizeVideoCodec = data.get('normalizeVideoCodec')
-        self.normalizeAudioCodec = data.get('normalizeAudioCodec')
-        self.normalizeResolution = data.get('normalizeResolution')
-        self.normalizeAudio = data.get('normalizeAudio')
-        self.maxFPS = data.get('maxFPS')
-        self.scalingAlgorithm = data.get('scalingAlgorithm')
-        self._id = data.get('_id')
+        self.configVersion = data.get("configVersion")
+        self.ffmpegPath = data.get("ffmpegPath")
+        self.threads = data.get("threads")
+        self.concatMuxDelay = data.get("concatMuxDelay")
+        self.logFfmpeg = data.get("logFfmpeg")
+        self.enableFFMPEGTranscoding = data.get("enableFFMPEGTranscoding")
+        self.audioVolumePercent = data.get("audioVolumePercent")
+        self.videoEncoder = data.get("videoEncoder")
+        self.audioEncoder = data.get("audioEncoder")
+        self.targetResolution = data.get("targetResolution")
+        self.videoBitrate = data.get("videoBitrate")
+        self.videoBufSize = data.get("videoBufSize")
+        self.audioBitrate = data.get("audioBitrate")
+        self.audioBufSize = data.get("audioBufSize")
+        self.audioSampleRate = data.get("audioSampleRate")
+        self.audioChannels = data.get("audioChannels")
+        self.errorScreen = data.get("errorScreen")
+        self.errorAudio = data.get("errorAudio")
+        self.normalizeVideoCodec = data.get("normalizeVideoCodec")
+        self.normalizeAudioCodec = data.get("normalizeAudioCodec")
+        self.normalizeResolution = data.get("normalizeResolution")
+        self.normalizeAudio = data.get("normalizeAudio")
+        self.maxFPS = data.get("maxFPS")
+        self.scalingAlgorithm = data.get("scalingAlgorithm")
+        self._id = data.get("_id")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self._id})"
@@ -215,26 +215,26 @@ def reset(self) -> bool:
 class PlexSettings(BaseAPIObject):
     def __init__(self, data: dict, dizque_instance):
         super().__init__(data, dizque_instance)
-        self.streamPath = data.get('streamPath')
-        self.debugLogging = data.get('debugLogging')
-        self.directStreamBitrate = data.get('directStreamBitrate')
-        self.transcodeBitrate = data.get('transcodeBitrate')
-        self.mediaBufferSize = data.get('mediaBufferSize')
-        self.transcodeMediaBufferSize = data.get('transcodeMediaBufferSize')
-        self.maxPlayableResolution = data.get('maxPlayableResolution')
-        self.maxTranscodeResolution = data.get('maxTranscodeResolution')
-        self.videoCodecs = data.get('videoCodecs')
-        self.audioCodecs = data.get('audioCodecs')
-        self.maxAudioChannels = data.get('maxAudioChannels')
-        self.audioBoost = data.get('audioBoost')
-        self.enableSubtitles = data.get('enableSubtitles')
-        self.subtitleSize = data.get('subtitleSize')
-        self.updatePlayStatus = data.get('updatePlayStatus')
-        self.streamProtocol = data.get('streamProtocol')
-        self.forceDirectPlay = data.get('forceDirectPlay')
-        self.pathReplace = data.get('pathReplace')
-        self.pathReplaceWith = data.get('pathReplaceWith')
-        self._id = data.get('_id')
+        self.streamPath = data.get("streamPath")
+        self.debugLogging = data.get("debugLogging")
+        self.directStreamBitrate = data.get("directStreamBitrate")
+        self.transcodeBitrate = data.get("transcodeBitrate")
+        self.mediaBufferSize = data.get("mediaBufferSize")
+        self.transcodeMediaBufferSize = data.get("transcodeMediaBufferSize")
+        self.maxPlayableResolution = data.get("maxPlayableResolution")
+        self.maxTranscodeResolution = data.get("maxTranscodeResolution")
+        self.videoCodecs = data.get("videoCodecs")
+        self.audioCodecs = data.get("audioCodecs")
+        self.maxAudioChannels = data.get("maxAudioChannels")
+        self.audioBoost = data.get("audioBoost")
+        self.enableSubtitles = data.get("enableSubtitles")
+        self.subtitleSize = data.get("subtitleSize")
+        self.updatePlayStatus = data.get("updatePlayStatus")
+        self.streamProtocol = data.get("streamProtocol")
+        self.forceDirectPlay = data.get("forceDirectPlay")
+        self.pathReplace = data.get("pathReplace")
+        self.pathReplaceWith = data.get("pathReplaceWith")
+        self._id = data.get("_id")
 
     def __repr__(self):
         return f"{self.__class__.__name__}({self._id})"
diff --git a/dizqueTV/models/templates.py b/dizqueTV/models/templates.py
index e320141..f5472a0 100644
--- a/dizqueTV/models/templates.py
+++ b/dizqueTV/models/templates.py
@@ -7,7 +7,7 @@
     "index": int,
     "arChannels": bool,
     "arGuide": bool,
-    "_id": str
+    "_id": str,
 }
 
 WATERMARK_SETTINGS_TEMPLATE = {
@@ -19,7 +19,7 @@
     "fixedSize": bool,
     "position": str,
     "url": str,
-    "animated": bool
+    "animated": bool,
 }
 
 WATERMARK_SETTINGS_DEFAULT = {
@@ -31,19 +31,19 @@
     "fixedSize": False,
     "position": "bottom-right",
     "url": "",
-    "animated": False
+    "animated": False,
 }
 
 CHANNEL_FFMPEG_SETTINGS_TEMPLATE = {
     "targetResolution": str,
     "videoBitrate": int,
-    "videoBufSize": int
+    "videoBufSize": int,
 }
 
 CHANNEL_FFMPEG_SETTINGS_DEFAULT = {
     "targetResolution": "",
     "videoBitrate": None,
-    "videoBufSize": None
+    "videoBufSize": None,
 }
 
 CHANNEL_ON_DEMAND_SETTINGS_TEMPLATE = {
@@ -62,11 +62,7 @@
     "playedOffset": 0,
 }
 
-TIME_SLOT_SETTINGS_TEMPLATE = {
-    "time": int,
-    "showId": str,
-    "order": str
-}
+TIME_SLOT_SETTINGS_TEMPLATE = {"time": int, "showId": str, "order": str}
 
 SCHEDULE_SETTINGS_TEMPLATE = {
     "lateness": int,
@@ -75,7 +71,7 @@
     "slots": [],
     "pad": int,
     "timeZoneOffset": int,
-    "fake": dict
+    "fake": dict,
 }
 
 SCHEDULE_SETTINGS_DEFAULT = {
@@ -85,9 +81,7 @@
     "slots": [],
     "pad": 1,
     "timeZoneOffset": 0,
-    "fake": {
-        "time": -1
-    }
+    "fake": {"time": -1},
 }
 
 RANDOM_SCHEDULE_SETTINGS_TEMPLATE = {
@@ -99,7 +93,7 @@
     "padStyle": str,
     "randomDistribution": str,
     "timeZoneOffset": int,
-    "fake": dict
+    "fake": dict,
 }
 
 RANDOM_SCHEDULE_SETTINGS_DEFAULT = {
@@ -111,9 +105,7 @@
     "padStyle": "slot",
     "randomDistribution": "uniform",
     "timeZoneOffset": 0,
-    "fake": {
-        "time": -1
-    }
+    "fake": {"time": -1},
 }
 
 CHANNEL_SETTINGS_TEMPLATE = {
@@ -137,7 +129,7 @@
     "guideFlexPlaceholder": str,
     "stealth": bool,
     "enabled": bool,
-    "groupTitle": str
+    "groupTitle": str,
 }
 
 CHANNEL_SETTINGS_DEFAULT = {
@@ -153,42 +145,25 @@
     "guideFlexPlaceholder": "",
     "enabled": True,
     "stealth": False,
-    "groupTitle": "dizqueTV"
+    "groupTitle": "dizqueTV",
 }
 
-FILLER_LIST_SETTINGS_TEMPLATE = {
-    "name": str,
-    "content": List,
-    "id": str
-}
+FILLER_LIST_SETTINGS_TEMPLATE = {"name": str, "content": List, "id": str}
 
-FILLER_LIST_SETTINGS_DEFAULT = {
-    "name": "New List",
-    "content": []
-}
+FILLER_LIST_SETTINGS_DEFAULT = {"name": "New List", "content": []}
 
-FILLER_LIST_CHANNEL_TEMPLATE = {
-    "id": str,
-    "weight": int,
-    "cooldown": int
-}
+FILLER_LIST_CHANNEL_TEMPLATE = {"id": str, "weight": int, "cooldown": int}
 
-FILLER_LIST_CHANNEL_DEFAULT = {
-    "weight": 300,
-    "cooldown": 0
-}
+FILLER_LIST_CHANNEL_DEFAULT = {"weight": 300, "cooldown": 0}
 
 REDIRECT_PROGRAM_TEMPLATE = {
     "isOffline": bool,
     "type": str,
     "duration": int,
-    "channel": int
+    "channel": int,
 }
 
-CUSTOM_SHOW_TEMPLATE = {
-    "name": str,
-    "content": List
-}
+CUSTOM_SHOW_TEMPLATE = {"name": str, "content": List}
 
 MOVIE_PROGRAM_TEMPLATE = {
     "title": str,
@@ -206,7 +181,7 @@
     "showTitle": str,
     "episode": int,
     "season": int,
-    "serverKey": str
+    "serverKey": str,
 }
 
 EPISODE_PROGRAM_TEMPLATE = {
@@ -228,7 +203,7 @@
     "serverKey": str,
     "showIcon": str,
     "episodeIcon": str,
-    "seasonIcon": str
+    "seasonIcon": str,
 }
 
 TRACK_PROGRAM_TEMPLATE = {
@@ -244,7 +219,7 @@
     "showTitle": str,
     "episode": int,
     "season": int,
-    "serverKey": str
+    "serverKey": str,
 }
 
 FILLER_ITEM_TEMPLATE = {
@@ -262,12 +237,12 @@
     "showTitle": str,
     "episode": int,
     "season": int,
-    "serverKey": str
+    "serverKey": str,
 }
 
 IMAGE_UPLOAD_RESPONSE_TEMPLATE = {
     "name": str,
     "mimetype": str,
     "size": int,
-    "fileUrl": str
+    "fileUrl": str,
 }
diff --git a/dizqueTV/plex_utils.py b/dizqueTV/plex_utils.py
index ba9e955..620519c 100644
--- a/dizqueTV/plex_utils.py
+++ b/dizqueTV/plex_utils.py
@@ -1,6 +1,6 @@
 from typing import List, Union
 
-from plexapi import server, media, library, playlist, myplex
+from plexapi import library, media, myplex, playlist, server
 
 from dizqueTV import convert_plex_server_to_dizque_plex_server
 
@@ -50,7 +50,7 @@ def library_sections(self) -> List[library.LibrarySection]:
         return self.server.library.sections()
 
     @property
-    def as_dizquetv_plex_server(self) -> 'dizqueTV.PlexServer':
+    def as_dizquetv_plex_server(self) -> "dizqueTV.PlexServer":
         """
         Get this Plex Media Server to a dizqueTV Plex server
         :return: dizqueTV Plex server
@@ -81,9 +81,9 @@ def get_playlist(self, playlist_name: str) -> Union[playlist.Playlist, None]:
         :return: Plex playlist or None
         :rtype: plexapi.playlist.Playlist | None
         """
-        for playlist in self.playlists:
-            if playlist.title == playlist_name:
-                return playlist
+        for pl in self.playlists:
+            if pl.title == playlist_name:
+                return pl
         return None
 
     def create_new_playlist(self, playlist_name: str, items: List[media.Media]) -> bool:
@@ -123,7 +123,9 @@ def reset_playlist(self, playlist_name: str, items: List[media.Media]) -> bool:
         except:
             return False
 
-    def get_all_section_items(self, section: library.LibrarySection) -> List[media.Media]:
+    def get_all_section_items(
+        self, section: library.LibrarySection
+    ) -> List[media.Media]:
         """
         Get all Plex media items in a specific library section
         NOTE: May be slow on large library sections
@@ -135,8 +137,9 @@ def get_all_section_items(self, section: library.LibrarySection) -> List[media.M
         """
         return section.all()
 
-    def search_for_plex_items(self, section_name: str = None, result_class: type = None, **search_terms) -> List[
-        media.Media]:
+    def search_for_plex_items(
+        self, section_name: str = None, result_class: type = None, **search_terms
+    ) -> List[media.Media]:
         """
         Search for Plex items
 
@@ -156,8 +159,9 @@ def search_for_plex_items(self, section_name: str = None, result_class: type = N
             return [item for item in results if isinstance(item, result_class)]
         return results
 
-    def search_for_plex_items_with_advanced_filters(self, section_name: str = None, result_class: type = None,
-                                                    **search_terms) -> List[media.Media]:
+    def search_for_plex_items_with_advanced_filters(
+        self, section_name: str = None, result_class: type = None, **search_terms
+    ) -> List[media.Media]:
         """
         Search for Plex items
 
@@ -169,10 +173,15 @@ def search_for_plex_items_with_advanced_filters(self, section_name: str = None,
         :return: List of matching Plex media items
         :rtype: List[plexapi.media.Media]
         """
-        return self.search_for_plex_items(section_name=section_name, result_class=result_class,
-                                          **{'filters': search_terms})
+        return self.search_for_plex_items(
+            section_name=section_name,
+            result_class=result_class,
+            **{"filters": search_terms}
+        )
 
-    def get_dizque_item_on_plex(self, dizque_item, section_name: str = None) -> Union[media.Media, None]:
+    def get_dizque_item_on_plex(
+        self, dizque_item, section_name: str = None
+    ) -> Union[media.Media, None]:
         """
         Locate a dizqueTV item on Plex
 
@@ -183,35 +192,47 @@ def get_dizque_item_on_plex(self, dizque_item, section_name: str = None) -> Unio
         :rtype: plexapi.media.Media | None
         """
         if section_name:
-            results = self.server.library.section(section_name).search(title=dizque_item.title)
+            results = self.server.library.section(section_name).search(
+                title=dizque_item.title
+            )
         else:
             results = self.server.library.search(title=dizque_item.title)
         for plex_item in results:
-            if plex_item.ratingKey and int(plex_item.ratingKey) == int(dizque_item.ratingKey):
+            if plex_item.ratingKey and int(plex_item.ratingKey) == int(
+                dizque_item.ratingKey
+            ):
                 return plex_item
         return None
 
 
 class PlexSearch(PlexUtils):
-    def __init__(self, url: str = None, token: str = None, plex_server: server.PlexServer = None):
+    def __init__(
+        self, url: str = None, token: str = None, plex_server: server.PlexServer = None
+    ):
         if not plex_server:
             super().__init__(url=url, token=token)
         else:
             self.server = plex_server
 
-    def _search_by_any_match_query_in_sections(self, query_key: str, query_values: list,
-                                               section_names: List[str] = None) -> List[media.Media]:
+    def _search_by_any_match_query_in_sections(
+        self, query_key: str, query_values: list, section_names: List[str] = None
+    ) -> List[media.Media]:
         matches = []
         if not section_names:
             section_names = [None]
 
         for section_name in section_names:
             for query_value in query_values:
-                matches.extend(self.search_for_plex_items(section_name=section_name, **{query_key: query_value}))
+                matches.extend(
+                    self.search_for_plex_items(
+                        section_name=section_name, **{query_key: query_value}
+                    )
+                )
         return list(set(matches))
 
-    def _search_by_any_advanced_filter_match_query_in_sections(self, query_key: str, query_values: list,
-                                                               section_names: List[str] = None) -> List[media.Media]:
+    def _search_by_any_advanced_filter_match_query_in_sections(
+        self, query_key: str, query_values: list, section_names: List[str] = None
+    ) -> List[media.Media]:
         matches = []
         if not section_names:
             section_names = [None]
@@ -219,12 +240,15 @@ def _search_by_any_advanced_filter_match_query_in_sections(self, query_key: str,
         for section_name in section_names:
             for query_value in query_values:
                 matches.extend(
-                    self.search_for_plex_items_with_advanced_filters(section_name=section_name,
-                                                                     **{query_key: query_value}))
+                    self.search_for_plex_items_with_advanced_filters(
+                        section_name=section_name, **{query_key: query_value}
+                    )
+                )
         return list(set(matches))
 
-    def search_by_any_keywords_in_summary(self, keywords: List[str], section_names: List[str] = None) -> List[
-        media.Media]:
+    def search_by_any_keywords_in_summary(
+        self, keywords: List[str], section_names: List[str] = None
+    ) -> List[media.Media]:
         """
         Find Plex media items with any of the keywords in their summary
 
@@ -235,10 +259,15 @@ def search_by_any_keywords_in_summary(self, keywords: List[str], section_names:
         :return: Matching Plex media item or None
         :rtype: plexapi.media.Media | None
         """
-        return self._search_by_any_match_query_in_sections(query_key='summary__icontains', query_values=keywords,
-                                                           section_names=section_names)
+        return self._search_by_any_match_query_in_sections(
+            query_key="summary__icontains",
+            query_values=keywords,
+            section_names=section_names,
+        )
 
-    def search_by_any_keyword_in_title(self, keywords: List[str], section_names: List[str] = None) -> List[media.Media]:
+    def search_by_any_keyword_in_title(
+        self, keywords: List[str], section_names: List[str] = None
+    ) -> List[media.Media]:
         """
         Find Plex media items with any of the keywords in their title
 
@@ -249,10 +278,15 @@ def search_by_any_keyword_in_title(self, keywords: List[str], section_names: Lis
         :return: Matching Plex media item or None
         :rtype: plexapi.media.Media | None
         """
-        return self._search_by_any_match_query_in_sections(query_key='title__icontains', query_values=keywords,
-                                                           section_names=section_names)
+        return self._search_by_any_match_query_in_sections(
+            query_key="title__icontains",
+            query_values=keywords,
+            section_names=section_names,
+        )
 
-    def search_by_genre(self, genres: List[str], section_names: List[str] = None) -> List[media.Media]:
+    def search_by_genre(
+        self, genres: List[str], section_names: List[str] = None
+    ) -> List[media.Media]:
         """
         Find Plex media items with any of the keywords in their title
 
@@ -263,5 +297,6 @@ def search_by_genre(self, genres: List[str], section_names: List[str] = None) ->
         :return: Matching Plex media item or None
         :rtype: plexapi.media.Media | None
         """
-        return self._search_by_any_advanced_filter_match_query_in_sections(query_key='genre&', query_values=[genres],
-                                                                           section_names=section_names)
+        return self._search_by_any_advanced_filter_match_query_in_sections(
+            query_key="genre&", query_values=[genres], section_names=section_names
+        )
diff --git a/requirements.txt b/requirements.txt
index 3f0f672..e5b83b2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-m3u8~=1.0.0
-plexapi~=4.9.1
-numpy~=1.22.1
-objectrest~=1.1.1
\ No newline at end of file
+m3u8==3.*
+PlexAPI==4.*; python_version >= "3.6"
+numpy==1.*
+objectrest==1.*
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 351401b..8ca02c0 100644
--- a/setup.py
+++ b/setup.py
@@ -7,6 +7,9 @@
 with open("requirements.txt", 'r') as fh:
     requirements = fh.read().splitlines()
 
+with open("dev_requirements.txt", 'r') as fh:
+    dev_requirements = fh.read().splitlines()
+
 setuptools.setup(
     name=package_info.__title__,  # How you named your package folder (MyLib)
     packages=setuptools.find_packages(),  # Choose the same as "name"
@@ -18,9 +21,12 @@
     author=package_info.__author__,  # Type in your name
     author_email=package_info.__author_email__,  # Type in your E-Mail
     url='https://github.com/nwithan8/dizqueTV-python',  # Provide either the link to your github or to your website
-    download_url=f'https://github.com/nwithan8/dizqueTV-python/archive/{package_info.__version__}.tar.gz',
+    download_url=f'https://github.com/nwithan8/dizqueTV-python/archive/refs/tags/{package_info.__version__}.tar.gz',
     keywords=package_info.__keywords__,  # Keywords that define your package best
     install_requires=requirements,
+    extras_require={
+        "dev": dev_requirements,
+    },
     classifiers=[
         'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
         'Development Status :: 4 - Beta',


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 1485035..84a58fc 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -38,10 +38,7 @@ jobs:
         python-version: 3.9
 
     - name: Install Python dependencies
-      run: |
-        python3 -m pip install --upgrade pip
-        pip3 install -r requirements_test.txt
+      run: make install
 
     - name: Test with pytest
-      run: |
-        pytest --exitfirst --verbose --failed-first
\ No newline at end of file
+      run: make test
\ No newline at end of file
diff --git a/requirements_test.txt b/requirements_test.txt
deleted file mode 100644
index 436fac8..0000000
--- a/requirements_test.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-m3u8~=1.0.0
-plexapi~=4.9.1
-numpy~=1.22.1
-objectrest~=1.1.1
-pytest~=6.2.5
-python-dotenv~=0.19.2
\ No newline at end of file
diff --git a/tests/setup.py b/tests/setup.py
index ffc06d4..bf43ab3 100644
--- a/tests/setup.py
+++ b/tests/setup.py
@@ -1,18 +1,18 @@
 import os
 
+import plexapi
 from dotenv import load_dotenv
 
 import dizqueTV
-import plexapi
 
 fake_plex_server = {
-    'name': 'Test',
-    'uri': 'http://localhost:32400',
-    'accessToken': '12345',
-    'index': 0,
-    'arChannels': False,
-    'arGuide': False,
-    '_id': 'myid',
+    "name": "Test",
+    "uri": "http://localhost:32400",
+    "accessToken": "12345",
+    "index": 0,
+    "arChannels": False,
+    "arGuide": False,
+    "_id": "myid",
 }
 
 
@@ -35,7 +35,7 @@ def _make_plex_utils() -> dizqueTV.PlexUtils:
     return dizqueTV.PlexUtils(url=url, token=token)
 
 
-def plex_server() -> 'plexapi.server.PlexServer':
+def plex_server() -> "plexapi.server.PlexServer":
     utils = _make_plex_utils()
     return utils.server
 
diff --git a/tests/test_dizquetv.py b/tests/test_dizquetv.py
index 68bb301..2498fba 100644
--- a/tests/test_dizquetv.py
+++ b/tests/test_dizquetv.py
@@ -3,7 +3,8 @@
 import pytest
 
 import dizqueTV
-from tests.setup import client, plex_server, plex_server_as_dizquetv_server, fake_plex_server
+from tests.setup import (client, fake_plex_server, plex_server,
+                         plex_server_as_dizquetv_server)
 
 REAL_PLEX_SERVER_ADDED = False
 
@@ -19,41 +20,41 @@ def use_real_plex():
 class TestGeneral:
     def test_dizquetv_server_details(self):
         details = client().dizquetv_server_details
-        assert details.server_version != ''
-        assert details.ffmpeg_version != ''
-        assert details.nodejs_version != ''
+        assert details.server_version != ""
+        assert details.ffmpeg_version != ""
+        assert details.nodejs_version != ""
 
     def test_dizquetv_version(self):
         version = client().dizquetv_version
-        assert version != ''
+        assert version != ""
 
     def test_ffmpeg_version(self):
         version = client().ffmpeg_version
-        assert version != ''
+        assert version != ""
 
     def test_nodejs_version(self):
         version = client().nodejs_version
-        assert version != ''
+        assert version != ""
 
     def test_ffmpeg_settings(self):
         settings = client().ffmpeg_settings
         assert settings is not None
-        assert settings.configVersion != ''
+        assert settings.configVersion != ""
 
     def test_plex_settings(self):
         settings = client().plex_settings
         assert settings is not None
-        assert settings.transcodeBitrate != ''
+        assert settings.transcodeBitrate != ""
 
     def test_xmltv_settings(self):
         settings = client().xmltv_settings
         assert settings is not None
-        assert settings.file != ''
+        assert settings.file != ""
 
     def test_hdhr_settings(self):
         settings = client().hdhr_settings
         assert settings is not None
-        assert settings.tunerCount != ''
+        assert settings.tunerCount != ""
 
     def test_channel_count(self):
         count = client().channel_count
@@ -67,7 +68,7 @@ def test_channel_list(self):
 class TestWithFakePlex:
     def test_add_plex_server(self):
         # add a fake Plex server
-        server = client().get_plex_server(server_name=fake_plex_server['name'])
+        server = client().get_plex_server(server_name=fake_plex_server["name"])
         assert server is None
         server = client().add_plex_server(**fake_plex_server)
         assert type(server) == dizqueTV.PlexServer
@@ -77,32 +78,36 @@ def test_plex_servers(self):
         assert type(servers) == list
 
     def test_plex_server_status(self):
-        status = client().plex_server_status(server_name=fake_plex_server['name'])
+        status = client().plex_server_status(server_name=fake_plex_server["name"])
         assert type(status) == bool
 
     def test_plex_server_foreign_status(self):
-        status = client().plex_server_foreign_status(server_name=fake_plex_server['name'])
+        status = client().plex_server_foreign_status(
+            server_name=fake_plex_server["name"]
+        )
         assert type(status) == bool
 
     def test_get_plex_server(self):
-        server = client().get_plex_server(server_name=fake_plex_server['name'])
+        server = client().get_plex_server(server_name=fake_plex_server["name"])
         assert type(server) in [dizqueTV.PlexServer, None]
 
     def test_update_plex_server(self):
-        server = client().get_plex_server(server_name=fake_plex_server['name'])
+        server = client().get_plex_server(server_name=fake_plex_server["name"])
         assert server.arGuide is False
-        success = client().update_plex_server(server_name=fake_plex_server['name'], arGuide=True)
+        success = client().update_plex_server(
+            server_name=fake_plex_server["name"], arGuide=True
+        )
         # request/update is successful, but throwing a timeout error, so success is False
-        server = client().get_plex_server(server_name=fake_plex_server['name'])
+        server = client().get_plex_server(server_name=fake_plex_server["name"])
         assert server.arGuide is True
 
     def test_delete_plex_server(self):
-        server = client().get_plex_server(server_name=fake_plex_server['name'])
+        server = client().get_plex_server(server_name=fake_plex_server["name"])
         assert server is not None
-        success = client().delete_plex_server(server_name=fake_plex_server['name'])
+        success = client().delete_plex_server(server_name=fake_plex_server["name"])
         # request/update is successful, but throwing a timeout error, so success is False
         sleep(1)
-        server = client().get_plex_server(server_name=fake_plex_server['name'])
+        server = client().get_plex_server(server_name=fake_plex_server["name"])
         assert server is None