Improved AMV UI

This commit is contained in:
Eduard Urbach 2018-04-15 10:36:51 +02:00
parent 1ecc3e3fa4
commit b6321de60b
13 changed files with 190 additions and 67 deletions

View File

@ -1,7 +1,18 @@
component AMV(amv *arn.AMV, user *arn.User)
p= amv.Title.ByUser(user)
.amv.mountable
.video-container
video.video(controls="controls", controlsList="nodownload")
source(src="", type="video/webm")
source(src="/videos/amvs/" + amv.File, type="video/webm")
AMVFooter(amv, user)
component AMVFooter(amv *arn.AMV, user *arn.User)
.amv-footer
if amv.Title.ByUser(user) == ""
a(href=amv.Link() + "/edit") untitled
else
a(href=amv.Link())= amv.Title.ByUser(user)
span posted
span.utc-date(data-date=amv.Created)
span by
a(href=amv.Creator().Link())= amv.Creator().Nick + " "

View File

@ -1,10 +1,30 @@
component AMVPage(amv *arn.AMV, user *arn.User)
AMVTabs(amv, user)
if amv.Title.String() == ""
h1 untitled
else
h1= amv.Title.ByUser(user)
.amv-page
if amv.Title.String() == ""
h1.mountable untitled
else
h1.mountable= amv.Title.ByUser(user)
if amv.File != ""
AMV(amv, user)
if amv.MainAnimeID != "" || len(amv.ExtraAnimeIDs) > 0
h3.mountable Anime
if amv.MainAnimeID != ""
.amv-main-anime.mountable
AnimeGrid([]*arn.Anime{amv.MainAnime()}, user)
if len(amv.ExtraAnimeIDs) > 0
.amv-extra-anime.mountable
AnimeGridSmall(amv.ExtraAnime(), user)
component AnimeGridSmall(animes []*arn.Anime, user *arn.User)
each anime in animes
a.mountable(href=anime.Link(), title=anime.Title.ByUser(user))
img.lazy(data-src=anime.ImageLink("small"), data-webp="true", data-color=anime.AverageColor(), alt=anime.Title.ByUser(user))
component AMVTabs(amv *arn.AMV, user *arn.User)
.tabs

39
pages/amv/amv.scarlet Normal file
View File

@ -0,0 +1,39 @@
.amvs
vertical
margin-top 1rem
.amv
width 100%
margin calc(content-padding / 2)
.video-container
box-shadow shadow-medium
.amv-footer
media-footer
.amv-page
vertical
align-items center
.amv-main-anime
margin-bottom 1rem
.amv-extra-anime
horizontal-wrap
a
display block
margin 0.4rem
img
border-radius ui-element-border-radius
> 500px
.amvs
horizontal-wrap
justify-content flex-start
margin-top 0
.amv
max-width 380px

View File

@ -1,17 +0,0 @@
.amvs
vertical
margin-top 1rem
.amv
width 100%
margin calc(content-padding / 2)
box-shadow shadow-medium
> 500px
.amvs
horizontal-wrap
justify-content flex-start
margin-top 0
.amv
max-width 380px

View File

@ -67,7 +67,24 @@ func Get(ctx *aero.Context) string {
})
sort.Slice(tracks, func(i, j int) bool {
return tracks[i].Title.ByUser(user) < tracks[j].Title.ByUser(user)
if len(tracks[i].Likes) == len(tracks[j].Likes) {
return tracks[i].Title.ByUser(user) < tracks[j].Title.ByUser(user)
}
return len(tracks[i].Likes) > len(tracks[j].Likes)
})
// AMVs
amvs := arn.FilterAMVs(func(track *arn.AMV) bool {
return !track.IsDraft && track.MainAnimeID == anime.ID
})
sort.Slice(amvs, func(i, j int) bool {
if len(amvs[i].Likes) == len(amvs[j].Likes) {
return amvs[i].Title.ByUser(user) < amvs[j].Title.ByUser(user)
}
return len(amvs[i].Likes) > len(amvs[j].Likes)
})
// Anime list item
@ -107,5 +124,5 @@ func Get(ctx *aero.Context) string {
ctx.Data = openGraph
return ctx.HTML(components.Anime(anime, animeListItem, tracks, episodes, friends, friendsAnimeListItems, user))
return ctx.HTML(components.Anime(anime, animeListItem, tracks, amvs, episodes, friends, friendsAnimeListItems, user))
}

