Skip to content

Commit

Permalink
Merge pull request #98 from nwithan8/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
nwithan8 authored Apr 9, 2022
2 parents cda70d4 + 12aa9d0 commit 90cd43d
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 104 deletions.
56 changes: 48 additions & 8 deletions dizqueTV/dizquetv.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import json
import logging
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
from typing import List, Union
from typing import List, Union, Dict
from xml.etree import ElementTree

import m3u8
Expand Down Expand Up @@ -467,6 +468,10 @@ def delete_plex_server(self, server_name: str) -> bool:

# Channels

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)

@property
def channels(self) -> List[Channel]:
"""
Expand All @@ -475,14 +480,17 @@ def channels(self) -> List[Channel]:
:return: List of Channel objects
:rtype: List[Channel]
"""
# temporary patch until /channels API is fixed. SLOW.
# temporary patch until /channels API is fixed. Runs concurrently to speed up.
numbers = self.channel_numbers
channels = []
for number in numbers:
json_data = self._get_json(endpoint=f'/channel/{number}', timeout=5)
# large JSON may take longer, so bigger timeout

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:
channels.append(Channel(data=json_data, dizque_instance=self))

return channels

def get_channel(self, channel_number: int = None, channel_name: str = None) -> Union[Channel, None]:
Expand Down Expand Up @@ -556,6 +564,38 @@ def channel_count(self) -> int:
"""
return len(self.channel_numbers)

@property
def highest_channel_number(self) -> int:
"""
Get the highest active channel number
:return: Int number of the highest active channel
:rtype: int
"""
return max(self.channel_numbers)

@property
def lowest_channel_number(self) -> int:
"""
Get the lowest active channel number
:return: Int number of the lowest active channel
:rtype: int
"""
return min(self.channel_numbers)

@property
def lowest_available_channel_number(self) -> int:
"""
Get the lowest channel number that doesn't currently exist
: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
# 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:
"""
Set some dynamic default values, such as channel number, start time and image URLs
Expand Down Expand Up @@ -1406,15 +1446,15 @@ def parse_custom_shows_and_non_custom_shows(self, items: list, non_custom_show_t
return final_items

def add_programs_to_channels(self,
programs: List[Program],
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
:param programs: List of Program objects
:type programs: List[Program]
:param programs: List of Program, CustomShow plexapi.video.Video, plexapi.video.Movie, plexapi.video.Episode or plexapi.audio.Track objects
:type programs: List[Union[Program, CustomShow, plexapi.video.Video, plexapi.video.Movie, plexapi.video.Episode, plexapi.audio.Track]]
:param channels: List of Channel objects (optional)
:type channels: List[Channel], optional
:param channel_numbers: List of channel numbers
Expand Down
30 changes: 30 additions & 0 deletions dizqueTV/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import os
import random
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
from datetime import datetime, timedelta
from typing import List, Union, Tuple

Expand All @@ -19,6 +20,35 @@


# Internal Helpers
def _multithread(func, elements: List, element_param_name: str, thread_count: int = 20, **kwargs) -> List:
"""
Multithread a function for elements in a list
:param func: Function to be multithreaded
:type func: function
:param elements: List of elements to be multithreaded
:type elements: list
:param element_param_name: Name of the parameter to be passed to the function
:type element_param_name: str
:param thread_count: Number of threads to use
:type thread_count: int, optional
:param kwargs: Keyword arguments to be passed to the function
:type kwargs: dict, optional
:return: List of results from the function
:rtype: list
"""
thread_list = []
pool = ThreadPoolExecutor(thread_count)

for element in elements:
temp_kwargs = kwargs.copy()
temp_kwargs[element_param_name] = element
thread_list.append(pool.submit(func, **temp_kwargs))

wait(thread_list, return_when=ALL_COMPLETED)
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:
Expand Down
52 changes: 52 additions & 0 deletions dizqueTV/models/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from typing import List, Union

from plexapi.audio import Track
from plexapi.collection import Collection
from plexapi.playlist import Playlist
from plexapi.server import PlexServer as PServer
from plexapi.video import Video, Movie, Episode

Expand Down Expand Up @@ -557,6 +559,56 @@ def add_programs(self,
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:
"""
Add a collection to this channel
:param collection: PlexAPI Collection to add to this channel
:type collection: plexapi.collection.Collection
:param plex_server: plexapi.server.PlexServer object
:type plex_server: plexapi.server.PlexServer
:return: True if successful, False if unsuccessful (Channel reloads in place)
:rtype: bool
"""
if not collection:
raise MissingParametersError("You must provide a collection to add to the channel.")
items = collection.items()
final_items = []
for item in items:
if type(item) in [Program, CustomShow, Video, Movie, Episode, Track]:
final_items.append(item)
if not final_items:
raise GeneralException("The collection you provided is empty.")
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:
"""
Add a playlist to this channel
:param playlist: PlexAPI Playlist to add to this channel
:type playlist: plexapi.playlist.Playlist
:param plex_server: plexapi.server.PlexServer object
:type plex_server: plexapi.server.PlexServer
:return: True if successful, False if unsuccessful (Channel reloads in place)
:rtype: bool
"""
if not playlist:
raise MissingParametersError("You must provide a playlist to add to the channel.")
items = playlist.items()
final_items = []
for item in items:
if type(item) in [Program, CustomShow, Video, Movie, Episode, Track]:
final_items.append(item)
if not final_items:
raise GeneralException("The playlist you provided is empty.")
return self.add_programs(programs=final_items, plex_server=plex_server)

@decorators.check_for_dizque_instance
def update_program(self,
program: Program,
Expand Down
Loading

0 comments on commit 90cd43d

Please sign in to comment.