From b6321de60b9f29b486fd1155d7a60473c4f57457 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Sun, 15 Apr 2018 10:36:51 +0200 Subject: [PATCH] Improved AMV UI --- mixins/AMV.pixy | 17 ++++++++-- pages/amv/amv.pixy | 28 ++++++++++++--- pages/amv/amv.scarlet | 39 +++++++++++++++++++++ pages/anime/amv.scarlet | 17 ---------- pages/anime/anime.go | 21 ++++++++++-- pages/anime/anime.pixy | 37 +++++++------------- pages/index.go | 1 + pages/soundtracks/soundtracks.scarlet | 8 +---- pages/upload/amv.go | 49 +++++++++++++++++++++++++++ profiler.go | 23 ++++++++----- styles/mixins/media-footer.scarlet | 8 +++++ utils/editform/editform.go | 6 +++- videos/amvs/.gitignore | 3 ++ 13 files changed, 190 insertions(+), 67 deletions(-) create mode 100644 pages/amv/amv.scarlet delete mode 100644 pages/anime/amv.scarlet create mode 100644 pages/upload/amv.go create mode 100644 styles/mixins/media-footer.scarlet create mode 100644 videos/amvs/.gitignore diff --git a/mixins/AMV.pixy b/mixins/AMV.pixy index 59b0c619..e37e0c25 100644 --- a/mixins/AMV.pixy +++ b/mixins/AMV.pixy @@ -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") \ No newline at end of file + 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 + " " \ No newline at end of file diff --git a/pages/amv/amv.pixy b/pages/amv/amv.pixy index 63ddb4e0..f5037027 100644 --- a/pages/amv/amv.pixy +++ b/pages/amv/amv.pixy @@ -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 diff --git a/pages/amv/amv.scarlet b/pages/amv/amv.scarlet new file mode 100644 index 00000000..cbbc7263 --- /dev/null +++ b/pages/amv/amv.scarlet @@ -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 \ No newline at end of file diff --git a/pages/anime/amv.scarlet b/pages/anime/amv.scarlet deleted file mode 100644 index 2dae71fe..00000000 --- a/pages/anime/amv.scarlet +++ /dev/null @@ -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 \ No newline at end of file diff --git a/pages/anime/anime.go b/pages/anime/anime.go index d28580d6..adc1a2e0 100644 --- a/pages/anime/anime.go +++ b/pages/anime/anime.go @@ -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)) } diff --git a/pages/anime/anime.pixy b/pages/anime/anime.pixy index 69740c39..28be5cc6 100644 --- a/pages/anime/anime.pixy +++ b/pages/anime/anime.pixy @@ -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) diff --git a/pages/index.go b/pages/index.go index bdc6629b..2962bcb9 100644 --- a/pages/index.go +++ b/pages/index.go @@ -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) diff --git a/pages/soundtracks/soundtracks.scarlet b/pages/soundtracks/soundtracks.scarlet index 078db85f..bf16ae40 100644 --- a/pages/soundtracks/soundtracks.scarlet +++ b/pages/soundtracks/soundtracks.scarlet @@ -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 diff --git a/pages/upload/amv.go b/pages/upload/amv.go new file mode 100644 index 00000000..86f8bfe8 --- /dev/null +++ b/pages/upload/amv.go @@ -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" +} diff --git a/profiler.go b/profiler.go index b77e04a3..9f3694fa 100644 --- a/profiler.go +++ b/profiler.go @@ -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")) } diff --git a/styles/mixins/media-footer.scarlet b/styles/mixins/media-footer.scarlet new file mode 100644 index 00000000..dfa58968 --- /dev/null +++ b/styles/mixins/media-footer.scarlet @@ -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 \ No newline at end of file diff --git a/utils/editform/editform.go b/utils/editform/editform.go index 5b6cda5c..8acdf44f 100644 --- a/utils/editform/editform.go +++ b/utils/editform/editform.go @@ -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"))) } diff --git a/videos/amvs/.gitignore b/videos/amvs/.gitignore new file mode 100644 index 00000000..34211e27 --- /dev/null +++ b/videos/amvs/.gitignore @@ -0,0 +1,3 @@ +* +!*/ +!.gitignore