Skip to content

Commit

Permalink
Merge pull request #333 from dres-dev/dev
Browse files Browse the repository at this point in the history
v1.2.1
  • Loading branch information
lucaro authored May 23, 2022
2 parents b68c5bc + 59d2b8b commit 7dcb10f
Show file tree
Hide file tree
Showing 22 changed files with 1,058 additions and 172 deletions.
66 changes: 51 additions & 15 deletions backend/src/main/kotlin/dev/dres/api/cli/MediaCollectionCommand.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.dres.api.cli

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.NoOpCliktCommand
import com.github.ajalt.clikt.core.subcommands
Expand Down Expand Up @@ -311,12 +311,30 @@ class MediaCollectionCommand(val collections: DAO<MediaCollection>, val items: D
}

val base = File(collection.basePath)

if (!base.exists()) {
println("Cannot scan collection, '${collection.basePath}' does not exist.")
return
}

if (!base.isDirectory) {
println("Cannot scan collection, '${collection.basePath}' is no directory.")
return
}

if (!base.canRead()) {
println("Cannot scan collection, '${collection.basePath}' is not readable.")
return
}

val files = base.walkTopDown().filter { it.isFile && (it.extension.toLowerCase() in imageTypes || it.extension in videoTypes) }

val buffer = mutableListOf<MediaItem>()

val issues = mutableMapOf<String, String>()

var fileCounter = 0

files.forEach { file ->

println("found ${file.absolutePath}")
Expand Down Expand Up @@ -383,6 +401,8 @@ class MediaCollectionCommand(val collections: DAO<MediaCollection>, val items: D
println("done")
}

++fileCounter

}

println()
Expand All @@ -394,11 +414,12 @@ class MediaCollectionCommand(val collections: DAO<MediaCollection>, val items: D
if(issues.isNotEmpty()){
val file = File("issues-scan-${collection.name}-${System.currentTimeMillis()}.json")
println("There have been ${issues.size} issues while scanning. You might want to check them at ${file.path}")
val om = ObjectMapper()
val om = jacksonObjectMapper()
om.writeValue(file, issues)
println("done")
}
println()
println("\nAdded $fileCounter elements to collection")


}

Expand Down Expand Up @@ -437,10 +458,11 @@ class MediaCollectionCommand(val collections: DAO<MediaCollection>, val items: D
}
}

