44import sys
55import threading
66import logging
7+ from typing import Callable
78
89import xbmc
910import xbmcvfs
1213import utils
1314import kodilogging
1415
15- from myepisodes import MyEpisodes
16+ from myepisodes import MyEpisodes , SHOW_ID_ERR
1617
1718_addon = xbmcaddon .Addon ()
1819_kodiversion = float (xbmcaddon .Addon ("xbmc.addon" ).getAddonInfo ("version" )[0 :4 ])
2526logger = logging .getLogger (__name__ )
2627
2728
28- class MyeMonitor (xbmc .Monitor ):
29- def __init__ (self , * args , ** kwargs ) :
29+ class MEMonitor (xbmc .Monitor ):
30+ def __init__ (self , * args : int , ** kwargs : Callable ) -> None :
3031 xbmc .Monitor .__init__ (self )
3132 self .action = kwargs ["action" ]
3233
33- def onSettingsChanged (self ):
34+ def onSettingsChanged (self ) -> None :
3435 logger .debug ("User changed settings" )
3536 self .action ()
3637
3738
38- def _initMyEpisodes ():
39- username = utils .getSetting ("Username" )
40- password = utils .getSetting ("Password" )
41-
42- login_notif = _language (32912 )
43- if not username or not password :
44- utils .notif (login_notif , time = 2500 )
45- return None
46-
47- mye = MyEpisodes (username , password )
48- mye .login ()
49- if mye .is_logged :
50- login_notif = f"{ username } { _language (32911 )} "
51- utils .notif (login_notif , time = 2500 )
52-
53- if mye .is_logged and (not mye .populate_shows ()):
54- utils .notif (_language (32927 ), time = 2500 )
55- return mye
39+ class MEProperties :
40+ def __init__ (self ) -> None :
41+ self .showid = self .episode = self .season = 0
42+ self .title = ""
43+ self .is_excluded = False
44+ self .total_time = sys .maxsize
45+ self .last_pos = 0
5646
5747
58- class MyePlayer (xbmc .Player ):
59- def __init__ (self ):
48+ class MEPlayer (xbmc .Player ):
49+ def __init__ (self ) -> None :
6050 xbmc .Player .__init__ (self )
61- logger .debug ("MyePlayer - init" )
51+ logger .debug ("MEPlayer - init" )
52+ self ._tracker = threading .Thread (target = self ._track_position )
53+ self ._reset ()
6254
63- self .mye = _initMyEpisodes ()
55+ def _reset (self ) -> None :
56+ logger .debug ("_reset called" )
57+ self .resetTracker ()
58+ if hasattr (self , "mye" ):
59+ del self .mye
60+ self .monitor = MEMonitor (action = self ._reset )
61+ self .props = MEProperties ()
62+ self ._playback_lock = threading .Event ()
63+ self .mye : MyEpisodes = MEPlayer .initMyEpisodes ()
6464 if not self .mye .is_logged :
6565 return
66-
6766 logger .debug ("MyePlayer - account is logged successfully." )
6867
69- self .showid = self .episode = self .title = self .season = None
70- self .is_excluded = False
71- self ._total_time = sys .maxsize
72- self ._last_pos = 0
73- self ._min_percent = utils .getSettingAsInt ("watched-percent" )
74- self ._tracker = None
75- self ._playback_lock = threading .Event ()
76- self .monitor = MyeMonitor (action = self ._reset )
77-
78- def _reset (self ):
79- logger .debug ("_reset called" )
80- self .tearDown ()
81- if self .mye :
82- del self .mye
83- self .__init__ ()
84-
85- def _trackPosition (self ):
86- while self ._playback_lock .isSet () and not self .monitor .abortRequested ():
87- try :
88- self ._last_pos = self .getTime ()
89- except :
90- self ._playback_lock .clear ()
91- logger .debug (f"Tracker time = { self ._last_pos } " )
92- xbmc .sleep (250 )
93- logger .debug (f"Tracker time (ended) = { self ._last_pos } " )
94-
95- def setUp (self ):
96- self ._playback_lock .set ()
97- self ._tracker = threading .Thread (target = self ._trackPosition )
98-
99- def tearDown (self ):
68+ def resetTracker (self ) -> None :
10069 if hasattr (self , "_playback_lock" ):
10170 self ._playback_lock .clear ()
10271 if not hasattr (self , "_tracker" ):
10372 return
104- if self ._tracker is None :
105- return
10673 if self ._tracker .is_alive ():
10774 self ._tracker .join ()
108- self ._tracker = None
75+ self ._tracker = threading .Thread (target = self ._track_position )
76+
77+ @classmethod
78+ def initMyEpisodes (cls ) -> MyEpisodes :
79+ username = utils .getSetting ("Username" )
80+ password = utils .getSetting ("Password" )
81+
82+ login_notif = _language (32912 )
83+ if not username or not password :
84+ utils .notif (login_notif , time = 2500 )
85+ return MyEpisodes ("" , "" )
86+
87+ mye = MyEpisodes (username , password )
88+ mye .login ()
89+ if mye .is_logged :
90+ login_notif = f"{ username } { _language (32911 )} "
91+ utils .notif (login_notif , time = 2500 )
10992
110- def _addShow (self ):
93+ if mye .is_logged and (not mye .populate_shows ()):
94+ utils .notif (_language (32927 ), time = 2500 )
95+ return mye
11196
97+ def _track_position (self ) -> None :
98+ while self ._playback_lock .is_set () and not self .monitor .abortRequested ():
99+ try :
100+ self .props .last_pos = self .getTime ()
101+ except :
102+ self ._playback_lock .clear ()
103+ logger .debug ("Tracker time = %d" , self .props .last_pos )
104+ xbmc .sleep (250 )
105+ logger .debug ("Tracker time (ended) = %d" , self .props .last_pos )
106+
107+ def _add_show (self ) -> None :
112108 if not utils .getSettingAsBool ("auto-add" ):
113109 logger .debug ("Auto-add function disabled." )
114110 return
@@ -117,118 +113,149 @@ def _addShow(self):
117113 self .mye .populate_shows ()
118114
119115 # Add the show if it's not already in our account
120- if self .showid in list (self .mye .shows .values ()):
116+ if self .props . showid in list (self .mye .shows .values ()):
121117 logger .debug ("Show is already in the account." )
122118 return
123119
124- was_added = self .mye .add_show (self .showid )
120+ was_added = self .mye .add_show (self .props . showid )
125121 added = 32926
126122 if was_added :
127123 added = 32925
128- utils .notif (f"{ self .title } { _language (added )} " )
124+ utils .notif (f"{ self .props . title } { _language (added )} " )
129125
130126 # For backward compatibility
131- def onPlayBackStarted (self ):
127+ def onPlayBackStarted (self ) -> None :
132128 if _kodiversion >= 17.9 :
133129 return
134130 # This call is only for Krypton and below
135131 self .onAVStarted ()
136132
137133 # Only available in Leia (18) and up
138- def onAVStarted (self ):
139- self .setUp ()
140- self ._total_time = self .getTotalTime ()
134+ def onAVStarted (self ) -> None :
135+ self ._playback_lock . set ()
136+ self .props . total_time = self .getTotalTime ()
141137 self ._tracker .start ()
142138
143139 filename_full_path = self .getPlayingFile ()
144140 # We don't want to take care of any URL because we can't really gain
145141 # information from it.
146- self .is_excluded = False
142+ self .props . is_excluded = False
147143 if utils .is_excluded (filename_full_path ):
148- self .is_excluded = True
149- self .tearDown ()
144+ self .props . is_excluded = True
145+ self .resetTracker ()
150146 return
151147
152148 # Try to find the title with the help of Kodi (Theses came from
153149 # Kodi.Subtitles add-ons)
154- self .season = str (xbmc .getInfoLabel ("VideoPlayer.Season" ))
155- logger .debug ("Player - Season: {self.season}" )
156- self .episode = str (xbmc .getInfoLabel ("VideoPlayer.Episode" ))
157- logger .debug ("Player - Episode: {self.episode}" )
158- self .title = xbmc .getInfoLabel ("VideoPlayer.TVshowtitle" )
159- logger .debug ("Player - TVShow: {self.title}" )
160- if self .title == "" :
150+ try :
151+ self .props .season = int (xbmc .getInfoLabel ("VideoPlayer.Season" ))
152+ except ValueError :
153+ self .props .season = 0
154+ logger .debug ("Player - Season: %02d" , self .props .season )
155+
156+ try :
157+ self .props .episode = int (xbmc .getInfoLabel ("VideoPlayer.Episode" ))
158+ except ValueError :
159+ self .props .episode = 0
160+ logger .debug ("Player - Episode: %02d" , self .props .episode )
161+
162+ self .props .title = xbmc .getInfoLabel ("VideoPlayer.TVshowtitle" )
163+ logger .debug ("Player - TVShow: %s" , self .props .title )
164+
165+ if self .props .title == "" :
161166 filename = os .path .basename (filename_full_path )
162- logger .debug ("Player - Filename: {filename}" )
163- self .title , self .season , self .episode = self .mye .get_info (filename )
164- logger .debug ("Player - TVShow: {self.title}" )
167+ logger .debug ("Player - Filename: '%s'" , filename )
168+ self .props .title , self .props .season , self .props .episode = self .mye .get_info (
169+ filename
170+ )
171+ logger .debug ("Player - TVShow: '%s'" , self .props .title )
165172
166173 logger .debug (
167- f"Title: { self .title } - Season: { self .season } - Ep: { self .episode } "
174+ "Title: '%s' - Season: %02d - Ep: %02d " ,
175+ self .props .title ,
176+ self .props .season ,
177+ self .props .episode ,
168178 )
169- if not self .season and not self .episode :
179+ if not self .props . season and not self . props .episode :
170180 # It's not a show. If it should be recognised as one. Send a bug.
171- self .tearDown ()
181+ self .resetTracker ()
172182 return
173183
174- self .showid = self .mye .find_show_id (self .title )
175- if self .showid is None :
176- utils .notif (f"{ self .title } { _language (32923 )} " , time = 3000 )
177- self .tearDown ()
184+ self .props . showid = self .mye .find_show_id (self . props .title )
185+ if self .props . showid == SHOW_ID_ERR :
186+ utils .notif (f"{ self .props . title } { _language (32923 )} " , time = 3000 )
187+ self .resetTracker ()
178188 return
179189 logger .debug (
180- f"Player - Found : { self .title } - { self .showid } (S{ self .season } E{ self .episode } "
190+ "Player - Found : '%s' - %02d (S%02d E%02d" ,
191+ self .props .title ,
192+ self .props .showid ,
193+ self .props .season ,
194+ self .props .episode ,
181195 )
182196
183- utils .notif (self .title , time = 2000 )
184- self ._addShow ()
197+ utils .notif (self .props . title , time = 2000 )
198+ self ._add_show ()
185199
186- def onPlayBackStopped (self ):
200+ def onPlayBackStopped (self ) -> None :
187201 # User stopped the playback
188202 self .onPlayBackEnded ()
189203
190- def onPlayBackEnded (self ):
191- self .tearDown ()
204+ def onPlayBackEnded (self ) -> None :
205+ self .resetTracker ()
192206
193- logger .debug (f "onPlayBackEnded: is_exluded: { self .is_excluded } " )
194- if self .is_excluded :
207+ logger .debug ("onPlayBackEnded: is_exluded: %r" , self .props . is_excluded )
208+ if self .props . is_excluded :
195209 return
196210
197- logger .debug (f"last_pos / total_time : { self ._last_pos } / { self ._total_time } " )
198-
199- actual_percent = (self ._last_pos / self ._total_time ) * 100
200211 logger .debug (
201- f"last_pos / total_time : { self ._last_pos } / { self ._total_time } = { actual_percent } %%" ,
212+ "last_pos / total_time : %d / %d" ,
213+ self .props .last_pos ,
214+ self .props .total_time ,
202215 )
203216
204- logger .debug (f"min_percent: { self ._min_percent } " )
217+ actual_percent = (self .props .last_pos / self .props .total_time ) * 100
218+ logger .debug (
219+ "last_pos / total_time : %d / %d = %d%%" ,
220+ self .props .last_pos ,
221+ self .props .total_time ,
222+ actual_percent ,
223+ )
205224
206- if actual_percent < self ._min_percent :
225+ min_percent = min (utils .getSettingAsInt ("watched-percent" ), 95 )
226+ logger .debug ("min_percent: %d%%" , min_percent )
227+ if actual_percent < min_percent :
207228 return
208229
209230 # In case it was deleted or whatever happened during playback
210- self ._addShow ()
231+ self ._add_show ()
211232
212233 # Playback is finished, set the items to watched
213234 found = 32923
214- if self .mye .set_episode_watched (self .showid , self .season , self .episode ):
235+ if self .mye .set_episode_watched (
236+ self .props .showid , self .props .season , self .props .episode
237+ ):
215238 found = 32924
216- utils .notif (f"{ self .title } ({ self .season } - { self .episode } ) { _language (found )} " )
239+ utils .notif (
240+ f"{ self .props .title } ({ self .props .season :02} - { self .props .episode :02} ) { _language (found )} "
241+ )
217242
218243
219244if __name__ == "__main__" :
220- player = MyePlayer ()
245+ player = MEPlayer ()
221246 if not player .mye .is_logged :
222247 sys .exit (0 )
223248
224249 logger .debug (
225- f"[{ _addon .getAddonInfo ('name' )} ] - Version: { _addon .getAddonInfo ('version' )} Started"
250+ "[%s] - Version: %s Started" ,
251+ _addon .getAddonInfo ("name" ),
252+ _addon .getAddonInfo ("version" ),
226253 )
227254
228255 while not player .monitor .abortRequested ():
229256 if player .monitor .waitForAbort (1 ):
230257 # Abort was requested while waiting. We should exit
231258 break
232259
233- player .tearDown ()
260+ player .resetTracker ()
234261 sys .exit (0 )
0 commit comments