Skip to content

Short player: Fit to content on desktop + some minor stuff#3394

Merged
tzarebczan merged 6 commits intomasterfrom
short-player-fit-to-content
Jan 8, 2026
Merged

Short player: Fit to content on desktop + some minor stuff#3394
tzarebczan merged 6 commits intomasterfrom
short-player-fit-to-content

Conversation

@keikari
Copy link
Contributor

@keikari keikari commented Jan 7, 2026

Summary by CodeRabbit

  • New Features

    • Responsive shorts viewer width now dynamically sizes to video metadata and layout, initializing promptly when video info becomes available.
  • Improvements

    • Shorts filtering and recommendations now use configurable duration and aspect-ratio thresholds (values updated to numeric and LTE semantics).
    • Breakpoints adjusted for improved shorts responsiveness across screen sizes.
  • Refactor

    • Resize handling consolidated into stable, memoized callbacks; resize hook now triggers an initial debounced update on mount.
  • Style

    • Viewer width exposed via a CSS variable for easy overrides.

✏️ Tip: You can customize this high-level summary in your review settings.

miko added 2 commits January 7, 2026 18:55
Updated shorts stuff to use the global constants (hopefully) everywhere
@coderabbitai
Copy link

coderabbitai bot commented Jan 7, 2026

📝 Walkthrough

Walkthrough

Replaces hardcoded Shorts thresholds with settings-driven constants; consolidates some imports; refactors several resize handlers to stable callbacks; adds responsive Shorts viewer width calculation (polls for video metadata) that sets a CSS variable; shifts styling breakpoints and replaces fixed 28vw with the CSS variable.

Changes

Cohort / File(s) Summary
Import Path Consolidation
ui/component/claimPreview/view.jsx, ui/component/videoRenderFloating/index.js
Switched isClaimShort imports from relative ../../util/claim to absolute util/claim. Usage unchanged.
Constants & Settings
ui/constants/settings.js
Removed SHORTS_DURATION_LIMIT/SHORTS_ASPECT_RATIO_LIMIT; updated SHORTS_ASPECT_RATIO_LTE0.7 and SHORTS_DURATION_LTE180 (numeric).
Shorts Filter Logic Migration
ui/page/claim/.../contentTab/view.jsx, ui/page/claim/.../shorts/index.js, ui/redux/selectors/claims.js, ui/util/claim.js, ui/util/search.js
Replaced hardcoded duration/aspect-ratio values with SETTINGS.SHORTS_DURATION_LTE and SETTINGS.SHORTS_ASPECT_RATIO_LTE; filters/search keys now use <= comparisons and SETTINGS-based values.
Resize Handler Refactoring
ui/component/common/expandable.jsx, ui/component/common/tabs.jsx, ui/component/portals/view.jsx
Replaced inline anonymous resize callbacks with memoized handleResize via React.useCallback; behavior preserved, callback stability changed.
Resize Effect Enhancement
ui/effects/use-on-resize.js
On mount, debounces-and-invokes the callback once (100ms); resize effect now depends on cb and no longer manually invokes the debounced handler inside the event effect.
Shorts Viewer Responsive Width
ui/page/claim/.../shorts/view.jsx
Added setShortViewerWidthFromVideo that computes width from video intrinsic size, viewport constraints, and side-panel state; updates --shorts-viewer-width via rAF; polls every 300ms for video metadata until available; wired into useOnResize.
Shorts Styling Updates
ui/scss/component/_shorts.scss, ui/scss/component/_content.scss, ui/component/shortsActions/swipeNavigation/style.scss
Breakpoints changed from large → medium; replaced hardcoded 28vw with var(--shorts-viewer-width, 28vw) fallbacks across selectors and positioning calculations.
Minor Comment / Formatting
ui/component/claimTilesDiscover/index.js
Updated an internal comment reference from SHORTS_DURATION_LIMIT to SHORTS_DURATION_LTE; no logic change.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Video as Video Element
participant ShortsView as Shorts Viewer Component
participant ResizeHook as useOnResize Hook
participant CSS as CSS Variable (--shorts-viewer-width)

Note over ShortsView,Video: On uri change or window resize
ShortsView->>Video: read videoWidth / videoHeight
alt metadata unavailable
ShortsView->>ShortsView: start polling (every 300ms) until metadata available
ShortsView->>Video: retry read metadata
end
ShortsView->>ResizeHook: register handle / call on resize
ResizeHook->>ShortsView: invoke setShortViewerWidthFromVideo
ShortsView->>ShortsView: compute vw width (viewport constraints, sidePanel state)
ShortsView->>CSS: update --shorts-viewer-width via requestAnimationFrame
CSS->>ShortsView: layout updates reflect new width

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I nibbled constants through the night,

Swapped hardcoded bounds for values right,
I poll the vid and wait a beat,
A CSS variable makes sizing neat,
My memoized paws catch every resize feat.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title partially describes the main changes but is vague and misleading. While the PR does include shorts viewer width calculations to fit content, the actual scope includes refactoring imports to absolute paths, updating shorts filter constants, adjusting breakpoints/widths in multiple SCSS files, and converting anonymous callbacks to memoized ones across multiple components. Consider a more specific title like 'Refactor shorts constants and implement dynamic viewer width' or 'Update shorts thresholds and fit viewer to content on desktop' to better capture the multi-faceted nature of this changeset.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/component/portals/view.jsx (1)

