@@ -711,8 +711,6 @@ def set_cwa_settings():
711711 int_value = max (500 , min (50000 , int_value ))
712712 elif setting == 'duplicate_scan_debounce_seconds' :
713713 int_value = max (5 , min (600 , int_value ))
714- elif setting == 'duplicate_auto_resolve_cooldown_minutes' :
715- int_value = max (0 , min (1440 , int_value )) # Clamp between 0 and 1440 minutes (24 hours)
716714 result [setting ] = int_value
717715 except (ValueError , TypeError ):
718716 # Use current value if conversion fails
@@ -726,8 +724,6 @@ def set_cwa_settings():
726724 result [setting ] = cwa_db .cwa_settings .get (setting , 2 ) # Default to 2 AM
727725 elif setting == 'duplicate_scan_debounce_seconds' :
728726 result [setting ] = cwa_db .cwa_settings .get (setting , 30 )
729- elif setting == 'duplicate_auto_resolve_cooldown_minutes' :
730- result [setting ] = cwa_db .cwa_settings .get (setting , 0 ) # Default to 0 (disabled)
731727 else :
732728 if setting == 'ingest_timeout_minutes' :
733729 result [setting ] = cwa_db .cwa_settings .get (setting , 15 ) # Default to 15 minutes
@@ -739,8 +735,6 @@ def set_cwa_settings():
739735 result [setting ] = cwa_db .cwa_settings .get (setting , 2 ) # Default to 2 AM
740736 elif setting == 'duplicate_scan_debounce_seconds' :
741737 result [setting ] = cwa_db .cwa_settings .get (setting , 30 )
742- elif setting == 'duplicate_auto_resolve_cooldown_minutes' :
743- result [setting ] = cwa_db .cwa_settings .get (setting , 0 ) # Default to 0 (disabled)
744738
745739 # Handle float settings
746740 for setting in float_settings :
@@ -2047,283 +2041,3 @@ def set_profile_picture():
20472041 return render_title_template ("profile_pictures.html" ,
20482042 title = _ ("CWA Profile Picture Management (WIP)" ),
20492043 page = "profile-picture" )
2050-
2051-
2052- # ========================================
2053- # Full Text Search (FTS) Management
2054- # ========================================
2055-
2056- def _get_fts_status_from_calibredb ():
2057- """
2058- Get FTS indexing status from calibredb.
2059- Returns dict with: enabled, indexed, total, percentage, error
2060- """
2061- from .admin import get_calibre_binarypath
2062-
2063- result = {
2064- 'enabled' : False ,
2065- 'indexed' : 0 ,
2066- 'total' : 0 ,
2067- 'percentage' : 0.0 ,
2068- 'error' : None
2069- }
2070-
2071- if not config .config_calibre_dir :
2072- result ['error' ] = _ ('No library path configured' )
2073- return result
2074-
2075- calibredb_path = get_calibre_binarypath ("calibredb" )
2076- if not calibredb_path or not os .path .isfile (calibredb_path ):
2077- result ['error' ] = _ ('calibredb not found' )
2078- return result
2079-
2080- try :
2081- # Set up environment with LD_LIBRARY_PATH for Calibre libraries
2082- env = os .environ .copy ()
2083- env ['LD_LIBRARY_PATH' ] = '/app/calibre/lib'
2084-
2085- # Run calibredb fts_index status
2086- cmd = [calibredb_path , 'fts_index' , 'status' , '--library-path' , config .config_calibre_dir ]
2087- proc_result = subprocess .run (
2088- cmd ,
2089- stdout = subprocess .PIPE ,
2090- stderr = subprocess .PIPE ,
2091- text = True ,
2092- timeout = 10 ,
2093- env = env
2094- )
2095-
2096- # Exit code 0 = enabled, exit code 2 = disabled (both are valid responses)
2097- if proc_result .returncode in [0 , 2 ]:
2098- output = proc_result .stdout .strip ()
2099-
2100- # Check if enabled or disabled
2101- if 'disabled' in output .lower ():
2102- result ['enabled' ] = False
2103- # When disabled, there are no books to count
2104- result ['indexed' ] = 0
2105- result ['total' ] = 0
2106- result ['percentage' ] = 0.0
2107- return result
2108- elif 'enabled' in output .lower ():
2109- result ['enabled' ] = True
2110-
2111- # Parse "X of Y books" pattern
2112- match = re .search (r'(\d+)\s+of\s+(\d+)\s+books' , output )
2113- if match :
2114- result ['indexed' ] = int (match .group (1 ))
2115- result ['total' ] = int (match .group (2 ))
2116- if result ['total' ] > 0 :
2117- result ['percentage' ] = (result ['indexed' ] / result ['total' ]) * 100
2118- else :
2119- result ['error' ] = proc_result .stderr .strip () or _ ('Failed to get FTS status' )
2120-
2121- except subprocess .TimeoutExpired :
2122- result ['error' ] = _ ('Timeout while checking FTS status' )
2123- except Exception as ex :
2124- result ['error' ] = str (ex )
2125- log .error (f"Error getting FTS status: { ex } " )
2126-
2127- return result
2128-
2129-
2130- def _initialize_fts_index ():
2131- """
2132- Initialize or disable Full Text Search indexing based on config.
2133- Returns a tuple of (success: bool, message: str or None)
2134- """
2135- from .admin import get_calibre_binarypath
2136-
2137- if not config .config_calibre_dir :
2138- return False , _ ('No library path configured' )
2139-
2140- fts_db_path = os .path .join (config .config_calibre_dir , "full-text-search.db" )
2141-
2142- # If FTS disabled but database exists, disable indexing
2143- if not config .config_fulltext_search and os .path .exists (fts_db_path ):
2144- try :
2145- calibredb_path = get_calibre_binarypath ("calibredb" )
2146- if not calibredb_path or not os .path .isfile (calibredb_path ):
2147- log .warning ("calibredb not found, cannot disable FTS indexing" )
2148- return False , _ ('calibredb not available. Cannot stop FTS indexing.' )
2149-
2150- env = os .environ .copy ()
2151- env ['LD_LIBRARY_PATH' ] = '/app/calibre/lib'
2152-
2153- cmd = [calibredb_path , 'fts_index' , 'disable' , '--library-path' , config .config_calibre_dir ]
2154- log .info ("Disabling FTS index: %s" , ' ' .join (cmd ))
2155-
2156- result = subprocess .run (
2157- cmd ,
2158- input = 'disable\n ' , # Must type "disable" to confirm
2159- stdout = subprocess .PIPE ,
2160- stderr = subprocess .PIPE ,
2161- text = True ,
2162- timeout = 30 ,
2163- env = env
2164- )
2165-
2166- if result .returncode == 0 :
2167- log .info ("FTS indexing disabled successfully" )
2168- return True , _ ('Full Text Search indexing has been disabled and stopped.' )
2169- else :
2170- log .error ("Failed to disable FTS indexing: %s" , result .stderr .strip ())
2171- return False , _ ('Failed to disable FTS indexing: %(error)s' , error = result .stderr .strip ())
2172- except Exception as ex :
2173- log .error ("Failed to disable FTS indexing: %s" , ex )
2174- return False , _ ('Error disabling FTS indexing: %(error)s' , error = str (ex ))
2175-
2176- # If FTS not enabled, nothing to do
2177- if not config .config_fulltext_search :
2178- return True , None
2179-
2180- # Check if FTS database already exists AND is enabled
2181- if os .path .exists (fts_db_path ):
2182- # Check current status to see if it's actually enabled
2183- current_status = _get_fts_status_from_calibredb ()
2184- if current_status ['enabled' ]:
2185- log .debug ("FTS database already exists and is enabled at %s" , fts_db_path )
2186- return True , None
2187- # If disabled, fall through to enable it
2188-
2189- # Try to enable FTS indexing using calibredb
2190- try :
2191- calibredb_path = get_calibre_binarypath ("calibredb" )
2192- if not calibredb_path or not os .path .isfile (calibredb_path ):
2193- log .warning ("calibredb not found, cannot initialize FTS indexing" )
2194- return False , _ ('Full Text Search enabled but calibredb not available. FTS indexing cannot be initialized.' )
2195-
2196- # Run calibredb fts_index enable
2197- env = os .environ .copy ()
2198- env ['LD_LIBRARY_PATH' ] = '/app/calibre/lib'
2199-
2200- cmd = [calibredb_path , 'fts_index' , 'enable' , '--library-path' , config .config_calibre_dir ]
2201- log .info ("Initializing FTS index: %s" , ' ' .join (cmd ))
2202-
2203- result = subprocess .run (
2204- cmd ,
2205- stdout = subprocess .PIPE ,
2206- stderr = subprocess .PIPE ,
2207- text = True ,
2208- timeout = 30 ,
2209- env = env
2210- )
2211-
2212- if result .returncode == 0 :
2213- log .info ("FTS indexing enabled successfully: %s" , result .stdout .strip ())
2214- return True , _ ('Full Text Search indexing enabled. Books are being indexed in the background.' )
2215- else :
2216- log .error ("Failed to enable FTS indexing: %s" , result .stderr .strip ())
2217- return False , _ ('Failed to enable FTS indexing: %(error)s' , error = result .stderr .strip ())
2218-
2219- except Exception as ex :
2220- log .error ("Failed to initialize FTS indexing: %s" , ex )
2221- return False , _ ('Error initializing FTS indexing: %(error)s' , error = str (ex ))
2222-
2223-
2224- @cwa_settings .route ('/fts-status' , methods = ['GET' ])
2225- @login_required_if_no_ano
2226- @admin_required
2227- def get_fts_status ():
2228- """
2229- Get current FTS indexing status.
2230- Returns JSON with status information.
2231- """
2232- status = _get_fts_status_from_calibredb ()
2233-
2234- # Determine if search is available (90% threshold)
2235- status ['available' ] = status ['enabled' ] and status ['percentage' ] >= 90.0
2236-
2237- # Check if indexing is currently active by comparing two sequential checks
2238- # If indexed count changes, indexing is active
2239- if status ['enabled' ] and status ['indexed' ] < status ['total' ]:
2240- sleep (0.5 ) # Brief pause
2241- status2 = _get_fts_status_from_calibredb ()
2242- status ['active' ] = status2 ['indexed' ] > status ['indexed' ]
2243- else :
2244- status ['active' ] = False
2245-
2246- return jsonify (status )
2247-
2248-
2249- @cwa_settings .route ('/fts-action' , methods = ['POST' ])
2250- @csrf .exempt
2251- @login_required_if_no_ano
2252- @admin_required
2253- def fts_action ():
2254- """
2255- Execute FTS actions: enable, disable, reindex.
2256- Returns JSON with success status and message.
2257- """
2258- from .admin import get_calibre_binarypath
2259-
2260- action = request .form .get ('action' )
2261-
2262- if action not in ['enable' , 'disable' , 'reindex' ]:
2263- return jsonify ({'success' : False , 'message' : _ ('Invalid action' )}), 400
2264-
2265- calibredb_path = get_calibre_binarypath ("calibredb" )
2266- if not calibredb_path or not os .path .isfile (calibredb_path ):
2267- return jsonify ({'success' : False , 'message' : _ ('calibredb not available' )}), 500
2268-
2269- if not config .config_calibre_dir :
2270- return jsonify ({'success' : False , 'message' : _ ('No library path configured' )}), 500
2271-
2272- try :
2273- env = os .environ .copy ()
2274- env ['LD_LIBRARY_PATH' ] = '/app/calibre/lib'
2275-
2276- if action == 'enable' :
2277- # Update config
2278- config .config_fulltext_search = True
2279- config .save ()
2280-
2281- # Initialize FTS
2282- success , message = _initialize_fts_index ()
2283- if success :
2284- return jsonify ({'success' : True , 'message' : message or _ ('FTS indexing enabled successfully' )})
2285- else :
2286- return jsonify ({'success' : False , 'message' : message }), 500
2287-
2288- elif action == 'disable' :
2289- # Update config
2290- try :
2291- config .config_fulltext_search = False
2292- config .save ()
2293- log .info ("FTS config setting disabled and saved" )
2294- except Exception as save_ex :
2295- log .error (f"Error saving config during FTS disable: { save_ex } " )
2296- return jsonify ({'success' : False , 'message' : f'Failed to save config: { str (save_ex )} ' }), 500
2297-
2298- # Disable FTS
2299- success , message = _initialize_fts_index ()
2300- if success :
2301- return jsonify ({'success' : True , 'message' : message or _ ('FTS indexing disabled successfully' )})
2302- else :
2303- return jsonify ({'success' : False , 'message' : message }), 500
2304-
2305- elif action == 'reindex' :
2306- if not config .config_fulltext_search :
2307- return jsonify ({'success' : False , 'message' : _ ('FTS must be enabled before reindexing' )}), 400
2308-
2309- cmd = [calibredb_path , 'fts_index' , 'reindex' , '--library-path' , config .config_calibre_dir ]
2310- log .info ("Reindexing FTS: %s" , ' ' .join (cmd ))
2311-
2312- result = subprocess .run (
2313- cmd ,
2314- input = 'reindex\n ' , # Must type "reindex" to confirm
2315- stdout = subprocess .PIPE ,
2316- stderr = subprocess .PIPE ,
2317- text = True ,
2318- timeout = 30 ,
2319- env = env
2320- )
2321-
2322- if result .returncode == 0 :
2323- return jsonify ({'success' : True , 'message' : _ ('FTS reindexing started successfully' )})
2324- else :
2325- return jsonify ({'success' : False , 'message' : result .stderr .strip ()}), 500
2326-
2327- except Exception as ex :
2328- log .error (f"FTS action failed: { ex } " )
2329- return jsonify ({'success' : False , 'message' : str (ex )}), 500
0 commit comments