[vlc-commits] [Git][videolan/vlc][master] 17 commits: macosx: Add starter lyrics sidebar view components
Felix Paul Kühne (@fkuehne)
gitlab at videolan.org
Wed May 6 06:52:19 UTC 2026
Felix Paul Kühne pushed to branch master at VideoLAN / VLC
Commits:
206556fe by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Add starter lyrics sidebar view components
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
e58239b7 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Set up lyrics sidebar view
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
160a86bc by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Add extra meta name handling in input item
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
35255a51 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Present lyrics sidebar if the current item has sylt data
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
e6b20b73 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Present lyrics in table view with current lyric highlighted
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
802726af by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: More efficiently handle standard playback case with lyric updating
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
e3f2b783 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Add explicit typing to collection types
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
540690c2 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Make clicking lyrics move playback to time of lyric
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
f730bfc4 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Fix type mismatch errors in lyrics sidebar
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
646dbf15 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Present lyrics within audio media decorative view, rather than sidebar
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
a0633f5a by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Provide info on whether track has lyrics in player controller
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
b5ff79a3 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Add ability to set lyrics showing in player controller
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
afcca128 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Add lyrics main menu entry
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
7e634f11 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Add lyrics button to main video view
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
35fde4a3 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Check for lyrics settings in player controller in audio media decorative view
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
b0bcbf18 by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Fix lyrics insets in the main video view controller
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
fd2acc9b by Claudio Cambra at 2026-05-06T08:37:43+02:00
macosx: Fix xib crashing on older macOS
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
16 changed files:
- modules/gui/macosx/UI/MainMenu.xib
- modules/gui/macosx/UI/VLCClassicMainVideoView.xib
- modules/gui/macosx/UI/VLCMainVideoView.xib
- modules/gui/macosx/UI/VLCMainVideoViewAudioMediaDecorativeView.xib
- modules/gui/macosx/library/VLCInputItem.h
- modules/gui/macosx/library/VLCInputItem.m
- modules/gui/macosx/library/VLCLibraryWindowSidebarRootViewController.m
- modules/gui/macosx/menus/VLCMainMenu.h
- modules/gui/macosx/menus/VLCMainMenu.m
- modules/gui/macosx/playqueue/VLCPlayerController.h
- modules/gui/macosx/playqueue/VLCPlayerController.m
- modules/gui/macosx/windows/controlsbar/VLCMainVideoViewControlsBar.h
- modules/gui/macosx/windows/controlsbar/VLCMainVideoViewControlsBar.m
- modules/gui/macosx/windows/video/VLCMainVideoViewAudioMediaDecorativeView.h
- modules/gui/macosx/windows/video/VLCMainVideoViewAudioMediaDecorativeView.m
- modules/gui/macosx/windows/video/VLCMainVideoViewController.m
Changes:
=====================================
modules/gui/macosx/UI/MainMenu.xib
=====================================
@@ -70,6 +70,7 @@
<outlet property="jumpToTime" destination="5138" id="XK6-rV-lr9"/>
<outlet property="libraryPlayQueueMode" destination="Zo7-ru-vku" id="uNJ-jw-lG2"/>
<outlet property="license" destination="2834" id="0tU-nu-6dP"/>
+ <outlet property="lyrics" destination="Lyr-Ics-Mni" id="Lyr-Ics-Out"/>
<outlet property="mcopyItem" destination="197" id="aBx-7l-f4e"/>
<outlet property="messages" destination="1003" id="q4C-pt-kQo"/>
<outlet property="minimize" destination="5606" id="tN3-Ho-T0c"/>
@@ -431,6 +432,11 @@
<action selector="goToSpecificTime:" target="-2" id="maw-9c-f5Q"/>
</connections>
</menuItem>
+ <menuItem title="Lyrics" id="Lyr-Ics-Mni">
+ <connections>
+ <action selector="toggleLyrics:" target="-2" id="Lyr-Ics-Con"/>
+ </connections>
+ </menuItem>
<menuItem isSeparatorItem="YES" id="5155">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
=====================================
modules/gui/macosx/UI/VLCClassicMainVideoView.xib
=====================================
@@ -38,6 +38,7 @@
<outlet property="fullscreenButton" destination="Dka-oG-Ar0" id="nqz-qB-etE"/>
<outlet property="jumpBackwardButton" destination="Y6X-Qj-wAU" id="ZDb-ZR-IDF"/>
<outlet property="jumpForwardButton" destination="omu-it-6Lt" id="gtC-uD-Mnu"/>
+ <outlet property="lyricsButton" destination="Lyr-Ics-Btn" id="Lyr-Ics-Out"/>
<outlet property="muteVolumeButton" destination="x8O-Jz-KS8" id="lIH-Am-21m"/>
<outlet property="pipButton" destination="ha3-L8-lMU" id="nqJ-hd-8M1"/>
<outlet property="playButton" destination="etJ-bh-XaL" id="3LP-if-Pah"/>
@@ -299,6 +300,16 @@
<stackView distribution="fillEqually" orientation="horizontal" alignment="centerY" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UCW-iN-Dk1">
<rect key="frame" x="874" y="5" width="148" height="28"/>
<subviews>
+ <button wantsLayer="YES" horizontalHuggingPriority="1000" verticalHuggingPriority="750" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="Lyr-Ics-Btn" customClass="VLCImageButton">
+ <rect key="frame" x="0.0" y="0.0" width="48" height="28"/>
+ <buttonCell key="cell" type="push" bezelStyle="rounded" image="music.note.list" catalog="system" imagePosition="only" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Lyr-Ics-Cel">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="toggleLyrics:" target="3" id="Lyr-Ics-Con"/>
+ </connections>
+ </button>
<button wantsLayer="YES" horizontalHuggingPriority="1000" verticalHuggingPriority="750" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="ha3-L8-lMU" customClass="VLCImageButton">
<rect key="frame" x="0.0" y="0.0" width="48" height="28"/>
<buttonCell key="cell" type="push" bezelStyle="rounded" image="pip.enter" catalog="system" imagePosition="only" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="a9e-eU-lIl">
@@ -334,11 +345,13 @@
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
+ <integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
+ <real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
=====================================
modules/gui/macosx/UI/VLCMainVideoView.xib
=====================================
@@ -48,6 +48,7 @@
<outlet property="fullscreenButton" destination="dYZ-ri-Kra" id="Cw2-BS-QG9"/>
<outlet property="jumpBackwardButton" destination="AXA-01-AU8" id="gfa-Yt-ezI"/>
<outlet property="jumpForwardButton" destination="aAq-uE-mLW" id="M7n-mW-tNe"/>
+ <outlet property="lyricsButton" destination="Lyr-Ics-Btn" id="Lyr-Ics-Out"/>
<outlet property="muteVolumeButton" destination="afi-4d-rQk" id="y6R-6o-2OM"/>
<outlet property="pipButton" destination="yEi-SZ-SIS" id="vFi-Ln-9lT"/>
<outlet property="playButton" destination="PCC-8a-sVF" id="ddT-ZM-Jhz"/>
@@ -197,6 +198,16 @@
<action selector="openSubtitlesMenu:" target="3" id="X6e-aG-mVF"/>
</connections>
</button>
+ <button wantsLayer="YES" horizontalHuggingPriority="1000" verticalHuggingPriority="750" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="Lyr-Ics-Btn" customClass="VLCImageButton">
+ <rect key="frame" x="204" y="0.0" width="45" height="28"/>
+ <buttonCell key="cell" type="recessed" bezelStyle="recessed" image="music.note.list" catalog="system" imagePosition="only" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Lyr-Ics-Cel">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="toggleLyrics:" target="3" id="Lyr-Ics-Con"/>
+ </connections>
+ </button>
<button wantsLayer="YES" horizontalHuggingPriority="1000" verticalHuggingPriority="750" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="4tZ-52-1q9" customClass="VLCImageButton">
<rect key="frame" x="204" y="0.0" width="42" height="28"/>
<buttonCell key="cell" type="recessed" bezelStyle="recessed" image="bookmark.fill" catalog="system" imagePosition="only" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bGc-fn-jgQ">
@@ -256,6 +267,7 @@
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
+ <integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
@@ -266,6 +278,7 @@
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
+ <real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
<stackView distribution="fill" orientation="horizontal" alignment="centerY" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zyp-45-IgR">
=====================================
modules/gui/macosx/UI/VLCMainVideoViewAudioMediaDecorativeView.xib
=====================================
@@ -30,6 +30,73 @@
</shadow>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="noart" id="m7g-tH-8dl"/>
</imageView>
+ <scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4vZ-4x-fwW">
+ <rect key="frame" x="0.0" y="0.0" width="316" height="336"/>
+ <clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="H6H-Cp-iPh">
+ <rect key="frame" x="0.0" y="0.0" width="316" height="336"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowSizeStyle="automatic" viewBased="YES" id="5mv-Qc-JwM" customClass="VLCPlayQueueTableView">
+ <rect key="frame" x="0.0" y="0.0" width="316" height="336"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <size key="intercellSpacing" width="3" height="2"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+ <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+ <tableColumns>
+ <tableColumn identifier="VLCMainVideoViewLyricsTableViewColumnIdentifier" editable="NO" width="284" minWidth="100" maxWidth="2000" id="9yW-DI-c08">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Lyric">
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
+ </tableHeaderCell>
+ <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="JOU-jI-2dC">
+ <font key="font" metaFont="message"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
+ <prototypeCellViews>
+ <tableCellView identifier="LyricCellIdentifier" id="ZTp-fs-5fE">
+ <rect key="frame" x="11" y="1" width="293" height="44"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Wdd-df-zUi">
+ <rect key="frame" x="0.0" y="0.0" width="293" height="44"/>
+ <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="Lyric Line" id="deP-dG-o27">
+ <font key="font" metaFont="message"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstItem="Wdd-df-zUi" firstAttribute="leading" secondItem="ZTp-fs-5fE" secondAttribute="leading" id="l-lead"/>
+ <constraint firstItem="Wdd-df-zUi" firstAttribute="trailing" secondItem="ZTp-fs-5fE" secondAttribute="trailing" id="l-trail"/>
+ <constraint firstItem="Wdd-df-zUi" firstAttribute="top" secondItem="ZTp-fs-5fE" secondAttribute="top" id="l-top"/>
+ <constraint firstItem="Wdd-df-zUi" firstAttribute="bottom" secondItem="ZTp-fs-5fE" secondAttribute="bottom" id="l-bot"/>
+ </constraints>
+ <connections>
+ <outlet property="textField" destination="Wdd-df-zUi" id="61g-Ze-nvR"/>
+ </connections>
+ </tableCellView>
+ </prototypeCellViews>
+ </tableColumn>
+ </tableColumns>
+ <connections>
+ <action selector="tableViewAction:" target="WRu-Ic-lQK" id="conn-action-001"/>
+ </connections>
+ </tableView>
+ </subviews>
+ <nil key="backgroundColor"/>
+ </clipView>
+ <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="L1S-02-OQF">
+ <rect key="frame" x="-100" y="-100" width="0.0" height="16"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="IJr-bf-Dsz">
+ <rect key="frame" x="300" y="0.0" width="16" height="336"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ </scrollView>
</subviews>
<constraints>
<constraint firstItem="40P-sL-Mzq" firstAttribute="centerX" secondItem="WRu-Ic-lQK" secondAttribute="centerX" id="4Ib-c0-egD"/>
@@ -45,12 +112,18 @@
<constraint firstAttribute="bottom" secondItem="D1e-fS-bwO" secondAttribute="bottom" id="toU-5j-lin"/>
<constraint firstAttribute="trailing" secondItem="cDv-dn-65H" secondAttribute="trailing" id="vEl-zP-vj9"/>
<constraint firstItem="40P-sL-Mzq" firstAttribute="centerY" secondItem="WRu-Ic-lQK" secondAttribute="centerY" priority="250" id="yFl-gc-ITT"/>
+ <constraint firstAttribute="trailing" secondItem="4vZ-4x-fwW" secondAttribute="trailing" id="Vo4-sT-MAu"/>
+ <constraint firstAttribute="bottom" secondItem="4vZ-4x-fwW" secondAttribute="bottom" id="aRK-vR-wkV"/>
+ <constraint firstItem="4vZ-4x-fwW" firstAttribute="top" secondItem="WRu-Ic-lQK" secondAttribute="top" id="ran-Af-QyV"/>
+ <constraint firstItem="4vZ-4x-fwW" firstAttribute="leading" secondItem="WRu-Ic-lQK" secondAttribute="leading" id="ran-Af-QyW"/>
</constraints>
<connections>
<outlet property="backgroundCoverArtView" destination="cDv-dn-65H" id="bw2-8i-Xg6"/>
<outlet property="backgroundVisualEffectView" destination="D1e-fS-bwO" id="Jkh-ep-Wyn"/>
<outlet property="foregroundCoverArtView" destination="40P-sL-Mzq" id="nVl-ga-BoM"/>
<outlet property="foregroundViewTopConstraint" destination="TVt-Xt-aoo" id="OFh-5C-XZF"/>
+ <outlet property="lyricsScrollView" destination="4vZ-4x-fwW" id="lyr-scroll-conn"/>
+ <outlet property="lyricsTableView" destination="5mv-Qc-JwM" id="lyr-table-conn"/>
</connections>
<point key="canvasLocation" x="66" y="-232"/>
</customView>
=====================================
modules/gui/macosx/library/VLCInputItem.h
=====================================
@@ -77,6 +77,9 @@ extern NSString * const VLCInputItemCommonDataDifferingFlagString;
@property (readonly) BOOL preparsed;
@property (readonly) BOOL isStream;
@property (readonly, nullable) NSArray<NSString *> *options;
+ at property (readonly) NSArray<NSString *> *extraMetaNames;
+
+- (nullable NSString *)extraMetaForKey:(NSString *)key;
- (void)parseInputItem;
- (void)cancelParsing;
=====================================
modules/gui/macosx/library/VLCInputItem.m
=====================================
@@ -372,6 +372,32 @@ static const struct input_item_parser_cbs_t parserCallbacks =
return @"";
}
+- (NSArray<NSString *> *)extraMetaNames
+{
+ char **ppsz_names;
+ const unsigned i_count = input_item_GetMetaExtraNames(_vlcInputItem, &ppsz_names);
+ if (i_count == 0) {
+ return @[];
+ }
+
+ NSMutableArray * const names = [NSMutableArray arrayWithCapacity:i_count];
+ for (unsigned i = 0; i < i_count; i++) {
+ [names addObject:toNSStr(ppsz_names[i])];
+ free(ppsz_names[i]);
+ }
+ free(ppsz_names);
+
+ return [names copy];
+}
+
+- (nullable NSString *)extraMetaForKey:(NSString *)key
+{
+ char * const psz_value = input_item_GetMetaExtra(_vlcInputItem, [key UTF8String]);
+ NSString * const returnValue = toNSStr(psz_value);
+ free(psz_value);
+ return returnValue;
+}
+
- (vlc_tick_t)duration
{
return _vlcInputItem->i_duration;
=====================================
modules/gui/macosx/library/VLCLibraryWindowSidebarRootViewController.m
=====================================
@@ -32,6 +32,7 @@
#import "library/VLCLibraryUIUnits.h"
#import "library/VLCLibraryWindow.h"
+#import "library/VLCInputItem.h"
#import "library/VLCLibraryWindowChaptersSidebarViewController.h"
#import "library/VLCLibraryWindowPlayQueueSidebarViewController.h"
#import "library/VLCLibraryWindowSidebarChildViewController.h"
@@ -89,6 +90,10 @@
selector:@selector(titleListChanged:)
name:VLCPlayerTitleListChanged
object:nil];
+ [notificationCenter addObserver:self
+ selector:@selector(mediaItemChanged:)
+ name:VLCPlayerCurrentMediaItemChanged
+ object:nil];
}
- (void)setupPlayQueueTitle
@@ -114,10 +119,11 @@
{
self.viewSelector.segmentCount = 1;
[self.viewSelector setLabel:self.playQueueSidebarViewController.title
- forSegment:self.viewSelector.segmentCount - 1];
+ forSegment:0];
VLCPlayQueueController * const playQueueController = VLCMain.sharedInstance.playQueueController;
VLCPlayerController * const playerController = playQueueController.playerController;
+
if (playerController.numberOfTitlesOfCurrentMedia > 0) {
self.viewSelector.segmentCount++;
[self.viewSelector setLabel:self.titlesSidebarViewController.title
@@ -160,37 +166,44 @@
[self updateViewSelectorState];
}
+- (void)mediaItemChanged:(NSNotification *)notification
+{
+ [self updateViewSelectorState];
+}
+
- (void)updateViewSelectorState
{
[self setupViewSelectorSegments];
- VLCPlayQueueController * const playQueueController = VLCMain.sharedInstance.playQueueController;
- VLCPlayerController * const playerController = playQueueController.playerController;
- const BOOL titlesEnabled = playerController.numberOfTitlesOfCurrentMedia > 0;
- const BOOL chaptersEnabled = playerController.numberOfChaptersForCurrentTitle > 0;
-
- self.viewSelector.hidden = !chaptersEnabled && !titlesEnabled;
- self.topInternalConstraint.active = !self.viewSelector.hidden;
+ const BOOL showSelector = self.viewSelector.segmentCount > 1;
+ self.viewSelector.hidden = !showSelector;
+ self.topInternalConstraint.active = showSelector;
+ self.playQueueHeaderLabel.hidden = showSelector;
const NSLayoutPriority playQueueCompressionPriority =
- self.viewSelector.hidden ? NSLayoutPriorityDefaultHigh : NSLayoutPriorityRequired;
- self.playQueueHeaderLabel.hidden = chaptersEnabled;
+ showSelector ? NSLayoutPriorityRequired : NSLayoutPriorityDefaultHigh;
[self.playQueueHeaderLabel setContentCompressionResistancePriority:playQueueCompressionPriority
forOrientation:NSLayoutConstraintOrientationVertical];
- self.playQueueHeaderTopConstraint.active = !self.playQueueHeaderLabel.hidden;
-
- NSLayoutConstraint * const counterLabelConstraintToActivate = self.viewSelector.hidden
- ? self.counterLabelInHeaderConstraint
- : self.counterLabelInChildViewConstraint;
- NSLayoutConstraint * const counterLabelConstraintToDeactivate = self.viewSelector.hidden
- ? self.counterLabelInChildViewConstraint
- : self.counterLabelInHeaderConstraint;
- counterLabelConstraintToActivate.active = YES;
- counterLabelConstraintToDeactivate.active = NO;
-
+ self.playQueueHeaderTopConstraint.active = !showSelector;
+
+ if (showSelector) {
+ self.counterLabelInHeaderConstraint.active = NO;
+ self.counterLabelInChildViewConstraint.active = YES;
+ } else {
+ self.counterLabelInHeaderConstraint.active = YES;
+ self.counterLabelInChildViewConstraint.active = NO;
+ }
+
NSString * const selectedSegmentLabel = [self.viewSelector labelForSegment:self.viewSelector.selectedSegment];
- if ((!chaptersEnabled && [selectedSegmentLabel isEqualToString:self.chaptersSidebarViewController.title]) ||
- (!titlesEnabled && [selectedSegmentLabel isEqualToString:self.titlesSidebarViewController.title])) {
+ BOOL selectedSegmentValid = NO;
+ for (NSInteger i = 0; i < self.viewSelector.segmentCount; i++) {
+ if ([[self.viewSelector labelForSegment:i] isEqualToString:selectedSegmentLabel]) {
+ selectedSegmentValid = YES;
+ break;
+ }
+ }
+
+ if (!selectedSegmentValid) {
self.viewSelector.selectedSegment = 0;
[self viewSelectorAction:self.viewSelector];
}
=====================================
modules/gui/macosx/menus/VLCMainMenu.h
=====================================
@@ -89,6 +89,7 @@
@property (readwrite, weak) IBOutlet NSMenuItem *random;
@property (readwrite, weak) IBOutlet NSMenuItem *repeat;
@property (readwrite, weak) IBOutlet NSMenuItem *AtoBloop;
+ at property (readwrite, weak) IBOutlet NSMenuItem *lyrics;
@property (readwrite, weak) IBOutlet NSMenuItem *libraryPlayQueueMode;
@property (readwrite, weak) IBOutlet NSMenuItem *sortPlayQueue;
@property (readwrite, weak) IBOutlet NSMenuItem *quitAfterPB;
=====================================
modules/gui/macosx/menus/VLCMainMenu.m
=====================================
@@ -385,6 +385,7 @@ typedef NS_ENUM(NSInteger, VLCObjectType) {
[_random setTitle: _NS("Random")];
[_repeat setTitle: _NS("Repeat")];
[_AtoBloop setTitle: _NS("A→B Loop")];
+ [_lyrics setTitle: _NS("Lyrics")];
[_libraryPlayQueueMode setTitle: _NS("Library Play Queue Mode")];
[_sortPlayQueue setTitle: _NS("Sort Play Queue")];
[_quitAfterPB setTitle: _NS("Quit after Playback")];
@@ -884,6 +885,11 @@ typedef NS_ENUM(NSInteger, VLCObjectType) {
[_playerController setABLoop];
}
+- (IBAction)toggleLyrics:(id)sender
+{
+ _playerController.showLyrics = !_playerController.showLyrics;
+}
+
- (IBAction)toggleLibraryPlayQueueMode:(id)sender
{
_playQueueController.libraryPlayQueueMode = !_playQueueController.libraryPlayQueueMode;
@@ -1944,6 +1950,9 @@ typedef NS_ENUM(NSInteger, VLCObjectType) {
mi.state = state ? NSOnState : NSOffState;
} else if (mi == self.fwd || mi == self.bwd || mi == self.jumpToTime) {
return _playerController.currentMedia != nil && _playerController.seekable;
+ } else if (mi == self.lyrics) {
+ mi.state = _playerController.showLyrics ? NSOnState : NSOffState;
+ return _playerController.lyricsAvailable;
} else if (mi == self.mute || mi == self.dockMenumute || mi == self.voutMenumute) {
mi.state = _playerController.mute ? NSOnState : NSOffState;
[self refreshAudioDeviceList];
=====================================
modules/gui/macosx/playqueue/VLCPlayerController.h
=====================================
@@ -242,6 +242,18 @@ extern NSString *VLCPlayerVolumeChanged;
*/
extern NSString *VLCPlayerMuteChanged;
+/**
+ * Listen to VLCPlayerLyricsAvailableChanged to be notified if the current media has synchronized lyrics available
+ * @note the affected player object will be the object of the notification
+ */
+extern NSString * const VLCPlayerLyricsAvailableChanged;
+
+/**
+ * Listen to VLCPlayerShowLyricsChanged to be notified if the show lyrics user preference changes
+ * @note the affected player object will be the object of the notification
+ */
+extern NSString * const VLCPlayerShowLyricsChanged;
+
extern const CGFloat VLCVolumeMaximum;
extern const CGFloat VLCVolumeDefault;
@@ -346,6 +358,16 @@ extern const CGFloat VLCVolumeDefault;
@property (readonly) BOOL currentMediaIsAudioOnly;
+/**
+ * user preference to show synchronized lyrics instead of artwork during audio playback
+ */
+ at property (readwrite, nonatomic) BOOL showLyrics;
+
+/**
+ * indicates if the currently playing media has synchronized lyrics available
+ */
+ at property (readonly) BOOL lyricsAvailable;
+
/**
* the current player state
* @return a value according to the vlc_player_state enum
=====================================
modules/gui/macosx/playqueue/VLCPlayerController.m
=====================================
@@ -82,6 +82,10 @@ NSString *VLCPlayerWallpaperModeChanged = @"VLCPlayerWallpaperModeChanged";
NSString *VLCPlayerListOfVideoOutputThreadsChanged = @"VLCPlayerListOfVideoOutputThreadsChanged";
NSString *VLCPlayerVolumeChanged = @"VLCPlayerVolumeChanged";
NSString *VLCPlayerMuteChanged = @"VLCPlayerMuteChanged";
+NSString * const VLCPlayerLyricsAvailableChanged = @"VLCPlayerLyricsAvailableChanged";
+NSString * const VLCPlayerShowLyricsChanged = @"VLCPlayerShowLyricsChanged";
+
+NSString * const VLCPlayerShowLyricsKey = @"VLCPlayerShowLyricsKey";
const CGFloat VLCVolumeMaximum = 2.;
const CGFloat VLCVolumeDefault = 1.;
@@ -673,6 +677,8 @@ static int BossCallback(vlc_object_t *p_this,
_playbackRate = 1.0;
+ _showLyrics = [NSUserDefaults.standardUserDefaults boolForKey:VLCPlayerShowLyricsKey];
+
libvlc_int_t *libvlc = vlc_object_instance(getIntf());
var_AddCallback(libvlc, "intf-boss", BossCallback, (__bridge void *)self);
}
@@ -737,6 +743,19 @@ static int BossCallback(vlc_object_t *p_this,
[_defaultNotificationCenter removeObserver:self];
}
+- (void)setShowLyrics:(BOOL)showLyrics
+{
+ if (_showLyrics == showLyrics) {
+ return;
+ }
+
+ _showLyrics = showLyrics;
+ [NSUserDefaults.standardUserDefaults setBool:showLyrics forKey:VLCPlayerShowLyricsKey];
+
+ [_defaultNotificationCenter postNotificationName:VLCPlayerShowLyricsChanged
+ object:self];
+}
+
- (VLCInputItem *)currentMedia
{
if (_currentMedia)
@@ -818,6 +837,18 @@ static int BossCallback(vlc_object_t *p_this,
- (void)metaDataChangedForInput:(input_item_t *)inputItem
{
+ NSString *syltData = nil;
+ if (_currentMedia) {
+ syltData = [_currentMedia extraMetaForKey:@"sylt-data"];
+ }
+
+ const BOOL lyricsAvailable = (syltData && syltData.length > 0);
+ if (_lyricsAvailable != lyricsAvailable) {
+ _lyricsAvailable = lyricsAvailable;
+ [_defaultNotificationCenter postNotificationName:VLCPlayerLyricsAvailableChanged
+ object:self];
+ }
+
[_defaultNotificationCenter postNotificationName:VLCPlayerMetadataChangedForCurrentMedia
object:self];
}
@@ -834,6 +865,19 @@ static int BossCallback(vlc_object_t *p_this,
- (void)currentMediaItemChanged:(input_item_t *)newMediaItem
{
_currentMedia = [[VLCInputItem alloc] initWithInputItem:newMediaItem];
+
+ NSString *syltData = nil;
+ if (_currentMedia) {
+ syltData = [_currentMedia extraMetaForKey:@"sylt-data"];
+ }
+
+ const BOOL lyricsAvailable = (syltData && syltData.length > 0);
+ if (_lyricsAvailable != lyricsAvailable) {
+ _lyricsAvailable = lyricsAvailable;
+ [_defaultNotificationCenter postNotificationName:VLCPlayerLyricsAvailableChanged
+ object:self];
+ }
+
[_defaultNotificationCenter postNotificationName:VLCPlayerCurrentMediaItemChanged object:self];
}
=====================================
modules/gui/macosx/windows/controlsbar/VLCMainVideoViewControlsBar.h
=====================================
@@ -30,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (readwrite, weak) IBOutlet NSButton *subtitlesButton;
@property (readwrite, weak) IBOutlet NSButton *audioButton;
@property (readwrite, weak) IBOutlet NSButton *videoButton;
+ at property (readwrite, weak) IBOutlet NSButton *lyricsButton;
@property (readwrite, weak) IBOutlet NSButton *floatOnTopButton;
@property (readwrite, weak) IBOutlet NSButton *playbackRateButton;
@@ -39,6 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
- (IBAction)openAudioMenu:(id)sender;
- (IBAction)openVideoMenu:(id)sender;
- (IBAction)toggleFloatOnTop:(id)sender;
+- (IBAction)toggleLyrics:(id)sender;
@end
=====================================
modules/gui/macosx/windows/controlsbar/VLCMainVideoViewControlsBar.m
=====================================
@@ -68,6 +68,9 @@
self.videoButton.toolTip = _NS("Video");
self.videoButton.accessibilityLabel = self.videoButton.toolTip;
+ self.lyricsButton.toolTip = _NS("Lyrics");
+ self.lyricsButton.accessibilityLabel = self.lyricsButton.toolTip;
+
self.playbackRateButton.toolTip = _NS("Playback Rate");
self.playbackRateButton.accessibilityLabel = self.playbackRateButton.toolTip;
@@ -91,6 +94,7 @@
[buttons addPointer:(__bridge void *)self.subtitlesButton];
[buttons addPointer:(__bridge void *)self.audioButton];
[buttons addPointer:(__bridge void *)self.videoButton];
+ [buttons addPointer:(__bridge void *)self.lyricsButton];
[buttons addPointer:(__bridge void *)self.fullscreenButton];
[buttons addPointer:(__bridge void *)self.floatOnTopButton];
[buttons addPointer:(__bridge void *)self.playbackRateButton];
@@ -133,6 +137,14 @@
selector:@selector(updateAvailableButtons:)
name:VLCPlayerCurrentMediaItemChanged
object:nil];
+ [notificationCenter addObserver:self
+ selector:@selector(updateLyricsButton:)
+ name:VLCPlayerShowLyricsChanged
+ object:nil];
+ [notificationCenter addObserver:self
+ selector:@selector(updateLyricsButton:)
+ name:VLCPlayerLyricsAvailableChanged
+ object:nil];
[self update];
}
@@ -142,6 +154,7 @@
[super update];
[self updateFloatOnTopButton];
[self updatePlaybackRateButton];
+ [self updateLyricsButton:nil];
}
- (void)floatOnTopChanged:(NSNotification *)notification
@@ -149,6 +162,21 @@
[self updateFloatOnTopButton];
}
+- (void)updateLyricsButton:(NSNotification *)notification
+{
+ const BOOL lyricsAvailable = _playerController.lyricsAvailable;
+ self.lyricsButton.enabled = lyricsAvailable;
+ self.lyricsButton.state = _playerController.showLyrics ? NSControlStateValueOn : NSControlStateValueOff;
+
+ if (@available(macOS 26.0, *)) {
+ self.lyricsButton.bezelColor =
+ _playerController.showLyrics ? NSColor.controlAccentColor : nil;
+ } else if (@available(macOS 10.14, *)) {
+ self.lyricsButton.contentTintColor =
+ _playerController.showLyrics ? NSColor.controlAccentColor : nil;
+ }
+}
+
- (vout_thread_t *)windowVoutThread
{
NSWindow * const window = self.floatOnTopButton.window;
@@ -277,6 +305,11 @@
vout_Release(p_vout);
}
+- (IBAction)toggleLyrics:(id)sender
+{
+ _playerController.showLyrics = !_playerController.showLyrics;
+}
+
- (void)updateAvailableButtons:(id)sender
{
const BOOL currentItemIsAudio = _playerController.currentMediaIsAudioOnly;
=====================================
modules/gui/macosx/windows/video/VLCMainVideoViewAudioMediaDecorativeView.h
=====================================
@@ -33,6 +33,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (readwrite, strong) IBOutlet NSVisualEffectView *backgroundVisualEffectView;
@property (readwrite, strong) IBOutlet NSLayoutConstraint *foregroundViewTopConstraint;
+ at property (readwrite, weak) IBOutlet NSScrollView *lyricsScrollView;
+ at property (readwrite, weak) IBOutlet NSTableView *lyricsTableView;
+
@end
NS_ASSUME_NONNULL_END
=====================================
modules/gui/macosx/windows/video/VLCMainVideoViewAudioMediaDecorativeView.m
=====================================
@@ -22,16 +22,26 @@
#import "VLCMainVideoViewAudioMediaDecorativeView.h"
+#import "extensions/NSColor+VLCAdditions.h"
+#import "extensions/NSFont+VLCAdditions.h"
#import "extensions/NSView+VLCAdditions.h"
#import "main/VLCMain.h"
#import "library/VLCLibraryDataTypes.h"
#import "library/VLCLibraryImageCache.h"
+#import "library/VLCInputItem.h"
#import "playqueue/VLCPlayQueueController.h"
#import "playqueue/VLCPlayerController.h"
+ at interface VLCMainVideoViewAudioMediaDecorativeView () <NSTableViewDataSource, NSTableViewDelegate>
+
+ at property (readwrite) NSArray<NSDictionary<NSString *, id> *> *lyricsEntries;
+ at property (readwrite) NSInteger currentLyricIndex;
+
+ at end
+
@implementation VLCMainVideoViewAudioMediaDecorativeView
+ (instancetype)fromNibWithOwner:(id)owner
@@ -43,17 +53,51 @@
- (void)awakeFromNib
{
+ _lyricsEntries = @[];
+ _currentLyricIndex = -1;
+
+ self.lyricsTableView.dataSource = self;
+ self.lyricsTableView.delegate = self;
+ self.lyricsTableView.headerView = nil;
+ self.lyricsTableView.backgroundColor = [NSColor clearColor];
+ self.lyricsTableView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone;
+
NSNotificationCenter * const notificationCenter = NSNotificationCenter.defaultCenter;
[notificationCenter addObserver:self
- selector:@selector(playerCurrentMediaItemChanged:)
+ selector:@selector(playerMetadataChanged:)
+ name:VLCPlayerMetadataChangedForCurrentMedia
+ object:nil];
+ [notificationCenter addObserver:self
+ selector:@selector(playerMetadataChanged:)
name:VLCPlayerCurrentMediaItemChanged
object:nil];
+ [notificationCenter addObserver:self
+ selector:@selector(playerTimeChanged:)
+ name:VLCPlayerTimeAndPositionChanged
+ object:nil];
+ [notificationCenter addObserver:self
+ selector:@selector(playerLyricsPreferenceChanged:)
+ name:VLCPlayerShowLyricsChanged
+ object:nil];
+
[self updateCoverArt];
+ [self updateLyricsData];
}
-- (void)playerCurrentMediaItemChanged:(NSNotification *)notification
+- (void)playerMetadataChanged:(NSNotification *)notification
{
[self updateCoverArt];
+ [self updateLyricsData];
+}
+
+- (void)playerLyricsPreferenceChanged:(NSNotification *)notification
+{
+ [self updateLyricsData];
+}
+
+- (void)playerTimeChanged:(NSNotification *)notification
+{
+ [self updateCurrentLyric];
}
- (void)updateCoverArt
@@ -79,4 +123,183 @@
_foregroundCoverArtView.image = coverArtImage;
}
+- (void)updateLyricsData
+{
+ VLCPlayerController * const playerController =
+ VLCMain.sharedInstance.playQueueController.playerController;
+
+ NSString *syltData = nil;
+ if (playerController.showLyrics && playerController.lyricsAvailable) {
+ syltData = [playerController.currentMedia extraMetaForKey:@"sylt-data"];
+ }
+
+ if (!syltData || syltData.length == 0) {
+ self.lyricsEntries = @[];
+ self.currentLyricIndex = -1;
+ [self.lyricsTableView reloadData];
+ self.lyricsScrollView.hidden = YES;
+ self.foregroundCoverArtView.hidden = NO;
+ return;
+ }
+
+ NSMutableArray * const entries = [NSMutableArray array];
+ NSArray<NSString *> * const rawEntries = [syltData componentsSeparatedByString:@"\x1E"];
+ for (NSString * const rawEntry in rawEntries) {
+ if (rawEntry.length == 0) {
+ continue;
+ }
+ NSArray<NSString *> * const parts = [rawEntry componentsSeparatedByString:@"\x1F"];
+ if (parts.count >= 2) {
+ NSDictionary<NSString *, id> * const entry = @{
+ @"time": @([parts[0] longLongValue]),
+ @"text": parts[1]
+ };
+ [entries addObject:entry];
+ }
+ }
+
+ self.lyricsEntries = [entries copy];
+ self.currentLyricIndex = -1;
+ [self.lyricsTableView reloadData];
+
+ const BOOL hasLyrics = self.lyricsEntries.count > 0;
+ self.lyricsScrollView.hidden = !hasLyrics;
+ self.foregroundCoverArtView.hidden = hasLyrics;
+
+ [self updateCurrentLyric];
+}
+
+- (void)updateCurrentLyric
+{
+ const NSInteger lyricCount = (NSInteger)self.lyricsEntries.count;
+ if (lyricCount == 0) {
+ return;
+ }
+
+ VLCPlayerController * const playerController =
+ VLCMain.sharedInstance.playQueueController.playerController;
+ const vlc_tick_t currentTime = playerController.time;
+ const long long currentTimeMs = MS_FROM_VLC_TICK(currentTime);
+
+ // 1. Check if we are still on the same lyric (most frequent case)
+ if (self.currentLyricIndex >= 0 && self.currentLyricIndex < lyricCount) {
+ const long long startTime =
+ [self.lyricsEntries[self.currentLyricIndex][@"time"] longLongValue];
+ const BOOL isLast = (self.currentLyricIndex == lyricCount - 1);
+ const long long nextStartTime = isLast
+ ? LLONG_MAX
+ : [self.lyricsEntries[self.currentLyricIndex + 1][@"time"] longLongValue];
+
+ if (currentTimeMs >= startTime && currentTimeMs < nextStartTime) {
+ return;
+ }
+
+ // 2. Check if it's simply the next one (normal linear playback transition)
+ if (!isLast && currentTimeMs >= nextStartTime) {
+ const NSInteger nextIndex = self.currentLyricIndex + 1;
+ const BOOL isNextLast = (nextIndex == lyricCount - 1);
+ const long long nextNextStartTime = isNextLast
+ ? LLONG_MAX
+ : [self.lyricsEntries[nextIndex + 1][@"time"] longLongValue];
+
+ if (currentTimeMs < nextNextStartTime) {
+ [self updateToLyricIndex:nextIndex];
+ return;
+ }
+ }
+ }
+
+ // 3. Fallback to search (for seeks, jumps, or initial playback)
+ NSInteger foundIndex = -1;
+ for (NSInteger i = 0; i < lyricCount; i++) {
+ if ([self.lyricsEntries[i][@"time"] longLongValue] <= currentTimeMs) {
+ foundIndex = i;
+ } else {
+ break;
+ }
+ }
+
+ if (foundIndex != self.currentLyricIndex) {
+ [self updateToLyricIndex:foundIndex];
+ }
+}
+
+- (void)updateToLyricIndex:(NSInteger)newIndex
+{
+ const NSInteger lyricCount = (NSInteger)self.lyricsEntries.count;
+ NSMutableIndexSet * const indicesToUpdate = [NSMutableIndexSet indexSet];
+ if (self.currentLyricIndex != -1 && self.currentLyricIndex < lyricCount) {
+ [indicesToUpdate addIndex:self.currentLyricIndex];
+ }
+
+ self.currentLyricIndex = newIndex;
+
+ if (self.currentLyricIndex != -1 && self.currentLyricIndex < lyricCount) {
+ [indicesToUpdate addIndex:self.currentLyricIndex];
+ };
+
+ if (indicesToUpdate.count > 0) {
+ [self.lyricsTableView noteHeightOfRowsWithIndexesChanged:indicesToUpdate];
+ [self.lyricsTableView reloadDataForRowIndexes:indicesToUpdate
+ columnIndexes:[NSIndexSet indexSetWithIndex:0]];
+ }
+
+ if (self.currentLyricIndex != -1) {
+ [self.lyricsTableView scrollRowToVisible:self.currentLyricIndex];
+ }
+}
+
+#pragma mark - Table View Data Source
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+ return (NSInteger)self.lyricsEntries.count;
+}
+
+#pragma mark - Table View Delegate
+
+- (NSView *)tableView:(NSTableView *)tableView
+ viewForTableColumn:(NSTableColumn *)tableColumn
+ row:(NSInteger)row
+{
+ NSTableCellView * const cellView =
+ [tableView makeViewWithIdentifier:@"LyricCellIdentifier" owner:self];
+ if (row < 0 || row >= (NSInteger)self.lyricsEntries.count) {
+ return cellView;
+ }
+
+ NSString * const text = self.lyricsEntries[row][@"text"];
+ cellView.textField.stringValue = text;
+
+ if (row == self.currentLyricIndex) {
+ cellView.textField.font = [NSFont boldSystemFontOfSize:22.0];
+ cellView.textField.textColor = [NSColor labelColor];
+ } else {
+ cellView.textField.font = [NSFont systemFontOfSize:16.0];
+ cellView.textField.textColor = [NSColor secondaryLabelColor];
+ }
+
+ return cellView;
+}
+
+- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
+{
+ return (row == self.currentLyricIndex) ? 60.0 : 40.0;
+}
+
+- (IBAction)tableViewAction:(id)sender
+{
+ const NSInteger clickedRow = self.lyricsTableView.clickedRow;
+ if (clickedRow < 0 || clickedRow >= (NSInteger)self.lyricsEntries.count) {
+ return;
+ }
+
+ const long long lyricTimeMs = [self.lyricsEntries[clickedRow][@"time"] longLongValue];
+ const vlc_tick_t vlcTime = VLC_TICK_FROM_MS(lyricTimeMs);
+
+ VLCPlayerController * const playerController =
+ VLCMain.sharedInstance.playQueueController.playerController;
+ [playerController setTimePrecise:vlcTime];
+}
+
@end
=====================================
modules/gui/macosx/windows/video/VLCMainVideoViewController.m
=====================================
@@ -172,6 +172,7 @@ NSString * const VLCUseClassicVideoPlayerLayoutKey = @"VLCUseClassicVideoPlayerL
// Only set up button constraints for standard layout
_bottomButtonStackViewConstraint =
[self.bottomBarView.topAnchor constraintEqualToAnchor:self.centralControlsStackView.bottomAnchor];
+ [self updateLyricsInsets];
}
VLCPlayerController * const controller =
@@ -219,6 +220,7 @@ NSString * const VLCUseClassicVideoPlayerLayoutKey = @"VLCUseClassicVideoPlayerL
[self setupAudioDecorativeView];
[self.controlsBar update];
[self updateFloatOnTopIndicator];
+ [self updateLyricsInsets];
// For classic layout, create constraint for video view to fill main view when controls are hidden
if (self.classic) {
@@ -245,6 +247,17 @@ NSString * const VLCUseClassicVideoPlayerLayoutKey = @"VLCUseClassicVideoPlayerL
}
}
+- (void)updateLyricsInsets
+{
+ const CGFloat topInset = self.fakeTitleBar.frame.size.height + VLCLibraryUIUnits.largeSpacing;
+ const CGFloat bottomInset = self.bottomBarView.frame.size.height + VLCLibraryUIUnits.largeSpacing;
+
+ NSScrollView * const scrollView = self.audioDecorativeView.lyricsScrollView;
+ scrollView.automaticallyAdjustsContentInsets = NO;
+ scrollView.contentInsets = NSEdgeInsetsMake(topInset, 0, bottomInset, 0);
+ scrollView.scrollerInsets = NSEdgeInsetsMake(topInset, 0, 0, 0);
+}
+
- (BOOL)isVisualizationActive
{
BOOL isVisualActive;
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/d0a89f94fb0003aa41b23b6b259946242f8f0476...fd2acc9bfc113600f6ba6447c02507eb4f193d13
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/d0a89f94fb0003aa41b23b6b259946242f8f0476...fd2acc9bfc113600f6ba6447c02507eb4f193d13
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list