58-69: Add null safety check for portals.mainPortal.

Line 62 accesses portals.mainPortal.portals.length without verifying that portals.mainPortal exists. If portals is defined but mainPortal is undefined, this will throw a runtime error.

Note that line 33 uses optional chaining (portals?.mainPortal?.portals?.length), indicating that mainPortal can be undefined.

🛡️ Proposed fix with defensive null check
 const handleResize = React.useCallback(() => {
   if (wrapper.current) {
     let wrapperWidth = wrapper.current.offsetWidth + 12;
     let tileNum = wrapperWidth > 954 ? 6 : wrapperWidth > 870 ? 5 : wrapperWidth > 470 ? 3 : 2;
-    if (tileNum === 6 && portals.mainPortal.portals.length < 9) {
+    if (tileNum === 6 && portals?.mainPortal?.portals && portals.mainPortal.portals.length < 9) {
       tileNum = portals.mainPortal.portals.length;
     }
     setWidth(wrapperWidth);
     setTileNum(tileNum);
     setTileWidth(wrapperWidth / tileNum);
   }
 }, [portals]);
🤖 Fix all issues with AI agents
In @ui/component/shortsActions/swipeNavigation/style.scss:
- Line 28: The fallback for the CSS variable is missing a unit: update the
declaration `width: var(--shorts-viewer-width, 28) !important;` to use a united
fallback such as `28vw` so it reads `width: var(--shorts-viewer-width, 28vw)
!important;`, referencing the `--shorts-viewer-width` variable and that specific
width declaration in style.scss.

In @ui/constants/settings.js:
- Line 57: The SHORTS_ASPECT_RATIO_LTE constant was changed from '0.95' to
'0.7', which will exclude videos with aspect ratios in (0.7,0.95) from all
shorts logic; confirm whether this is intentional with product—if not, revert
SHORTS_ASPECT_RATIO_LTE back to '0.95'; if intentional, update all dependent
code and documentation (uses in ui/util/claim.js, ui/redux/selectors/claims.js
and search/discovery components), adjust any tests or fixtures that assume the
old threshold, and add a short comment near SHORTS_ASPECT_RATIO_LTE explaining
the product rationale for the new threshold.

In
@ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/view.jsx:
- Around line 204-206: The maxDuration prop passed to SearchResults is receiving
SETTINGS.SHORTS_DURATION_LTE (a string) but SearchResults expects ?number;
locate where maxDuration is set (prop name maxDuration on the SearchResults
component) and either convert the value to a number before passing (e.g.,
parseInt of SETTINGS.SHORTS_DURATION_LTE) or change the SearchResults prop type
to accept ?string | ?number for consistency with maxAspectRatio; ensure you
update all usages of maxDuration or the prop type definition in the
SearchResults component accordingly.

In @ui/scss/component/_shorts.scss:
- Line 253: The CSS variable --shorts-viewer-width is set dynamically in
view.jsx but not removed on navigation; update the navigation cleanup inside the
history.listen effect where doClearShortsPlaylist() is called (the
history.listen cleanup handler in view.jsx) to also call
document.documentElement?.style?.removeProperty('--shorts-viewer-width') so the
CSS variable is cleared when leaving the shorts player.

In @ui/util/claim.js:
- Around line 233-240: The comparisons in isShortDuration and isVertical use
string constants (SETTINGS.SHORTS_DURATION_LTE and
SETTINGS.SHORTS_ASPECT_RATIO_LTE) against numeric values (media.duration and
aspectRatio), which is error-prone; fix by converting the SETTINGS values to
numbers before comparison (e.g., wrap with Number(...) at the use site) or
change the constants to numeric types, and ensure you perform
Number(SETTINGS.SHORTS_DURATION_LTE) when computing isShortDuration and
Number(SETTINGS.SHORTS_ASPECT_RATIO_LTE) when computing isVertical so
media.duration and aspectRatio are compared as numbers.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 584e6d8 and 4dcbcd4.

📒 Files selected for processing (17)
  • ui/component/claimPreview/view.jsx
  • ui/component/claimTilesDiscover/index.js
  • ui/component/common/expandable.jsx
  • ui/component/common/tabs.jsx
  • ui/component/portals/view.jsx
  • ui/component/shortsActions/swipeNavigation/style.scss
  • ui/component/videoRenderFloating/index.js
  • ui/constants/settings.js
  • ui/effects/use-on-resize.js
  • ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/view.jsx
  • ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/index.js
  • ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx
  • ui/redux/selectors/claims.js
  • ui/scss/component/_content.scss
  • ui/scss/component/_shorts.scss
  • ui/util/claim.js
  • ui/util/search.js
🧰 Additional context used
🧬 Code graph analysis (7)
ui/effects/use-on-resize.js (3)
ui/component/common/expandable.jsx (1)
  • handleResize (52-54)
ui/component/common/tabs.jsx (2)
  • handleResize (52-56)
  • handleResize (106-110)
ui/component/portals/view.jsx (1)
  • handleResize (58-69)
ui/component/common/expandable.jsx (3)
ui/component/common/tabs.jsx (3)
  • handleResize (52-56)
  • handleResize (106-110)
  • ref (114-114)
ui/component/portals/view.jsx (1)
  • handleResize (58-69)
ui/effects/use-on-resize.js (1)
  • useOnResize (4-23)
ui/util/claim.js (3)
ui/redux/selectors/claims.js (2)
  • isShortDuration (377-377)
  • isVertical (378-378)
ui/component/claimPreviewTile/index.js (1)
  • media (24-24)
ui/component/claimPreview/index.js (1)
  • media (32-32)
ui/redux/selectors/claims.js (1)
ui/util/claim.js (2)
  • isShortDuration (233-233)
  • isVertical (240-240)
ui/component/portals/view.jsx (3)
ui/component/common/expandable.jsx (1)
  • handleResize (52-54)
ui/component/common/tabs.jsx (2)
  • handleResize (52-56)
  • handleResize (106-110)
ui/effects/use-on-resize.js (1)
  • useOnResize (4-23)
ui/component/common/tabs.jsx (3)
ui/component/common/expandable.jsx (2)
  • handleResize (52-54)
  • ref (21-21)
ui/component/portals/view.jsx (1)
  • handleResize (58-69)
ui/effects/use-on-resize.js (1)
  • useOnResize (4-23)
ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx (1)
ui/effects/use-on-resize.js (1)
  • useOnResize (4-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: lint
🔇 Additional comments (20)
ui/component/claimTilesDiscover/index.js (1)

193-193: LGTM: Documentation update aligns with settings refactor.

The comment now correctly references SETTINGS.SHORTS_DURATION_LTE instead of the deprecated SHORTS_DURATION_LIMIT, maintaining consistency with the broader PR changes.

ui/component/videoRenderFloating/index.js (1)

22-22: LGTM: Import consolidation improves maintainability.

The change to an absolute import path aligns with the PR's goal of consolidating imports and improves code maintainability.

ui/component/claimPreview/view.jsx (1)

12-12: LGTM: Consistent import path refactoring.

The change to an absolute import path from util/claim aligns with the codebase-wide consolidation effort and improves maintainability.

ui/component/shortsActions/swipeNavigation/style.scss (1)

27-27: Verify responsive breakpoint change doesn't affect UX.

The breakpoint was reduced from 1600px to 1150px, which means the dynamic width behavior will now apply to smaller screens. Please verify that this breakpoint change provides the intended user experience across different screen sizes and doesn't cause layout issues.

ui/util/search.js (1)

152-152: The aspect ratio threshold of 0.7 is properly centralized in SETTINGS.SHORTS_ASPECT_RATIO_LTE and used consistently across the recommendation, filtering, and detection systems throughout the codebase (13+ usages across query-params, claim detection, search, and channel content tabs). An aspect ratio of 0.7 correctly identifies portrait-oriented content (height at least 1.43x the width), which is appropriate for Shorts. The change from a hardcoded value to a configurable setting follows best practices and enables consistent behavior across the application.

ui/scss/component/_content.scss (1)

849-854: LGTM! Dynamic width control via CSS variable.

The shift from $breakpoint-large to $breakpoint-medium and the introduction of var(--shorts-viewer-width, 28vw) enables JavaScript-driven responsive width adjustments while maintaining a sensible fallback.

ui/effects/use-on-resize.js (2)

7-12: LGTM! Initial resize calculation on mount.

The immediate invocation ensures sizing calculations run on mount, complementing the window resize listener.


22-22: Good addition of cb to dependencies.

Including cb in the dependency array ensures the resize listener updates when the callback changes. This works correctly because all callers (tabs.jsx, expandable.jsx, portals/view.jsx) now pass memoized callbacks via React.useCallback.

ui/component/common/tabs.jsx (2)

52-57: LGTM! Memoized resize handler.

The stable callback reference prevents unnecessary re-registration of the resize listener.


106-111: LGTM! Consistent memoization pattern.

Matches the pattern established in the parent Tabs component.

ui/component/common/expandable.jsx (1)

52-55: LGTM! Proper callback memoization.

The memoized handleResize with expandableRef dependency ensures a stable reference for useOnResize, preventing unnecessary listener re-registration.

ui/redux/selectors/claims.js (2)

30-30: LGTM! Settings import for configurable thresholds.

Importing SETTINGS constants enables centralized configuration of shorts detection criteria.


377-379: The aspect ratio analysis is incorrect—the change actually restricts the shorts definition, not expands it.

The current code with SHORTS_ASPECT_RATIO_LTE = '0.7' does not allow square (1:1) or near-square (4:5) videos; it requires videos narrower than ~1:1.43. The recent change from 0.95 to 0.7 threshold is more restrictive, not more permissive. The code correctly consolidates shorts detection into centralized constants and is consistently used throughout the codebase.

Likely an incorrect or invalid review comment.

ui/scss/component/_shorts.scss (1)

251-263: Breakpoint change aligns with intended responsive design.

The change from $breakpoint-large (1600px) to $breakpoint-medium (1150px) is intentional and part of a coordinated responsive design update. The CSS variable --shorts-viewer-width is dynamically computed in JavaScript based on video dimensions, allowing flexible layout adjustment. This approach extends the positioning logic to a broader range of screen sizes starting at 1150px, which is the intended behavior.

ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/index.js (4)

29-37: LGTM! Import paths refactored to absolute paths.

The consolidation from relative to absolute import paths improves maintainability and aligns with the PR's objective of refactoring shorts-related functionality.


56-59: LGTM! Query key construction now uses settings constants.

The aspect ratio filter now correctly references SETTINGS.SHORTS_ASPECT_RATIO_LTE, ensuring consistency with the centralized settings approach.


74-75: LGTM! Search parameters now driven by settings.

The duration and aspect ratio filters correctly use SETTINGS.SHORTS_DURATION_LTE and SETTINGS.SHORTS_ASPECT_RATIO_LTE, replacing hardcoded values and centralizing configuration.


170-171: LGTM! Channel shorts fetching aligned with settings.

The doFetchChannelShorts function now correctly applies the same settings-driven filters, ensuring consistent behavior across all shorts-related queries.

ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx (2)

17-17: LGTM! Import added for resize handling.

The useOnResize hook import is appropriate for implementing responsive width calculations.


173-173: LGTM! Resize handler integration looks correct.

The useOnResize hook is properly used with the memoized callback. The hook will update the resize listener when setShortViewerWidthFromVideo changes (when sidePanelOpen changes).

export const AUTOPLAY_NEXT_SHORTS = 'autoplay_next_shorts';
export const SHORTS_ASPECT_RATIO_LIMIT = '1';
export const SHORTS_ASPECT_RATIO_LTE = '0.95';
export const SHORTS_ASPECT_RATIO_LTE = '0.7';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check the current state of the constants file
cat -n ui/constants/settings.js | grep -A 2 -B 2 "SHORTS_ASPECT_RATIO"

Repository: OdyseeTeam/odysee-frontend

Length of output: 425


🏁 Script executed:

# Find all usages of SHORTS_ASPECT_RATIO_LTE
rg -n "SHORTS_ASPECT_RATIO_LTE" --type=js --type=jsx -C 3

Repository: OdyseeTeam/odysee-frontend

Length of output: 97


🏁 Script executed:

# Search for aspect ratio logic in the codebase
rg -n "aspectRatio" --type=js --type=jsx -C 2 | head -100

Repository: OdyseeTeam/odysee-frontend

Length of output: 97


🏁 Script executed:

# Check git history for this file to see if value changed from 0.95
cd ui/constants && git log -p --follow settings.js | grep -A 5 -B 5 "SHORTS_ASPECT_RATIO_LTE" | head -50

Repository: OdyseeTeam/odysee-frontend

Length of output: 52


🏁 Script executed:

# Find all usages of SHORTS_ASPECT_RATIO_LTE
rg -n "SHORTS_ASPECT_RATIO_LTE" -C 3

Repository: OdyseeTeam/odysee-frontend

Length of output: 9451


🏁 Script executed:

# Search for aspect ratio comparisons
rg -n "aspectRatio.*<=" -C 2

Repository: OdyseeTeam/odysee-frontend

Length of output: 317


🏁 Script executed:

# Check if there are any short-related files that use aspect ratio logic
fd -e js -e ts | xargs rg -l "aspectRatio|SHORTS" | head -20

Repository: OdyseeTeam/odysee-frontend

Length of output: 920


🏁 Script executed:

# Search for any mention of 0.95 in relation to aspect ratio
rg -n "0\.95" -C 3

Repository: OdyseeTeam/odysee-frontend

Length of output: 7774


🏁 Script executed:

# Check git blame for this specific line
git blame ui/constants/settings.js | grep "SHORTS_ASPECT_RATIO_LTE"

Repository: OdyseeTeam/odysee-frontend

Length of output: 161


🏁 Script executed:

# Look at recent commits affecting this file
git log --oneline -20 -- ui/constants/settings.js

Repository: OdyseeTeam/odysee-frontend

Length of output: 188


Confirm this significant aspect ratio threshold change is intentional.

The aspect ratio limit was changed from '0.95' to '0.7', making the shorts filter substantially more restrictive. This change affects video classification across the codebase (ui/util/claim.js, ui/redux/selectors/claims.js, and multiple search/discovery components) and will exclude videos with aspect ratios between 0.7 and 0.95 from shorts feeds.

Verify this aligns with current product requirements.

🤖 Prompt for AI Agents
In @ui/constants/settings.js at line 57, The SHORTS_ASPECT_RATIO_LTE constant
was changed from '0.95' to '0.7', which will exclude videos with aspect ratios
in (0.7,0.95) from all shorts logic; confirm whether this is intentional with
product—if not, revert SHORTS_ASPECT_RATIO_LTE back to '0.95'; if intentional,
update all dependent code and documentation (uses in ui/util/claim.js,
ui/redux/selectors/claims.js and search/discovery components), adjust any tests
or fixtures that assume the old threshold, and add a short comment near
SHORTS_ASPECT_RATIO_LTE explaining the product rationale for the new threshold.

Comment on lines +204 to +206
duration: `<=${SETTINGS.SHORTS_DURATION_LTE}`,
contentType: CS.FILE_VIDEO,
contentAspectRatio: `<${SETTINGS.SHORTS_ASPECT_RATIO_LTE}`,
contentAspectRatio: `<=${SETTINGS.SHORTS_ASPECT_RATIO_LTE}`,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the exact file location
find . -name "view.jsx" -path "*contentTab*" 2>/dev/null

Repository: OdyseeTeam/odysee-frontend

Length of output: 159


🏁 Script executed:

#!/bin/bash
# Search for SETTINGS definitions related to shorts
rg -n "SHORTS_DURATION_LTE|SHORTS_ASPECT_RATIO_LTE" --type=js --type=jsx -B 2 -A 2

Repository: OdyseeTeam/odysee-frontend

Length of output: 97


🏁 Script executed:

#!/bin/bash
# Find ClaimListDiscover component definition
rg -n "ClaimListDiscover" --type=js --type=jsx | head -20

Repository: OdyseeTeam/odysee-frontend

Length of output: 97


🏁 Script executed:

#!/bin/bash
# Find SearchResults component definition
rg -n "SearchResults" --type=js --type=jsx | head -20

Repository: OdyseeTeam/odysee-frontend

Length of output: 97


🏁 Script executed:

#!/bin/bash
# Read the view.jsx file to see lines 204-206 and 247-248
wc -l ./ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 163


🏁 Script executed:

#!/bin/bash
# Read relevant lines from view.jsx
sed -n '200,210p' ./ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 582


🏁 Script executed:

#!/bin/bash
# Read lines around 247-248
sed -n '240,255p' ./ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 708


🏁 Script executed:

#!/bin/bash
# Search for SETTINGS constants (without type flag)
rg -n "SHORTS_DURATION_LTE|SHORTS_ASPECT_RATIO_LTE" -B 2 -A 2

Repository: OdyseeTeam/odysee-frontend

Length of output: 9030


🏁 Script executed:

#!/bin/bash
# Search for ClaimListDiscover or SearchResults usage without type flag
rg -n "ClaimListDiscover|SearchResults" -A 5 | head -40

Repository: OdyseeTeam/odysee-frontend

Length of output: 2584


🏁 Script executed:

#!/bin/bash
# Find ClaimListDiscover component and check prop handling
rg -n "maxDuration|maxAspectRatio" ui/component/claimListDiscover/ -A 3 -B 1

Repository: OdyseeTeam/odysee-frontend

Length of output: 1053


🏁 Script executed:

#!/bin/bash
# Read ClaimListDiscover view.jsx to understand prop handling
head -100 ui/component/claimListDiscover/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 3565


🏁 Script executed:

#!/bin/bash
# Find the SearchResults component definition in contentTab
rg -n "export.*SearchResults|const SearchResults" ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/

Repository: OdyseeTeam/odysee-frontend

Length of output: 224


🏁 Script executed:

#!/bin/bash
# Get more context on how contentAspectRatio and duration are processed
rg -n "contentAspectRatio|duration" ui/component/claimListDiscover/view.jsx -B 2 -A 2 | head -60

Repository: OdyseeTeam/odysee-frontend

Length of output: 1752


🏁 Script executed:

#!/bin/bash
# Check the SearchResults component props definition
sed -n '1,50p' ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/internal/searchResults.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 1477


🏁 Script executed:

#!/bin/bash
# Search for maxDuration and maxAspectRatio as props in components
rg -n "maxDuration|maxAspectRatio" ui/component/ -B 2 -A 2

Repository: OdyseeTeam/odysee-frontend

Length of output: 5024


🏁 Script executed:

#!/bin/bash
# Check if ClaimListDiscover has any other prop handling we might have missed
sed -n '100,200p' ui/component/claimListDiscover/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 2466


🏁 Script executed:

#!/bin/bash
# Search for SearchResults component implementation
cat ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/internal/searchResults.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 4504


Fix type mismatch for maxDuration prop passed to SearchResults.

Lines 247-248 pass SETTINGS.SHORTS_DURATION_LTE (string '180') to the maxDuration prop, which expects ?number. The maxAspectRatio prop correctly accepts ?string | ?number, so that assignment is compatible.

To fix the type error, either convert the string to a number when passing it:

maxDuration: parseInt(SETTINGS.SHORTS_DURATION_LTE, 10)

Or update the SearchResults prop type definition to accept ?string | ?number for consistency with maxAspectRatio.

Lines 204-206 are correct—the string templates for API query parameters are appropriate.

🤖 Prompt for AI Agents
In
@ui/page/claim/internal/claimPageComponent/internal/channelPage/tabs/contentTab/view.jsx
around lines 204 - 206, The maxDuration prop passed to SearchResults is
receiving SETTINGS.SHORTS_DURATION_LTE (a string) but SearchResults expects
?number; locate where maxDuration is set (prop name maxDuration on the
SearchResults component) and either convert the value to a number before passing
(e.g., parseInt of SETTINGS.SHORTS_DURATION_LTE) or change the SearchResults
prop type to accept ?string | ?number for consistency with maxAspectRatio;
ensure you update all usages of maxDuration or the prop type definition in the
SearchResults component accordingly.

Comment on lines +151 to +171
const setShortViewerWidthFromVideo = React.useCallback(() => {
const videoElement = document.querySelector('video');
const videoW = videoElement?.videoWidth;
const videoH = videoElement?.videoHeight;
if (!videoW || !videoH) return;

const maxHeight = window.innerHeight * 0.9;

const scale = maxHeight / videoH;
const computedWidthPx = videoW * scale;

// Convert to vw (viewport width %)
const maxWidth = sidePanelOpen ? 30 : 80; // in percentages
const widthVW = (computedWidthPx / window.innerWidth) * 100;
const clampedVW = Math.min(widthVW, maxWidth); // Avoid overflow

requestAnimationFrame(() => {
// $FlowFixMe
document.documentElement?.style?.setProperty('--shorts-viewer-width', `${clampedVW}vw`);
});
}, [sidePanelOpen]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Scope the video selector to prevent selecting wrong elements.

Line 152 uses document.querySelector('video'), which could select any video element on the page, not just the shorts video. If multiple videos exist (e.g., ads, other embedded content), this will select the first one in DOM order, leading to incorrect width calculations.

🔍 Recommended fix: scope the selector to the shorts container
 const setShortViewerWidthFromVideo = React.useCallback(() => {
-  const videoElement = document.querySelector('video');
+  const videoElement = shortsContainerRef.current?.querySelector('video');
   const videoW = videoElement?.videoWidth;
   const videoH = videoElement?.videoHeight;
   if (!videoW || !videoH) return;

Alternatively, use a more specific selector:

-  const videoElement = document.querySelector('video');
+  const videoElement = document.querySelector('.shorts__viewer video, .vjs-tech');

Extract magic numbers as named constants.

Lines 157, 163 contain magic numbers (0.9, 30, 80) that should be extracted as named constants for clarity and maintainability.

♻️ Suggested refactor
+const MAX_HEIGHT_VIEWPORT_RATIO = 0.9;
+const MAX_WIDTH_WITH_PANEL = 30;
+const MAX_WIDTH_WITHOUT_PANEL = 80;
+
 const setShortViewerWidthFromVideo = React.useCallback(() => {
   const videoElement = shortsContainerRef.current?.querySelector('video');
   const videoW = videoElement?.videoWidth;
   const videoH = videoElement?.videoHeight;
   if (!videoW || !videoH) return;

-  const maxHeight = window.innerHeight * 0.9;
+  const maxHeight = window.innerHeight * MAX_HEIGHT_VIEWPORT_RATIO;

   const scale = maxHeight / videoH;
   const computedWidthPx = videoW * scale;

   // Convert to vw (viewport width %)
-  const maxWidth = sidePanelOpen ? 30 : 80; // in percentages
+  const maxWidth = sidePanelOpen ? MAX_WIDTH_WITH_PANEL : MAX_WIDTH_WITHOUT_PANEL;
   const widthVW = (computedWidthPx / window.innerWidth) * 100;
   const clampedVW = Math.min(widthVW, maxWidth); // Avoid overflow

   requestAnimationFrame(() => {
-    // $FlowFixMe
     document.documentElement?.style?.setProperty('--shorts-viewer-width', `${clampedVW}vw`);
   });
 }, [sidePanelOpen]);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +348 to +362
React.useEffect(() => {
let timeoutId;
function loop() {
const video = document.querySelector('video');
if (!video || !video.videoWidth || !video.videoHeight) {
timeoutId = setTimeout(loop, 300);
return;
}
setShortViewerWidthFromVideo();
}

timeoutId = setTimeout(loop, 300);

return () => clearTimeout(timeoutId);
}, [uri, setShortViewerWidthFromVideo]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Apply the same selector scoping fix here.

Line 351 has the same unscoped document.querySelector('video') issue as line 152. This should be fixed to scope the selector to the shorts container or use a more specific selector.


Consider using video events instead of polling.

The current polling approach (lines 348-362) works but is not optimal. Using the video element's loadedmetadata event would be more efficient and precise.

♻️ Suggested event-based approach
 React.useEffect(() => {
-  let timeoutId;
-  function loop() {
-    const video = document.querySelector('video');
-    if (!video || !video.videoWidth || !video.videoHeight) {
-      timeoutId = setTimeout(loop, 300);
-      return;
-    }
-    setShortViewerWidthFromVideo();
-  }
-
-  timeoutId = setTimeout(loop, 300);
-
-  return () => clearTimeout(timeoutId);
+  // Wait for video element to appear
+  const checkInterval = setInterval(() => {
+    const video = shortsContainerRef.current?.querySelector('video');
+    if (video) {
+      clearInterval(checkInterval);
+      
+      const handleLoadedMetadata = () => {
+        setShortViewerWidthFromVideo();
+      };
+      
+      // If metadata already loaded
+      if (video.videoWidth && video.videoHeight) {
+        setShortViewerWidthFromVideo();
+      } else {
+        video.addEventListener('loadedmetadata', handleLoadedMetadata, { once: true });
+      }
+    }
+  }, 100);
+
+  return () => clearInterval(checkInterval);
 }, [uri, setShortViewerWidthFromVideo]);

This approach:

  • Still polls for video element existence (unavoidable since React may not have rendered it yet)
  • Uses the standard loadedmetadata event instead of polling for dimensions
  • Handles the case where metadata is already loaded
  • Uses a shorter polling interval (100ms) since we're only checking element existence

Committable suggestion skipped: line range outside the PR's diff.

@media (min-width: $breakpoint-medium) {
.shorts-page__info-button.shorts-page-menu__button {
right: calc(49.8% - 28vw / 2 - 60px + 7.5px);
right: calc(49.8% - var(--shorts-viewer-width, 28vw) / 2 - 60px + 7.5px);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for where the CSS variable --shorts-viewer-width is being set in JavaScript/TypeScript files

# Search for direct references to the variable name
rg -n "shorts-viewer-width" --type=js --type=jsx --type=ts --type=tsx -C 3

# Also search for setProperty calls that might set CSS variables
rg -n "setProperty.*shorts|shorts.*setProperty" --type=js --type=jsx --type=ts --type=tsx -C 3

Repository: OdyseeTeam/odysee-frontend

Length of output: 125


🏁 Script executed:

#!/bin/bash
# Search for the CSS variable in any file type
rg -n "shorts-viewer-width" -C 3

# Search for setProperty calls related to CSS variables
rg -n "setProperty.*--" --type=js --type=ts -C 2 | head -100

# Also check if there's any reference to setting CSS custom properties
rg -n "style\.setProperty" --type=js --type=ts -C 2 | head -100

Repository: OdyseeTeam/odysee-frontend

Length of output: 18375


🏁 Script executed:

#!/bin/bash
# Get the full context of the shorts view.jsx file where the variable is set
sed -n '160,180p' ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

# Also check if there's any cleanup or removal of the variable
rg -n "removeProperty.*shorts|shorts.*removeProperty" --type=ts --type=js

# Search for variable cleanup in the shorts component
rg -n "setProperty.*--shorts-viewer-width|removeProperty" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx -A 5

Repository: OdyseeTeam/odysee-frontend

Length of output: 2026


🏁 Script executed:

#!/bin/bash
# Look at the full useEffect that sets the variable
sed -n '155,175p' ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

# Search for any cleanup functions or unmount handlers in the component
grep -n "useEffect\|cleanup\|return\s*().*=>" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx | head -30

# Check if there's any unmount handling that clears CSS variables
rg -n "removeProperty\|removeAttribute" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 1398


🏁 Script executed:

#!/bin/bash
# Get more context around the setProperty call to see the full useEffect
sed -n '150,180p' ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

# Look for the function name that contains setProperty
rg -B 10 "setProperty.*--shorts-viewer-width" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx | head -20

Repository: OdyseeTeam/odysee-frontend

Length of output: 1648


🏁 Script executed:

#!/bin/bash
# Look for where setShortViewerWidthFromVideo is called or if there's any cleanup
sed -n '1,250p' ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx | grep -n "setShortViewerWidthFromVideo\|useEffect\|return ()"

# Check the end of the component for any cleanup or unmount handlers
tail -100 ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx | grep -n "useEffect\|return ()\|removeProperty"

# Look for the full component export to see if there's any cleanup
rg -A 5 "export.*ShortsPage|export default" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 358


🏁 Script executed:

#!/bin/bash
# Search for any cleanup that might remove the CSS variable when leaving shorts
rg -n "componentWillUnmount|useEffect.*return|useEffect.*\[\]" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx | head -20

# Check if there's a cleanup function that removes document styles
rg -B 5 -A 5 "return ()" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx | grep -A 5 -B 5 "removeProperty\|--shorts"

# Look for the file size and check the actual end of the component
wc -l ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

# Check the last 50 lines to see if there's any cleanup before export
tail -50 ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

Repository: OdyseeTeam/odysee-frontend

Length of output: 1892


🏁 Script executed:

#!/bin/bash
# Look for all useEffect hooks in the file to find any with cleanup functions
rg -B 2 "React.useEffect.*\[\]" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

# Check if setShortViewerWidthFromVideo is called in any useEffect with cleanup
sed -n '145,230p' ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

# Look for any useEffect that might clean up the CSS variable
rg -B 3 -A 8 "React.useEffect\(\(\)" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx | head -80

Repository: OdyseeTeam/odysee-frontend

Length of output: 5481


🏁 Script executed:

#!/bin/bash
# Look for the history.listen cleanup function to see if it clears CSS variables
sed -n '295,330p' ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx

# Check doClearShortsPlaylist to see if it clears the CSS variable
rg -n "doClearShortsPlaylist" ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx -A 2

# Search for the definition of doClearShortsPlaylist in the codebase
rg -n "doClearShortsPlaylist" -A 10 --type=js --type=ts

Repository: OdyseeTeam/odysee-frontend

Length of output: 10882


🏁 Script executed:

#!/bin/bash
# Check if doClearShortsPlaylist removes the CSS variable
sed -n '28,32p' ui/redux/actions/shorts.js

# Search for where doClearShortsPlaylist is handled in reducers
rg -n "CLEAR_SHORTS_PLAYLIST" --type=js --type=ts -A 5

# Check if the CSS variable is explicitly removed anywhere in the shorts reducer or component
rg -n "removeProperty.*--shorts-viewer-width|documentElement.*removeProperty" --type=js --type=ts

Repository: OdyseeTeam/odysee-frontend

Length of output: 1182


Add cleanup to remove the CSS variable when navigating away from shorts.

The CSS variable is correctly set dynamically based on video dimensions in view.jsx line 169 with proper fallback handling. However, it is never removed when navigating away from the shorts player. While doClearShortsPlaylist() clears the Redux state in the navigation cleanup handler (lines 295–346), it does not remove the --shorts-viewer-width property from document.documentElement.style.

Add document.documentElement?.style?.removeProperty('--shorts-viewer-width') to the cleanup function in the history.listen effect to prevent the CSS variable from persisting in the document after the user leaves the shorts view.

🤖 Prompt for AI Agents
In @ui/scss/component/_shorts.scss at line 253, The CSS variable
--shorts-viewer-width is set dynamically in view.jsx but not removed on
navigation; update the navigation cleanup inside the history.listen effect where
doClearShortsPlaylist() is called (the history.listen cleanup handler in
view.jsx) to also call
document.documentElement?.style?.removeProperty('--shorts-viewer-width') so the
CSS variable is cleared when leaving the shorts player.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx (1)

151-173: Good improvement on selector scoping.

The selector has been improved to use .shorts__viewer as a scope, which addresses the major concern from the previous review about selecting the wrong video element. The instanceof check on line 154 adds additional type safety.

The magic numbers (0.9, 30, 80) on lines 159 and 165 remain in the code. Extracting these as named constants would improve maintainability.

♻️ Optional: Extract magic numbers as constants
+const MAX_HEIGHT_VIEWPORT_RATIO = 0.9;
+const MAX_WIDTH_WITH_PANEL = 30;
+const MAX_WIDTH_WITHOUT_PANEL = 80;
+
 const setShortViewerWidthFromVideo = React.useCallback(() => {
   // $FlowFixMe
   const video = document.querySelector('.shorts__viewer')?.querySelector('video');
   if (!(video instanceof HTMLVideoElement)) return;
   const videoW = video?.videoWidth;
   const videoH = video?.videoHeight;
   if (!videoW || !videoH) return;

-  const maxHeight = window.innerHeight * 0.9;
+  const maxHeight = window.innerHeight * MAX_HEIGHT_VIEWPORT_RATIO;

   const scale = maxHeight / videoH;
   const computedWidthPx = videoW * scale;

   // Convert to vw (viewport width %)
-  const maxWidth = sidePanelOpen ? 30 : 80; // in percentages
+  const maxWidth = sidePanelOpen ? MAX_WIDTH_WITH_PANEL : MAX_WIDTH_WITHOUT_PANEL;
   const widthVW = (computedWidthPx / window.innerWidth) * 100;
   const clampedVW = Math.min(widthVW, maxWidth); // Avoid overflow

   requestAnimationFrame(() => {
     // $FlowFixMe
     document.documentElement?.style?.setProperty('--shorts-viewer-width', `${clampedVW}vw`);
   });
 }, [sidePanelOpen]);
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c48ae7a and 9b376ec.

📒 Files selected for processing (1)
  • ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx
🧰 Additional context used
🧬 Code graph analysis (1)
ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx (3)
ui/component/videoRenderFloating/view.jsx (1)
  • maxHeight (700-702)
ui/effects/use-on-resize.js (1)
  • useOnResize (4-23)
ui/component/videoRenderFloating/index.js (1)
  • uri (44-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: lint
🔇 Additional comments (3)
ui/page/claim/internal/claimPageComponent/internal/streamClaimPage/internal/shorts/view.jsx (3)

17-17: LGTM: Clean import addition.

The useOnResize hook import is correctly added and necessary for the new responsive width calculation feature.


175-175: LGTM: Correct hook usage.

The useOnResize hook is correctly used with the memoized callback, ensuring the shorts viewer width is recalculated on mount and resize events.


367-369: LGTM: Correct reactive behavior.

This effect ensures the shorts viewer width is recalculated immediately when the side panel state changes, maintaining the correct max width constraint (30% when open, 80% when closed).

@tzarebczan tzarebczan merged commit e0a8473 into master Jan 8, 2026
3 checks passed
@tzarebczan tzarebczan deleted the short-player-fit-to-content branch January 8, 2026 14:18
@coderabbitai coderabbitai bot mentioned this pull request Jan 30, 2026
@coderabbitai coderabbitai bot mentioned this pull request Feb 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants