Files
Azornes-Comfyui-Model-Resolver/web/resolver/utils/url_utils.js
T

108 lines
3.6 KiB
JavaScript

/**
* URL Utilities for Model Resolver
*/
import { getSourceKeyFromText } from './source_labels.js';
/**
* Resolve a supported provider key from a URL host.
* @param {string} value
* @param {{fallbackToText?: boolean}} options
* @returns {string}
*/
export function getSourceKeyFromUrl(value, { fallbackToText = false } = {}) {
const url = String(value || '').trim();
if (!url) return '';
try {
const baseUrl = globalThis.location?.origin || 'http://localhost';
const parsed = new URL(url, baseUrl);
const host = parsed.hostname.toLowerCase().replace(/^www\./, '');
if (host === 'huggingface.co' || host.endsWith('.huggingface.co')) return 'huggingface';
if (host === 'civarchive.com' || host.endsWith('.civarchive.com')) return 'civarchive';
if (host === 'civitai.com' || host.endsWith('.civitai.com') || host === 'civitai.red' || host.endsWith('.civitai.red')) return 'civitai';
} catch {
// Preserve the caller's optional text fallback for malformed URLs.
}
return fallbackToText ? getSourceKeyFromText(url) : '';
}
/**
* Parse a Hugging Face blob/resolve file URL into repository coordinates.
* @param {string} value
* @returns {{repo: string, revision: string, path: string, filename: string}|null}
*/
export function parseHuggingFaceFileUrl(value) {
if (!value) return null;
try {
const url = new URL(String(value));
const host = url.hostname.toLowerCase().replace(/^www\./, '');
if (host !== 'huggingface.co') return null;
const parts = url.pathname.split('/').filter(Boolean);
if (parts.length < 5 || !['resolve', 'blob'].includes(parts[2])) {
return null;
}
const decodePart = part => decodeURIComponent(part);
const repo = `${decodePart(parts[0])}/${decodePart(parts[1])}`;
const revision = decodePart(parts[3]);
const path = parts.slice(4).map(decodePart).join('/');
if (!repo || !revision || !path) return null;
return {
repo,
revision,
path,
filename: path.split('/').pop() || ''
};
} catch {
return null;
}
}
/**
* Parses the download URL and returns the model card URL.
* Supports HuggingFace and CivitAI platforms.
* @param {string} downloadUrl
* @returns {string|null} Model card URL or null on failure
*/
export function getModelCardUrl(downloadUrl) {
if (!downloadUrl) return null;
try {
// HuggingFace URLs
if (downloadUrl.includes('huggingface.co')) {
const file = parseHuggingFaceFileUrl(downloadUrl);
if (file) {
const encodedRevision = encodeURIComponent(file.revision);
const encodedPath = file.path
.split('/')
.map(part => encodeURIComponent(part))
.join('/');
return `https://huggingface.co/${file.repo}/blob/${encodedRevision}/${encodedPath}`;
}
const match = downloadUrl.match(/huggingface\.co\/([^/]+\/[^/]+)/);
if (match) {
return `https://huggingface.co/${match[1]}`;
}
}
// CivitAI URLs
if (downloadUrl.includes('civitai.com')) {
// Format: /api/download/models/123456 or /models/123456/...
const modelIdMatch = downloadUrl.match(/models\/(\d+)/);
if (modelIdMatch) {
return `https://civitai.com/models/${modelIdMatch[1]}`;
}
}
} catch (e) {
console.error('Error parsing model card URL:', e);
}
return null;
}