inner class DeleteItemCommand : AbstractCollectionCommand("deleteItem", help = "Deletes a Media Item") {
inner class DeleteItemCommand : AbstractCollectionCommand("deleteItem", help = "Deletes Media Item(s)") {

private val itemName: String by option("-in", "--itemName", help = "Name of the Item").default("")
private val itemIdInput: UID? by option("-ii", "--itemId", help = "Id of the Item").convert { it.UID() }
private val nameRegex: Regex? by option("-e", "--regex", help="Regex for item names").convert { it.toRegex() }

override fun run() {

Expand All @@ -450,22 +472,36 @@ class MediaCollectionCommand(val collections: DAO<MediaCollection>, val items: D
return
}

if (itemName.isBlank() && itemIdInput == null) {
println("Item not specified.")
if ((itemName.isBlank() && itemIdInput == null) && nameRegex == null) {
println("Item(s) not specified.")
return
}
if(itemName.isNotBlank() || itemIdInput != null){
val itemId = itemIdInput
?: this@MediaCollectionCommand.items.find { it.collection == collectionId && it.name == itemName }?.id

val itemId = itemIdInput
?: this@MediaCollectionCommand.items.find { it.collection == collectionId && it.name == itemName }?.id
if (itemId == null) {
println("Item not found.")
return
}

if (itemId == null) {
println("Item not found.")
return
this@MediaCollectionCommand.items.delete(itemId)
println("Item '${itemId.string}' deleted")
}else if(nameRegex != null){
val regex = nameRegex!!
val ids = this@MediaCollectionCommand.items.filter { it.collection == collectionId && regex.matches(it.name) }.map{it.id}
if(ids.isEmpty()){
println("No items found for regex $regex")
return
}
ids.forEach {
this@MediaCollectionCommand.items.delete(it)
println("Item '$it' deleted")
}
}else{
println("Nothing was specified, hence no deletion occured")
}

this@MediaCollectionCommand.items.delete(itemId)
println("Item '${itemId.string}' deleted")

}
}

Expand Down Expand Up @@ -672,4 +708,4 @@ class MediaCollectionCommand(val collections: DAO<MediaCollection>, val items: D
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class CreateCompetitionRunAdminHandler(

val outputFile = File(cacheLocation, it.cacheItemName())
if (!outputFile.exists()) {
logger.warn("query video file for item ${it.item} not found, rendering to ${outputFile.absolutePath}")
logger.warn("Query video file for item ${it.item} not found, rendering to ${outputFile.absolutePath}")
FFmpegUtil.prepareMediaSegmentTask(it, collection.basePath, cacheLocation)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import dev.dres.data.model.UID
import dev.dres.data.model.submissions.Submission
import dev.dres.data.model.submissions.SubmissionStatus
import dev.dres.run.eventstream.*
import org.slf4j.LoggerFactory
import java.io.File
import java.io.PrintWriter

Expand All @@ -15,6 +16,8 @@ class SubmissionStatisticsHandler : StreamEventHandler {
private val taskStartMap = mutableMapOf<UID, Long>()
private val taskNameMap = mutableMapOf<UID, String>()

private val logger = LoggerFactory.getLogger(this.javaClass)

init {
writer.println("task,team,type,value")
}
Expand All @@ -30,7 +33,16 @@ class SubmissionStatisticsHandler : StreamEventHandler {
submissionTaskMap[event.taskId]!!.add(event.submission)
}
is TaskEndEvent -> {
computeStatistics(submissionTaskMap[event.taskId]!!, taskStartMap[event.taskId]!!, taskNameMap[event.taskId]!!)
val submissions = submissionTaskMap[event.taskId]
val start = taskStartMap[event.taskId]
val name = taskNameMap[event.taskId]

if (submissions == null || start == null || name == null) {
logger.info("Task '{}' not found in previously started tasks. Already ended previously?", name)
return
}

computeStatistics(submissions, start, name)
submissionTaskMap.remove(event.taskId)
taskStartMap.remove(event.taskId)
taskNameMap.remove(event.taskId)
Expand Down
12 changes: 6 additions & 6 deletions backend/src/main/kotlin/dev/dres/utilities/FFmpegUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ object FFmpegUtil {

private data class FrameRequest(val video: Path, val timecode: String, val outputImage: Path)

private val frameRequestQueue = ConcurrentLinkedQueue<FrameRequest>()
private val frameRequestStack = ConcurrentLinkedDeque<FrameRequest>()

private const val concurrentFrameRequests = 4
private var threadRunning = true
Expand All @@ -62,7 +62,7 @@ object FFmpegUtil {

if (futureList.size < concurrentFrameRequests) {

val request = frameRequestQueue.poll()
val request = frameRequestStack.pollFirst()

if (request != null) {
futureList.add(
Expand Down Expand Up @@ -91,7 +91,7 @@ object FFmpegUtil {

fun previewImageStream(path: Path): CompletableFuture<InputStream>? {

if (!Files.exists(path) && frameRequestQueue.none { it.outputImage == path }) {
if (!Files.exists(path) && frameRequestStack.none { it.outputImage == path }) {
return null //image neither exists nor is scheduled to be generated
}

Expand Down Expand Up @@ -140,7 +140,7 @@ object FFmpegUtil {
val seconds = (ms % 60_000) / 1000
val milliseconds = ms % 1000

return "$hours:$minutes:$seconds.$milliseconds"
return "$hours:$minutes:$seconds.${"%03d".format(milliseconds)}"
}


Expand All @@ -158,8 +158,8 @@ object FFmpegUtil {

fun extractFrame(video: Path, timecode: String, outputImage: Path) {
val request = FrameRequest(video, timecode, outputImage)
if (!Files.exists(outputImage) && !frameRequestQueue.contains(request)) {
frameRequestQueue.add(request)
if (!Files.exists(outputImage) && !frameRequestStack.contains(request)) {
frameRequestStack.push(request)
logger.info(logMarker, "Enqueued frame request $request")
}

Expand Down
4 changes: 2 additions & 2 deletions frontend/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
# cd frontend
# yarn lint-staged
cd frontend
yarn lint-staged
9 changes: 9 additions & 0 deletions frontend/.stylelintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": [
"stylelint-config-standard",
"stylelint-config-html",
"stylelint-config-prettier",
"stylelint-config-standard-scss",
"stylelint-config-prettier-scss"
]
}
2 changes: 1 addition & 1 deletion frontend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ configurations {
def includeConfig = project.hasProperty('includeConfig')

node {
version = '16.10.0'
version = '18.1.0'
download = true
workDir = file("${project.projectDir}/.gradle/nodejs")
yarnWorkDir = file("${project.projectDir}/.gradle/yarn")
Expand Down
10 changes: 8 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
"postinstall": "cd .. && husky install frontend/.husky"
},
"lint-staged": {
"*.ts": "eslint --cache",
"*.{css,scss,sass,html}": "stylelint"
"*.ts": "eslint --cache"
},
"private": true,
"dependencies": {
Expand Down Expand Up @@ -72,6 +71,13 @@
"prettier": "2.6.2",
"prettier-eslint": "^14.0.1",
"protractor": "7.0.x",
"stylelint": "^14.8.2",
"stylelint-config-html": "^1.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-prettier-scss": "^0.0.1",
"stylelint-config-scss": "^1.0.0-security",
"stylelint-config-standard": "^25.0.0",
"stylelint-config-standard-scss": "^3.0.0",
"ts-node": "8.3.x",
"typescript": "4.5.x"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,24 +522,23 @@ export class CompetitionFormBuilder {
});

/* Initialize start, end and time unit based on target. */
console.log(`type=${group.get('segment_time_unit').value}`);
// fetch target time unit
const targetTimeUnit = (this.form.get('target') as FormArray).controls[0].get('segment_time_unit').value;
if (targetTimeUnit && this.taskType.targetType.option === 'SINGLE_MEDIA_SEGMENT') {
group.get('segment_time_unit').setValue(targetTimeUnit);
console.log(`Unit=${targetTimeUnit}`);
}

console.log(`targetStart: ${!group.get('segment_start').value}, type=${this.taskType.targetType.option}`);
if (!group.get('segment_start').value && this.taskType.targetType.option === 'SINGLE_MEDIA_SEGMENT') {
group.get('segment_start').setValue((this.form.get('target') as FormArray).controls[0].get('segment_start').value);
console.log(`Start=${(this.form.get('target') as FormArray).controls[0].get('segment_start').value}`);
}

if (!group.get('segment_end').value && this.taskType.targetType.option === 'SINGLE_MEDIA_SEGMENT') {
group.get('segment_end').setValue((this.form.get('target') as FormArray).controls[0].get('segment_end').value);
}

/* Manually setting the duration of the hint equal to the duration of the task, this way the validators are happy */
group.get('end').setValue(this.taskType.taskDuration);

group
.get('segment_start')
.setValidators([Validators.required, this.temporalPointValidator(group.get('segment_time_unit') as FormControl)]);
Expand Down
Loading

0 comments on commit 7dcb10f

Please sign in to comment.