From 5151c53facac1a861d11e982c6d78fcafa5d80a4 Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Sat, 9 Aug 2025 11:14:42 -0700 Subject: [PATCH] incremental working better? --- .../database_update_worker.cpython-312.pyc | Bin 30371 -> 30371 bytes .../plex_scan_manager.cpython-310.pyc | Bin 0 -> 10528 bytes core/plex_scan_manager.py | 100 ++++++++++++++++-- ui/pages/__pycache__/artists.cpython-312.pyc | Bin 254307 -> 254689 bytes ui/pages/__pycache__/sync.cpython-312.pyc | Bin 247907 -> 248289 bytes ui/pages/artists.py | 5 + ui/pages/sync.py | 5 + 7 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 core/__pycache__/plex_scan_manager.cpython-310.pyc diff --git a/core/__pycache__/database_update_worker.cpython-312.pyc b/core/__pycache__/database_update_worker.cpython-312.pyc index 0b310c7082c1b0b36700d917a203c04c0c81d395..136439b038c00fed171112420c17aec5cbfa026d 100644 GIT binary patch delta 22 ccmZ4dmT~c0M()$Ryj%=Gu(fFVM(!D909*P8r2qf` delta 22 ccmZ4dmT~c0M()$Ryj%=G5U_jNM(!D909xn=hyVZp diff --git a/core/__pycache__/plex_scan_manager.cpython-310.pyc b/core/__pycache__/plex_scan_manager.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4879857cdcbaa63a87269179810cb32c158da03a GIT binary patch literal 10528 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 F@jnsqrG5Ya literal 0 HcmV?d00001 diff --git a/core/plex_scan_manager.py b/core/plex_scan_manager.py index 185d754a..8a59055f 100644 --- a/core/plex_scan_manager.py +++ b/core/plex_scan_manager.py @@ -35,6 +35,11 @@ class PlexScanManager: self._scan_start_time = None # Track when scan started for timeout self._max_scan_time = 1800 # Maximum scan time in seconds (30 minutes) + # New periodic update system + self._periodic_update_timer = None # Timer for 5-minute periodic updates + self._periodic_update_interval = 300 # 5 minutes in seconds + self._is_doing_periodic_updates = False # Track if we're in periodic update mode + logger.info(f"PlexScanManager initialized with {delay_seconds}s debounce delay") def request_scan(self, reason: str = "Download completed"): @@ -107,8 +112,8 @@ class PlexScanManager: if success: logger.info("✅ Plex library scan initiated successfully") - # Start polling to detect when scan actually completes - self._start_scan_monitoring() + # Start new periodic update system instead of completion detection + self._start_periodic_updates() else: logger.error("❌ Failed to initiate Plex library scan") self._reset_scan_state() @@ -117,16 +122,81 @@ class PlexScanManager: logger.error(f"Exception during Plex library scan: {e}") self._reset_scan_state() - def _start_scan_monitoring(self): - """Start monitoring Plex scan status with polling""" + def _start_periodic_updates(self): + """Start periodic database updates while Plex is scanning""" try: - # Initial delay before starting to poll (let scan actually start) - threading.Timer(15, self._poll_scan_status).start() - logger.debug("Started Plex scan status monitoring (30-second intervals, 30-minute timeout)") + with self._lock: + if self._is_doing_periodic_updates: + logger.debug("Periodic updates already in progress") + return + + self._is_doing_periodic_updates = True + + logger.info(f"🕒 Starting periodic database updates - will check/update every {self._periodic_update_interval//60} minutes") + + # Schedule first periodic update after 5 minutes + self._periodic_update_timer = threading.Timer(self._periodic_update_interval, self._do_periodic_update) + self._periodic_update_timer.start() + except Exception as e: - logger.error(f"Error starting scan monitoring: {e}") + logger.error(f"Error starting periodic updates: {e}") self._reset_scan_state() + def _do_periodic_update(self): + """Execute periodic database update and check if scanning continues""" + try: + with self._lock: + if not self._scan_in_progress: + logger.debug("Scan no longer in progress, stopping periodic updates") + return + + # Check for timeout + if self._scan_start_time and (time.time() - self._scan_start_time) > self._max_scan_time: + logger.warning(f"Plex scan timeout reached ({self._max_scan_time}s), stopping periodic updates") + self._stop_periodic_updates() + return + + # Check if Plex is still scanning + is_scanning = self.plex_client.is_library_scanning("Music") + elapsed_time = time.time() - self._scan_start_time if self._scan_start_time else 0 + + logger.info(f"🕒 PERIODIC UPDATE: After {elapsed_time//60:.0f} minutes - Plex scanning: {is_scanning}") + + if is_scanning: + # Still scanning - trigger database update and continue periodic updates + logger.info("🔄 Plex still scanning - triggering database update") + self._call_completion_callbacks() + + # Schedule next periodic update + logger.info(f"🕒 Scheduling next periodic update in {self._periodic_update_interval//60} minutes") + self._periodic_update_timer = threading.Timer(self._periodic_update_interval, self._do_periodic_update) + self._periodic_update_timer.start() + else: + # Scanning stopped - final update and cleanup + logger.info("✅ Plex scanning completed - doing final database update") + self._call_completion_callbacks() + self._stop_periodic_updates() + + except Exception as e: + logger.error(f"Error during periodic update: {e}") + self._stop_periodic_updates() + + def _stop_periodic_updates(self): + """Stop periodic updates and clean up""" + try: + with self._lock: + self._is_doing_periodic_updates = False + + if self._periodic_update_timer: + self._periodic_update_timer.cancel() + self._periodic_update_timer = None + + logger.info("🕒 Stopped periodic database updates") + self._scan_completed() + + except Exception as e: + logger.error(f"Error stopping periodic updates: {e}") + def _poll_scan_status(self): """Poll Plex to check if library scan is still running""" try: @@ -204,6 +274,12 @@ class PlexScanManager: with self._lock: self._scan_in_progress = False self._scan_start_time = None + + # Cancel periodic updates if running + if self._periodic_update_timer: + self._periodic_update_timer.cancel() + self._periodic_update_timer = None + self._is_doing_periodic_updates = False def force_scan(self): """ @@ -238,4 +314,10 @@ class PlexScanManager: if self._timer: self._timer.cancel() self._timer = None - logger.info("PlexScanManager shutdown - cancelled pending scan") \ No newline at end of file + + if self._periodic_update_timer: + self._periodic_update_timer.cancel() + self._periodic_update_timer = None + + self._is_doing_periodic_updates = False + logger.info("PlexScanManager shutdown - cancelled all pending timers") \ No newline at end of file diff --git a/ui/pages/__pycache__/artists.cpython-312.pyc b/ui/pages/__pycache__/artists.cpython-312.pyc index 1e728b0e9c5db432822169ff3519ef0741fc6991..afc7f9d3d22103269d98ae6efc638e2ba2bff7f8 100644 GIT binary patch delta 2882 zcmZ`*dsLLy5#PD9`=QIjMNkm|mxsthdBljs<54V%BpxF*nraip6;?z9^xLH>5y4}O zgti=&>ewnuj3FkZikf&6Q=_73f>8@bK`=_Cty)s3=$KF|@#+-Kl_=cjh;b zJ9qz9*XQz=eZ0Q$^fVjP@AyhuaP@;#UTeJI6E9I(2v>*-#al3ylD-8ib$t)+@B&>9 zf&mr97kwzM6ax?pP68tYQSDmrps00V_B3Snsu8TuV9Lbu2 zmvKm_ZLI(wr2pVIUpO7g~6wsDYkcFw8P!nv1lR+H!NxcPT72 zEW=rbr9epog+KlM4Y7M}t9!03J1>1{c3x)w(pIlbn`6Pee4Cz`zSx#!FBq$IUEf|& zW}RlAuiG69?3val5^ChM&9gb|R)^E(%yu}lGaOdie5YNv+6tWc)`G=Kz)l-hh>@e* z^-HMyYh#$M2

}3SLprI!NzPo&H!|`crk(yh2p=KCMWU7_J+=si;Vd9KCt=**?)9 zyM1bGPE2h~Ol^4SmuKT%J8$uAwpbf2)@Dm=qb0W4GP%(*`K)Eicb5L-zTUkd;PtbX z*;G>`=Jrp9WRu~TsdsW59`o``j>corrsOyoyiz0p%%GXYVhni7jm4q@;Wdg}EheeY zlGSRrzudK2lp7&djw%(U{$QgcJ46IbmjB!#t^`6BH5?JUVHFi06-7`&508qMV2wXbHn&hJ5 z%aNM?HXkTs_zlBvX-0!cQ3kg*h(XXOKWz|^0xrt-Ga>~2UBdA!_Zgdgjz_~d_T?1R zB=*BrI@2VEL6>~gB<8wV7Vv%x?|U&Uq=pXRM{6&MZIDgjZ6X|c$ti6j0i)h}R?>Cw z5}zsM4L>&aM^({!wvoKsgfFb6x^@u-!)0f?KqKs??kg&odnn?nTJ5m|3uw_*kz{eO zhGVR&o*{?+bXAOieRTb*2!@fe?=`VmCz9V!V^WyJSljEH}eHMrR9 zWFl*LI)>SB5L&e?d!DLeeI75b=H*P<*s0hYpp%^<6lTinouV9}oQk_e9PFjqZZWm* z=SteachqXtQ&{Uk^1h)MWXXgZBGjnuWNq(J`fc%ZGp8zLdSo9J<%73HVB`+ob7jGm zfDt_XX&QNL>!v%RpMMn(-%;RDC7{fyUysEvDE5x9!U~yoN2D3yD7|xEjDtgT`M#I{ z>nZ$!conLt=z$mvn`Pw#F~|fv=`+Cm9#{NmyueNVHLU)l|Dk>tbqkDxqcQ~Xpi%jK z(G9o2`?S0lM!H|{QhaVHJ|zZfye0* zT?$4wNRn5A@k^myV5{HJ-Y|?+;Zr8<+Se>=r6n=g&m-NwIQ<6$Q)KQC<$=1Or=syZ zWXkGc=m}t_kB8$um`{6RFvgcFprALWY+{~dL@r7|f`F%Szp1X;Gv$4l1}9=Ttd}W?nCA%{^vOi!su$I!U|mnN zTnRGEb(7Ex+P~P54ysDUNbNY&97=nqVi0wvVsF?e@1){24F<@+PQ^46bjbJ_m;l-> zK6G2=zKZifbQmeP4*i7QMgRVVvK%7&&&26&a6;y!;~Y>WePS+d(7;5qvv8O&nCRD8 z818n;qKF??ubC5rWK$L{6!dnMDxOysVn0=v*$Xj3osk;@)%TG_n*bGLz+~LR_Z7K&mZKcO*w%F2TXQVK6}%9tL+h zT80s@O?H%Fl81WKqX~6oWgB4(8$C@b=I!!6;VP3_E~-R7h@?%GN^z<@REZw}MA5?S zN@y0*c9eaeV=6yxHW4(pN>NRhzpKJ==9mbzuSYQ?atIT-PnId>x;wAE%cH|wRPXV~ zgP;b(+=ug46R#r0)!_3GL-rahh79?S8eC&mymAg;ydqzD0Hfi!tUrL=IM~(agV@L+ zhD-)m&vbRqbre4le1u*~T?a83?n}$(cuP~Nv^p$M59o?Ij4`U(srfVR)$Z}x4x0BB zPKOCne#Nm#qAT^7u3B!&34GH{^_*`SF+`idR438RMitbt6mUkVo+HPe!DSfedK|ix zzpa|nmSZ39)UDhxf*Eq?+jB~^mTsL>jiW*iYQmH7;(9jAC-f<-_Nn;GYWhr&*~3D= z@jCyHaipogJ~0`K>^42!wrE~Ku44w-0&rh(Y7&Kn7Qh0FNRWTxH}csL?$2U~oO+Jz3!Ciwt8K zYFU-55~i6duD1lzmJ1lG`Ix4_jVRf00Y5}INpG~N%RNu-Yr`t=&a^_vx}moW{M9Ea GqW=Xa4@Hy! delta 2591 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 delta 7008 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 I9hYJM2SSHW*8l(j diff --git a/ui/pages/artists.py b/ui/pages/artists.py index 93be5746..a33d0eb2 100644 --- a/ui/pages/artists.py +++ b/ui/pages/artists.py @@ -3069,6 +3069,11 @@ class ArtistsPage(QWidget): else: logger.info("💡 Automatic database update completed - no new content found") + # Refresh database statistics in the dashboard to update live display + if hasattr(self, 'main_window') and hasattr(self.main_window, 'dashboard_page'): + self.main_window.dashboard_page.refresh_database_statistics() + logger.info("📊 Refreshed dashboard database statistics after auto update") + # Clean up the worker if hasattr(self, '_auto_database_worker'): self._auto_database_worker.deleteLater() diff --git a/ui/pages/sync.py b/ui/pages/sync.py index babedeaf..2c2976f1 100644 --- a/ui/pages/sync.py +++ b/ui/pages/sync.py @@ -2080,6 +2080,11 @@ class SyncPage(QWidget): else: logger.info("💡 Automatic database update completed - no new content found") + # Refresh database statistics in the dashboard to update live display + if hasattr(self, 'main_window') and hasattr(self.main_window, 'dashboard_page'): + self.main_window.dashboard_page.refresh_database_statistics() + logger.info("📊 Refreshed dashboard database statistics after auto update") + # Clean up the worker if hasattr(self, '_auto_database_worker'): self._auto_database_worker.deleteLater()