From 24389590b91e539deea89d4d934aaa295a67c3e9 Mon Sep 17 00:00:00 2001 From: Philip Wang Date: Thu, 22 Jan 2026 14:13:03 -0500 Subject: [PATCH] modded --- internal/api/routes_scene.go | 37 +++++++++++++++++++ package-lock.json | 22 +++++++++++ package.json | 5 +++ .../SceneDetails/ExternalPlayerButton.tsx | 19 ++++++++-- 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/internal/api/routes_scene.go b/internal/api/routes_scene.go index 2905bd53a..b2ec83269 100644 --- a/internal/api/routes_scene.go +++ b/internal/api/routes_scene.go @@ -8,6 +8,10 @@ import ( "strconv" "strings" + // Added by Philip + "os" + // Added ends. + "github.com/go-chi/chi/v5" "github.com/stashapp/stash/internal/manager" @@ -69,6 +73,8 @@ func (rs sceneRoutes) Routes() chi.Router { r.Get("/stream.mpd/{segment}_v.webm", rs.StreamDASHVideoSegment) r.Get("/stream.mpd/{segment}_a.webm", rs.StreamDASHAudioSegment) + r.Get("/stream/org/{streamOrgFile}", rs.StreamOrgDirect) // Added by Philip + r.Get("/screenshot", rs.Screenshot) r.Get("/preview", rs.Preview) r.Get("/webp", rs.Webp) @@ -99,6 +105,37 @@ func (rs sceneRoutes) StreamDirect(w http.ResponseWriter, r *http.Request) { ss.StreamSceneDirect(scene, w, r) } +// Added by Philip +func (rs sceneRoutes) StreamOrgDirect(w http.ResponseWriter, r *http.Request) { + scene := r.Context().Value(sceneKey).(*models.Scene) + // check if it's funscript + aStr := strings.Split(chi.URLParam(r, "streamOrgFile"), ".") + // aStr := strings.Split(r.RequestURI, ".") + if strings.ToLower(aStr[len(aStr)-1]) == "funscript" { + // it's a funscript request + rs.Funscript(w, r) + return + } + + // return 404 if the scene does not have a primary file + f := scene.Files.Primary() + if f == nil { + w.WriteHeader(http.StatusNotFound) + if _, err := w.Write([]byte("Primary file not found for streaming original file.")); err != nil { + logger.Warnf("[scene] error getting primary file for streaming original: $v", err) + } + return + } + // Also return 404 if the actual video file cannot be found + if _, err := os.Stat(f.Path); errors.Is(err, os.ErrNotExist) { + w.WriteHeader(http.StatusNotFound) + return + } + http.ServeFile(w, r, f.Path) +} + +// Added ends. + func (rs sceneRoutes) StreamMp4(w http.ResponseWriter, r *http.Request) { rs.streamTranscode(w, r, ffmpeg.StreamTypeMP4) } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..210f4f17d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "stash4deovr", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "baseline-browser-mapping": "^2.9.17" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.17", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz", + "integrity": "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..5f1acfe1a --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "baseline-browser-mapping": "^2.9.17" + } +} diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx index 3701f4138..35d066838 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx @@ -19,8 +19,16 @@ export const ExternalPlayerButton: React.FC = ({ const { paths } = scene; - if (!paths || !paths.stream || (!isAndroid && !isAppleDevice)) - return ; + // Added by Philip + const alwaysShow = true; + const { files } = scene; + const { path } = files[0]; + const pathStr = path??''; + const fileName = pathStr.split('/').pop()?.split('\\').pop()??''; + // Added ends. + + if (!paths || !paths.stream || (!isAndroid && !isAppleDevice && !alwaysShow)) // Modded by Philip + return ; const { stream } = paths; const title = objectTitle(scene); @@ -47,7 +55,10 @@ export const ExternalPlayerButton: React.FC = ({ url = streamURL .toString() .replace(new RegExp(`^${streamURL.protocol}`), "vlc-x-callback:"); + } else if (alwaysShow) { // Added by Philip + url = stream + "/org/" + encodeURIComponent(fileName); // like http://192.168.1.10:9999/scene/123/stream/org/file.mp4 } + // Added ends. return ( ); };