admin: Can import videos
This commit is contained in:
parent
dfe62e0b97
commit
223f44572e
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"srs.epita.fr/fic-server/admin/sync"
|
||||
@ -87,6 +89,39 @@ func declareSyncRoutes(router *gin.RouterGroup) {
|
||||
// Exercices
|
||||
declareSyncExercicesRoutes(apiSyncRoutes)
|
||||
declareSyncExercicesRoutes(apiSyncThemesRoutes)
|
||||
|
||||
// Videos sync imports resolution.mp4 from path stored in database.
|
||||
apiSyncRoutes.POST("/videos", func(c *gin.Context) {
|
||||
exercices, err := fic.GetExercices()
|
||||
if err != nil {
|
||||
log.Println("Unable to GetExercices:", err.Error())
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to retrieve exercices list."})
|
||||
return
|
||||
}
|
||||
|
||||
for _, e := range exercices {
|
||||
if len(e.VideoURI) == 0 || !strings.HasPrefix(e.VideoURI, "$RFILES$/") {
|
||||
continue
|
||||
}
|
||||
|
||||
vpath, err := url.PathUnescape(strings.TrimPrefix(e.VideoURI, "$RFILES$/"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusExpectationFailed, gin.H{"errmsg": fmt.Sprintf("Unable to perform URL unescape: %s", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = sync.ImportFile(sync.GlobalImporter, vpath, func(filePath, URI string) (interface{}, error) {
|
||||
e.VideoURI = path.Join("$FILES$", strings.TrimPrefix(filePath, fic.FilesDir))
|
||||
return e.Update()
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(http.StatusExpectationFailed, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, true)
|
||||
})
|
||||
}
|
||||
|
||||
func declareSyncExercicesRoutes(router *gin.RouterGroup) {
|
||||
|
@ -740,6 +740,19 @@ angular.module("FICApp")
|
||||
});
|
||||
});
|
||||
};
|
||||
$scope.syncVideos = function() {
|
||||
$scope.addToast('warning', 'Synchroniser les vidéos de résolution ?', 'ATTENTION il ne faut pas lancer cette synchronisation durant le challenge. Seulement une fois le challenge terminé, cela permet de rendre les vidéos accessibles dans l\'interface joueurs.',
|
||||
function() {
|
||||
$scope.deepSyncInProgress = true;
|
||||
$http.post("api/sync/videos").then(function() {
|
||||
$scope.deepSyncInProgress = false;
|
||||
$scope.addToast('success', 'Import des vidéos terminé.');
|
||||
}, function(response) {
|
||||
$scope.deepSyncInProgress = false;
|
||||
$scope.addToast('danger', 'Import des vidéos terminé.', response.data.errmsg);
|
||||
});
|
||||
});
|
||||
};
|
||||
})
|
||||
|
||||
.controller("PKIController", function($scope, $rootScope, Certificate, CACertificate, Team, $location, $http) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col text-center" ng-if="exercice.videoURI">
|
||||
<video src="vids/{{exercice.videoURI.replace('\$FILES\$/','').replace('?', '%3F')}}" controls style="height: 80vh; margin: auto;"></video>
|
||||
<video src="{{exercice.videoURI.replace('\$RFILES\$/','vids/').replace('\$FILES\$/','files/').replace('?', '%3F')}}" controls style="height: 80vh; margin: auto;"></video>
|
||||
</div>
|
||||
<div class="col" ng-if="exercice.resolution" ng-bind-html="exercice.resolution.replaceAll('\$FILES\$/','files/')">
|
||||
</div>
|
||||
|
@ -50,6 +50,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" ng-click="speedyDeepSync()" ng-disabled="deepSyncInProgress"><span class="glyphicon glyphicon-import" aria-hidden="true"></span> Synchronisation sans fichiers</button>
|
||||
<button type="button" class="btn btn-info" ng-click="syncVideos()" ng-disabled="deepSyncInProgress"><span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> Mettre à disposition les vidéos</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -236,7 +236,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
||||
errs = append(errs, fmt.Sprintf("%q: resolution.mp4: The file is empty!", edir))
|
||||
e.VideoURI = ""
|
||||
} else {
|
||||
e.VideoURI = strings.Replace(url.PathEscape(path.Join("$FILES$", e.VideoURI)), "%2F", "/", -1)
|
||||
e.VideoURI = strings.Replace(url.PathEscape(path.Join("$RFILES$", e.VideoURI)), "%2F", "/", -1)
|
||||
resolutionFound = true
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,11 @@
|
||||
</script>
|
||||
|
||||
<CardBody class="text-indent ratio ratio-16x9">
|
||||
<iframe type="text/html" src="{uri.replace('$FILES$', base+'/resolution')}" class="embed-responsive-item" title="Vidéo de résolution">
|
||||
Regardez la vidéo de résolution de ce défi : <a href="{uri.replace('$FILES$',base+'/resolution')}">{uri.replace('$FILES$',base+'/resolution')}</a>.
|
||||
</iframe>
|
||||
{#if uri.length > 0 && uri[0] === '/'}
|
||||
<video controls src={uri} />
|
||||
{:else}
|
||||
<iframe type="text/html" src="{uri.replace('$RFILES$', base+'/resolution')}" class="embed-responsive-item" title="Vidéo de résolution">
|
||||
Regardez la vidéo de résolution de ce défi : <a href="{uri.replace('$RFILES$',base+'/resolution')}">{uri.replace('$RFILES$',base+'/resolution')}</a>.
|
||||
</iframe>
|
||||
{/if}
|
||||
</CardBody>
|
||||
|
@ -133,7 +133,7 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
|
||||
if t == nil {
|
||||
exercice.Overview = strings.Replace(e.Overview, "$FILES$", FilesDir, -1)
|
||||
exercice.Finished = strings.Replace(e.Finished, "$FILES$", FilesDir, -1)
|
||||
exercice.VideoURI = e.VideoURI
|
||||
exercice.VideoURI = strings.Replace(e.VideoURI, "$FILES$", FilesDir, -1)
|
||||
exercice.Resolution = strings.Replace(e.Resolution, "$FILES$", FilesDir, -1)
|
||||
exercice.TotalTries = e.TriedCount()
|
||||
exercice.Gain = int(float64(e.Gain) * e.Coefficient * GlobalScoreCoefficient)
|
||||
|
Loading…
Reference in New Issue
Block a user