[vlc-commits] [Git][videolan/vlc][master] macosx: expose recently played network streams
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Tue May 26 11:36:40 UTC 2026
Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC
Commits:
6c0693a3 by Felix Paul Kühne at 2026-05-26T13:18:25+02:00
macosx: expose recently played network streams
This fetches the recent networks streams from the media library and
fixes #18838. AppKit handles recent files only and refuses any
non-file URL.
- - - - -
9 changed files:
- extras/package/macosx/VLC.xcodeproj/project.pbxproj
- modules/gui/macosx/Makefile.am
- modules/gui/macosx/UI/MainMenu.xib
- modules/gui/macosx/menus/VLCMainMenu.h
- modules/gui/macosx/menus/VLCMainMenu.m
- + modules/gui/macosx/menus/VLCRecentStreamsMenuController.h
- + modules/gui/macosx/menus/VLCRecentStreamsMenuController.m
- modules/gui/macosx/playqueue/VLCPlayQueueController.m
- po/POTFILES.in
Changes:
=====================================
extras/package/macosx/VLC.xcodeproj/project.pbxproj
=====================================
@@ -221,6 +221,7 @@
7D66D4362200BC340040D04A /* VLCClickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D66D4352200BC340040D04A /* VLCClickerManager.m */; };
7D66D4392200C5B80040D04A /* VLCVideoFilterHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D66D4382200C5B80040D04A /* VLCVideoFilterHelper.m */; };
7D67318622C8F4060000AD40 /* VLCMediaSourceCollectionViewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D67318422C8F4050000AD40 /* VLCMediaSourceCollectionViewItem.m */; };
+ 7D6CCA6F2FBE1BA400088B47 /* VLCRecentStreamsMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D6CCA6E2FBE1BA400088B47 /* VLCRecentStreamsMenuController.m */; };
7D713D322201AE350042BEB7 /* VLCLibraryWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D713D312201AE350042BEB7 /* VLCLibraryWindow.m */; };
7D713D362201DC640042BEB7 /* VLCLibraryWindow.xib in Sources */ = {isa = PBXBuildFile; fileRef = 7D713D332201BB130042BEB7 /* VLCLibraryWindow.xib */; };
7D903E0E22438F8F00917358 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C64E331223DB3B60046F895 /* error.c */; };
@@ -829,6 +830,8 @@
7D67318322C8F3F60000AD40 /* VLCMediaSourceCollectionViewItem.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VLCMediaSourceCollectionViewItem.xib; sourceTree = "<group>"; };
7D67318422C8F4050000AD40 /* VLCMediaSourceCollectionViewItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCMediaSourceCollectionViewItem.m; sourceTree = "<group>"; };
7D67318522C8F4050000AD40 /* VLCMediaSourceCollectionViewItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCMediaSourceCollectionViewItem.h; sourceTree = "<group>"; };
+ 7D6CCA6D2FBE1BA400088B47 /* VLCRecentStreamsMenuController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCRecentStreamsMenuController.h; sourceTree = "<group>"; };
+ 7D6CCA6E2FBE1BA400088B47 /* VLCRecentStreamsMenuController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCRecentStreamsMenuController.m; sourceTree = "<group>"; };
7D713D302201AE350042BEB7 /* VLCLibraryWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLibraryWindow.h; sourceTree = "<group>"; };
7D713D312201AE350042BEB7 /* VLCLibraryWindow.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLibraryWindow.m; sourceTree = "<group>"; };
7D713D332201BB130042BEB7 /* VLCLibraryWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = VLCLibraryWindow.xib; sourceTree = "<group>"; };
@@ -1312,6 +1315,8 @@
7DB40D2920CBCEB500F63173 /* VLCMainMenu.m */,
7DB40D2C20CBCEC200F63173 /* VLCStatusBarIcon.h */,
7DB40D2B20CBCEC200F63173 /* VLCStatusBarIcon.m */,
+ 7D6CCA6D2FBE1BA400088B47 /* VLCRecentStreamsMenuController.h */,
+ 7D6CCA6E2FBE1BA400088B47 /* VLCRecentStreamsMenuController.m */,
);
path = menus;
sourceTree = "<group>";
@@ -2252,7 +2257,7 @@
};
};
};
- buildConfigurationList = C2F2A6EA09588F1B00018C74 /* Build configuration list for PBXProject "vlc" */;
+ buildConfigurationList = C2F2A6EA09588F1B00018C74 /* Build configuration list for PBXProject "VLC" */;
compatibilityVersion = "Xcode 6.3";
developmentRegion = en;
hasScannedForEncodings = 1;
@@ -2402,6 +2407,7 @@
53903D3A29576ED500D0B308 /* VLCLibraryAudioGroupDataSource.m in Sources */,
1C31139A1E508C6900D4DD76 /* VLCBookmarksWindowController.m in Sources */,
6B0AB0F01F1AC8B3003A1B4E /* VLCPlaybackProgressSlider.m in Sources */,
+ 7D6CCA6F2FBE1BA400088B47 /* VLCRecentStreamsMenuController.m in Sources */,
53741A5A2DCA7B4C00E112CD /* VLCSnowEffectView.m in Sources */,
7D28E6362275B4820098D30E /* NSColor+VLCAdditions.m in Sources */,
534D28B42DB2B3C0006869CD /* NSTableCellView+VLCAdditions.m in Sources */,
@@ -2954,7 +2960,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
- C2F2A6EA09588F1B00018C74 /* Build configuration list for PBXProject "vlc" */ = {
+ C2F2A6EA09588F1B00018C74 /* Build configuration list for PBXProject "VLC" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C2F2A6EB09588F1B00018C74 /* Development */,
=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -338,6 +338,8 @@ libmacosx_plugin_la_SOURCES = \
gui/macosx/main/macosx.m \
gui/macosx/menus/VLCMainMenu.h \
gui/macosx/menus/VLCMainMenu.m \
+ gui/macosx/menus/VLCRecentStreamsMenuController.h \
+ gui/macosx/menus/VLCRecentStreamsMenuController.m \
gui/macosx/menus/VLCStatusBarIcon.h \
gui/macosx/menus/VLCStatusBarIcon.m \
gui/macosx/menus/renderers/VLCRendererDiscovery.h \
=====================================
modules/gui/macosx/UI/MainMenu.xib
=====================================
@@ -85,6 +85,8 @@
<outlet property="open_generic" destination="72" id="HZC-SG-Njq"/>
<outlet property="open_net" destination="446" id="mcx-C9-l0u"/>
<outlet property="open_recent" destination="4815" id="Hzh-wK-cxa"/>
+ <outlet property="recent_streams" destination="rstr-mi-0001" id="rstr-ol-0001"/>
+ <outlet property="recent_streamsMenu" destination="rstr-sm-0001" id="rstr-ol-0002"/>
<outlet property="pasteItem" destination="203" id="H04-s9-3uF"/>
<outlet property="play" destination="5142" id="B2I-n1-EOc"/>
<outlet property="playQueue" destination="1002" id="nhI-Gw-yev"/>
@@ -314,6 +316,10 @@
</items>
</menu>
</menuItem>
+ <menuItem title="Recent Streams" id="rstr-mi-0001">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Recent Streams" id="rstr-sm-0001"/>
+ </menuItem>
<menuItem isSeparatorItem="YES" id="3946">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
=====================================
modules/gui/macosx/menus/VLCMainMenu.h
=====================================
@@ -1,7 +1,7 @@
/*****************************************************************************
*MainMenu.h: MacOS X interface module
*****************************************************************************
- *Copyright (C) 2011-2018 Felix Paul Kühne
+ *Copyright (C) 2011-2026 Felix Paul Kühne
*
*Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
*
@@ -52,6 +52,8 @@
@property (readwrite, weak) IBOutlet NSMenuItem *open_capture;
@property (readwrite, weak) IBOutlet NSMenuItem *connect_to_server;
@property (readwrite, weak) IBOutlet NSMenuItem *open_recent;
+ at property (readwrite, weak) IBOutlet NSMenuItem *recent_streams;
+ at property (readwrite, weak) IBOutlet NSMenu *recent_streamsMenu;
@property (readwrite, weak) IBOutlet NSMenuItem *close_window;
@property (readwrite, weak) IBOutlet NSMenuItem *convertandsave;
@property (readwrite, weak) IBOutlet NSMenuItem *save_playlist;
=====================================
modules/gui/macosx/menus/VLCMainMenu.m
=====================================
@@ -1,7 +1,7 @@
/*****************************************************************************
*MainMenu.m: MacOS X interface module
*****************************************************************************
- *Copyright (C) 2011-2019 Felix Paul Kühne
+ *Copyright (C) 2011-2026 Felix Paul Kühne
*
*Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
*
@@ -32,6 +32,7 @@
#import "main/VLCMain.h"
+#import "menus/VLCRecentStreamsMenuController.h"
#import "menus/renderers/VLCRendererMenuController.h"
#import "panels/VLCAudioEffectsWindowController.h"
@@ -107,6 +108,7 @@ typedef NS_ENUM(NSInteger, VLCObjectType) {
VLCPlayerController *_playerController;
VLCPlayQueueSortingMenuController *_playQueueSortingController;
VLCInformationWindowController *_infoWindowController;
+ VLCRecentStreamsMenuController *_recentStreamsMenuController;
__strong VLCTimeSelectionPanelController *_timeSelectionPanel;
__strong VLCCustomCropArWindowController *_customARController;
@@ -158,6 +160,8 @@ typedef NS_ENUM(NSInteger, VLCObjectType) {
_rendererMenuController.rendererMenu = _rendererMenu;
_playQueueSortingController = [[VLCPlayQueueSortingMenuController alloc] init];
_sortPlayQueue.submenu = _playQueueSortingController.playQueueSortingMenu;
+ _recentStreamsMenuController =
+ [[VLCRecentStreamsMenuController alloc] initWithSubmenu:_recent_streamsMenu];
[self mediaItemChanged:nil];
[self playbackStateChanged:nil];
@@ -353,6 +357,7 @@ typedef NS_ENUM(NSInteger, VLCObjectType) {
[_open_capture setTitle: _NS("Open Capture Device...")];
[_connect_to_server setTitle: _NS("Connect to Server...")];
[_open_recent setTitle: _NS("Open Recent")];
+ [_recent_streams setTitle: _NS("Recent Streams")];
[_close_window setTitle: _NS("Close Window")];
[_convertandsave setTitle: _NS("Convert / Stream...")];
[_save_playlist setTitle: _NS("Save Playlist...")];
=====================================
modules/gui/macosx/menus/VLCRecentStreamsMenuController.h
=====================================
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * VLCRecentStreamsMenuController.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCRecentStreamsMenuController : NSObject
+
+- (instancetype)initWithSubmenu:(NSMenu *)submenu;
+
+ at end
+
+NS_ASSUME_NONNULL_END
=====================================
modules/gui/macosx/menus/VLCRecentStreamsMenuController.m
=====================================
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ * VLCRecentStreamsMenuController.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCRecentStreamsMenuController.h"
+#import "extensions/NSString+Helpers.h"
+#import "main/VLCMain.h"
+#import "playqueue/VLCPlayQueueController.h"
+#import "windows/VLCOpenInputMetadata.h"
+#import <vlc_media_library.h>
+
+ at interface VLCRecentStreamsMenuController ()
+{
+ vlc_medialibrary_t *_mediaLibrary;
+ vlc_ml_event_callback_t *_eventCallback;
+ NSMenu *_submenu;
+}
+
+- (void)rebuild;
+
+ at end
+
+static void recentStreamsLibraryCallback(void *p_data, const vlc_ml_event_t *p_event)
+{
+ if (p_event->i_type != VLC_ML_EVENT_HISTORY_CHANGED)
+ return;
+
+ VLCRecentStreamsMenuController *controller =
+ (__bridge VLCRecentStreamsMenuController *)p_data;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [controller rebuild];
+ });
+}
+
+ at implementation VLCRecentStreamsMenuController
+
+- (instancetype)initWithSubmenu:(NSMenu *)submenu
+{
+ if (self = [super init]) {
+ _submenu = submenu;
+ _submenu.autoenablesItems = NO;
+
+ _mediaLibrary = vlc_ml_instance_get(getIntf());
+ if (_mediaLibrary != NULL) {
+ _eventCallback = vlc_ml_event_register_callback(_mediaLibrary,
+ recentStreamsLibraryCallback,
+ (__bridge void *)self);
+ [NSNotificationCenter.defaultCenter addObserver:self
+ selector:@selector(applicationWillTerminate:)
+ name:NSApplicationWillTerminateNotification
+ object:nil];
+ }
+ [self rebuild];
+ }
+ return self;
+}
+
+- (void)applicationWillTerminate:(NSNotification *)notification
+{
+ if (_eventCallback != NULL) {
+ vlc_ml_event_unregister_callback(_mediaLibrary, _eventCallback);
+ _eventCallback = NULL;
+ }
+}
+
+- (void)dealloc
+{
+ [NSNotificationCenter.defaultCenter removeObserver:self];
+}
+
+- (void)rebuild
+{
+ [_submenu removeAllItems];
+
+ if (_mediaLibrary == NULL) {
+ return;
+ }
+
+ BOOL hasEntries = NO;
+ vlc_ml_query_params_t params = vlc_ml_query_params_create();
+ params.i_nbResults = 30;
+ vlc_ml_media_list_t *list = vlc_ml_list_history(_mediaLibrary, ¶ms, VLC_ML_HISTORY_TYPE_NETWORK);
+ if (list != NULL) {
+ for (size_t i = 0; i < list->i_nb_items; i++) {
+ const vlc_ml_media_t *ml_media = &list->p_items[i];
+ if (ml_media->p_files == NULL || ml_media->p_files->i_nb_items == 0)
+ continue;
+
+ NSString *mrlString = toNSStr(ml_media->p_files->p_items[0].psz_mrl);
+ NSString *title = toNSStr(ml_media->psz_title);
+ if (title.length == 0)
+ title = mrlString;
+
+ NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title
+ action:@selector(openRecentStreamItem:)
+ keyEquivalent:@""];
+ item.target = self;
+ item.representedObject = mrlString;
+ item.toolTip = mrlString;
+ [_submenu addItem:item];
+ hasEntries = YES;
+ }
+
+ if (hasEntries)
+ [_submenu addItem:[NSMenuItem separatorItem]];
+
+ vlc_ml_media_list_release(list);
+ }
+
+ NSMenuItem *clearItem = [[NSMenuItem alloc] initWithTitle:_NS("Clear Menu")
+ action:@selector(clearRecentStreams:)
+ keyEquivalent:@""];
+ clearItem.target = self;
+ clearItem.enabled = hasEntries;
+ [_submenu addItem:clearItem];
+}
+
+- (void)openRecentStreamItem:(NSMenuItem *)sender
+{
+ VLCOpenInputMetadata *meta = [[VLCOpenInputMetadata alloc] init];
+ meta.MRLString = sender.representedObject;
+ [VLCMain.sharedInstance.playQueueController addPlayQueueItems:@[meta]];
+}
+
+- (void)clearRecentStreams:(id)sender
+{
+ vlc_ml_clear_history(_mediaLibrary, VLC_ML_HISTORY_TYPE_NETWORK);
+}
+
+ at end
=====================================
modules/gui/macosx/playqueue/VLCPlayQueueController.m
=====================================
@@ -1,7 +1,7 @@
/*****************************************************************************
* VLCPlayQueueController.m: MacOS X interface module
*****************************************************************************
- * Copyright (C) 2019-2025 VLC authors and VideoLAN
+ * Copyright (C) 2019-2026 VLC authors and VideoLAN
*
* Authors: Felix Paul Kühne <fkuehne # videolan -dot- org>
*
@@ -693,6 +693,25 @@ static const struct vlc_playlist_callbacks playlist_callbacks = {
if (url != nil && var_InheritBool(getIntf(), "macosx-recentitems"))
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:url];
+ /* Recent Streams menu */
+ if (url != nil && !url.isFileURL) {
+ vlc_medialibrary_t *ml = vlc_ml_instance_get(getIntf());
+ if (ml != NULL) {
+ const char *psz_uri = uri.UTF8String;
+ vlc_ml_media_t * ml_media = vlc_ml_get_media_by_mrl(ml, psz_uri);
+ if (ml_media == NULL) {
+ // create new entry if we don't have it yet
+ ml_media = vlc_ml_new_stream(ml, psz_uri);
+ }
+ if (ml_media != NULL) {
+ vlc_ml_media_set_played(ml, ml_media->i_id, true);
+ vlc_ml_media_release(ml_media);
+ }
+ } else {
+ msg_Dbg(p_intf, "ML unavailable, won't remember stream");
+ }
+ }
+
return p_input;
}
=====================================
po/POTFILES.in
=====================================
@@ -503,6 +503,8 @@ modules/gui/macosx/main/VLCMain.m
modules/gui/macosx/main/macosx.m
modules/gui/macosx/menus/VLCMainMenu.h
modules/gui/macosx/menus/VLCMainMenu.m
+modules/gui/macosx/menus/VLCRecentStreamsMenuController.h
+modules/gui/macosx/menus/VLCRecentStreamsMenuController.m
modules/gui/macosx/menus/VLCStatusBarIcon.h
modules/gui/macosx/menus/VLCStatusBarIcon.m
modules/gui/macosx/menus/renderers/VLCRendererDiscovery.h
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/6c0693a32730db447dae010f16798a213a64baf4
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/6c0693a32730db447dae010f16798a213a64baf4
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help
More information about the vlc-commits
mailing list