feat: ajout de la gestion des sources de contenu avec création de composants, formulaires et API pour l'importation, l'exportation et la configuration des sources de scraping.
This commit is contained in:
parent
32b4e4fbb2
commit
dac2f91998
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Types de scraping disponibles
|
||||
*/
|
||||
export const SCRAPING_TYPES = {
|
||||
HTML: 'html',
|
||||
JAVASCRIPT: 'javascript'
|
||||
};
|
||||
|
||||
/**
|
||||
* Orientations de lecture
|
||||
*/
|
||||
export const READING_ORIENTATIONS = {
|
||||
VERTICAL: 'vertical',
|
||||
HORIZONTAL: 'horizontal'
|
||||
};
|
||||
|
||||
/**
|
||||
* États des sources
|
||||
*/
|
||||
export const SOURCE_STATUS = {
|
||||
ACTIVE: 'active',
|
||||
INACTIVE: 'inactive',
|
||||
ERROR: 'error'
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration par défaut pour une nouvelle source
|
||||
*/
|
||||
export const DEFAULT_SOURCE_CONFIG = {
|
||||
baseUrl: '',
|
||||
chapterUrlFormat: '',
|
||||
scrapingType: SCRAPING_TYPES.HTML,
|
||||
imageSelector: '',
|
||||
nextPageSelector: '',
|
||||
chapterSelector: '',
|
||||
token: ''
|
||||
};
|
||||
|
||||
/**
|
||||
* Validateurs pour les champs
|
||||
*/
|
||||
export const VALIDATORS = {
|
||||
URL_PATTERN: /^https?:\/\/.+/,
|
||||
SELECTOR_PATTERN: /^[.#]?[\w\-\s.#\[\]=\"':()>+~,]+$/
|
||||
};
|
||||
|
||||
/**
|
||||
* Messages d'erreur
|
||||
*/
|
||||
export const ERROR_MESSAGES = {
|
||||
INVALID_URL: 'L\'URL doit commencer par http:// ou https://',
|
||||
INVALID_SELECTOR: 'Le sélecteur CSS n\'est pas valide',
|
||||
REQUIRED_FIELD: 'Ce champ est obligatoire',
|
||||
CHAPTER_URL_FORMAT_REQUIRED: 'Le format d\'URL des chapitres est obligatoire'
|
||||
};
|
||||
116
assets/vue/app/domain/setting/domain/models/ContentSource.js
Normal file
116
assets/vue/app/domain/setting/domain/models/ContentSource.js
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Modèle représentant une source de contenu pour le scraping
|
||||
*/
|
||||
export class ContentSource {
|
||||
constructor({
|
||||
id = null,
|
||||
baseUrl = '',
|
||||
chapterUrlFormat = '',
|
||||
scrapingType = 'HTML',
|
||||
imageSelector = null,
|
||||
nextPageSelector = null,
|
||||
chapterSelector = null,
|
||||
cleanBaseUrl = '',
|
||||
token = null
|
||||
} = {}) {
|
||||
this.id = id;
|
||||
this.baseUrl = baseUrl;
|
||||
this.chapterUrlFormat = chapterUrlFormat;
|
||||
this.scrapingType = scrapingType;
|
||||
this.imageSelector = imageSelector;
|
||||
this.nextPageSelector = nextPageSelector;
|
||||
this.chapterSelector = chapterSelector;
|
||||
this.cleanBaseUrl = cleanBaseUrl || this.extractCleanBaseUrl(baseUrl);
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrait une URL propre à partir de l'URL de base
|
||||
*/
|
||||
extractCleanBaseUrl(url) {
|
||||
if (!url) return '';
|
||||
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
return urlObj.hostname;
|
||||
} catch (error) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la source est valide
|
||||
*/
|
||||
isValid() {
|
||||
return !!(this.baseUrl && this.chapterUrlFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la source est de type JavaScript
|
||||
*/
|
||||
isJavascriptSource() {
|
||||
return this.scrapingType === 'Javascript';
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la source est de type HTML
|
||||
*/
|
||||
isHtmlSource() {
|
||||
return this.scrapingType === 'HTML';
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine l'orientation basée sur les sélecteurs
|
||||
*/
|
||||
getOrientation() {
|
||||
return this.nextPageSelector ? 'vertical' : 'horizontal';
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère une URL de chapitre basée sur le format
|
||||
*/
|
||||
generateChapterUrl(slug, chapterNumber) {
|
||||
return this.chapterUrlFormat
|
||||
.replace('{slug}', slug)
|
||||
.replace('{chapterNumber}', chapterNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit l'objet en format API
|
||||
*/
|
||||
toApiFormat() {
|
||||
return {
|
||||
baseUrl: this.baseUrl,
|
||||
chapterUrlFormat: this.chapterUrlFormat,
|
||||
scrapingType: this.scrapingType,
|
||||
imageSelector: this.imageSelector,
|
||||
nextPageSelector: this.nextPageSelector,
|
||||
chapterSelector: this.chapterSelector,
|
||||
token: this.token
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une instance depuis les données API
|
||||
*/
|
||||
static fromApiData(data) {
|
||||
return new ContentSource(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone l'instance
|
||||
*/
|
||||
clone() {
|
||||
return new ContentSource({
|
||||
id: this.id,
|
||||
baseUrl: this.baseUrl,
|
||||
chapterUrlFormat: this.chapterUrlFormat,
|
||||
scrapingType: this.scrapingType,
|
||||
imageSelector: this.imageSelector,
|
||||
nextPageSelector: this.nextPageSelector,
|
||||
chapterSelector: this.chapterSelector,
|
||||
cleanBaseUrl: this.cleanBaseUrl,
|
||||
token: this.token
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user