refactor(cef): inject transcoding classification seams
- commit
- a8274e612f765edd559d89399fba6dd59aa1843a
- author
- brice · · 2026-04-11 13:14 UTC
- parent
- 51da5d5
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +66 -20
M internal/infrastructure/cef/engine_init.go +3 -1
| @@ -71,7 +71,7 @@ func NewEngine( | |||
| 71 | 71 | } | |
| 72 | 72 | os.Args = savedArgs | |
| 73 | 73 | ||
| 74 | - | return wireEngine(ctx, eng, cfg, transcodingCfg, windowlessFrameRate, audioFactory, logger, deps.CurrentConfigPayload, deps.DefaultConfigPayload) | |
| 74 | + | return wireEngine(ctx, eng, cfg, transcodingCfg, windowlessFrameRate, audioFactory, logger, deps.MediaClassifier.normalize(), deps.CurrentConfigPayload, deps.DefaultConfigPayload) | |
| 75 | 75 | } | |
| 76 | 76 | ||
| 77 | 77 | func resolvedStateRoot(opts port.EngineOptions) string { | |
| @@ -153,6 +153,7 @@ func initializeCEF(eng *Engine, settings purecef.Settings, logger *zerolog.Logge | |||
| 153 | 153 | func wireEngine( | |
| 154 | 154 | ctx context.Context, eng *Engine, cfg RuntimeConfig, transcodingCfg TranscodingRuntimeConfig, | |
| 155 | 155 | windowlessFrameRate int32, audioFactory port.AudioOutputFactory, logger *zerolog.Logger, | |
| 156 | + | mediaClassifier MediaClassifier, | |
| 156 | 157 | currentConfigPayload func() ([]byte, error), defaultConfigPayload func() ([]byte, error), | |
| 157 | 158 | ) (*Engine, error) { | |
| 158 | 159 | gl, err := newGLLoader() | |
| @@ -196,6 +197,7 @@ func wireEngine( | |||
| 196 | 197 | windowlessFrameRate: windowlessFrameRate, | |
| 197 | 198 | enableContextMenuHandler: cfg.EnableContextMenuHandler, | |
| 198 | 199 | transcoder: mediaTranscoder, | |
| 200 | + | mediaClassifier: mediaClassifier, | |
| 199 | 201 | audioOutputFactory: audioFactory, | |
| 200 | 202 | }) | |
| 201 | 203 | pool := newWebViewPool(factory) | |
| @@ -71,7 +71,7 @@ func NewEngine( | |||||
| 71 | } | 71 | } | ||
| 72 | os.Args = savedArgs | 72 | os.Args = savedArgs | ||
| 73 | 73 | ||||
| 74 | - | return wireEngine(ctx, eng, cfg, transcodingCfg, windowlessFrameRate, audioFactory, logger, deps.CurrentConfigPayload, deps.DefaultConfigPayload) | 74 | + | return wireEngine(ctx, eng, cfg, transcodingCfg, windowlessFrameRate, audioFactory, logger, deps.MediaClassifier.normalize(), deps.CurrentConfigPayload, deps.DefaultConfigPayload) |
| 75 | } | 75 | } | ||
| 76 | 76 | ||||
| 77 | func resolvedStateRoot(opts port.EngineOptions) string { | 77 | func resolvedStateRoot(opts port.EngineOptions) string { | ||
| @@ -153,6 +153,7 @@ func initializeCEF(eng *Engine, settings purecef.Settings, logger *zerolog.Logge | |||||
| 153 | func wireEngine( | 153 | func wireEngine( | ||
| 154 | ctx context.Context, eng *Engine, cfg RuntimeConfig, transcodingCfg TranscodingRuntimeConfig, | 154 | ctx context.Context, eng *Engine, cfg RuntimeConfig, transcodingCfg TranscodingRuntimeConfig, | ||
| 155 | windowlessFrameRate int32, audioFactory port.AudioOutputFactory, logger *zerolog.Logger, | 155 | windowlessFrameRate int32, audioFactory port.AudioOutputFactory, logger *zerolog.Logger, | ||
| 156 | + | mediaClassifier MediaClassifier, | |||
| 156 | currentConfigPayload func() ([]byte, error), defaultConfigPayload func() ([]byte, error), | 157 | currentConfigPayload func() ([]byte, error), defaultConfigPayload func() ([]byte, error), | ||
| 157 | ) (*Engine, error) { | 158 | ) (*Engine, error) { | ||
| 158 | gl, err := newGLLoader() | 159 | gl, err := newGLLoader() | ||
| @@ -196,6 +197,7 @@ func wireEngine( | |||||
| 196 | windowlessFrameRate: windowlessFrameRate, | 197 | windowlessFrameRate: windowlessFrameRate, | ||
| 197 | enableContextMenuHandler: cfg.EnableContextMenuHandler, | 198 | enableContextMenuHandler: cfg.EnableContextMenuHandler, | ||
| 198 | transcoder: mediaTranscoder, | 199 | transcoder: mediaTranscoder, | ||
| 200 | + | mediaClassifier: mediaClassifier, | |||
| 199 | audioOutputFactory: audioFactory, | 201 | audioOutputFactory: audioFactory, | ||
| 200 | }) | 202 | }) | ||
| 201 | pool := newWebViewPool(factory) | 203 | pool := newWebViewPool(factory) | ||
M internal/infrastructure/cef/factory.go +4 -1
| @@ -25,6 +25,7 @@ type WebViewFactory struct { | |||
| 25 | 25 | enableContextMenuHandler bool | |
| 26 | 26 | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | |
| 27 | 27 | transcoder port.MediaTranscoder | |
| 28 | + | mediaClassifier MediaClassifier | |
| 28 | 29 | audioOutputFactory port.AudioOutputFactory | |
| 29 | 30 | } | |
| 30 | 31 | ||
| @@ -33,6 +34,7 @@ type webViewFactoryOptions struct { | |||
| 33 | 34 | windowlessFrameRate int32 | |
| 34 | 35 | enableContextMenuHandler bool | |
| 35 | 36 | transcoder port.MediaTranscoder | |
| 37 | + | mediaClassifier MediaClassifier | |
| 36 | 38 | audioOutputFactory port.AudioOutputFactory | |
| 37 | 39 | } | |
| 38 | 40 | ||
| @@ -52,6 +54,7 @@ func newWebViewFactory(engine *Engine, gl *glLoader, opts webViewFactoryOptions) | |||
| 52 | 54 | windowlessFrameRate: opts.windowlessFrameRate, | |
| 53 | 55 | enableContextMenuHandler: opts.enableContextMenuHandler, | |
| 54 | 56 | transcoder: opts.transcoder, | |
| 57 | + | mediaClassifier: opts.mediaClassifier, | |
| 55 | 58 | audioOutputFactory: opts.audioOutputFactory, | |
| 56 | 59 | } | |
| 57 | 60 | } | |
| @@ -81,7 +84,7 @@ func (f *WebViewFactory) Create(ctx context.Context) (port.WebView, error) { | |||
| 81 | 84 | ||
| 82 | 85 | var transcodingHandler purecef.ResourceRequestHandler | |
| 83 | 86 | if f.transcoder != nil { | |
| 84 | - | transcodingHandler = newTranscodingRequestHandler(f.transcoder, func() context.Context { | |
| 87 | + | transcodingHandler = newTranscodingRequestHandler(f.transcoder, f.mediaClassifier, func() context.Context { | |
| 85 | 88 | if f.engine != nil { | |
| 86 | 89 | return f.engine.currentContext() | |
| 87 | 90 | } | |
| @@ -25,6 +25,7 @@ type WebViewFactory struct { | |||||
| 25 | enableContextMenuHandler bool | 25 | enableContextMenuHandler bool | ||
| 26 | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | 26 | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | ||
| 27 | transcoder port.MediaTranscoder | 27 | transcoder port.MediaTranscoder | ||
| 28 | + | mediaClassifier MediaClassifier | |||
| 28 | audioOutputFactory port.AudioOutputFactory | 29 | audioOutputFactory port.AudioOutputFactory | ||
| 29 | } | 30 | } | ||
| 30 | 31 | ||||
| @@ -33,6 +34,7 @@ type webViewFactoryOptions struct { | |||||
| 33 | windowlessFrameRate int32 | 34 | windowlessFrameRate int32 | ||
| 34 | enableContextMenuHandler bool | 35 | enableContextMenuHandler bool | ||
| 35 | transcoder port.MediaTranscoder | 36 | transcoder port.MediaTranscoder | ||
| 37 | + | mediaClassifier MediaClassifier | |||
| 36 | audioOutputFactory port.AudioOutputFactory | 38 | audioOutputFactory port.AudioOutputFactory | ||
| 37 | } | 39 | } | ||
| 38 | 40 | ||||
| @@ -52,6 +54,7 @@ func newWebViewFactory(engine *Engine, gl *glLoader, opts webViewFactoryOptions) | |||||
| 52 | windowlessFrameRate: opts.windowlessFrameRate, | 54 | windowlessFrameRate: opts.windowlessFrameRate, | ||
| 53 | enableContextMenuHandler: opts.enableContextMenuHandler, | 55 | enableContextMenuHandler: opts.enableContextMenuHandler, | ||
| 54 | transcoder: opts.transcoder, | 56 | transcoder: opts.transcoder, | ||
| 57 | + | mediaClassifier: opts.mediaClassifier, | |||
| 55 | audioOutputFactory: opts.audioOutputFactory, | 58 | audioOutputFactory: opts.audioOutputFactory, | ||
| 56 | } | 59 | } | ||
| 57 | } | 60 | } | ||
| @@ -81,7 +84,7 @@ func (f *WebViewFactory) Create(ctx context.Context) (port.WebView, error) { | |||||
| 81 | 84 | ||||
| 82 | var transcodingHandler purecef.ResourceRequestHandler | 85 | var transcodingHandler purecef.ResourceRequestHandler | ||
| 83 | if f.transcoder != nil { | 86 | if f.transcoder != nil { | ||
| 84 | - | transcodingHandler = newTranscodingRequestHandler(f.transcoder, func() context.Context { | 87 | + | transcodingHandler = newTranscodingRequestHandler(f.transcoder, f.mediaClassifier, func() context.Context { |
| 85 | if f.engine != nil { | 88 | if f.engine != nil { | ||
| 86 | return f.engine.currentContext() | 89 | return f.engine.currentContext() | ||
| 87 | } | 90 | } | ||
M internal/infrastructure/cef/transcoding_handler.go +23 -18
| @@ -4,7 +4,6 @@ import ( | |||
| 4 | 4 | "context" | |
| 5 | 5 | "errors" | |
| 6 | 6 | "io" | |
| 7 | - | "strings" | |
| 8 | 7 | "sync" | |
| 9 | 8 | "time" | |
| 10 | 9 | "unsafe" | |
| @@ -12,7 +11,6 @@ import ( | |||
| 12 | 11 | purecef "github.com/bnema/purego-cef/cef" | |
| 13 | 12 | ||
| 14 | 13 | "github.com/bnema/dumber/internal/application/port" | |
| 15 | - | "github.com/bnema/dumber/internal/infrastructure/transcoder" | |
| 16 | 14 | "github.com/bnema/dumber/internal/logging" | |
| 17 | 15 | "github.com/rs/zerolog" | |
| 18 | 16 | ) | |
| @@ -185,6 +183,7 @@ func (rh *transcodingResourceHandler) Skip(_ int64, _ unsafe.Pointer, _ purecef. | |||
| 185 | 183 | ||
| 186 | 184 | type transcodingRequestHandler struct { | |
| 187 | 185 | transcoder port.MediaTranscoder | |
| 186 | + | classifier MediaClassifier | |
| 188 | 187 | transcodableURLs sync.Map // url string -> requestInfo | |
| 189 | 188 | ctxf func() context.Context | |
| 190 | 189 | } | |
| @@ -197,10 +196,11 @@ type requestInfo struct { | |||
| 197 | 196 | // proprietary video containers and HLS/DASH manifest entrypoints, then | |
| 198 | 197 | // restarts those requests through a GPU transcoding ResourceHandler. | |
| 199 | 198 | func newTranscodingRequestHandler( | |
| 200 | - | tc port.MediaTranscoder, ctxf func() context.Context, | |
| 199 | + | tc port.MediaTranscoder, classifier MediaClassifier, ctxf func() context.Context, | |
| 201 | 200 | ) purecef.ResourceRequestHandler { | |
| 202 | 201 | return purecef.NewResourceRequestHandler(&transcodingRequestHandler{ | |
| 203 | 202 | transcoder: tc, | |
| 203 | + | classifier: classifier.normalize(), | |
| 204 | 204 | ctxf: ctxf, | |
| 205 | 205 | }) | |
| 206 | 206 | } | |
| @@ -219,10 +219,8 @@ func (h *transcodingRequestHandler) OnResourceResponse( | |||
| 219 | 219 | url := request.GetURL() | |
| 220 | 220 | ||
| 221 | 221 | log := h.logger() | |
| 222 | - | isProprietary := transcoder.IsProprietaryVideoMIME(mimeType) | |
| 223 | - | isAlreadyOpen := transcoder.IsOpenVideoMIME(mimeType) | |
| 224 | - | isManifest := !isAlreadyOpen && (transcoder.IsStreamingManifestMIME(mimeType) || transcoder.IsStreamingManifestURL(url)) | |
| 225 | - | if isLikelyMediaResponse(url, mimeType) { | |
| 222 | + | isProprietary, isAlreadyOpen, isManifest := classifyMediaResponse(h.classifier, url, mimeType) | |
| 223 | + | if isProprietary || isAlreadyOpen || isManifest { | |
| 226 | 224 | log.Debug(). | |
| 227 | 225 | Str("url", logging.TruncateURL(url, maxTranscodingURLLength)). | |
| 228 | 226 | Str("mime_type", mimeType). | |
| @@ -275,7 +273,7 @@ func (h *transcodingRequestHandler) GetResourceHandler( | |||
| 275 | 273 | return nil | |
| 276 | 274 | } | |
| 277 | 275 | info = cached | |
| 278 | - | } else if syntheticSourceURL, referer, origin, synthetic := transcoder.ParseSyntheticTranscodeURL(url); synthetic { | |
| 276 | + | } else if syntheticSourceURL, referer, origin, synthetic := resolveTranscodeSource(h.classifier, url); synthetic { | |
| 279 | 277 | eager = true | |
| 280 | 278 | sourceURL = syntheticSourceURL | |
| 281 | 279 | info = buildRequestInfo(request) | |
| @@ -285,9 +283,6 @@ func (h *transcodingRequestHandler) GetResourceHandler( | |||
| 285 | 283 | if origin != "" && info.headers["Origin"] == "" { | |
| 286 | 284 | info.headers["Origin"] = origin | |
| 287 | 285 | } | |
| 288 | - | } else if transcoder.IsEagerTranscodeURL(url) { | |
| 289 | - | eager = true | |
| 290 | - | info = buildRequestInfo(request) | |
| 291 | 286 | } else { | |
| 292 | 287 | return nil | |
| 293 | 288 | } | |
| @@ -317,6 +312,23 @@ func (h *transcodingRequestHandler) GetResourceHandler( | |||
| 317 | 312 | }) | |
| 318 | 313 | } | |
| 319 | 314 | ||
| 315 | + | func classifyMediaResponse(classifier MediaClassifier, rawURL, mimeType string) (bool, bool, bool) { | |
| 316 | + | proprietary := classifier.IsProprietaryVideoMIME(mimeType) | |
| 317 | + | alreadyOpen := classifier.IsOpenVideoMIME(mimeType) | |
| 318 | + | manifest := !alreadyOpen && (classifier.IsStreamingManifestMIME(mimeType) || classifier.IsStreamingManifestURL(rawURL)) | |
| 319 | + | return proprietary, alreadyOpen, manifest | |
| 320 | + | } | |
| 321 | + | ||
| 322 | + | func resolveTranscodeSource(classifier MediaClassifier, rawURL string) (string, string, string, bool) { | |
| 323 | + | if sourceURL, referer, origin, ok := classifier.ParseSyntheticTranscodeURL(rawURL); ok { | |
| 324 | + | return sourceURL, referer, origin, true | |
| 325 | + | } | |
| 326 | + | if classifier.IsEagerTranscodeURL(rawURL) { | |
| 327 | + | return rawURL, "", "", true | |
| 328 | + | } | |
| 329 | + | return "", "", "", false | |
| 330 | + | } | |
| 331 | + | ||
| 320 | 332 | // --- No-op methods required by purecef.ResourceRequestHandler --- | |
| 321 | 333 | ||
| 322 | 334 | func (h *transcodingRequestHandler) GetCookieAccessFilter( | |
| @@ -351,13 +363,6 @@ func (h *transcodingRequestHandler) OnResourceLoadComplete( | |||
| 351 | 363 | func (h *transcodingRequestHandler) OnProtocolExecution(_ purecef.Browser, _ purecef.Frame, _ purecef.Request, _ unsafe.Pointer) { | |
| 352 | 364 | } | |
| 353 | 365 | ||
| 354 | - | func isLikelyMediaResponse(rawURL, mimeType string) bool { | |
| 355 | - | return strings.HasPrefix(mimeType, "video/") || | |
| 356 | - | strings.HasPrefix(mimeType, "audio/") || | |
| 357 | - | transcoder.IsStreamingManifestMIME(mimeType) || | |
| 358 | - | transcoder.IsStreamingManifestURL(rawURL) | |
| 359 | - | } | |
| 360 | - | ||
| 361 | 366 | func buildRequestInfo(request purecef.Request) requestInfo { | |
| 362 | 367 | headers := make(map[string]string) | |
| 363 | 368 | if request == nil { | |
| @@ -4,7 +4,6 @@ import ( | |||||
| 4 | "context" | 4 | "context" | ||
| 5 | "errors" | 5 | "errors" | ||
| 6 | "io" | 6 | "io" | ||
| 7 | - | "strings" | |||
| 8 | "sync" | 7 | "sync" | ||
| 9 | "time" | 8 | "time" | ||
| 10 | "unsafe" | 9 | "unsafe" | ||
| @@ -12,7 +11,6 @@ import ( | |||||
| 12 | purecef "github.com/bnema/purego-cef/cef" | 11 | purecef "github.com/bnema/purego-cef/cef" | ||
| 13 | 12 | ||||
| 14 | "github.com/bnema/dumber/internal/application/port" | 13 | "github.com/bnema/dumber/internal/application/port" | ||
| 15 | - | "github.com/bnema/dumber/internal/infrastructure/transcoder" | |||
| 16 | "github.com/bnema/dumber/internal/logging" | 14 | "github.com/bnema/dumber/internal/logging" | ||
| 17 | "github.com/rs/zerolog" | 15 | "github.com/rs/zerolog" | ||
| 18 | ) | 16 | ) | ||
| @@ -185,6 +183,7 @@ func (rh *transcodingResourceHandler) Skip(_ int64, _ unsafe.Pointer, _ purecef. | |||||
| 185 | 183 | ||||
| 186 | type transcodingRequestHandler struct { | 184 | type transcodingRequestHandler struct { | ||
| 187 | transcoder port.MediaTranscoder | 185 | transcoder port.MediaTranscoder | ||
| 186 | + | classifier MediaClassifier | |||
| 188 | transcodableURLs sync.Map // url string -> requestInfo | 187 | transcodableURLs sync.Map // url string -> requestInfo | ||
| 189 | ctxf func() context.Context | 188 | ctxf func() context.Context | ||
| 190 | } | 189 | } | ||
| @@ -197,10 +196,11 @@ type requestInfo struct { | |||||
| 197 | // proprietary video containers and HLS/DASH manifest entrypoints, then | 196 | // proprietary video containers and HLS/DASH manifest entrypoints, then | ||
| 198 | // restarts those requests through a GPU transcoding ResourceHandler. | 197 | // restarts those requests through a GPU transcoding ResourceHandler. | ||
| 199 | func newTranscodingRequestHandler( | 198 | func newTranscodingRequestHandler( | ||
| 200 | - | tc port.MediaTranscoder, ctxf func() context.Context, | 199 | + | tc port.MediaTranscoder, classifier MediaClassifier, ctxf func() context.Context, |
| 201 | ) purecef.ResourceRequestHandler { | 200 | ) purecef.ResourceRequestHandler { | ||
| 202 | return purecef.NewResourceRequestHandler(&transcodingRequestHandler{ | 201 | return purecef.NewResourceRequestHandler(&transcodingRequestHandler{ | ||
| 203 | transcoder: tc, | 202 | transcoder: tc, | ||
| 203 | + | classifier: classifier.normalize(), | |||
| 204 | ctxf: ctxf, | 204 | ctxf: ctxf, | ||
| 205 | }) | 205 | }) | ||
| 206 | } | 206 | } | ||
| @@ -219,10 +219,8 @@ func (h *transcodingRequestHandler) OnResourceResponse( | |||||
| 219 | url := request.GetURL() | 219 | url := request.GetURL() | ||
| 220 | 220 | ||||
| 221 | log := h.logger() | 221 | log := h.logger() | ||
| 222 | - | isProprietary := transcoder.IsProprietaryVideoMIME(mimeType) | 222 | + | isProprietary, isAlreadyOpen, isManifest := classifyMediaResponse(h.classifier, url, mimeType) |
| 223 | - | isAlreadyOpen := transcoder.IsOpenVideoMIME(mimeType) | 223 | + | if isProprietary || isAlreadyOpen || isManifest { |
| 224 | - | isManifest := !isAlreadyOpen && (transcoder.IsStreamingManifestMIME(mimeType) || transcoder.IsStreamingManifestURL(url)) | |||
| 225 | - | if isLikelyMediaResponse(url, mimeType) { | |||
| 226 | log.Debug(). | 224 | log.Debug(). | ||
| 227 | Str("url", logging.TruncateURL(url, maxTranscodingURLLength)). | 225 | Str("url", logging.TruncateURL(url, maxTranscodingURLLength)). | ||
| 228 | Str("mime_type", mimeType). | 226 | Str("mime_type", mimeType). | ||
| @@ -275,7 +273,7 @@ func (h *transcodingRequestHandler) GetResourceHandler( | |||||
| 275 | return nil | 273 | return nil | ||
| 276 | } | 274 | } | ||
| 277 | info = cached | 275 | info = cached | ||
| 278 | - | } else if syntheticSourceURL, referer, origin, synthetic := transcoder.ParseSyntheticTranscodeURL(url); synthetic { | 276 | + | } else if syntheticSourceURL, referer, origin, synthetic := resolveTranscodeSource(h.classifier, url); synthetic { |
| 279 | eager = true | 277 | eager = true | ||
| 280 | sourceURL = syntheticSourceURL | 278 | sourceURL = syntheticSourceURL | ||
| 281 | info = buildRequestInfo(request) | 279 | info = buildRequestInfo(request) | ||
| @@ -285,9 +283,6 @@ func (h *transcodingRequestHandler) GetResourceHandler( | |||||
| 285 | if origin != "" && info.headers["Origin"] == "" { | 283 | if origin != "" && info.headers["Origin"] == "" { | ||
| 286 | info.headers["Origin"] = origin | 284 | info.headers["Origin"] = origin | ||
| 287 | } | 285 | } | ||
| 288 | - | } else if transcoder.IsEagerTranscodeURL(url) { | |||
| 289 | - | eager = true | |||
| 290 | - | info = buildRequestInfo(request) | |||
| 291 | } else { | 286 | } else { | ||
| 292 | return nil | 287 | return nil | ||
| 293 | } | 288 | } | ||
| @@ -317,6 +312,23 @@ func (h *transcodingRequestHandler) GetResourceHandler( | |||||
| 317 | }) | 312 | }) | ||
| 318 | } | 313 | } | ||
| 319 | 314 | ||||
| 315 | + | func classifyMediaResponse(classifier MediaClassifier, rawURL, mimeType string) (bool, bool, bool) { | |||
| 316 | + | proprietary := classifier.IsProprietaryVideoMIME(mimeType) | |||
| 317 | + | alreadyOpen := classifier.IsOpenVideoMIME(mimeType) | |||
| 318 | + | manifest := !alreadyOpen && (classifier.IsStreamingManifestMIME(mimeType) || classifier.IsStreamingManifestURL(rawURL)) | |||
| 319 | + | return proprietary, alreadyOpen, manifest | |||
| 320 | + | } | |||
| 321 | + | ||||
| 322 | + | func resolveTranscodeSource(classifier MediaClassifier, rawURL string) (string, string, string, bool) { | |||
| 323 | + | if sourceURL, referer, origin, ok := classifier.ParseSyntheticTranscodeURL(rawURL); ok { | |||
| 324 | + | return sourceURL, referer, origin, true | |||
| 325 | + | } | |||
| 326 | + | if classifier.IsEagerTranscodeURL(rawURL) { | |||
| 327 | + | return rawURL, "", "", true | |||
| 328 | + | } | |||
| 329 | + | return "", "", "", false | |||
| 330 | + | } | |||
| 331 | + | ||||
| 320 | // --- No-op methods required by purecef.ResourceRequestHandler --- | 332 | // --- No-op methods required by purecef.ResourceRequestHandler --- | ||
| 321 | 333 | ||||
| 322 | func (h *transcodingRequestHandler) GetCookieAccessFilter( | 334 | func (h *transcodingRequestHandler) GetCookieAccessFilter( | ||
| @@ -351,13 +363,6 @@ func (h *transcodingRequestHandler) OnResourceLoadComplete( | |||||
| 351 | func (h *transcodingRequestHandler) OnProtocolExecution(_ purecef.Browser, _ purecef.Frame, _ purecef.Request, _ unsafe.Pointer) { | 363 | func (h *transcodingRequestHandler) OnProtocolExecution(_ purecef.Browser, _ purecef.Frame, _ purecef.Request, _ unsafe.Pointer) { | ||
| 352 | } | 364 | } | ||
| 353 | 365 | ||||
| 354 | - | func isLikelyMediaResponse(rawURL, mimeType string) bool { | |||
| 355 | - | return strings.HasPrefix(mimeType, "video/") || | |||
| 356 | - | strings.HasPrefix(mimeType, "audio/") || | |||
| 357 | - | transcoder.IsStreamingManifestMIME(mimeType) || | |||
| 358 | - | transcoder.IsStreamingManifestURL(rawURL) | |||
| 359 | - | } | |||
| 360 | - | ||||
| 361 | func buildRequestInfo(request purecef.Request) requestInfo { | 366 | func buildRequestInfo(request purecef.Request) requestInfo { | ||
| 362 | headers := make(map[string]string) | 367 | headers := make(map[string]string) | ||
| 363 | if request == nil { | 368 | if request == nil { | ||
A internal/infrastructure/cef/transcoding_handler_test.go +36 -0
| @@ -0,0 +1,36 @@ | |||
| 1 | + | package cef | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "testing" | |
| 5 | + | ||
| 6 | + | "github.com/stretchr/testify/require" | |
| 7 | + | ) | |
| 8 | + | ||
| 9 | + | func TestClassifyMediaResponse_UsesInjectedClassifier(t *testing.T) { | |
| 10 | + | classifier := MediaClassifier{ | |
| 11 | + | IsProprietaryVideoMIME: func(string) bool { return true }, | |
| 12 | + | IsOpenVideoMIME: func(string) bool { return false }, | |
| 13 | + | IsStreamingManifestMIME: func(string) bool { return false }, | |
| 14 | + | IsStreamingManifestURL: func(string) bool { return false }, | |
| 15 | + | }.normalize() | |
| 16 | + | ||
| 17 | + | proprietary, alreadyOpen, manifest := classifyMediaResponse(classifier, "https://cdn.example/video.mp4", "video/mp4") | |
| 18 | + | require.True(t, proprietary) | |
| 19 | + | require.False(t, alreadyOpen) | |
| 20 | + | require.False(t, manifest) | |
| 21 | + | } | |
| 22 | + | ||
| 23 | + | func TestResolveTranscodeSource_UsesInjectedClassifier(t *testing.T) { | |
| 24 | + | classifier := MediaClassifier{ | |
| 25 | + | ParseSyntheticTranscodeURL: func(string) (string, string, string, bool) { | |
| 26 | + | return "https://cdn.example/video.mp4", "https://example.com", "https://example.com", true | |
| 27 | + | }, | |
| 28 | + | IsEagerTranscodeURL: func(string) bool { return false }, | |
| 29 | + | }.normalize() | |
| 30 | + | ||
| 31 | + | src, referer, origin, eager := resolveTranscodeSource(classifier, "https://dumber.invalid/__dumber__/transcode.webm?src=x") | |
| 32 | + | require.True(t, eager) | |
| 33 | + | require.Equal(t, "https://cdn.example/video.mp4", src) | |
| 34 | + | require.Equal(t, "https://example.com", referer) | |
| 35 | + | require.Equal(t, "https://example.com", origin) | |
| 36 | + | } | |
| @@ -0,0 +1,36 @@ | |||||
| 1 | + | package cef | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "testing" | |||
| 5 | + | ||||
| 6 | + | "github.com/stretchr/testify/require" | |||
| 7 | + | ) | |||
| 8 | + | ||||
| 9 | + | func TestClassifyMediaResponse_UsesInjectedClassifier(t *testing.T) { | |||
| 10 | + | classifier := MediaClassifier{ | |||
| 11 | + | IsProprietaryVideoMIME: func(string) bool { return true }, | |||
| 12 | + | IsOpenVideoMIME: func(string) bool { return false }, | |||
| 13 | + | IsStreamingManifestMIME: func(string) bool { return false }, | |||
| 14 | + | IsStreamingManifestURL: func(string) bool { return false }, | |||
| 15 | + | }.normalize() | |||
| 16 | + | ||||
| 17 | + | proprietary, alreadyOpen, manifest := classifyMediaResponse(classifier, "https://cdn.example/video.mp4", "video/mp4") | |||
| 18 | + | require.True(t, proprietary) | |||
| 19 | + | require.False(t, alreadyOpen) | |||
| 20 | + | require.False(t, manifest) | |||
| 21 | + | } | |||
| 22 | + | ||||
| 23 | + | func TestResolveTranscodeSource_UsesInjectedClassifier(t *testing.T) { | |||
| 24 | + | classifier := MediaClassifier{ | |||
| 25 | + | ParseSyntheticTranscodeURL: func(string) (string, string, string, bool) { | |||
| 26 | + | return "https://cdn.example/video.mp4", "https://example.com", "https://example.com", true | |||
| 27 | + | }, | |||
| 28 | + | IsEagerTranscodeURL: func(string) bool { return false }, | |||
| 29 | + | }.normalize() | |||
| 30 | + | ||||
| 31 | + | src, referer, origin, eager := resolveTranscodeSource(classifier, "https://dumber.invalid/__dumber__/transcode.webm?src=x") | |||
| 32 | + | require.True(t, eager) | |||
| 33 | + | require.Equal(t, "https://cdn.example/video.mp4", src) | |||
| 34 | + | require.Equal(t, "https://example.com", referer) | |||
| 35 | + | require.Equal(t, "https://example.com", origin) | |||
| 36 | + | } | |||