feat: Add tag support to qBittorrent (#610)

Added support for adding tag(s) to torrents sent to qBittorrent via
shelfmark.
![Screenshot 2026-02-11 at 3 58
20 AM](https://github.com/user-attachments/assets/aa9b440a-27fd-4166-953b-31f5179688a3)
![Screenshot 2026-02-11 at 3 53
14 AM](https://github.com/user-attachments/assets/15084b44-9a68-493c-85e8-328c92206c85)
This commit is contained in:
arjunsrinivasan1997
2026-02-12 14:52:34 +00:00
committed by GitHub
parent 5bed0b20f4
commit a7064939ce
6 changed files with 76 additions and 15 deletions
@@ -9,7 +9,7 @@ interface TagListFieldProps {
requiredTags?: string[]; // Tags that cannot be removed
}
function normalizeTag(raw: string): string {
function normalizeTag(raw: string, normalizeUrls: boolean): string {
let s = raw.trim();
if (!s) return '';
@@ -21,16 +21,18 @@ function normalizeTag(raw: string): string {
s = s.slice(1, -1).trim();
}
// Avoid special sentinel values.
if (s.toLowerCase() === 'auto') return '';
if (normalizeUrls) {
// Avoid special sentinel values.
if (s.toLowerCase() === 'auto') return '';
// Basic URL normalization to keep UX friendly; backend also normalizes on save.
// Only add https:// if it looks like a domain (contains a dot) and has no protocol.
// This avoids adding prefixes to non-URL values like OIDC scopes (openid, email, etc.)
if (!s.includes('://') && !s.startsWith('/') && s.includes('.')) {
s = `https://${s}`;
// Basic URL normalization to keep UX friendly; backend also normalizes on save.
// Only add https:// if it looks like a domain (contains a dot) and has no protocol.
// This avoids adding prefixes to non-URL values like OIDC scopes (openid, email, etc.)
if (!s.includes('://') && !s.startsWith('/') && s.includes('.')) {
s = `https://${s}`;
}
s = s.replace(/\/+$/, '');
}
s = s.replace(/\/+$/, '');
return s.trim();
}
@@ -39,6 +41,7 @@ export const TagListField = ({ field, value, onChange, disabled, requiredTags }:
const required = requiredTags ?? [];
const inputRef = useRef<HTMLInputElement>(null);
const [draft, setDraft] = useState('');
const normalizeUrls = field.normalizeUrls ?? true;
const tags = useMemo(() => (value ?? []).map(String).filter((t) => t.trim() !== ''), [value]);
@@ -52,7 +55,7 @@ export const TagListField = ({ field, value, onChange, disabled, requiredTags }:
const next = [...tags];
for (const part of parts) {
const normalized = normalizeTag(part);
const normalized = normalizeTag(part, normalizeUrls);
if (!normalized) continue;
if (next.includes(normalized)) continue;
next.push(normalized);
@@ -152,4 +155,3 @@ export const TagListField = ({ field, value, onChange, disabled, requiredTags }:
</div>
);
};
+1
View File
@@ -99,6 +99,7 @@ export interface TagListFieldConfig extends BaseField {
type: 'TagListField';
value: string[];
placeholder?: string;
normalizeUrls?: boolean;
}
// OrderableListField types - generic drag-and-drop reorderable list