mirror of
https://github.com/photoprism/photoprism.git
synced 2025-10-09 10:40:33 +08:00
151 lines
4.1 KiB
Go
151 lines
4.1 KiB
Go
package api
|
|
|
|
import (
|
|
"archive/zip"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/ulule/deepcopier"
|
|
|
|
"github.com/photoprism/photoprism/internal/config/customize"
|
|
"github.com/photoprism/photoprism/internal/entity"
|
|
"github.com/photoprism/photoprism/internal/entity/query"
|
|
"github.com/photoprism/photoprism/internal/entity/search"
|
|
"github.com/photoprism/photoprism/internal/photoprism"
|
|
"github.com/photoprism/photoprism/internal/photoprism/get"
|
|
"github.com/photoprism/photoprism/pkg/clean"
|
|
"github.com/photoprism/photoprism/pkg/fs"
|
|
"github.com/photoprism/photoprism/pkg/i18n"
|
|
"github.com/photoprism/photoprism/pkg/media"
|
|
)
|
|
|
|
// AlbumDownloadName returns the album download file name type.
|
|
func AlbumDownloadName(c *gin.Context) customize.DownloadName {
|
|
switch c.Query("name") {
|
|
case "file":
|
|
return customize.DownloadNameFile
|
|
case "share":
|
|
return customize.DownloadNameShare
|
|
case "original":
|
|
return customize.DownloadNameOriginal
|
|
default:
|
|
return get.Config().Settings().Albums.Download.Name
|
|
}
|
|
}
|
|
|
|
// DownloadAlbum streams the album contents as zip archive.
|
|
//
|
|
// @Summary streams the album contents as zip archiv
|
|
// @Id DownloadAlbum
|
|
// @Tags Images, Albums
|
|
// @Produce application/zip
|
|
// @Failure 403,404,500 {object} i18n.Response
|
|
// @Success 200 {file} application/zip
|
|
// @Param uid path string true "Album UID"
|
|
// @Router /api/v1/albums/{uid}/dl [get]
|
|
func DownloadAlbum(router *gin.RouterGroup) {
|
|
router.GET("/albums/:uid/dl", func(c *gin.Context) {
|
|
if InvalidDownloadToken(c) {
|
|
AbortForbidden(c)
|
|
return
|
|
}
|
|
|
|
conf := get.Config()
|
|
|
|
if !conf.Settings().Features.Download || conf.Settings().Albums.Download.Disabled {
|
|
AbortFeatureDisabled(c)
|
|
return
|
|
}
|
|
|
|
start := time.Now()
|
|
a, err := query.AlbumByUID(clean.UID(c.Param("uid")))
|
|
|
|
if err != nil {
|
|
AbortAlbumNotFound(c)
|
|
return
|
|
}
|
|
|
|
results, err := search.AlbumPhotos(a, 10000, true)
|
|
|
|
if err != nil {
|
|
AbortEntityNotFound(c)
|
|
return
|
|
}
|
|
|
|
// Configure file names.
|
|
dlName := AlbumDownloadName(c)
|
|
settings := get.Config().Settings().Albums
|
|
zipFileName := a.ZipName()
|
|
|
|
AddDownloadHeader(c, zipFileName)
|
|
|
|
zipWriter := zip.NewWriter(c.Writer)
|
|
defer func(w *zip.Writer) {
|
|
logErr("zip", w.Close())
|
|
}(zipWriter)
|
|
|
|
var aliases = make(map[string]int)
|
|
|
|
for _, result := range results {
|
|
if result.FileName == "" {
|
|
log.Warnf("album: %s cannot be downloaded (empty file name)", clean.Log(result.FileUID))
|
|
continue
|
|
} else if result.FileHash == "" {
|
|
log.Warnf("album: %s cannot be downloaded (empty file hash)", clean.Log(result.FileName))
|
|
continue
|
|
}
|
|
|
|
if settings.Download.Originals && result.FileRoot != "/" {
|
|
log.Debugf("album: generated file %s not included in download", clean.Log(result.FileName))
|
|
continue
|
|
}
|
|
|
|
if !settings.Download.MediaSidecar && result.FileSidecar {
|
|
log.Debugf("album: sidecar file %s not included in download", clean.Log(result.FileName))
|
|
continue
|
|
}
|
|
|
|
if !settings.Download.MediaRaw && media.Raw.Equal(result.MediaType) {
|
|
log.Debugf("album: raw file %s not included in download", clean.Log(result.FileName))
|
|
continue
|
|
}
|
|
|
|
// Create file model from search result.
|
|
file := entity.File{}
|
|
|
|
if err = deepcopier.Copy(&file).From(result); err != nil {
|
|
log.Warnf("album: %s in %s (deepcopier)", err, clean.Log(result.FileName))
|
|
continue
|
|
}
|
|
|
|
file.ID = result.FileID
|
|
|
|
fileName := photoprism.FileName(file.FileRoot, file.FileName)
|
|
alias := file.DownloadName(dlName, 0)
|
|
key := strings.ToLower(alias)
|
|
|
|
if seq := aliases[key]; seq > 0 {
|
|
alias = file.DownloadName(dlName, seq)
|
|
}
|
|
|
|
aliases[key] += 1
|
|
|
|
if fs.FileExists(fileName) {
|
|
if zipErr := fs.ZipFile(zipWriter, fileName, alias, false); zipErr != nil {
|
|
log.Errorf("album: failed to zip %s (%s)", clean.Log(result.FileName), zipErr)
|
|
Abort(c, http.StatusInternalServerError, i18n.ErrZipFailed)
|
|
return
|
|
}
|
|
|
|
log.Infof("album: zipped %s as %s", clean.Log(result.FileName), clean.Log(alias))
|
|
} else {
|
|
log.Warnf("album: %s not found", clean.Log(result.FileName))
|
|
}
|
|
}
|
|
|
|
log.Infof("album: %s has been downloaded [%s]", clean.Log(a.AlbumTitle), time.Since(start))
|
|
})
|
|
}
|