View File

@ -1,11 +1,11 @@
component Anime(anime *arn.Anime, listItem *arn.AnimeListItem, tracks []*arn.SoundTrack, episodes []*arn.AnimeEpisode, friends []*arn.User, listItems map[*arn.User]*arn.AnimeListItem, user *arn.User)
component Anime(anime *arn.Anime, listItem *arn.AnimeListItem, tracks []*arn.SoundTrack, amvs []*arn.AMV, episodes []*arn.AnimeEpisode, friends []*arn.User, listItems map[*arn.User]*arn.AnimeListItem, user *arn.User)
.anime
.anime-main-column
AnimeMainColumn(anime, listItem, tracks, episodes, user)
AnimeMainColumn(anime, listItem, tracks, amvs, episodes, user)
.anime-side-column
AnimeSideColumn(anime, friends, listItems, user)
component AnimeMainColumn(anime *arn.Anime, listItem *arn.AnimeListItem, tracks []*arn.SoundTrack, episodes []*arn.AnimeEpisode, user *arn.User)
component AnimeMainColumn(anime *arn.Anime, listItem *arn.AnimeListItem, tracks []*arn.SoundTrack, amvs []*arn.AMV, episodes []*arn.AnimeEpisode, user *arn.User)
.anime-header(data-id=anime.ID)
a.anime-image-container.mountable(href=anime.ImageLink("original"), target="_blank")
img.anime-cover-image.lazy(data-src=anime.ImageLink("large"), data-webp="true", data-color=anime.AverageColor(), alt=anime.Title.ByUser(user))
@ -28,29 +28,18 @@ component AnimeMainColumn(anime *arn.Anime, listItem *arn.AnimeListItem, tracks
AnimeCharacters(anime, user, false)
AnimeRelations(anime, user, false)
AnimeTracks(anime, tracks, user, false)
if anime.ID == "LbbCcKiig"
section.anime-section.mountable
h3.anime-section-name AMVs
.amvs
.amv.mountable
.video-container
video.video(controls="controls", controlsList="nodownload")
source(src="/videos/unchained.webm", type="video/webm")
if anime.ID == "7VjCpFiiR"
section.anime-section.mountable
h3.anime-section-name AMVs
.amvs
.amv.mountable
.video-container
video.video(controls="controls", controlsList="nodownload")
source(src="/videos/sunlight.webm", type="video/webm")
AnimeAMVs(anime, amvs, user)
AnimeEpisodes(anime, episodes, user, false)
component AnimeAMVs(anime *arn.Anime, amvs []*arn.AMV, user *arn.User)
if len(amvs) > 0
section.anime-section.mountable
h3.anime-section-name AMVs
.amvs
each amv in amvs
AMV(amv, user)
component AnimeSideColumn(anime *arn.Anime, friends []*arn.User, listItems map[*arn.User]*arn.AnimeListItem, user *arn.User)
AnimeTrailer(anime)
AnimeInformation(anime)

View File

@ -265,6 +265,7 @@ func Configure(app *aero.Application) {
app.Post("/api/upload/avatar", upload.Avatar)
app.Post("/api/upload/cover", upload.Cover)
app.Post("/api/upload/anime/:id/image", upload.AnimeImage)
app.Post("/api/upload/amv/:id/file", upload.AMVFile)
// Admin
l.Page("/admin", admin.Get)

View File

@ -115,13 +115,7 @@ animation change-color
filter brightness(50%)
.soundtrack-footer
text-align center
margin-bottom 1rem
margin-top 0.4rem
font-size 0.9em
span
opacity 0.65
media-footer
.soundtrack-anime-link
display none

49
pages/upload/amv.go Normal file
View File

@ -0,0 +1,49 @@
package upload
import (
"net/http"
"github.com/animenotifier/arn"
"github.com/aerogo/aero"
"github.com/animenotifier/notify.moe/utils"
)
// AMVFile handles the video upload for AMV files.
func AMVFile(ctx *aero.Context) string {
user := utils.GetUser(ctx)
amvID := ctx.Get("id")
if user == nil {
return ctx.Error(http.StatusUnauthorized, "Not logged in", nil)
}
amv, err := arn.GetAMV(amvID)
if err != nil {
return ctx.Error(http.StatusNotFound, "AMV not found", err)
}
// Retrieve file from post body
data, err := ctx.Request().Body().Bytes()
if err != nil {
return ctx.Error(http.StatusInternalServerError, "Reading request body failed", err)
}
// Set amv image file
err = amv.SetVideoBytes(data)
if err != nil {
return ctx.Error(http.StatusInternalServerError, "Invalid video format", err)
}
// Save image information
amv.Save()
// Write log entry
logEntry := arn.NewEditLogEntry(user.ID, "edit", "AMV", amv.ID, "File", "", "")
logEntry.Save()
return "ok"
}

View File

@ -1,16 +1,21 @@
package main
import (
"net/http"
"net/http/pprof"
)
func init() {
// Uncomment these if you want to enable live profiling via /debug/pprof
// app.Router.HandlerFunc("GET", "/debug/pprof/", http.HandlerFunc(pprof.Index))
// app.Router.HandlerFunc("GET", "/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
// app.Router.HandlerFunc("GET", "/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
// app.Router.HandlerFunc("GET", "/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
// app.Router.HandlerFunc("GET", "/debug/pprof/trace", http.HandlerFunc(pprof.Trace))
app.Router.HandlerFunc("GET", "/debug/pprof/", http.HandlerFunc(pprof.Index))
app.Router.HandlerFunc("GET", "/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
app.Router.HandlerFunc("GET", "/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
app.Router.HandlerFunc("GET", "/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
app.Router.HandlerFunc("GET", "/debug/pprof/trace", http.HandlerFunc(pprof.Trace))
// app.Router.Handler("GET", "/debug/pprof/goroutine", pprof.Handler("goroutine"))
// app.Router.Handler("GET", "/debug/pprof/heap", pprof.Handler("heap"))
// app.Router.Handler("GET", "/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
// app.Router.Handler("GET", "/debug/pprof/block", pprof.Handler("block"))
app.Router.Handler("GET", "/debug/pprof/goroutine", pprof.Handler("goroutine"))
app.Router.Handler("GET", "/debug/pprof/heap", pprof.Handler("heap"))
app.Router.Handler("GET", "/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
app.Router.Handler("GET", "/debug/pprof/block", pprof.Handler("block"))
}

View File

@ -0,0 +1,8 @@
mixin media-footer
text-align center
margin-bottom 1rem
margin-top 0.4rem
font-size 0.9em
span
opacity 0.65

View File

@ -142,7 +142,11 @@ func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, i
} else if field.Tag.Get("type") == "textarea" {
b.WriteString(components.InputTextArea(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip")))
} else if field.Tag.Get("type") == "upload" {
b.WriteString(components.InputFileUpload(idPrefix+field.Name, field.Name, field.Tag.Get("filetype"), field.Tag.Get("endpoint")))
endpoint := field.Tag.Get("endpoint")
id := v.FieldByName("ID").String()
endpoint = strings.Replace(endpoint, ":id", id, 1)
b.WriteString(components.InputFileUpload(idPrefix+field.Name, field.Name, field.Tag.Get("filetype"), endpoint))
} else {
b.WriteString(components.InputText(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip")))
}

3
videos/amvs/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!*/
!.gitignore