mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
Implement user soft-delete and improve search ranking
Adds soft-delete support for local users, including backend, API, and UI changes to allow admins to delete local users while preserving their requests. Updates user queries to exclude deleted users and allows username reuse for deleted accounts. Refines search and ranking logic for torrents: uses title-only queries for broader results, increases max results to 100, applies a minimum score threshold (30/100), and logs detailed ranking breakdowns. Updates the ranking algorithm to prioritize title/author match, adjusts scoring weights, and improves BookDate compatibility with Audiobookshelf by disabling rating-based features when unsupported. Enhances file copy operations for large files, improves metadata tagging, and updates documentation to reflect new search and ranking strategies.
This commit is contained in:
@@ -21,6 +21,11 @@ export function SettingsWidget({ isOpen, onClose, isOnboarding = false, onOnboar
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||
const [backendCapabilities, setBackendCapabilities] = useState<{
|
||||
supportsRatings: boolean;
|
||||
}>({
|
||||
supportsRatings: true, // Default assume Plex
|
||||
});
|
||||
|
||||
// Load current preferences
|
||||
useEffect(() => {
|
||||
@@ -48,6 +53,7 @@ export function SettingsWidget({ isOpen, onClose, isOnboarding = false, onOnboar
|
||||
const data = await response.json();
|
||||
setLibraryScope(data.libraryScope || 'full');
|
||||
setCustomPrompt(data.customPrompt || '');
|
||||
setBackendCapabilities(data.backendCapabilities || { supportsRatings: true });
|
||||
} catch (error: any) {
|
||||
console.error('Load preferences error:', error);
|
||||
setError(error.message || 'Failed to load preferences');
|
||||
@@ -186,24 +192,34 @@ export function SettingsWidget({ isOpen, onClose, isOnboarding = false, onOnboar
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className={`flex items-start p-4 border-2 rounded-lg cursor-pointer transition-all hover:bg-gray-50 dark:hover:bg-gray-700/50 ${libraryScope === 'rated' ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20' : 'border-gray-200 dark:border-gray-600'}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="libraryScope"
|
||||
value="rated"
|
||||
checked={libraryScope === 'rated'}
|
||||
onChange={(e) => setLibraryScope(e.target.value as 'full' | 'rated')}
|
||||
className="mt-1 h-4 w-4 text-blue-600 focus:ring-blue-500"
|
||||
/>
|
||||
<div className="ml-3 flex-1">
|
||||
<div className="font-medium text-gray-900 dark:text-white">
|
||||
Rated Books Only
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400 mt-1">
|
||||
Only consider books you've rated for recommendations
|
||||
{/* Show "Rated Books Only" only if backend supports it */}
|
||||
{backendCapabilities.supportsRatings && (
|
||||
<label className={`flex items-start p-4 border-2 rounded-lg cursor-pointer transition-all hover:bg-gray-50 dark:hover:bg-gray-700/50 ${libraryScope === 'rated' ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20' : 'border-gray-200 dark:border-gray-600'}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="libraryScope"
|
||||
value="rated"
|
||||
checked={libraryScope === 'rated'}
|
||||
onChange={(e) => setLibraryScope(e.target.value as 'full' | 'rated')}
|
||||
className="mt-1 h-4 w-4 text-blue-600 focus:ring-blue-500"
|
||||
/>
|
||||
<div className="ml-3 flex-1">
|
||||
<div className="font-medium text-gray-900 dark:text-white">
|
||||
Rated Books Only
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400 mt-1">
|
||||
Only consider books you've rated for recommendations
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
||||
{/* Show info message if ratings not supported */}
|
||||
{!backendCapabilities.supportsRatings && (
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400 mt-2 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg">
|
||||
Note: Your backend does not support user ratings. Only "Full Library" scope is available.
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -192,8 +192,16 @@ export function InteractiveTorrentSearchModal({
|
||||
{result.rank}
|
||||
</td>
|
||||
<td className="px-3 py-3 text-sm text-gray-900 dark:text-gray-100">
|
||||
<div className="max-w-xs lg:max-w-md truncate" title={result.title}>
|
||||
{result.title}
|
||||
<div className="max-w-xs lg:max-w-md truncate">
|
||||
<a
|
||||
href={result.guid}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:underline"
|
||||
title={result.title}
|
||||
>
|
||||
{result.title}
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex gap-2 mt-1 flex-wrap">
|
||||
{result.format && (
|
||||
|
||||
Reference in New Issue
Block a user