Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
MBetterd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mbetter
MBetterd
Commits
5c9c82a2
Commit
5c9c82a2
authored
Sep 26, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'refs/remotes/origin/master'
parents
19895c99
9f0510d0
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
166 additions
and
63 deletions
+166
-63
fixture_detail.html
app/templates/main/fixture_detail.html
+108
-40
match_detail.html
app/templates/main/match_detail.html
+54
-20
routes.py
app/upload/routes.py
+4
-3
No files found.
app/templates/main/fixture_detail.html
View file @
5c9c82a2
...
@@ -534,8 +534,10 @@
...
@@ -534,8 +534,10 @@
function
uploadFileInChunks
(
file
,
matchId
)
{
function
uploadFileInChunks
(
file
,
matchId
)
{
const
totalChunks
=
Math
.
ceil
(
file
.
size
/
CHUNK_SIZE
);
const
totalChunks
=
Math
.
ceil
(
file
.
size
/
CHUNK_SIZE
);
const
uploadId
=
Date
.
now
()
+
'_'
+
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
);
const
uploadId
=
Date
.
now
()
+
'_'
+
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
);
const
maxConcurrent
=
3
;
// Upload up to 3 chunks simultaneously
let
currentChunk
=
0
;
let
uploadedChunks
=
0
;
let
failed
=
false
;
// Show progress bar and hide upload form
// Show progress bar and hide upload form
const
uploadForm
=
document
.
getElementById
(
`upload_form_
${
matchId
}
`
);
const
uploadForm
=
document
.
getElementById
(
`upload_form_
${
matchId
}
`
);
...
@@ -548,48 +550,80 @@
...
@@ -548,48 +550,80 @@
statusDiv
.
className
=
'upload-status uploading'
;
statusDiv
.
className
=
'upload-status uploading'
;
statusDiv
.
textContent
=
'Uploading... 0%'
;
statusDiv
.
textContent
=
'Uploading... 0%'
;
function
uploadChunk
()
{
function
uploadChunk
(
chunkIndex
)
{
if
(
currentChunk
>=
totalChunks
)
{
if
(
failed
)
return
;
// All chunks uploaded, finalize
finalizeUpload
(
uploadId
,
file
.
name
,
matchId
);
return
;
}
const
start
=
c
urrentChunk
*
CHUNK_SIZE
;
const
start
=
c
hunkIndex
*
CHUNK_SIZE
;
const
end
=
Math
.
min
(
start
+
CHUNK_SIZE
,
file
.
size
);
const
end
=
Math
.
min
(
start
+
CHUNK_SIZE
,
file
.
size
);
const
chunk
=
file
.
slice
(
start
,
end
);
const
chunk
=
file
.
slice
(
start
,
end
);
const
formData
=
new
FormData
();
const
formData
=
new
FormData
();
formData
.
append
(
'chunk'
,
chunk
);
formData
.
append
(
'chunk'
,
chunk
);
formData
.
append
(
'chunkIndex'
,
c
urrentChunk
);
formData
.
append
(
'chunkIndex'
,
c
hunkIndex
);
formData
.
append
(
'totalChunks'
,
totalChunks
);
formData
.
append
(
'totalChunks'
,
totalChunks
);
formData
.
append
(
'uploadId'
,
uploadId
);
formData
.
append
(
'uploadId'
,
uploadId
);
formData
.
append
(
'fileName'
,
file
.
name
);
formData
.
append
(
'fileName'
,
file
.
name
);
formData
.
append
(
'matchId'
,
matchId
);
formData
.
append
(
'matchId'
,
matchId
);
fetch
(
'/upload/chunk'
,
{
return
fetch
(
'/upload/chunk'
,
{
method
:
'POST'
,
method
:
'POST'
,
body
:
formData
body
:
formData
})
})
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
.
then
(
data
=>
{
if
(
data
.
success
)
{
if
(
!
data
.
success
)
{
currentChunk
++
;
const
progress
=
(
currentChunk
/
totalChunks
)
*
100
;
updateProgress
(
matchId
,
Math
.
round
(
progress
));
statusDiv
.
textContent
=
`Uploading...
${
Math
.
round
(
progress
)}
%`
;
uploadChunk
();
}
else
{
throw
new
Error
(
data
.
error
||
'Upload failed'
);
throw
new
Error
(
data
.
error
||
'Upload failed'
);
}
}
uploadedChunks
++
;
const
progress
=
(
uploadedChunks
/
totalChunks
)
*
100
;
updateProgress
(
matchId
,
Math
.
round
(
progress
));
statusDiv
.
textContent
=
`Uploading...
${
Math
.
round
(
progress
)}
%`
;
});
}
// Start uploading chunks in parallel
const
promises
=
[];
for
(
let
i
=
0
;
i
<
Math
.
min
(
maxConcurrent
,
totalChunks
);
i
++
)
{
promises
.
push
(
uploadNextChunk
(
i
));
}
function
uploadNextChunk
(
startIndex
)
{
let
currentIndex
=
startIndex
;
return
new
Promise
((
resolve
,
reject
)
=>
{
function
uploadNext
()
{
if
(
currentIndex
>=
totalChunks
||
failed
)
{
resolve
();
return
;
}
uploadChunk
(
currentIndex
)
.
then
(()
=>
{
currentIndex
+=
maxConcurrent
;
if
(
currentIndex
<
totalChunks
)
{
uploadNext
();
}
else
{
resolve
();
}
})
.
catch
(
error
=>
{
failed
=
true
;
reject
(
error
);
});
}
uploadNext
();
});
}
Promise
.
all
(
promises
)
.
then
(()
=>
{
if
(
!
failed
)
{
finalizeUpload
(
uploadId
,
file
.
name
,
matchId
);
}
})
})
.
catch
(
error
=>
{
.
catch
(
error
=>
{
statusDiv
.
className
=
'upload-status error'
;
statusDiv
.
className
=
'upload-status error'
;
statusDiv
.
textContent
=
'Upload failed: '
+
error
.
message
;
statusDiv
.
textContent
=
'Upload failed: '
+
error
.
message
;
});
});
}
uploadChunk
();
}
}
function
finalizeUpload
(
uploadId
,
fileName
,
matchId
)
{
function
finalizeUpload
(
uploadId
,
fileName
,
matchId
)
{
...
@@ -690,8 +724,10 @@
...
@@ -690,8 +724,10 @@
function
uploadFixtureFileInChunks
(
file
)
{
function
uploadFixtureFileInChunks
(
file
)
{
const
totalChunks
=
Math
.
ceil
(
file
.
size
/
CHUNK_SIZE
);
const
totalChunks
=
Math
.
ceil
(
file
.
size
/
CHUNK_SIZE
);
const
uploadId
=
Date
.
now
()
+
'_'
+
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
);
const
uploadId
=
Date
.
now
()
+
'_'
+
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
);
const
maxConcurrent
=
3
;
// Upload up to 3 chunks simultaneously
let
currentChunk
=
0
;
let
uploadedChunks
=
0
;
let
failed
=
false
;
// Show progress bar and hide upload form
// Show progress bar and hide upload form
const
uploadForm
=
document
.
getElementById
(
'fixture_upload_form'
);
const
uploadForm
=
document
.
getElementById
(
'fixture_upload_form'
);
...
@@ -704,48 +740,80 @@
...
@@ -704,48 +740,80 @@
statusDiv
.
className
=
'upload-status uploading'
;
statusDiv
.
className
=
'upload-status uploading'
;
statusDiv
.
textContent
=
'Uploading to all matches... 0%'
;
statusDiv
.
textContent
=
'Uploading to all matches... 0%'
;
function
uploadChunk
()
{
function
uploadChunk
(
chunkIndex
)
{
if
(
currentChunk
>=
totalChunks
)
{
if
(
failed
)
return
;
// All chunks uploaded, finalize
finalizeFixtureUpload
(
uploadId
,
file
.
name
);
return
;
}
const
start
=
c
urrentChunk
*
CHUNK_SIZE
;
const
start
=
c
hunkIndex
*
CHUNK_SIZE
;
const
end
=
Math
.
min
(
start
+
CHUNK_SIZE
,
file
.
size
);
const
end
=
Math
.
min
(
start
+
CHUNK_SIZE
,
file
.
size
);
const
chunk
=
file
.
slice
(
start
,
end
);
const
chunk
=
file
.
slice
(
start
,
end
);
const
formData
=
new
FormData
();
const
formData
=
new
FormData
();
formData
.
append
(
'chunk'
,
chunk
);
formData
.
append
(
'chunk'
,
chunk
);
formData
.
append
(
'chunkIndex'
,
c
urrentChunk
);
formData
.
append
(
'chunkIndex'
,
c
hunkIndex
);
formData
.
append
(
'totalChunks'
,
totalChunks
);
formData
.
append
(
'totalChunks'
,
totalChunks
);
formData
.
append
(
'uploadId'
,
uploadId
);
formData
.
append
(
'uploadId'
,
uploadId
);
formData
.
append
(
'fileName'
,
file
.
name
);
formData
.
append
(
'fileName'
,
file
.
name
);
fetch
(
'/upload/chunk'
,
{
return
fetch
(
'/upload/chunk'
,
{
method
:
'POST'
,
method
:
'POST'
,
body
:
formData
body
:
formData
})
})
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
.
then
(
data
=>
{
if
(
data
.
success
)
{
if
(
!
data
.
success
)
{
currentChunk
++
;
const
progress
=
(
currentChunk
/
totalChunks
)
*
100
;
updateFixtureProgress
(
Math
.
round
(
progress
));
statusDiv
.
textContent
=
`Uploading to all matches...
${
Math
.
round
(
progress
)}
%`
;
uploadChunk
();
}
else
{
throw
new
Error
(
data
.
error
||
'Upload failed'
);
throw
new
Error
(
data
.
error
||
'Upload failed'
);
}
}
uploadedChunks
++
;
const
progress
=
(
uploadedChunks
/
totalChunks
)
*
100
;
updateFixtureProgress
(
Math
.
round
(
progress
));
statusDiv
.
textContent
=
`Uploading to all matches...
${
Math
.
round
(
progress
)}
%`
;
});
}
// Start uploading chunks in parallel
const
promises
=
[];
for
(
let
i
=
0
;
i
<
Math
.
min
(
maxConcurrent
,
totalChunks
);
i
++
)
{
promises
.
push
(
uploadNextChunk
(
i
));
}
function
uploadNextChunk
(
startIndex
)
{
let
currentIndex
=
startIndex
;
return
new
Promise
((
resolve
,
reject
)
=>
{
function
uploadNext
()
{
if
(
currentIndex
>=
totalChunks
||
failed
)
{
resolve
();
return
;
}
uploadChunk
(
currentIndex
)
.
then
(()
=>
{
currentIndex
+=
maxConcurrent
;
if
(
currentIndex
<
totalChunks
)
{
uploadNext
();
}
else
{
resolve
();
}
})
.
catch
(
error
=>
{
failed
=
true
;
reject
(
error
);
});
}
uploadNext
();
});
}
Promise
.
all
(
promises
)
.
then
(()
=>
{
if
(
!
failed
)
{
finalizeFixtureUpload
(
uploadId
,
file
.
name
);
}
})
})
.
catch
(
error
=>
{
.
catch
(
error
=>
{
statusDiv
.
className
=
'upload-status error'
;
statusDiv
.
className
=
'upload-status error'
;
statusDiv
.
textContent
=
'Upload failed: '
+
error
.
message
;
statusDiv
.
textContent
=
'Upload failed: '
+
error
.
message
;
fixtureUploadActive
=
false
;
fixtureUploadActive
=
false
;
});
});
}
uploadChunk
();
}
}
function
finalizeFixtureUpload
(
uploadId
,
fileName
)
{
function
finalizeFixtureUpload
(
uploadId
,
fileName
)
{
...
...
app/templates/main/match_detail.html
View file @
5c9c82a2
...
@@ -766,8 +766,10 @@
...
@@ -766,8 +766,10 @@
function
uploadFileInChunks
(
file
,
matchId
)
{
function
uploadFileInChunks
(
file
,
matchId
)
{
const
totalChunks
=
Math
.
ceil
(
file
.
size
/
CHUNK_SIZE
);
const
totalChunks
=
Math
.
ceil
(
file
.
size
/
CHUNK_SIZE
);
const
uploadId
=
Date
.
now
()
+
'_'
+
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
);
const
uploadId
=
Date
.
now
()
+
'_'
+
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
);
const
maxConcurrent
=
3
;
// Upload up to 3 chunks simultaneously
let
currentChunk
=
0
;
let
uploadedChunks
=
0
;
let
failed
=
false
;
// Show progress bar and hide upload form
// Show progress bar and hide upload form
const
uploadForm
=
document
.
getElementById
(
`upload_form_
${
matchId
}
`
);
const
uploadForm
=
document
.
getElementById
(
`upload_form_
${
matchId
}
`
);
...
@@ -780,48 +782,80 @@
...
@@ -780,48 +782,80 @@
statusDiv
.
className
=
'upload-status uploading'
;
statusDiv
.
className
=
'upload-status uploading'
;
statusDiv
.
textContent
=
'Uploading... 0%'
;
statusDiv
.
textContent
=
'Uploading... 0%'
;
function
uploadChunk
()
{
function
uploadChunk
(
chunkIndex
)
{
if
(
currentChunk
>=
totalChunks
)
{
if
(
failed
)
return
;
// All chunks uploaded, finalize
finalizeUpload
(
uploadId
,
file
.
name
,
matchId
);
return
;
}
const
start
=
c
urrentChunk
*
CHUNK_SIZE
;
const
start
=
c
hunkIndex
*
CHUNK_SIZE
;
const
end
=
Math
.
min
(
start
+
CHUNK_SIZE
,
file
.
size
);
const
end
=
Math
.
min
(
start
+
CHUNK_SIZE
,
file
.
size
);
const
chunk
=
file
.
slice
(
start
,
end
);
const
chunk
=
file
.
slice
(
start
,
end
);
const
formData
=
new
FormData
();
const
formData
=
new
FormData
();
formData
.
append
(
'chunk'
,
chunk
);
formData
.
append
(
'chunk'
,
chunk
);
formData
.
append
(
'chunkIndex'
,
c
urrentChunk
);
formData
.
append
(
'chunkIndex'
,
c
hunkIndex
);
formData
.
append
(
'totalChunks'
,
totalChunks
);
formData
.
append
(
'totalChunks'
,
totalChunks
);
formData
.
append
(
'uploadId'
,
uploadId
);
formData
.
append
(
'uploadId'
,
uploadId
);
formData
.
append
(
'fileName'
,
file
.
name
);
formData
.
append
(
'fileName'
,
file
.
name
);
formData
.
append
(
'matchId'
,
matchId
);
formData
.
append
(
'matchId'
,
matchId
);
fetch
(
'/upload/chunk'
,
{
return
fetch
(
'/upload/chunk'
,
{
method
:
'POST'
,
method
:
'POST'
,
body
:
formData
body
:
formData
})
})
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
.
then
(
data
=>
{
if
(
data
.
success
)
{
if
(
!
data
.
success
)
{
currentChunk
++
;
const
progress
=
(
currentChunk
/
totalChunks
)
*
100
;
updateProgress
(
matchId
,
Math
.
round
(
progress
));
statusDiv
.
textContent
=
`Uploading...
${
Math
.
round
(
progress
)}
%`
;
uploadChunk
();
}
else
{
throw
new
Error
(
data
.
error
||
'Upload failed'
);
throw
new
Error
(
data
.
error
||
'Upload failed'
);
}
}
uploadedChunks
++
;
const
progress
=
(
uploadedChunks
/
totalChunks
)
*
100
;
updateProgress
(
matchId
,
Math
.
round
(
progress
));
statusDiv
.
textContent
=
`Uploading...
${
Math
.
round
(
progress
)}
%`
;
});
}
// Start uploading chunks in parallel
const
promises
=
[];
for
(
let
i
=
0
;
i
<
Math
.
min
(
maxConcurrent
,
totalChunks
);
i
++
)
{
promises
.
push
(
uploadNextChunk
(
i
));
}
function
uploadNextChunk
(
startIndex
)
{
let
currentIndex
=
startIndex
;
return
new
Promise
((
resolve
,
reject
)
=>
{
function
uploadNext
()
{
if
(
currentIndex
>=
totalChunks
||
failed
)
{
resolve
();
return
;
}
uploadChunk
(
currentIndex
)
.
then
(()
=>
{
currentIndex
+=
maxConcurrent
;
if
(
currentIndex
<
totalChunks
)
{
uploadNext
();
}
else
{
resolve
();
}
})
.
catch
(
error
=>
{
failed
=
true
;
reject
(
error
);
});
}
uploadNext
();
});
}
Promise
.
all
(
promises
)
.
then
(()
=>
{
if
(
!
failed
)
{
finalizeUpload
(
uploadId
,
file
.
name
,
matchId
);
}
})
})
.
catch
(
error
=>
{
.
catch
(
error
=>
{
statusDiv
.
className
=
'upload-status error'
;
statusDiv
.
className
=
'upload-status error'
;
statusDiv
.
textContent
=
'Upload failed: '
+
error
.
message
;
statusDiv
.
textContent
=
'Upload failed: '
+
error
.
message
;
});
});
}
uploadChunk
();
}
}
function
finalizeUpload
(
uploadId
,
fileName
,
matchId
)
{
function
finalizeUpload
(
uploadId
,
fileName
,
matchId
)
{
...
...
app/upload/routes.py
View file @
5c9c82a2
...
@@ -985,14 +985,15 @@ def finalize_upload():
...
@@ -985,14 +985,15 @@ def finalize_upload():
# Create a file-like object for the assembled file
# Create a file-like object for the assembled file
class
FileLike
:
class
FileLike
:
def
__init__
(
self
,
path
):
def
__init__
(
self
,
path
,
filename
):
self
.
path
=
path
self
.
path
=
path
self
.
name
=
file_name
self
.
filename
=
filename
self
.
name
=
filename
def
save
(
self
,
dst
):
def
save
(
self
,
dst
):
shutil
.
move
(
self
.
path
,
dst
)
shutil
.
move
(
self
.
path
,
dst
)
mock_file
=
FileLike
(
final_path
)
mock_file
=
FileLike
(
final_path
,
file_name
)
if
match_id
:
if
match_id
:
# ZIP upload for match
# ZIP upload for match
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment