diff --git a/pkg/api/deovr.go b/pkg/api/deovr.go index b8f2a9b5d..1f21792a0 100644 --- a/pkg/api/deovr.go +++ b/pkg/api/deovr.go @@ -12,6 +12,7 @@ import ( restfulspec "github.com/emicklei/go-restful-openapi/v2" "github.com/emicklei/go-restful/v3" "github.com/markphelps/optional" + "github.com/tidwall/gjson" "github.com/xbapps/xbvr/pkg/common" "github.com/xbapps/xbvr/pkg/config" "github.com/xbapps/xbvr/pkg/models" @@ -113,6 +114,46 @@ type DeoSceneHSPFile struct { URL string `json:"url"` } +type DeoSceneChromaKey struct { + Enabled string `json:"enabled"` + HasAlpha string `json:"hasAlpha"` + H float64 `json:"h"` + Opacity float64 `json:"opacity"` + S float64 `json:"s"` + Threshold float64 `json:"threshold"` + V float64 `json:"v"` +} + +type DeoScenePassthrough struct { + ID uint `json:"id"` + Title string `json:"title"` + Authorized uint `json:"authorized"` + Description string `json:"description"` + Date int64 `json:"date"` + Paysite DeoScenePaysite `json:"paysite"` + IsFavorite bool `json:"isFavorite"` + IsScripted bool `json:"isScripted"` + IsWatchlist bool `json:"isWatchlist"` + Is3D bool `json:"is3d"` + ThumbnailURL string `json:"thumbnailUrl"` + RatingAvg float64 `json:"rating_avg"` + ScreenType string `json:"screenType"` + StereoMode string `json:"stereoMode"` + VideoLength int `json:"videoLength"` + VideoThumbnail string `json:"videoThumbnail"` + VideoPreview string `json:"videoPreview,omitempty"` + Encodings []DeoSceneEncoding `json:"encodings"` + EncodingsSpatial []DeoSceneEncoding `json:"encodings_spatial"` + Timestamps []DeoSceneTimestamp `json:"timeStamps"` + Actors []DeoSceneActor `json:"actors"` + Categories []DeoSceneCategory `json:"categories,omitempty"` + Fleshlight []DeoSceneScriptFile `json:"fleshlight,omitempty"` + HSProfile []DeoSceneHSPFile `json:"hsp,omitempty"` + FullVideoReady bool `json:"fullVideoReady"` + FullAccess bool `json:"fullAccess"` + ChromaKey DeoSceneChromaKey `json:"chromakey"` +} + func isDeoAuthEnabled() bool { if config.Config.Interfaces.DeoVR.AuthEnabled && config.Config.Interfaces.DeoVR.Username != "" && @@ -458,6 +499,30 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response) title := scene.Title thumbnailURL := session.DeoRequestHost + "/img/700x/" + strings.Replace(scene.CoverURL, "://", ":/", -1) + //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) + _ = chromaKey + if gjson.Valid(scene.ChromaKey) { + if err := json.Unmarshal([]byte(scene.ChromaKey), &ckdata); err != nil { + fmt.Println("Error:", err) + } + result := gjson.Get(scene.ChromaKey, "hasAlpha") + if !result.Exists() || ckdata["hasAlpha"] == "" { + // if ckdata["."].(map[string]interface{})["hasAlpha"] = "false" || ckdata["."].(map[string]interface{})["hasAlpha"] = "" { + + //setting hasAlpha to false + ckdata["hasAlpha"] = "false" + } + // Convert back to JSON string + ckup, err := json.Marshal(ckdata) + if err != nil { + fmt.Println("Error:", err) + } + chromaKey = gjson.ParseBytes(ckup) + } + if scene.IsScripted { title = scene.GetFunscriptTitle() if config.Config.Interfaces.DeoVR.RenderHeatmaps { @@ -502,7 +567,39 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response) deoScene.VideoPreview = fmt.Sprintf("%v/api/dms/preview/%v", session.DeoRequestHost, scene.SceneID) } - resp.WriteHeaderAndEntity(http.StatusOK, deoScene) + if gjson.Valid(scene.ChromaKey) { + deoPtScene := DeoScenePassthrough{ + ID: scene.ID, + Authorized: 1, + Title: title, + Description: scene.Synopsis, + Date: finalDate, + Actors: actors, + Paysite: DeoScenePaysite{ID: 1, Name: scene.Site, Is3rdParty: true}, + IsFavorite: scene.Favourite, + IsScripted: scene.IsScripted, + IsWatchlist: scene.Watchlist, + RatingAvg: scene.StarRating, + FullVideoReady: true, + FullAccess: true, + ThumbnailURL: thumbnailURL, + StereoMode: stereoMode, + Is3D: true, + ScreenType: screenType, + Encodings: sources, + EncodingsSpatial: sourcesSpatial, + VideoLength: int(videoLength), + Timestamps: cuepoints, + Categories: categories, + Fleshlight: deoScriptFiles, + HSProfile: deoHSPFiles, + ChromaKey: DeoSceneChromaKey{Enabled: chromaKey.Get("enabled").String(), HasAlpha: chromaKey.Get("hasAlpha").String(), H: chromaKey.Get("h").Float(), Opacity: chromaKey.Get("opacity").Float(), S: chromaKey.Get("s").Float(), Threshold: chromaKey.Get("threshold").Float(), V: chromaKey.Get("v").Float()}, + VideoPreview: deoScene.VideoPreview, + } + resp.WriteHeaderAndEntity(http.StatusOK, deoPtScene) + } else { + resp.WriteHeaderAndEntity(http.StatusOK, deoScene) + } } func (i DeoVRResource) getDeoLibrary(req *restful.Request, resp *restful.Response) { diff --git a/pkg/migrations/migrations.go b/pkg/migrations/migrations.go index 94ad42bc3..853af7c43 100644 --- a/pkg/migrations/migrations.go +++ b/pkg/migrations/migrations.go @@ -705,6 +705,15 @@ func Migrate() { return nil }, }, + { + ID: "0065-scenes-add-chromakey-for-passthrough", + Migrate: func(tx *gorm.DB) error { + type Scene struct { + ChromaKey string `json:"chromakey" xbvrbackup:"chromakey"` + } + return tx.AutoMigrate(Scene{}).Error + }, + }, // =============================================================================================== // Put DB Schema migrations above this line and migrations that rely on the updated schema below diff --git a/pkg/models/model_scene.go b/pkg/models/model_scene.go index 81a7b95df..923487390 100644 --- a/pkg/models/model_scene.go +++ b/pkg/models/model_scene.go @@ -102,6 +102,7 @@ type Scene struct { EditsApplied bool `json:"edits_applied" gorm:"default:false" xbvrbackup:"-"` TrailerType string `json:"trailer_type" xbvrbackup:"trailer_type"` TrailerSource string `gorm:"size:1000" json:"trailer_source" xbvrbackup:"trailer_source"` + ChromaKey string `json:"passthrough" xbvrbackup:"passthrough"` Trailerlist bool `json:"trailerlist" gorm:"default:false" xbvrbackup:"trailerlist"` IsSubscribed bool `json:"is_subscribed" gorm:"default:false"` IsHidden bool `json:"is_hidden" gorm:"default:false" xbvrbackup:"is_hidden"` @@ -431,6 +432,8 @@ func SceneCreateUpdateFromExternal(db *gorm.DB, ext ScrapedScene) error { o.SceneURL = ext.HomepageURL o.MemberURL = ext.MembersUrl + o.ChromaKey = ext.ChromaKey + // Trailers o.TrailerType = ext.TrailerType o.TrailerSource = ext.TrailerSrc diff --git a/pkg/models/model_scraper.go b/pkg/models/model_scraper.go index 4e1b2104d..671065dd2 100644 --- a/pkg/models/model_scraper.go +++ b/pkg/models/model_scraper.go @@ -36,6 +36,7 @@ type ScrapedScene struct { MembersUrl string `json:"members_url"` TrailerType string `json:"trailer_type"` TrailerSrc string `json:"trailer_source"` + ChromaKey string `json:"chromakey"` ActorDetails map[string]ActorDetails `json:"actor_details"` } diff --git a/pkg/scrape/slrstudios.go b/pkg/scrape/slrstudios.go index 7d3aaeea7..d46db8794 100644 --- a/pkg/scrape/slrstudios.go +++ b/pkg/scrape/slrstudios.go @@ -7,6 +7,7 @@ import ( "strings" "sync" + "github.com/go-resty/resty/v2" "github.com/gocolly/colly/v2" "github.com/thoas/go-funk" "github.com/tidwall/gjson" @@ -74,6 +75,7 @@ func SexLikeReal(wg *sync.WaitGroup, updateSite bool, knownScenes []string, out // Could split by / but would run into issues with "f/f/m" and "shorts / skirts" var videotype string var FB360 string + alphA := "false" e.ForEach(`ul.c-meta--scene-tags li a`, func(id int, e *colly.HTMLElement) { if !skiptags[e.Attr("title")] { sc.Tags = append(sc.Tags, e.Attr("title")) @@ -87,6 +89,11 @@ func SexLikeReal(wg *sync.WaitGroup, updateSite bool, knownScenes []string, out FB360 = "_FB360.MKV" } + // Passthrough? + if e.Attr("title") == "Passthrough" || e.Attr("title") == "Passthrough hack" || e.Attr("title") == "Passthrough AR" { + alphA = "PT" + } + }) // Duration @@ -158,8 +165,6 @@ func SexLikeReal(wg *sync.WaitGroup, updateSite bool, knownScenes []string, out } } - // Filenames - appendFilenames(&sc, siteID, filenameRegEx, videotype, FB360) } }) @@ -177,7 +182,7 @@ func SexLikeReal(wg *sync.WaitGroup, updateSite bool, knownScenes []string, out // Filenames // trans videos don't appear to follow video type naming conventions - appendFilenames(&sc, siteID, filenameRegEx, "", "") + // appendFilenames(&sc, siteID, filenameRegEx, "", "", alphA) } }) @@ -192,6 +197,21 @@ func SexLikeReal(wg *sync.WaitGroup, updateSite bool, knownScenes []string, out }) } + // Passthrough "chromaKey":{"enabled":false,"hasAlpha":true,"h":0,"opacity":1,"s":0,"threshold":0,"v":0} + if alphA == "PT" { + s, _ := resty.New().R(). + SetHeader("User-Agent", UserAgent). + Get(sc.TrailerSrc) + JsonMetadataA := s.String() + if gjson.Get(JsonMetadataA, "chromaKey").Exists() { + sc.ChromaKey = gjson.Get(JsonMetadataA, "chromaKey").String() + } + alphA = gjson.Get(JsonMetadataA, "chromaKey.hasAlpha").String() + } + + // Filenames + appendFilenames(&sc, siteID, filenameRegEx, videotype, FB360, alphA) + // actor details sc.ActorDetails = make(map[string]models.ActorDetails) e.ForEach(`a[data-qa="scene-model-list-item-photo-link-to-profile"]`, func(id int, e_a *colly.HTMLElement) { @@ -244,10 +264,10 @@ func SexLikeReal(wg *sync.WaitGroup, updateSite bool, knownScenes []string, out return nil } -func appendFilenames(sc *models.ScrapedScene, siteID string, filenameRegEx *regexp.Regexp, videotype string, FB360 string) { +func appendFilenames(sc *models.ScrapedScene, siteID string, filenameRegEx *regexp.Regexp, videotype string, FB360 string, AlphA string) { // Only shown for logged in users so need to generate them // Format: SLR_siteID_Title__SceneID__<180/360>.mp4 - resolutions := []string{"_6400p_", "_4000p_", "_3840p_", "_3360p_", "_3160p_", "_3072p_", "_2900p_", "_2880p_", "_2700p_", "_2650p_", "_2160p_", "_1920p_", "_1440p_", "_1080p_", "_original_"} + resolutions := []string{"_6400p_", "_4096p_", "_4000p_", "_3840p_", "_3360p_", "_3160p_", "_3072p_", "_3000p_", "_2900p_", "_2880p_", "_2700p_", "_2650p_", "_2160p_", "_1920p_", "_1440p_", "_1080p_", "_original_"} baseName := "SLR_" + strings.TrimSuffix(siteID, " (SLR)") + "_" + filenameRegEx.ReplaceAllString(sc.Title, "_") switch videotype { case "360°": // Sadly can't determine if TB or MONO so have to add both @@ -257,11 +277,19 @@ func appendFilenames(sc *models.ScrapedScene, siteID string, filenameRegEx *rege } case "Fisheye": // 200° videos named with MKX200 for i := range resolutions { - sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_MKX200.mp4") - sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_MKX220.mp4") - sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_RF52.mp4") - sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_FISHEYE190.mp4") - sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_VRCA220.mp4") + if AlphA == "true" { + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_MKX200_alpha.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_MKX220_alpha.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_RF52_alpha.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_FISHEYE190_alpha.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_VRCA220_alpha.mp4") + } else { + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_MKX200.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_MKX220.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_RF52.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_FISHEYE190.mp4") + sc.Filenames = append(sc.Filenames, baseName+resolutions[i]+sc.SiteID+"_VRCA220.mp4") + } } default: // Assuming everything else is 180 and LR, yet to find a TB_180 for i := range resolutions {