fix: some bugs

This commit is contained in:
Tom Boullay
2026-04-14 16:57:23 +02:00
parent 3a7a5e2eea
commit 110d64ec33
8 changed files with 37 additions and 34 deletions
+3 -3
View File
@@ -4,8 +4,8 @@ GIT_BRANCH=main
GIT_REPO_URL=https://github.com/your-org/your-repo.git GIT_REPO_URL=https://github.com/your-org/your-repo.git
BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
# Nextcloud Drive (WebDAV) # Nextcloud Drive (public share WebDAV)
NEXTCLOUD_URL=https://cloud.example.com NEXTCLOUD_URL=https://cloud.example.com
NEXTCLOUD_USER=your-nextcloud-username NEXTCLOUD_SHARE_TOKEN=your-public-share-token
NEXTCLOUD_PASSWORD=your-nextcloud-password NEXTCLOUD_SHARE_PASSWORD=
NEXTCLOUD_BASE_PATH=Models NEXTCLOUD_BASE_PATH=Models
+6 -7
View File
@@ -36,10 +36,10 @@ GIT_BRANCH=main
GIT_REPO_URL=https://github.com/your-org/your-repo.git GIT_REPO_URL=https://github.com/your-org/your-repo.git
BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
# Nextcloud Drive (WebDAV) # Nextcloud Drive (public share WebDAV)
NEXTCLOUD_URL=https://cloud.example.com NEXTCLOUD_URL=https://cloud.example.com
NEXTCLOUD_USER=your-nextcloud-username NEXTCLOUD_SHARE_TOKEN=your-public-share-token
NEXTCLOUD_PASSWORD=your-nextcloud-password NEXTCLOUD_SHARE_PASSWORD=
NEXTCLOUD_BASE_PATH=Models NEXTCLOUD_BASE_PATH=Models
``` ```
@@ -51,8 +51,8 @@ NEXTCLOUD_BASE_PATH=Models
| `GIT_REPO_URL` | Target GitHub repository URL | Yes | | `GIT_REPO_URL` | Target GitHub repository URL | Yes |
| `BLENDER_PATH` | Path to Blender binary (default: `blender`) | No | | `BLENDER_PATH` | Path to Blender binary (default: `blender`) | No |
| `NEXTCLOUD_URL` | Nextcloud instance URL | Yes | | `NEXTCLOUD_URL` | Nextcloud instance URL | Yes |
| `NEXTCLOUD_USER` | Nextcloud username (Basic auth) | Yes | | `NEXTCLOUD_SHARE_TOKEN` | Public share token (the part after `/s/` in the share link) | Yes |
| `NEXTCLOUD_PASSWORD` | Nextcloud password (Basic auth) | Yes | | `NEXTCLOUD_SHARE_PASSWORD` | Public share password (empty if none) | No |
| `NEXTCLOUD_BASE_PATH` | Root folder on the Drive (default: `Models`) | No | | `NEXTCLOUD_BASE_PATH` | Root folder on the Drive (default: `Models`) | No |
> To create a GitHub token: GitHub > Settings > Developer settings > Fine-grained personal access tokens > select the target repo > Permissions > Contents: Read and write. > To create a GitHub token: GitHub > Settings > Developer settings > Fine-grained personal access tokens > select the target repo > Permissions > Contents: Read and write.
@@ -78,8 +78,7 @@ docker run -p 3000:3000 \
-e GITHUB_TOKEN=ghp_xxx \ -e GITHUB_TOKEN=ghp_xxx \
-e GIT_REPO_URL=https://github.com/org/repo.git \ -e GIT_REPO_URL=https://github.com/org/repo.git \
-e NEXTCLOUD_URL=https://cloud.example.com \ -e NEXTCLOUD_URL=https://cloud.example.com \
-e NEXTCLOUD_USER=user \ -e NEXTCLOUD_SHARE_TOKEN=your-share-token \
-e NEXTCLOUD_PASSWORD=pass \
upload-gltf upload-gltf
``` ```
+2 -2
View File
@@ -35,9 +35,9 @@ export async function POST(req: NextRequest) {
if (authError) return authError if (authError) return authError
// --- Check Nextcloud config --- // --- Check Nextcloud config ---
if (!process.env.NEXTCLOUD_URL || !process.env.NEXTCLOUD_USER || !process.env.NEXTCLOUD_PASSWORD) { if (!process.env.NEXTCLOUD_URL || !process.env.NEXTCLOUD_SHARE_TOKEN) {
return NextResponse.json( return NextResponse.json(
{ success: false, error: 'Nextcloud non configure sur le serveur' }, { success: false, error: 'Nextcloud non configure sur le serveur (NEXTCLOUD_URL, NEXTCLOUD_SHARE_TOKEN)' },
{ status: 500 }, { status: 500 },
) )
} }
+4 -2
View File
@@ -108,9 +108,11 @@ export async function POST(req: NextRequest) {
const isModel = MODEL_EXTENSIONS.has(ext) const isModel = MODEL_EXTENSIONS.has(ext)
if (isModel) { if (isModel) {
// Model: always re-push since compression makes size comparison unreliable // Model: always re-push since compression makes size comparison unreliable.
// Mark as 'unchanged' for the commit message when the folder already exists,
// because we can't know if the model really changed after Blender compression.
const remoteSize = remoteFileMap.get(filename.toLowerCase()) const remoteSize = remoteFileMap.get(filename.toLowerCase())
fileChanges.set(filename.toLowerCase(), remoteSize === undefined ? 'new' : 'changed') fileChanges.set(filename.toLowerCase(), remoteSize === undefined ? 'new' : 'unchanged')
changedFilesToPush.push(f) changedFilesToPush.push(f)
} else { } else {
// Texture: compare by size // Texture: compare by size
+3 -5
View File
@@ -278,7 +278,7 @@ export default function UploadZone() {
// ---- Step 1: Drive upload ---- // ---- Step 1: Drive upload ----
updateEntry(i, { updateEntry(i, {
status: 'uploading', status: 'uploading',
progress: 0, progress: 1,
error: undefined, error: undefined,
driveStatus: 'uploading', driveStatus: 'uploading',
driveError: undefined, driveError: undefined,
@@ -300,7 +300,7 @@ export default function UploadZone() {
return return
} }
updateEntry(i, { driveStatus: 'success' }) updateEntry(i, { driveStatus: 'success', progress: 50 })
// ---- Step 2: Git upload ---- // ---- Step 2: Git upload ----
await pushGit(i, controller.signal) await pushGit(i, controller.signal)
@@ -314,13 +314,11 @@ export default function UploadZone() {
const pushGit = async (index: number, signal?: AbortSignal) => { const pushGit = async (index: number, signal?: AbortSignal) => {
const folderEntry = entries[index] const folderEntry = entries[index]
updateEntry(index, { progress: 5 })
const gitResult = await uploadGit( const gitResult = await uploadGit(
folderEntry, folderEntry,
secret, secret,
destination!, destination!,
(pct) => updateEntry(index, { progress: pct }), (pct) => updateEntry(index, { progress: 50 + Math.round(pct / 2) }),
signal, signal,
) )
+8 -7
View File
@@ -62,7 +62,7 @@ export default function FolderCard({ entry, index, onToggleViewer, onRemove }: F
<span className="shrink-0 text-xs px-1.5 py-0.5 rounded-full bg-gray-700 text-gray-300">Dossier</span> <span className="shrink-0 text-xs px-1.5 py-0.5 rounded-full bg-gray-700 text-gray-300">Dossier</span>
</div> </div>
<div className="flex items-center gap-2 mt-0.5"> <div className="flex items-center gap-2 mt-0.5">
<span className="text-xs text-gray-500">modele : {entry.modelFile.name}</span> <span className="text-xs text-gray-500">model : {entry.modelFile.name}</span>
{entry.status === 'error' && entry.error && ( {entry.status === 'error' && entry.error && (
<span className="text-xs text-red-400 truncate">{entry.error}</span> <span className="text-xs text-red-400 truncate">{entry.error}</span>
)} )}
@@ -71,8 +71,8 @@ export default function FolderCard({ entry, index, onToggleViewer, onRemove }: F
)} )}
</div> </div>
{/* Drive status sub-line */} {/* Drive status sub-line (only during upload, not after success) */}
{entry.driveStatus && entry.driveStatus !== 'pending' && ( {entry.status !== 'success' && entry.driveStatus && entry.driveStatus !== 'pending' && (
<div className="flex items-center gap-1.5 mt-0.5"> <div className="flex items-center gap-1.5 mt-0.5">
{entry.driveStatus === 'uploading' && ( {entry.driveStatus === 'uploading' && (
<> <>
@@ -80,15 +80,16 @@ export default function FolderCard({ entry, index, onToggleViewer, onRemove }: F
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" /> <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg> </svg>
<span className="text-xs text-gray-400">Drive en cours...</span> <span className="text-xs text-gray-400">Upload Drive en cours...</span>
</> </>
)} )}
{entry.driveStatus === 'success' && ( {entry.driveStatus === 'success' && (
<> <>
<svg className="w-3 h-3 text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}> <svg className="w-3 h-3 text-gray-400 animate-spin" fill="none" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg> </svg>
<span className="text-xs text-green-400">Drive OK</span> <span className="text-xs text-gray-400">Upload Git en cours...</span>
</> </>
)} )}
{entry.driveStatus === 'error' && ( {entry.driveStatus === 'error' && (
+4 -1
View File
@@ -26,7 +26,7 @@ export function buildCommitMessage(
const lines: string[] = [title, ''] const lines: string[] = [title, '']
// Model section — only show if changed or new // Model section — show status for new, changed, or unchanged
const modelChange = fileChanges.get(modelFilename.toLowerCase()) const modelChange = fileChanges.get(modelFilename.toLowerCase())
if (modelChange === 'new') { if (modelChange === 'new') {
lines.push('📦 Model') lines.push('📦 Model')
@@ -34,6 +34,9 @@ export function buildCommitMessage(
} else if (modelChange === 'changed') { } else if (modelChange === 'changed') {
lines.push('📦 Model') lines.push('📦 Model')
lines.push(` 🔄 ${modelFilename}${compressed ? ' (compressed)' : ''}`) lines.push(` 🔄 ${modelFilename}${compressed ? ' (compressed)' : ''}`)
} else if (modelChange === 'unchanged') {
lines.push('📦 Model')
lines.push(` ↔️ ${modelFilename} (inchange)`)
} }
// Textures section — only show lines that have changes // Textures section — only show lines that have changes
+7 -7
View File
@@ -5,17 +5,17 @@
function getConfig() { function getConfig() {
const url = process.env.NEXTCLOUD_URL const url = process.env.NEXTCLOUD_URL
const user = process.env.NEXTCLOUD_USER const token = process.env.NEXTCLOUD_SHARE_TOKEN
const password = process.env.NEXTCLOUD_PASSWORD const password = process.env.NEXTCLOUD_SHARE_PASSWORD || ''
const basePath = process.env.NEXTCLOUD_BASE_PATH || 'Models' const basePath = process.env.NEXTCLOUD_BASE_PATH || 'Models'
if (!url || !user || !password) { if (!url || !token) {
throw new Error('Nextcloud non configure (NEXTCLOUD_URL, NEXTCLOUD_USER, NEXTCLOUD_PASSWORD)') throw new Error('Nextcloud non configure (NEXTCLOUD_URL, NEXTCLOUD_SHARE_TOKEN)')
} }
// WebDAV base: https://cloud.example.com/remote.php/dav/files/{user}/ // Public share WebDAV: https://cloud.example.com/public.php/webdav/
const davBase = `${url.replace(/\/+$/, '')}/remote.php/dav/files/${encodeURIComponent(user)}` const davBase = `${url.replace(/\/+$/, '')}/public.php/webdav`
const auth = 'Basic ' + Buffer.from(`${user}:${password}`).toString('base64') const auth = 'Basic ' + Buffer.from(`${token}:${password}`).toString('base64')
return { davBase, auth, basePath } return { davBase, auth, basePath }
} }