From 2a4dc5638c34315ce5be4cbc9d63e77bd440be98 Mon Sep 17 00:00:00 2001 From: alex <85208095+alexnsfw@users.noreply.github.com> Date: Sun, 3 Sep 2023 03:21:45 -0400 Subject: [PATCH 1/5] remove scene counts when querying for heresphere/deo --- pkg/api/deovr.go | 18 ++++++++++-------- pkg/api/heresphere.go | 1 + pkg/models/model_scene.go | 25 +++++++++++++++---------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/pkg/api/deovr.go b/pkg/api/deovr.go index 1f21792a0..d9f01e295 100644 --- a/pkg/api/deovr.go +++ b/pkg/api/deovr.go @@ -13,11 +13,12 @@ import ( "github.com/emicklei/go-restful/v3" "github.com/markphelps/optional" "github.com/tidwall/gjson" + "golang.org/x/crypto/bcrypt" + "github.com/xbapps/xbvr/pkg/common" "github.com/xbapps/xbvr/pkg/config" "github.com/xbapps/xbvr/pkg/models" "github.com/xbapps/xbvr/pkg/session" - "golang.org/x/crypto/bcrypt" ) type DeoLibrary struct { @@ -285,8 +286,8 @@ func (i DeoVRResource) getDeoFile(req *restful.Request, resp *restful.Response) var file models.File db.Where(&models.File{ID: uint(fileId)}).First(&file) - var height = file.VideoHeight - var width = file.VideoWidth + height := file.VideoHeight + width := file.VideoWidth var sources []DeoSceneEncoding sources = append(sources, DeoSceneEncoding{ Name: fmt.Sprintf("File 1/1 - %v", humanize.Bytes(uint64(file.Size))), @@ -389,9 +390,9 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response) var sceneMultiProjection bool = true for i, file := range videoFiles { - var height = file.VideoHeight - var width = file.VideoWidth - var source = DeoSceneEncoding{ + height := file.VideoHeight + width := file.VideoWidth + source := DeoSceneEncoding{ Name: fmt.Sprintf("File %v/%v %vp - %v", i+1, len(videoFiles), file.VideoHeight, humanize.Bytes(uint64(file.Size))), VideoSources: []DeoSceneVideoSource{ { @@ -499,7 +500,7 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response) title := scene.Title thumbnailURL := session.DeoRequestHost + "/img/700x/" + strings.Replace(scene.CoverURL, "://", ":/", -1) - //Passthrough + // Passthrough var ckdata map[string]interface{} // nochromaKey := `{"enabled":false,"hasAlpha":false,"h":0,"opacity":0,"s":0,"threshold":0,"v":0}` chromaKey := gjson.Parse(scene.ChromaKey) @@ -512,7 +513,7 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response) if !result.Exists() || ckdata["hasAlpha"] == "" { // if ckdata["."].(map[string]interface{})["hasAlpha"] = "false" || ckdata["."].(map[string]interface{})["hasAlpha"] = "" { - //setting hasAlpha to false + // setting hasAlpha to false ckdata["hasAlpha"] = "false" } // Convert back to JSON string @@ -625,6 +626,7 @@ func (i DeoVRResource) getDeoLibrary(req *restful.Request, resp *restful.Respons r.IsAccessible = optional.NewBool(true) r.IsAvailable = optional.NewBool(true) r.Limit = optional.NewInt(10000) + r.Counts = optional.NewBool(false) q := models.QueryScenes(r, false) sceneLists = append(sceneLists, DeoListScenes{ diff --git a/pkg/api/heresphere.go b/pkg/api/heresphere.go index 1886f5903..920131ef9 100644 --- a/pkg/api/heresphere.go +++ b/pkg/api/heresphere.go @@ -970,6 +970,7 @@ func (i HeresphereResource) getHeresphereLibrary(req *restful.Request, resp *res r.IsAccessible = optional.NewBool(true) r.IsAvailable = optional.NewBool(true) r.Limit = optional.NewInt(20000) + r.Counts = optional.NewBool(false) q := models.QueryScenes(r, false) diff --git a/pkg/models/model_scene.go b/pkg/models/model_scene.go index 7d612a272..222b1201e 100644 --- a/pkg/models/model_scene.go +++ b/pkg/models/model_scene.go @@ -546,6 +546,7 @@ type RequestSceneList struct { DlState optional.String `json:"dlState"` Limit optional.Int `json:"limit"` Offset optional.Int `json:"offset"` + Counts optional.Bool `json:"counts"` IsAvailable optional.Bool `json:"isAvailable"` IsAccessible optional.Bool `json:"isAccessible"` IsWatched optional.Bool `json:"isWatched"` @@ -1160,12 +1161,14 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { tx = tx.Order("release_date desc") } - // Count other variations - tx.Group("scenes.scene_id").Where("is_hidden = ?", false).Count(&out.CountAny) - tx.Group("scenes.scene_id").Where("is_available = ?", true).Where("is_accessible = ?", true).Where("is_hidden = ?", false).Count(&out.CountAvailable) - tx.Group("scenes.scene_id").Where("is_available = ?", true).Where("is_hidden = ?", false).Count(&out.CountDownloaded) - tx.Group("scenes.scene_id").Where("is_available = ?", false).Where("is_hidden = ?", false).Count(&out.CountNotDownloaded) - tx.Group("scenes.scene_id").Where("is_hidden = ?", true).Count(&out.CountHidden) + if r.Counts.OrElse(true) { + // Count other variations + tx.Group("scenes.scene_id").Where("is_hidden = ?", false).Count(&out.CountAny) + tx.Group("scenes.scene_id").Where("is_available = ?", true).Where("is_accessible = ?", true).Where("is_hidden = ?", false).Count(&out.CountAvailable) + tx.Group("scenes.scene_id").Where("is_available = ?", true).Where("is_hidden = ?", false).Count(&out.CountDownloaded) + tx.Group("scenes.scene_id").Where("is_available = ?", false).Where("is_hidden = ?", false).Count(&out.CountNotDownloaded) + tx.Group("scenes.scene_id").Where("is_hidden = ?", true).Count(&out.CountHidden) + } // Apply avail/accessible after counting if r.IsAvailable.Present() { @@ -1182,10 +1185,12 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { tx = tx.Where("is_hidden = ?", false) } - // Count totals for selection - tx. - Group("scenes.scene_id"). - Count(&out.Results) + if r.Counts.OrElse(true) { + // Count totals for selection + tx. + Group("scenes.scene_id"). + Count(&out.Results) + } // Get scenes tx. From 96f0ffa4bc96af7fc98351798422c4a74b887697 Mon Sep 17 00:00:00 2001 From: alex <85208095+alexnsfw@users.noreply.github.com> Date: Sun, 3 Sep 2023 03:25:28 -0400 Subject: [PATCH 2/5] simplify filtering on attributes --- pkg/models/model_scene.go | 319 +++++++++----------------------------- 1 file changed, 69 insertions(+), 250 deletions(-) diff --git a/pkg/models/model_scene.go b/pkg/models/model_scene.go index 222b1201e..1994cb1d6 100644 --- a/pkg/models/model_scene.go +++ b/pkg/models/model_scene.go @@ -636,23 +636,15 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { var orAttribute []string var andAttribute []string combinedWhere := "" - for idx, attribute := range r.Attributes { - truefalse := true + for _, attribute := range r.Attributes { fieldName := attribute.OrElse("") - sceneAlias := "scenes_f" + strconv.Itoa(idx) - fileAlias := "files_f" + strconv.Itoa(idx) - scenecastAlias := "scene_cast_f" + strconv.Itoa(idx) - actorsAlias := "actors_f" + strconv.Itoa(idx) - scenecuepointAlias := "scene_cuepoints_f" + strconv.Itoa(idx) - erlAlias := "external_reference_links_f" + strconv.Itoa(idx) - - if strings.HasPrefix(fieldName, "!") { // ! prefix indicate NOT filtering - truefalse = false - fieldName = fieldName[1:] - } - if strings.HasPrefix(fieldName, "&") { // & prefix indicate must have filtering + + negate := strings.HasPrefix(fieldName, "!") // ! prefix indicate NOT filtering + mustHave := strings.HasPrefix(fieldName, "&") // & prefix indicate must have filtering + if negate || mustHave { fieldName = fieldName[1:] } + value := "" if strings.HasPrefix(fieldName, "Resolution ") { value = strings.Replace(fieldName[11:], "K", "", 1) @@ -666,287 +658,114 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { value = fieldName[6:] fieldName = "Codec" } + if strings.HasPrefix(fieldName, "Rating ") { + value = fieldName[7:] + fieldName = "Rating" + } + where := "" switch fieldName { case "Multiple Video Files": - if truefalse { - where = "scenes.id in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'video' group by " + fileAlias + ".scene_id having count(*) >1)" - } else { - where = "scenes.id not in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'video' group by " + fileAlias + ".scene_id having count(*) >1)" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' group by files.scene_id having count(*) > 1)" case "Single Video File": - if truefalse { - where = "scenes.id in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'video' group by " + fileAlias + ".scene_id having count(*) =1)" - } else { - where = "scenes.id not in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'video' group by " + fileAlias + ".scene_id having count(*) =1)" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' group by files.scene_id having count(*) = 1)" case "Multiple Script Files": - if truefalse { - where = "scenes.id in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'script' group by " + fileAlias + ".scene_id having count(*) >1)" - } else { - where = "scenes.id not in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'script' group by " + fileAlias + ".scene_id having count(*) >1)" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'script' group by files.scene_id having count(*) > 1)" case "Single Script File": - if truefalse { - where = "scenes.id in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'script' group by " + fileAlias + ".scene_id having count(*) =1)" - } else { - where = "scenes.id not in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'script' group by " + fileAlias + ".scene_id having count(*) =1)" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'script' group by files.scene_id having count(*) = 1)" case "Has Hsp File": - if truefalse { - where = "scenes.id in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'hsp' group by " + fileAlias + ".scene_id having count(*) >0)" - } else { - where = "scenes.id not in (select " + sceneAlias + ".id from scenes " + sceneAlias + " join files " + fileAlias + " on " + fileAlias + ".scene_id = " + sceneAlias + ".id and " + fileAlias + ".`type` = 'hsp' where " + sceneAlias + ".id=scenes.id group by " + sceneAlias + ".id)" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'hsp')" case "Has Subtitles File": - if truefalse { - where = "scenes.id in (select " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".`type` = 'subtitles' group by " + fileAlias + ".scene_id having count(*) >0)" - } else { - where = "scenes.id not in (select " + sceneAlias + ".id from scenes " + sceneAlias + " join files " + fileAlias + " on " + fileAlias + ".scene_id = " + sceneAlias + ".id and " + fileAlias + ".`type` = 'subtitles' where " + sceneAlias + ".id=scenes.id group by " + sceneAlias + ".id)" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'subtitles')" case "Has Rating": - if truefalse { - where = "scenes.star_rating > 0" - } else { - where = "scenes.star_rating = 0" - } + where = "scenes.star_rating > 0" case "Has Cuepoints": - if truefalse { - where = "scenes.id in (select " + scenecuepointAlias + ".scene_id from scene_cuepoints " + scenecuepointAlias + " where " + scenecuepointAlias + ".scene_id =scenes.id)" - } else { - where = "scenes.id not in (select " + scenecuepointAlias + ".scene_id from scene_cuepoints " + scenecuepointAlias + " where " + scenecuepointAlias + ".scene_id =scenes.id)" - } + where = "exists (select 1 from scene_cuepoints where scene_cuepoints.scene_id = scenes.id)" case "Has Simple Cuepoints": - if truefalse { - where = "scenes.id in (select " + scenecuepointAlias + ".scene_id from scene_cuepoints " + scenecuepointAlias + " where " + scenecuepointAlias + ".scene_id =scenes.id and track is null)" - } else { - where = "scenes.id not in (select " + scenecuepointAlias + ".scene_id from scene_cuepoints " + scenecuepointAlias + " where " + scenecuepointAlias + ".scene_id =scenes.id and track is null)" - } + where = "exists (select 1 from scene_cuepoints where scene_cuepoints.scene_id = scenes.id and track is null)" case "Has HSP Cuepoints": - if truefalse { - where = "scenes.id in (select " + scenecuepointAlias + ".scene_id from scene_cuepoints " + scenecuepointAlias + " where " + scenecuepointAlias + ".scene_id =scenes.id and track is not null)" - } else { - where = "scenes.id not in (select " + scenecuepointAlias + ".scene_id from scene_cuepoints " + scenecuepointAlias + " where " + scenecuepointAlias + ".scene_id =scenes.id and track is not null)" - } + where = "exists (select 1 from scene_cuepoints where scene_cuepoints.scene_id = scenes.id and track is not null)" case "In Trailer List": - if truefalse { - where = "trailerlist = 1" - } else { - where = "trailerlist = 0" - } + where = "trailerlist = 1" case "Has Subscription": - if truefalse { - where = "is_subscribed = 1" - } else { - where = "is_subscribed = 0" - } - case "Rating 0", "Rating .5", "Rating 1", "Rating 1.5", "Rating 2", "Rating 2.5", "Rating 3", "Rating 3.5", "Rating 4", "Rating 4.5", "Rating 5": - if truefalse { - where = "scenes.star_rating = " + fieldName[7:] - } else { - where = "scenes.star_rating <> " + fieldName[7:] - } + where = "is_subscribed = 1" + case "Rating": + where = "scenes.star_rating = " + value case "Cast 6+": - if truefalse { - where = "scenes.id in (select " + scenecastAlias + ".scene_id from scene_cast " + scenecastAlias + " join actors " + actorsAlias + " on " + actorsAlias + ".id =" + scenecastAlias + ".actor_id where " + scenecastAlias + ".scene_id =scenes.id and " + actorsAlias + ".name not like 'aka:%' group by " + scenecastAlias + ".scene_id having count(*)>5)" - } else { - where = "scenes.id not in (select " + scenecastAlias + ".scene_id from scene_cast " + scenecastAlias + " join actors " + actorsAlias + " on " + actorsAlias + ".id =" + scenecastAlias + ".actor_id where " + scenecastAlias + ".scene_id =scenes.id and " + actorsAlias + ".name not like 'aka:%' group by " + scenecastAlias + ".scene_id having count(*)>5)" - } + where = "exists (select 1 from scene_cast join actors on actors.id = scene_cast.actor_id where scene_cast.scene_id = scenes.id and actors.name not like 'aka:%' group by scene_cast.scene_id having count(*) > 5)" case "Cast 1", "Cast 2", "Cast 3", "Cast 4", "Cast 5": - if truefalse { - where = "scenes.id in (select " + scenecastAlias + ".scene_id from scene_cast " + scenecastAlias + " join actors " + actorsAlias + " on " + actorsAlias + ".id =" + scenecastAlias + ".actor_id where " + scenecastAlias + ".scene_id =scenes.id and " + actorsAlias + ".name not like 'aka:%' group by " + scenecastAlias + ".scene_id having count(*)=" + fieldName[5:] + ")" - } else { - where = "scenes.id not in (select " + scenecastAlias + ".scene_id from scene_cast " + scenecastAlias + " join actors " + actorsAlias + " on " + actorsAlias + ".id =" + scenecastAlias + ".actor_id where " + scenecastAlias + ".scene_id =scenes.id and " + actorsAlias + ".name not like 'aka:%' group by " + scenecastAlias + ".scene_id having count(*)=" + fieldName[5:] + ")" - } + where = "exists (select 1 from scene_cast join actors on actors.id = scene_cast.actor_id where scene_cast.scene_id = scenes.id and actors.name not like 'aka:%' group by scene_cast.scene_id having count(*) = " + fieldName[5:] + ")" case "Resolution": - switch db.Dialect().GetName() { - case "mysql": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and case when " + fileAlias + ".video_projection = '360_tb' then (" + fileAlias + ".video_width+499)*2 div 1000 else (" + fileAlias + ".video_width+499) div 1000 end = " + value + ")" - } else { - where = "scenes.id not in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and case when " + fileAlias + ".video_projection = '360_tb' then (" + fileAlias + ".video_width+499)*2 div 1000 else (" + fileAlias + ".video_width+499) div 1000 end = " + value + ")" - } - default: - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and case when " + fileAlias + ".video_projection = '360_tb' then (" + fileAlias + ".video_width+499)*2 / 1000 else (" + fileAlias + ".video_width+499) / 1000 end = " + value + ")" - } else { - where = "scenes.id not in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and case when " + fileAlias + ".video_projection = '360_tb' then (" + fileAlias + ".video_width+499)*2 / 1000 else (" + fileAlias + ".video_width+499) / 1000 end = " + value + ")" - } + div := "/" + if db.Dialect().GetName() == "mysql" { + div = "div" } + where = "exists (select 1 from files where files.scene_id = scenes.id and ((files.video_width * (case when files.video_projection like '%_tb' then 2 else 1 end) + 500) " + div + " 1000) = " + value + ")" case "Frame Rate": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_avg_frame_rate_val = " + value + " and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id not in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_avg_frame_rate_val = " + value + " and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_avg_frame_rate_val = " + value + ")" case "Flat video": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='flat' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='flat' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection = 'flat')" case "FOV: 180°": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('180_mono','180_sbs','fisheye') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('180_mono','180_sbs','fisheye') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('180_mono','180_sbs','fisheye'))" case "FOV: 190°": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('rf52','fisheye190') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('rf52','fisheye190') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('rf52','fisheye190'))" case "FOV: 200°": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='mkx200' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='mkx200' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection = 'mkx200')" case "FOV: 220°": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('mkx220','vrca220') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('mkx220','vrca220') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('mkx220','vrca220'))" case "FOV: 360°": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('360_mono','360_tb') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('360_mono','360_tb') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('360_mono','360_tb'))" case "Projection Perspective": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='flat' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='flat' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection = 'flat')" case "Projection Equirectangular": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('180_mono','180_sbs') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('180_mono','180_sbs') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('180_mono','180_sbs'))" case "Projection Equirectangular360": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('360_tb','360_mono') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('360_tb','360_mono') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('360_tb','360_mono'))" case "Projection Fisheye": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('mkx200','mkx220','vrca220','rf52','fisheye190','fisheye') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('mkx200','mkx220','vrca220','rf52','fisheye190','fisheye') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('mkx200','mkx220','vrca220','rf52','fisheye190','fisheye'))" case "Mono": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('flat','180_mono','360_mono') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('flat','180_mono','360_mono') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('flat','180_mono','360_mono'))" case "Top/Bottom": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='360_tb' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='360_tb' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection in ('180_tb','360_tb'))" case "Side by Side": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection not in ('360_tb','flat','180_mono','360_mono') and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection in ('360_tb','flat','180_mono','360_mono') and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection not in (flat','180_mono','360_mono', '180_tb', '360_tb'))" case "MKX200": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='mkx200' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='mkx200' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection = 'mkx200')" case "MKX220": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='mkx220' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='mkx220' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection = 'mkx220')" case "VRCA220": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='vrca220' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_projection ='vrca220' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_projection = 'vrca220')" case "Codec": - if truefalse { - where = "scenes.id in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_codec_name = '" + value + "' and " + fileAlias + ".`type` = 'video')" - } else { - where = "scenes.id not in (select distinct " + fileAlias + ".scene_id from files " + fileAlias + " where " + fileAlias + ".scene_id = scenes.id and " + fileAlias + ".video_codec_name = '" + value + "' and " + fileAlias + ".`type` = 'video')" - } + where = "exists (select 1 from files where files.scene_id = scenes.id and files.`type` = 'video' and files.video_codec_name = '" + value + "')" case "In Watchlist": - if truefalse { - where = "scenes.watchlist = 1" - } else { - where = "scenes.watchlist = 0" - } + where = "watchlist = 1" case "Is Scripted": - if truefalse { - where = "is_scripted = 1" - } else { - where = "is_scripted = 0" - } + where = "is_scripted = 1" case "Is Favourite": - if truefalse { - where = "scenes.favourite = 1" - } else { - where = "scenes.favourite = 0" - } + where = "favourite = 1" case "Is Passthrough": - if truefalse { - where = "chroma_key != ''" - } else { - where = "chroma_key = ''" - } + where = "chroma_key <> ''" case "Stashdb Linked": - if truefalse { - where = "(select count(*) from external_reference_links " + erlAlias + " where " + erlAlias + ".internal_db_id = scenes.id and " + erlAlias + ".`external_source` = 'stashdb scene') > 0" - } else { - where = "(select count(*) from external_reference_links " + erlAlias + " where " + erlAlias + ".internal_db_id = scenes.id and " + erlAlias + ".`external_source` = 'stashdb scene') = 0" - } + where = "exists (select 1 from external_reference_links erl where erl.internal_db_id = scenes.id and erl.external_source = 'stashdb scene')" case "POVR Scraper": - if truefalse { - where = `scenes.scene_id like "povr-%"` - } else { - where = `scenes.scene_id not like "povr-%"` - } + where = `scenes.scene_id like "povr-%"` case "SLR Scraper": - if truefalse { - where = `scenes.scene_id like "slr-%"` - } else { - where = `scenes.scene_id not like "slr-%"` - } + where = `scenes.scene_id like "slr-%"` case "VRPHub Scraper": - if truefalse { - where = `scenes.scene_id like "vrphub-%"` - } else { - where = `scenes.scene_id not like "vrphub-%"` - } + where = `scenes.scene_id like "vrphub-%"` case "VRPorn Scraper": - if truefalse { - where = `scenes.scene_id like "vrporn-%"` - } else { - where = `scenes.scene_id not like "vrporn-%"` - } + where = `scenes.scene_id like "vrporn-%"` case "Has Script Download": - if truefalse { - where = "scenes.script_published > '0001-01-01 00:00:00+00:00'" - } else { - where = "scenes.script_published < '0001-01-02 00:00:00+00:00'" - } + where = "scenes.script_published > '0001-01-01 00:00:00+00:00'" } - switch firstchar := string(attribute.OrElse(" ")[0]); firstchar { - case "&", "!": + if negate { + where = "not " + where + } + + if negate || mustHave { andAttribute = append(andAttribute, where) - default: + } else { orAttribute = append(orAttribute, where) } } @@ -1131,19 +950,19 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { tx = tx.Order("total_watch_time asc") case "rating_desc": tx = tx. - Where("scenes.star_rating > ?", 0). + Where("scenes.star_rating > 0"). Order("scenes.star_rating desc") case "rating_asc": tx = tx. - Where("scenes.star_rating > ?", 0). + Where("scenes.star_rating > 0"). Order("scenes.star_rating asc") case "last_opened_desc": tx = tx. - Where("last_opened > ?", "0001-01-01 00:00:00+00:00"). + Where("last_opened > '0001-01-01 00:00:00+00:00'"). Order("last_opened desc") case "last_opened_asc": tx = tx. - Where("last_opened > ?", "0001-01-01 00:00:00+00:00"). + Where("last_opened > '0001-01-01 00:00:00+00:00'"). Order("last_opened asc") case "scene_added_desc": tx = tx.Order("created_at desc") From 4cd6ebd5b3ca7fb0a221d1f8b1d6a7bc177a1a49 Mon Sep 17 00:00:00 2001 From: alex <85208095+alexnsfw@users.noreply.github.com> Date: Sun, 3 Sep 2023 03:49:04 -0400 Subject: [PATCH 3/5] enable content encoding --- pkg/api/dms.go | 5 +++++ pkg/server/server.go | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/api/dms.go b/pkg/api/dms.go index 0a6fc9496..995a0d29b 100644 --- a/pkg/api/dms.go +++ b/pkg/api/dms.go @@ -11,6 +11,7 @@ import ( restfulspec "github.com/emicklei/go-restful-openapi/v2" "github.com/emicklei/go-restful/v3" "github.com/jinzhu/gorm" + "github.com/xbapps/xbvr/pkg/common" "github.com/xbapps/xbvr/pkg/models" "github.com/xbapps/xbvr/pkg/session" @@ -36,18 +37,22 @@ func (i DMSResource) WebService() *restful.WebService { ws.Route(ws.GET("/file/{file-id}").To(i.getFile). Param(ws.PathParameter("file-id", "File ID").DataType("int")). + ContentEncodingEnabled(false). Metadata(restfulspec.KeyOpenAPITags, tags)) ws.Route(ws.GET("/file/{file-id}/{var:*}").To(i.getFile). Param(ws.PathParameter("file-id", "File ID").DataType("int")). + ContentEncodingEnabled(false). Metadata(restfulspec.KeyOpenAPITags, tags)) ws.Route(ws.GET("/heatmap/{file-id}").To(i.getHeatmap). Param(ws.PathParameter("file-id", "File ID").DataType("int")). + ContentEncodingEnabled(false). Metadata(restfulspec.KeyOpenAPITags, tags)) ws.Route(ws.GET("/preview/{scene-id}").To(i.getPreview). Param(ws.PathParameter("scene-id", "Scene ID")). + ContentEncodingEnabled(false). Metadata(restfulspec.KeyOpenAPITags, tags)) return ws diff --git a/pkg/server/server.go b/pkg/server/server.go index fee000904..bbcc575f5 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -20,6 +20,8 @@ import ( "github.com/koding/websocketproxy" "github.com/peterbourgon/diskv" "github.com/rs/cors" + "willnorris.com/go/imageproxy" + "github.com/xbapps/xbvr/pkg/api" "github.com/xbapps/xbvr/pkg/common" "github.com/xbapps/xbvr/pkg/config" @@ -28,7 +30,6 @@ import ( "github.com/xbapps/xbvr/pkg/session" "github.com/xbapps/xbvr/pkg/tasks" "github.com/xbapps/xbvr/ui" - "willnorris.com/go/imageproxy" ) var ( @@ -63,6 +64,8 @@ func StartServer(version, commit, branch, date string) { models.InitSites() + restful.DefaultContainer.EnableContentEncoding(true) + // API endpoints ws := new(restful.WebService) ws.Route(ws.GET("/").To(func(req *restful.Request, resp *restful.Response) { @@ -88,7 +91,7 @@ func StartServer(version, commit, branch, date string) { WebServices: restful.RegisteredWebServices(), APIPath: "/api.json", PostBuildSwaggerObjectHandler: func(swo *spec.Swagger) { - var e = spec.VendorExtensible{} + e := spec.VendorExtensible{} e.AddExtension("x-logo", map[string]interface{}{ "url": "/ui/icons/xbvr-512.png", }) From 30bb42453969281a01f22045f1275214c2324c96 Mon Sep 17 00:00:00 2001 From: alex <85208095+alexnsfw@users.noreply.github.com> Date: Sun, 3 Sep 2023 07:55:40 -0400 Subject: [PATCH 4/5] only fetch ids for heresphere api --- pkg/api/heresphere.go | 10 ++---- pkg/models/model_scene.go | 69 +++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/pkg/api/heresphere.go b/pkg/api/heresphere.go index 920131ef9..7a2be160f 100644 --- a/pkg/api/heresphere.go +++ b/pkg/api/heresphere.go @@ -969,15 +969,11 @@ func (i HeresphereResource) getHeresphereLibrary(req *restful.Request, resp *res if err := json.Unmarshal([]byte(savedPlaylists[i].SearchParams), &r); err == nil { r.IsAccessible = optional.NewBool(true) r.IsAvailable = optional.NewBool(true) - r.Limit = optional.NewInt(20000) - r.Counts = optional.NewBool(false) - q := models.QueryScenes(r, false) + list := models.QuerySceneIDs(r) - list := make([]string, len(q.Scenes)) - for i := range q.Scenes { - url := fmt.Sprintf("%v://%v/heresphere/%v", getProto(req), req.Request.Host, q.Scenes[i].ID) - list[i] = url + for i := range list { + list[i] = fmt.Sprintf("%v://%v/heresphere/%v", getProto(req), req.Request.Host, list[i]) } sceneLists = append(sceneLists, HeresphereListScenes{ diff --git a/pkg/models/model_scene.go b/pkg/models/model_scene.go index 1994cb1d6..8739bbd03 100644 --- a/pkg/models/model_scene.go +++ b/pkg/models/model_scene.go @@ -590,25 +590,51 @@ func QueryScenesFull(r RequestSceneList) ResponseSceneList { } func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { - limit := r.Limit.OrElse(100) - offset := r.Offset.OrElse(0) + r.Limit = optional.NewInt(r.Limit.OrElse(100)) db, _ := GetDB() defer db.Close() - var scenes []Scene - tx := db.Model(&scenes) + preCountTx, finalTx := queryScenes(db, r) var out ResponseSceneList + // Count other variations + preCountTx.Where("is_hidden = ?", false).Count(&out.CountAny) + preCountTx.Where("is_available = ?", true).Where("is_accessible = ?", true).Where("is_hidden = ?", false).Count(&out.CountAvailable) + preCountTx.Where("is_available = ?", true).Where("is_hidden = ?", false).Count(&out.CountDownloaded) + preCountTx.Where("is_available = ?", false).Where("is_hidden = ?", false).Count(&out.CountNotDownloaded) + preCountTx.Where("is_hidden = ?", true).Count(&out.CountHidden) + + finalTx.Count(&out.Results) + if enablePreload { - tx = tx. + finalTx = finalTx. Preload("Cast"). Preload("Tags"). Preload("Files"). Preload("History"). Preload("Cuepoints") } + finalTx.Find(&out.Scenes) + + return out +} + +func QuerySceneIDs(r RequestSceneList) []string { + db, _ := GetDB() + defer db.Close() + + _, finalTx := queryScenes(db, r) + + var ids []string + finalTx.Pluck("scenes.id", &ids) + + return ids +} + +func queryScenes(db *gorm.DB, r RequestSceneList) (*gorm.DB, *gorm.DB) { + tx := db.Model(&Scene{}) if r.IsWatched.Present() { tx = tx.Where("is_watched = ?", r.IsWatched.OrElse(true)) @@ -697,7 +723,7 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { where = "exists (select 1 from scene_cast join actors on actors.id = scene_cast.actor_id where scene_cast.scene_id = scenes.id and actors.name not like 'aka:%' group by scene_cast.scene_id having count(*) = " + fieldName[5:] + ")" case "Resolution": div := "/" - if db.Dialect().GetName() == "mysql" { + if tx.Dialect().GetName() == "mysql" { div = "div" } where = "exists (select 1 from files where files.scene_id = scenes.id and ((files.video_width * (case when files.video_projection like '%_tb' then 2 else 1 end) + 500) " + div + " 1000) = " + value + ")" @@ -927,14 +953,14 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { case "release_asc": tx = tx.Order("release_date asc") case "title_desc": - switch db.Dialect().GetName() { + switch tx.Dialect().GetName() { case "mysql": tx = tx.Order("title desc") case "sqlite3": tx = tx.Order("title COLLATE NOCASE desc") } case "title_asc": - switch db.Dialect().GetName() { + switch tx.Dialect().GetName() { case "mysql": tx = tx.Order("title asc") case "sqlite3": @@ -980,14 +1006,8 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { tx = tx.Order("release_date desc") } - if r.Counts.OrElse(true) { - // Count other variations - tx.Group("scenes.scene_id").Where("is_hidden = ?", false).Count(&out.CountAny) - tx.Group("scenes.scene_id").Where("is_available = ?", true).Where("is_accessible = ?", true).Where("is_hidden = ?", false).Count(&out.CountAvailable) - tx.Group("scenes.scene_id").Where("is_available = ?", true).Where("is_hidden = ?", false).Count(&out.CountDownloaded) - tx.Group("scenes.scene_id").Where("is_available = ?", false).Where("is_hidden = ?", false).Count(&out.CountNotDownloaded) - tx.Group("scenes.scene_id").Where("is_hidden = ?", true).Count(&out.CountHidden) - } + preCountTx := tx.Group("scenes.scene_id") + tx = tx.Group("scenes.scene_id") // Apply avail/accessible after counting if r.IsAvailable.Present() { @@ -1004,21 +1024,12 @@ func QueryScenes(r RequestSceneList, enablePreload bool) ResponseSceneList { tx = tx.Where("is_hidden = ?", false) } - if r.Counts.OrElse(true) { - // Count totals for selection - tx. - Group("scenes.scene_id"). - Count(&out.Results) + // Pagination + if r.Limit.Present() { + tx = tx.Limit(r.Limit.MustGet()).Offset(r.Offset.OrElse(0)) } - // Get scenes - tx. - Group("scenes.scene_id"). - Limit(limit). - Offset(offset). - Find(&out.Scenes) - - return out + return preCountTx, tx } func setCuepointString(cuepoint string) string { From d0369038810dbc4c8b790a8985f9474632285608 Mon Sep 17 00:00:00 2001 From: alex <85208095+alexnsfw@users.noreply.github.com> Date: Sun, 3 Sep 2023 16:12:20 -0400 Subject: [PATCH 5/5] fetch only as much as necessary for deovr lists --- pkg/api/deovr.go | 17 ++++++++--------- pkg/models/model_scene.go | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/pkg/api/deovr.go b/pkg/api/deovr.go index d9f01e295..25c32c0c9 100644 --- a/pkg/api/deovr.go +++ b/pkg/api/deovr.go @@ -33,7 +33,7 @@ type DeoListScenes struct { type DeoListItem struct { Title string `json:"title"` - VideoLength int `json:"videoLength"` + VideoLength uint `json:"videoLength"` ThumbnailURL string `json:"thumbnailUrl"` VideoURL string `json:"video_url"` } @@ -625,13 +625,11 @@ func (i DeoVRResource) getDeoLibrary(req *restful.Request, resp *restful.Respons if err := json.Unmarshal([]byte(savedPlaylists[i].SearchParams), &r); err == nil { r.IsAccessible = optional.NewBool(true) r.IsAvailable = optional.NewBool(true) - r.Limit = optional.NewInt(10000) - r.Counts = optional.NewBool(false) - q := models.QueryScenes(r, false) + summaries := models.QuerySceneSummaries(r) sceneLists = append(sceneLists, DeoListScenes{ Name: savedPlaylists[i].Name, - List: scenesToDeoList(req, q.Scenes), + List: scenesToDeoList(req, summaries), }) } } @@ -656,15 +654,16 @@ func (i DeoVRResource) getDeoLibrary(req *restful.Request, resp *restful.Respons }) } -func scenesToDeoList(req *restful.Request, scenes []models.Scene) []DeoListItem { +func scenesToDeoList(req *restful.Request, scenes []models.SceneSummary) []DeoListItem { setDeoPlayerHost(req) list := make([]DeoListItem, 0) for i := range scenes { - thumbnailURL := fmt.Sprintf("%v/img/700x/%v", session.DeoRequestHost, strings.Replace(scenes[i].CoverURL, "://", ":/", -1)) - + var thumbnailURL string if config.Config.Interfaces.DeoVR.RenderHeatmaps && scenes[i].IsScripted { thumbnailURL = fmt.Sprintf("%v/imghm/%d/%v", session.DeoRequestHost, scenes[i].ID, strings.Replace(scenes[i].CoverURL, "://", ":/", -1)) + } else { + thumbnailURL = fmt.Sprintf("%v/img/700x/%v", session.DeoRequestHost, strings.Replace(scenes[i].CoverURL, "://", ":/", -1)) } item := DeoListItem{ @@ -695,7 +694,7 @@ func filesToDeoList(req *restful.Request, files []models.File) []DeoListItem { } item := DeoListItem{ Title: files[i].Filename, - VideoLength: int(files[i].VideoDuration), + VideoLength: uint(files[i].VideoDuration), ThumbnailURL: session.DeoRequestHost + "/ui/images/blank.png", VideoURL: fmt.Sprintf("%v/deovr/file/%v%v", session.DeoRequestHost, files[i].ID, dnt), } diff --git a/pkg/models/model_scene.go b/pkg/models/model_scene.go index 8739bbd03..5f523db91 100644 --- a/pkg/models/model_scene.go +++ b/pkg/models/model_scene.go @@ -633,6 +633,26 @@ func QuerySceneIDs(r RequestSceneList) []string { return ids } +type SceneSummary struct { + ID uint + Title string + Duration uint + CoverURL string + IsScripted bool +} + +func QuerySceneSummaries(r RequestSceneList) []SceneSummary { + db, _ := GetDB() + defer db.Close() + + _, finalTx := queryScenes(db, r) + + var summaries []SceneSummary + finalTx.Select("scenes.id, title, duration, cover_url, is_scripted").Scan(&summaries) + + return summaries +} + func queryScenes(db *gorm.DB, r RequestSceneList) (*gorm.DB, *gorm.DB) { tx := db.Model(&Scene{}) @@ -1006,6 +1026,9 @@ func queryScenes(db *gorm.DB, r RequestSceneList) (*gorm.DB, *gorm.DB) { tx = tx.Order("release_date desc") } + // Add second order to keep things stable in case of ties + tx = tx.Order("scenes.id asc") + preCountTx := tx.Group("scenes.scene_id") tx = tx.Group("scenes.scene_id")