feat: Add regex-based stream sorting with API key protection (#156)

* feat: add regex-based stream sorting with API key protection

* refactor: optimize regex matching for stream sorting

* fix: add set regex sort pattern in loadFromConfig
This commit is contained in:
Vidhin
2025-05-02 19:03:14 -05:00
committed by GitHub
parent b7e512b3d9
commit d4db3aff2b
4 changed files with 69 additions and 0 deletions
+23
View File
@@ -740,6 +740,29 @@ export class AIOStreams {
(resolution) => resolution[b.resolution]
)
);
} else if (field === 'regexSort') {
if (!this.config.regexSortPattern) return 0;
try {
const regex = new RegExp(this.config.regexSortPattern);
const aMatch = a.filename ? regex.test(a.filename) : false;
const bMatch = b.filename ? regex.test(b.filename) : false;
// If both match or both don't match, they are equal
if ((aMatch && bMatch) || (!aMatch && !bMatch)) return 0;
// If one matches and the other doesn't, use direction to determine order
const direction = this.config.sortBy.find((sort) => Object.keys(sort)[0] === 'regexSort')?.direction;
if (direction === 'asc') {
// In ascending order, matching files come last
return aMatch ? 1 : -1;
} else {
// In descending order, matching files come first
return aMatch ? -1 : 1;
}
} catch (e) {
return 0;
}
} else if (field === 'cached') {
let aCanbeCached = a.provider;
let bCanbeCached = b.provider;
+20
View File
@@ -465,5 +465,25 @@ export function validateConfig(
}
}
if (config.regexSortPattern) {
if (!config.apiKey) {
return createResponse(
false,
'missingApiKey',
'Regex sorting requires an API key to be set'
);
}
try {
new RegExp(config.regexSortPattern);
} catch (e) {
return createResponse(
false,
'invalidRegexSortPattern',
'Invalid regex sort pattern'
);
}
}
return createResponse(true, null, null);
}
@@ -118,6 +118,7 @@ const defaultSortCriteria: SortBy[] = [
{ quality: false },
{ seeders: false, direction: 'desc' },
{ addon: false },
{ regexSort: false, direction: 'desc' },
];
const defaultResolutions: Resolution[] = [
@@ -219,6 +220,7 @@ export default function Configure() {
excludePattern?: string;
includePattern?: string;
}>({});
const [regexSortPattern, setRegexSortPattern] = useState<string>('');
useEffect(() => {
// get config from the server
@@ -284,6 +286,7 @@ export default function Configure() {
excludePattern: regexFilters.excludePattern || undefined,
includePattern: regexFilters.includePattern || undefined
} : undefined,
regexSortPattern: regexSortPattern,
};
return config;
};
@@ -553,6 +556,7 @@ export default function Configure() {
})) || []
);
setRegexFilters(decodedConfig.regexFilters || {});
setRegexSortPattern(decodedConfig.regexSortPattern || '');
setServices(loadValidServices(decodedConfig.services));
setMaxMovieSize(
@@ -1064,6 +1068,27 @@ export default function Configure() {
</div>
)}
{showApiKeyInput && (
<div className={styles.section}>
<h2 style={{ padding: '5px' }}>Regex Sort Pattern</h2>
<p style={{ padding: '5px' }}>
Enter a regex pattern to sort streams. This will sort streams based on whether their filename matches the pattern. Matching files will come first in descending order, and last in ascending order.
</p>
{/* <div className={styles.settingInput}> */}
<input
type="text"
value={regexSortPattern}
onChange={(e) => setRegexSortPattern(e.target.value)}
placeholder="Example: \b(3L|BiZKiT|BLURANiUM)"
style={{
width: '97.5%',
padding: '5px',
marginLeft: '5px',
}}
className={styles.input}
/>
</div>
)}
<div className={styles.section}>
<div className={styles.slidersSetting}>
<div>
+1
View File
@@ -181,6 +181,7 @@ export interface Config {
enabled: boolean;
credentials: { [key: string]: string };
}[];
regexSortPattern?: string;
}
interface BaseOptionDetail {