30a6b080eb
Replace the server-rendered release upload form with a Livewire component, introducing an interactive admin release form that supports dynamic episode management, real‑time CDN path validation, and direct download file checks. Key changes: - New `AdminReleaseForm` Livewire component with dynamic episode fields, Tagify integration, and upload handling via Livewire's file uploads. - Added `CdnPathValidator` service to verify download and stream paths across all configured mirrors, caching results and capturing file sizes. - Extended `EpisodeService` and `GalleryService` to support array‑based data and temporary uploaded files from Livewire. - Persist validated download sizes and store the validation timestamp on the `downloads` table via a new migration; also add a unique constraint on `hentais.slug` to prevent duplicates. - Remove the old POST `/admin/release/upload` route and controller logic, along with the legacy `upload.js` script. - Add comprehensive feature and unit tests covering the new component and the CDN validation service.
67 lines
1.8 KiB
JavaScript
67 lines
1.8 KiB
JavaScript
import Tagify from '@yaireo/tagify';
|
|
import '@yaireo/tagify/dist/tagify.css';
|
|
|
|
document.addEventListener('livewire:init', () => {
|
|
const Alpine = window.Alpine;
|
|
|
|
const dropdownOptions = {
|
|
classname: "color-blue",
|
|
enabled: 0,
|
|
maxItems: 10,
|
|
position: "text",
|
|
closeOnSelect: false,
|
|
highlightFirst: true
|
|
};
|
|
|
|
Alpine.data('adminReleaseTags', () => ({
|
|
tagify: null,
|
|
|
|
init() {
|
|
const el = this.$refs.tags;
|
|
|
|
window.axios.get('/admin/tags').then((response) => {
|
|
if (response.status != 200) {
|
|
return;
|
|
}
|
|
|
|
this.tagify = new Tagify(el, {
|
|
whitelist: response.data.tags,
|
|
dropdown: dropdownOptions
|
|
});
|
|
|
|
this.tagify.on('change', () => {
|
|
this.$wire.set('tags', this.tagify.value.map((t) => t.value));
|
|
});
|
|
}).catch((error) => {
|
|
console.log(error);
|
|
});
|
|
}
|
|
}));
|
|
|
|
Alpine.data('adminReleaseStudio', () => ({
|
|
tagify: null,
|
|
|
|
init() {
|
|
const el = this.$refs.studio;
|
|
|
|
window.axios.get('/admin/studios').then((response) => {
|
|
if (response.status != 200) {
|
|
return;
|
|
}
|
|
|
|
this.tagify = new Tagify(el, {
|
|
whitelist: response.data.studios,
|
|
dropdown: dropdownOptions
|
|
});
|
|
|
|
this.tagify.on('change', () => {
|
|
const values = this.tagify.value.map((t) => t.value);
|
|
this.$wire.set('studio', values.length ? values[values.length - 1] : '');
|
|
});
|
|
}).catch((error) => {
|
|
console.log(error);
|
|
});
|
|
}
|
|
}));
|
|
});
|