diff options
| -rw-r--r-- | config.py | 2 | ||||
| -rw-r--r-- | database.py | 4 | ||||
| -rw-r--r-- | interface.py | 20 | ||||
| -rw-r--r-- | jellyfin.py | 25 |
4 files changed, 24 insertions, 27 deletions
| @@ -14,7 +14,7 @@ def read_config_file(): | |||
| 14 | return parser | 14 | return parser |
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | def write_config_file(parser): | 17 | def write_config_file(parser:ConfigParser): |
| 18 | """ Write ConfigParser contents back to config file """ | 18 | """ Write ConfigParser contents back to config file """ |
| 19 | with open(os.path.expanduser(CONFIG_FILE), "w") as conf: | 19 | with open(os.path.expanduser(CONFIG_FILE), "w") as conf: |
| 20 | parser.write(conf) | 20 | parser.write(conf) |
diff --git a/database.py b/database.py index 1c5304c..039a893 100644 --- a/database.py +++ b/database.py | |||
| @@ -27,7 +27,7 @@ class Database(object): | |||
| 27 | )""") | 27 | )""") |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | def query_playstate(self, item_id): | 30 | def query_playstate(self, item_id:str): |
| 31 | """ Gets the playstate data for a given item id """ | 31 | """ Gets the playstate data for a given item id """ |
| 32 | with sqlite3.connect(self.path) as conn: | 32 | with sqlite3.connect(self.path) as conn: |
| 33 | c = conn.cursor() | 33 | c = conn.cursor() |
| @@ -39,7 +39,7 @@ class Database(object): | |||
| 39 | return playstate | 39 | return playstate |
| 40 | 40 | ||
| 41 | 41 | ||
| 42 | def update_playstate(self, item_id, pct_played, sec_played): | 42 | def update_playstate(self, item_id:str, pct_played:float, sec_played:int): |
| 43 | """ Updates the playstate of a given item id """ | 43 | """ Updates the playstate of a given item id """ |
| 44 | with sqlite3.connect(self.path) as conn: | 44 | with sqlite3.connect(self.path) as conn: |
| 45 | c = conn.cursor() | 45 | c = conn.cursor() |
diff --git a/interface.py b/interface.py index 5d3ff24..817e7b1 100644 --- a/interface.py +++ b/interface.py | |||
| @@ -130,7 +130,7 @@ class Interface: | |||
| 130 | 130 | ||
| 131 | def build(self): | 131 | def build(self): |
| 132 | """ Build urwid/curses UI """ | 132 | """ Build urwid/curses UI """ |
| 133 | self.header = urwid.AttrWrap(urwid.Text("joc"), "header") | 133 | self.header = urwid.AttrWrap(urwid.Text("Main Mode"), "header") |
| 134 | self.content = urwid.SimpleFocusListWalker([]) | 134 | self.content = urwid.SimpleFocusListWalker([]) |
| 135 | self.body = urwid.ListBox(self.content) | 135 | self.body = urwid.ListBox(self.content) |
| 136 | self.display_contents = self.libs | 136 | self.display_contents = self.libs |
| @@ -163,11 +163,11 @@ class Interface: | |||
| 163 | sys.exit(0) | 163 | sys.exit(0) |
| 164 | 164 | ||
| 165 | 165 | ||
| 166 | def keypress(self, key): | 166 | def keypress(self, key:str): |
| 167 | """ Handle a key press by the user """ | 167 | """ Handle a key press by the user """ |
| 168 | if self.ui_main.get_focus() == "body": | 168 | if self.ui_main.get_focus() == "body": |
| 169 | if key == 'h' or key == 'left': | 169 | if key == 'h' or key == 'left': |
| 170 | if not self.search_mode: | 170 | if not self.search_mode and not self.info_mode: |
| 171 | self.shift_left() | 171 | self.shift_left() |
| 172 | self.clear_buffer() | 172 | self.clear_buffer() |
| 173 | elif key == 'enter': | 173 | elif key == 'enter': |
| @@ -188,7 +188,7 @@ class Interface: | |||
| 188 | self.content.set_focus(self.focus) | 188 | self.content.set_focus(self.focus) |
| 189 | self.clear_buffer() | 189 | self.clear_buffer() |
| 190 | elif key == 'l'or key == 'right': | 190 | elif key == 'l'or key == 'right': |
| 191 | if not self.search_mode: | 191 | if not self.search_mode and not self.info_mode: |
| 192 | self.shift_right() | 192 | self.shift_right() |
| 193 | self.clear_buffer() | 193 | self.clear_buffer() |
| 194 | elif key == 'i': | 194 | elif key == 'i': |
| @@ -422,9 +422,9 @@ class Interface: | |||
| 422 | self.display_contents = content | 422 | self.display_contents = content |
| 423 | 423 | ||
| 424 | if self.info_mode: | 424 | if self.info_mode: |
| 425 | content = content[0].split("\n") | ||
| 425 | for line in content: | 426 | for line in content: |
| 426 | self.content.append(urwid.AttrWrap( | 427 | self.content.append(urwid.AttrWrap(urwid.Text(line), 'text')) |
| 427 | urwid.Text(line), 'text','focus')) | ||
| 428 | self.content.set_focus(0) | 428 | self.content.set_focus(0) |
| 429 | return | 429 | return |
| 430 | 430 | ||
| @@ -468,7 +468,7 @@ class Interface: | |||
| 468 | self.content.set_focus(self.focus) | 468 | self.content.set_focus(self.focus) |
| 469 | 469 | ||
| 470 | 470 | ||
| 471 | def is_media(self, item): | 471 | def is_media(self, item:dict): |
| 472 | """ Determines if an item is a piece of media (as opposed to a container) | 472 | """ Determines if an item is a piece of media (as opposed to a container) |
| 473 | and returns a boolean. Determination is made by 'Type' field in Jellyfin | 473 | and returns a boolean. Determination is made by 'Type' field in Jellyfin |
| 474 | item JSON. """ | 474 | item JSON. """ |
| @@ -593,7 +593,7 @@ class Interface: | |||
| 593 | 593 | ||
| 594 | 594 | ||
| 595 | 595 | ||
| 596 | def get_playstate(self, item_id): | 596 | def get_playstate(self, item_id:str): |
| 597 | DB_ITEMID_INDEX = 0 | 597 | DB_ITEMID_INDEX = 0 |
| 598 | DB_PCT_INDEX = 1 | 598 | DB_PCT_INDEX = 1 |
| 599 | DB_SEC_INDEX = 2 | 599 | DB_SEC_INDEX = 2 |
| @@ -602,7 +602,7 @@ class Interface: | |||
| 602 | playstate = self.db.query_playstate(item_id) | 602 | playstate = self.db.query_playstate(item_id) |
| 603 | return playstate[DB_PCT_INDEX],playstate[DB_SEC_INDEX] | 603 | return playstate[DB_PCT_INDEX],playstate[DB_SEC_INDEX] |
| 604 | 604 | ||
| 605 | def set_playstate(self, item_id, pct_played, sec_played): | 605 | def set_playstate(self, item_id:str, pct_played:str, sec_played:str): |
| 606 | """ Updates playstate in local db of an item """ | 606 | """ Updates playstate in local db of an item """ |
| 607 | pct_played = float(pct_played) | 607 | pct_played = float(pct_played) |
| 608 | sec_played = int(sec_played) | 608 | sec_played = int(sec_played) |
| @@ -623,4 +623,4 @@ class Interface: | |||
| 623 | focus_item = self.display_contents[self.focus] | 623 | focus_item = self.display_contents[self.focus] |
| 624 | 624 | ||
| 625 | info = self.jellyfin.get_info(focus_item["Id"]) | 625 | info = self.jellyfin.get_info(focus_item["Id"]) |
| 626 | self.display(info) | 626 | self.display([info]) |
diff --git a/jellyfin.py b/jellyfin.py index 007dccf..05c020a 100644 --- a/jellyfin.py +++ b/jellyfin.py | |||
| @@ -13,6 +13,7 @@ import threading | |||
| 13 | import subprocess | 13 | import subprocess |
| 14 | import ssl | 14 | import ssl |
| 15 | import shlex | 15 | import shlex |
| 16 | from configparser import ConfigParser | ||
| 16 | 17 | ||
| 17 | APP_NAME = "joc" | 18 | APP_NAME = "joc" |
| 18 | CLIENT_VERSION = "0.01" | 19 | CLIENT_VERSION = "0.01" |
| @@ -38,7 +39,7 @@ def die(msg): | |||
| 38 | 39 | ||
| 39 | class JellyfinConnection(object): | 40 | class JellyfinConnection(object): |
| 40 | 41 | ||
| 41 | def __init__(self, parser): | 42 | def __init__(self, parser:ConfigParser): |
| 42 | 43 | ||
| 43 | self.parser = parser | 44 | self.parser = parser |
| 44 | 45 | ||
| @@ -96,7 +97,7 @@ class JellyfinConnection(object): | |||
| 96 | warnings.filterwarnings("ignore") | 97 | warnings.filterwarnings("ignore") |
| 97 | return client | 98 | return client |
| 98 | 99 | ||
| 99 | def login(self, server, username, password): | 100 | def login(self, server:str, username:str, password:str): |
| 100 | """ Login to Jellyfin server with JellyfinClient instance """ | 101 | """ Login to Jellyfin server with JellyfinClient instance """ |
| 101 | 102 | ||
| 102 | client = self.client_factory() | 103 | client = self.client_factory() |
| @@ -126,7 +127,7 @@ class JellyfinConnection(object): | |||
| 126 | folders = self.api.get_media_folders()["Items"] | 127 | folders = self.api.get_media_folders()["Items"] |
| 127 | return sorted(folders,key=lambda folder: folder["Name"]) | 128 | return sorted(folders,key=lambda folder: folder["Name"]) |
| 128 | 129 | ||
| 129 | def get_children(self,parent_id): | 130 | def get_children(self,parent_id:str): |
| 130 | """ Get children of a given parent_id. | 131 | """ Get children of a given parent_id. |
| 131 | Sorts by date created if items are videos or by name otherwise. | 132 | Sorts by date created if items are videos or by name otherwise. |
| 132 | Returns the sotrted list """ | 133 | Returns the sotrted list """ |
| @@ -143,7 +144,7 @@ class JellyfinConnection(object): | |||
| 143 | 144 | ||
| 144 | return children | 145 | return children |
| 145 | 146 | ||
| 146 | def get_previous(self,item_id): | 147 | def get_previous(self,item_id:str): |
| 147 | """Gets items that were shown on the previous screen, i.e. | 148 | """Gets items that were shown on the previous screen, i.e. |
| 148 | the parent item's siblings, i.e. the children of the grandparent item """ | 149 | the parent item's siblings, i.e. the children of the grandparent item """ |
| 149 | 150 | ||
| @@ -158,7 +159,7 @@ class JellyfinConnection(object): | |||
| 158 | return self.get_children(grandparent["Id"]) | 159 | return self.get_children(grandparent["Id"]) |
| 159 | 160 | ||
| 160 | 161 | ||
| 161 | def get_parent(self,item_id): | 162 | def get_parent(self,item_id:str): |
| 162 | """ Get parent (first ancestor) of a given item """ | 163 | """ Get parent (first ancestor) of a given item """ |
| 163 | 164 | ||
| 164 | PARENT_INDEX = 0 | 165 | PARENT_INDEX = 0 |
| @@ -166,7 +167,7 @@ class JellyfinConnection(object): | |||
| 166 | parent = ancestors[PARENT_INDEX] | 167 | parent = ancestors[PARENT_INDEX] |
| 167 | return parent | 168 | return parent |
| 168 | 169 | ||
| 169 | def search(self, term): | 170 | def search(self, term:str): |
| 170 | """ Search for a given term and return a alphabetically sorted list """ | 171 | """ Search for a given term and return a alphabetically sorted list """ |
| 171 | 172 | ||
| 172 | items = self.api.search_media_items(term,MEDIA_TYPES,None)["Items"] | 173 | items = self.api.search_media_items(term,MEDIA_TYPES,None)["Items"] |
| @@ -178,25 +179,21 @@ class JellyfinConnection(object): | |||
| 178 | string representation of the item """ | 179 | string representation of the item """ |
| 179 | 180 | ||
| 180 | item = self.api.get_item(item_id) | 181 | item = self.api.get_item(item_id) |
| 181 | return json.dumps(item,indent=4) | 182 | return json.dumps(item,indent=2) |
| 182 | 183 | ||
| 183 | def mark_watched(self, item_id, watched=True): | 184 | def mark_watched(self, item_id:str, watched=True): |
| 184 | """ Mark an item as watched or unwatched""" | 185 | """ Mark an item as watched or unwatched""" |
| 185 | self.api.item_played(item_id, watched) | 186 | self.api.item_played(item_id, watched) |
| 186 | 187 | ||
| 187 | def mark_favorite(self, item_id, favorite=True): | 188 | def mark_favorite(self, item_id:str, favorite=True): |
| 188 | """ Mark an item as a favorite or unfavorite the item""" | 189 | """ Mark an item as a favorite or unfavorite the item""" |
| 189 | self.api.favorite(item_id, favorite) | 190 | self.api.favorite(item_id, favorite) |
| 190 | 191 | ||
| 191 | def get_url(self, item_id): | 192 | def get_url(self, item_id:str): |
| 192 | """ Get download URL of the selected media item """ | 193 | """ Get download URL of the selected media item """ |
| 193 | url = self.api.download_url(item_id) | 194 | url = self.api.download_url(item_id) |
| 194 | return url | 195 | return url |
| 195 | 196 | ||
| 196 | def set_played_progress(self, item:dict, ticks): | ||
| 197 | item["UserData"]["PlaybackPositionTicks"] = int(ticks) | ||
| 198 | res = self.api.session_progress(item) | ||
| 199 | |||
| 200 | 197 | ||
| 201 | if __name__ == '__main__': | 198 | if __name__ == '__main__': |
| 202 | main() | 199 | main() |
