From dc6233cd71f611dc92db256d5009cd1db33a2030 Mon Sep 17 00:00:00 2001 From: Hank Anderson <ataganak@gmail.com> Date: Fri, 22 Apr 2022 14:24:54 +0900 Subject: [PATCH] Move metadata management to the VLCMediaMetaData class. --- Headers/Internal/VLCLibVLCBridging.h | 12 + Headers/Public/MobileVLCKit.h | 2 + Headers/Public/TVVLCKit.h | 2 + Headers/Public/VLCKit.h | 2 + Headers/Public/VLCMedia.h | 86 +---- Headers/Public/VLCMediaMetaData.h | 199 +++++++++++ Sources/VLCMedia.m | 273 +------------- Sources/VLCMediaMetaData.m | 513 +++++++++++++++++++++++++++ VLCKit.xcodeproj/project.pbxproj | 16 + 9 files changed, 759 insertions(+), 346 deletions(-) create mode 100644 Headers/Public/VLCMediaMetaData.h create mode 100644 Sources/VLCMediaMetaData.m diff --git a/Headers/Internal/VLCLibVLCBridging.h b/Headers/Internal/VLCLibVLCBridging.h index f6e8fa58..9a0a109c 100644 --- a/Headers/Internal/VLCLibVLCBridging.h +++ b/Headers/Internal/VLCLibVLCBridging.h @@ -30,6 +30,7 @@ #import <VLCMediaList.h> #import <VLCMedia.h> #import <VLCAudio.h> +#import <VLCMediaMetaData.h> #if !TARGET_OS_TV #import <VLCRendererItem.h> #endif // !TARGET_OS_TV @@ -219,3 +220,14 @@ - (instancetype)initWithSubtitleTrack:(libvlc_subtitle_track_t *)subtitle; @end + +/** + * Bridges functionality between libvlc and VLCMediaMetaData implementation. + */ +@interface VLCMediaMetaData (LibVLCBridging) + +- (instancetype)initWithMedia:(VLCMedia *)media; + +- (void)handleMediaMetaChanged:(libvlc_meta_t)type; + +@end diff --git a/Headers/Public/MobileVLCKit.h b/Headers/Public/MobileVLCKit.h index 121389dd..5f8ce2de 100644 --- a/Headers/Public/MobileVLCKit.h +++ b/Headers/Public/MobileVLCKit.h @@ -34,6 +34,7 @@ #import <MobileVLCKit/VLCTranscoder.h> #import <MobileVLCKit/VLCRendererDiscoverer.h> #import <MobileVLCKit/VLCRendererItem.h> +#import <MobileVLCKit/VLCMediaMetaData.h> @class VLCMedia; @class VLCMediaList; @@ -47,3 +48,4 @@ @class VLCRendererDiscoverer; @class VLCRendererDiscovererDescription; @class VLCRendererItem; +@class VLCMediaMetaData; diff --git a/Headers/Public/TVVLCKit.h b/Headers/Public/TVVLCKit.h index 7dd11fea..d1af9a9a 100644 --- a/Headers/Public/TVVLCKit.h +++ b/Headers/Public/TVVLCKit.h @@ -31,6 +31,7 @@ #import <TVVLCKit/VLCMediaThumbnailer.h> #import <TVVLCKit/VLCTime.h> #import <TVVLCKit/VLCDialogProvider.h> +#import <TVVLCKit/VLCMediaMetaData.h> @class VLCMedia; @class VLCMediaList; @@ -40,3 +41,4 @@ @class VLCMediaThumbnailer; @class VLCMediaListPlayer; @class VLCMediaPlayer; +@class VLCMediaMetaData; diff --git a/Headers/Public/VLCKit.h b/Headers/Public/VLCKit.h index dd1ccdda..27d6105c 100644 --- a/Headers/Public/VLCKit.h +++ b/Headers/Public/VLCKit.h @@ -37,8 +37,10 @@ #import <VLCKit/VLCVideoLayer.h> #import <VLCKit/VLCRendererDiscoverer.h> #import <VLCKit/VLCRendererItem.h> +#import <VLCKit/VLCMediaMetaData.h> @class VLCMedia; @class VLCMediaList; @class VLCTime; @class VLCVideoView; +@class VLCMediaMetaData; diff --git a/Headers/Public/VLCMedia.h b/Headers/Public/VLCMedia.h index 162507d8..d76ccf87 100644 --- a/Headers/Public/VLCMedia.h +++ b/Headers/Public/VLCMedia.h @@ -27,67 +27,10 @@ #import <Foundation/Foundation.h> -@class VLCTime, VLCMediaTracksInformation; +@class VLCTime, VLCMediaTracksInformation, VLCMediaMetaData; NS_ASSUME_NONNULL_BEGIN -/* Meta Dictionary Keys */ -/** - * Standard dictionary keys for retreiving meta data. - */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationTitle; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationArtist; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationGenre; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationCopyright; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationAlbum; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationTrackNumber; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationDescription; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationRating; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationDate; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationSetting; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationURL; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationLanguage; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationNowPlaying; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationPublisher; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationEncodedBy; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationArtworkURL; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationArtwork; /* NSImage */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationTrackID; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationTrackTotal; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationDirector; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationSeason; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationEpisode; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationShowName; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationActors; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationAlbumArtist; /* NSString */ -OBJC_VISIBLE OBJC_EXTERN -NSString *const VLCMetaInformationDiscNumber; /* NSString */ - /* Notification Messages */ /** * Available notification messages. @@ -313,32 +256,9 @@ typedef NS_ENUM(unsigned, VLCMediaParsedStatus) @property (nonatomic, readonly, strong, nullable) VLCMediaList * subitems; /** - * get meta property for key - * \note for performance reasons, fetching the metaDictionary will be faster! - * \see metaDictionary - * \see dictionary keys above + * meta data */ -- (nullable NSString *)metadataForKey:(NSString *)key; - -/** - * set meta property for key - * \param data the metadata to set as NSString - * \param key the metadata key - * \see dictionary keys above - */ -- (void)setMetadata:(NSString *)data forKey:(NSString *)key; - -/** - * Save the previously changed metadata - * \return true if saving was successful - */ -@property (NS_NONATOMIC_IOSONLY, readonly) BOOL saveMetadata; - -/** - * The receiver's meta data as a NSDictionary object. - */ -@property (nonatomic, readonly, copy) NSDictionary * metaDictionary; - +@property (nonatomic, readonly) VLCMediaMetaData *metaData; /** * returns a bool whether is the media is expected to play fluently on this diff --git a/Headers/Public/VLCMediaMetaData.h b/Headers/Public/VLCMediaMetaData.h new file mode 100644 index 00000000..30990e41 --- /dev/null +++ b/Headers/Public/VLCMediaMetaData.h @@ -0,0 +1,199 @@ +/***************************************************************************** + * VLCMediaMetaData.h: VLCKit.framework VLCMediaMetaData header + ***************************************************************************** + * Copyright (C) 2022 VLC authors and VideoLAN + * $Id$ + * + * Authors: + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 <Foundation/Foundation.h> + +/** + * UIImage or NSImage + */ +typedef +#if TARGET_OS_IPHONE +UIImage +#else +NSImage +#endif +VLCPlatformImage; + +NS_ASSUME_NONNULL_BEGIN + +/** + * VLCMediaMetaData + */ +@interface VLCMediaMetaData : NSObject + +/** + * meta title + */ +@property(nonatomic, copy, nullable) NSString *title; + +/** + * meta artist + */ +@property(nonatomic, copy, nullable) NSString *artist; + +/** + * meta genre + */ +@property(nonatomic, copy, nullable) NSString *genre; + +/** + * meta copyright + */ +@property(nonatomic, copy, nullable) NSString *copyright; + +/** + * meta album + */ +@property(nonatomic, copy, nullable) NSString *album; + +/** + * meta track number + */ +@property(nonatomic) unsigned trackNumber; + +/** + * meta description + */ +@property(nonatomic, copy, nullable) NSString *metaDescription; + +/** + * meta rating + */ +@property(nonatomic, copy, nullable) NSString *rating; + +/** + * meta date + */ +@property(nonatomic, copy, nullable) NSString *date; + +/** + * meta setting + */ +@property(nonatomic, copy, nullable) NSString *setting; + +/** + * meta url + */ +@property(nonatomic, nullable) NSURL *url; + +/** + * meta language + */ +@property(nonatomic, copy, nullable) NSString *language; + +/** + * meta now playing + */ +@property(nonatomic, copy, nullable) NSString *nowPlaying; + +/** + * meta publisher + */ +@property(nonatomic, copy, nullable) NSString *publisher; + +/** + * meta encoded by + */ +@property(nonatomic, copy, nullable) NSString *encodedBy; + +/** + * meta artwork URL + */ +@property(nonatomic, nullable) NSURL *artworkURL; + +/** + * meta track ID + */ +@property(nonatomic) unsigned trackID; + +/** + * meta track total + */ +@property(nonatomic) unsigned trackTotal; + +/** + * meta director + */ +@property(nonatomic, copy, nullable) NSString *director; + +/** + * meta season + */ +@property(nonatomic) unsigned season; + +/** + * meta episode + */ +@property(nonatomic) unsigned episode; + +/** + * meta show name + */ +@property(nonatomic, copy, nullable) NSString *showName; + +/** + * meta actors + */ +@property(nonatomic, copy, nullable) NSString *actors; + +/** + * meta album artist + */ +@property(nonatomic, copy, nullable) NSString *albumArtist; + +/** + * meta disc number + */ +@property(nonatomic) unsigned discNumber; + +/** + * meta disc total + */ +@property(nonatomic) unsigned discTotal; + +/** + * artwork + */ +@property(nonatomic, readonly, nullable) VLCPlatformImage *artwork; + + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; + +/** + * Save the previously changed metadata + * \return true if saving was successful + */ +- (BOOL)save; + +/** + * Note, you need to call libvlc_media_parse_with_options() or play the media at least once before calling this function. + */ +- (void)prefetch; + + +- (void)clearCache; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Sources/VLCMedia.m b/Sources/VLCMedia.m index f1d9fdd2..7faa1324 100644 --- a/Sources/VLCMedia.m +++ b/Sources/VLCMedia.m @@ -31,37 +31,10 @@ #import <VLCLibrary.h> #import <VLCLibVLCBridging.h> #import <VLCTime.h> +#import <VLCMediaMetaData.h> #import <vlc/libvlc.h> #import <sys/sysctl.h> // for sysctlbyname -/* Meta Dictionary Keys */ -NSString *const VLCMetaInformationTitle = @"title"; -NSString *const VLCMetaInformationArtist = @"artist"; -NSString *const VLCMetaInformationGenre = @"genre"; -NSString *const VLCMetaInformationCopyright = @"copyright"; -NSString *const VLCMetaInformationAlbum = @"album"; -NSString *const VLCMetaInformationTrackNumber = @"trackNumber"; -NSString *const VLCMetaInformationDescription = @"description"; -NSString *const VLCMetaInformationRating = @"rating"; -NSString *const VLCMetaInformationDate = @"date"; -NSString *const VLCMetaInformationSetting = @"setting"; -NSString *const VLCMetaInformationURL = @"url"; -NSString *const VLCMetaInformationLanguage = @"language"; -NSString *const VLCMetaInformationNowPlaying = @"nowPlaying"; -NSString *const VLCMetaInformationPublisher = @"publisher"; -NSString *const VLCMetaInformationEncodedBy = @"encodedBy"; -NSString *const VLCMetaInformationArtworkURL = @"artworkURL"; -NSString *const VLCMetaInformationArtwork = @"artwork"; -NSString *const VLCMetaInformationTrackID = @"trackID"; -NSString *const VLCMetaInformationTrackTotal = @"trackTotal"; -NSString *const VLCMetaInformationDirector = @"director"; -NSString *const VLCMetaInformationSeason = @"season"; -NSString *const VLCMetaInformationEpisode = @"episode"; -NSString *const VLCMetaInformationShowName = @"showName"; -NSString *const VLCMetaInformationActors = @"actors"; -NSString *const VLCMetaInformationAlbumArtist = @"AlbumArtist"; -NSString *const VLCMetaInformationDiscNumber = @"discNumber"; - /* Notification Messages */ NSString *const VLCMediaMetaChanged = @"VLCMediaMetaChanged"; @@ -121,36 +94,18 @@ void close_cb(void *opaque) { @interface VLCMedia() { void * p_md; ///< Internal media descriptor instance - BOOL isArtFetched; ///< Value used to determine of the artwork has been parsed - BOOL areOthersMetaFetched; ///< Value used to determine of the other meta has been parsed - BOOL isArtURLFetched; ///< Value used to determine of the other meta has been preparsed BOOL eventsAttached; ///< YES when events are attached - NSMutableDictionary *_metaDictionary; ///< Dictionary to cache metadata read from libvlc NSInputStream *stream; ///< Stream object if instance is initialized via NSInputStream to pass to callbacks } /* Make our properties internally readwrite */ @property (nonatomic, readwrite, strong, nullable) VLCMediaList * subitems; -/* Statics */ -+ (libvlc_meta_t)stringToMetaType:(NSString *)string; -+ (NSString *)metaTypeToString:(libvlc_meta_t)type; - -/* Initializers */ -- (void)initInternalMediaDescriptor; - -/* Operations */ -- (void)fetchMetaInformationFromLibVLCWithType:(NSString*)metaType; -#if !TARGET_OS_IPHONE -- (void)fetchMetaInformationForArtWorkWithURL:(NSString *)anURL; -- (void)setArtwork:(NSImage *)art; -#endif - - (void)parseIfNeeded; /* Callback Methods */ - (void)parsedChanged:(NSNumber *)isParsedAsNumber; -- (void)metaChanged:(NSString *)metaType; +- (void)metaChanged:(NSNumber *)metaType; - (void)subItemAdded; @end @@ -163,7 +118,7 @@ static void HandleMediaMetaChanged(const libvlc_event_t * event, void * self) @autoreleasepool { [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self) withMethod:@selector(metaChanged:) - withArgumentAsObject:[VLCMedia metaTypeToString:event->u.media_meta_changed.meta_type]]; + withArgumentAsObject:@(event->u.media_meta_changed.meta_type)]; } } @@ -239,8 +194,6 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) p_md = libvlc_media_new_location(library.instance, url); - _metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3]; - [self initInternalMediaDescriptor]; } return self; @@ -256,8 +209,6 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) self->stream = stream; p_md = libvlc_media_new_callbacks(library.instance, open_cb, read_cb, seek_cb, close_cb, (__bridge void *)(stream)); - _metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3]; - [self initInternalMediaDescriptor]; } return self; @@ -267,9 +218,7 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) { if (self = [super init]) { p_md = libvlc_media_new_as_node([VLCLibrary sharedInstance], [aName UTF8String]); - - _metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3]; - + [self initInternalMediaDescriptor]; } return self; @@ -702,114 +651,14 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) return YES; } -- (nullable NSString *)metadataForKey:(NSString *)key -{ - if (!p_md) - return nil; - - char *returnValue = libvlc_media_get_meta(p_md, [VLCMedia stringToMetaType:key]); - - if (!returnValue) - return nil; - - NSString *actualReturnValue = @(returnValue); - free(returnValue); - - return actualReturnValue; -} - -- (void)setMetadata:(NSString *)data forKey:(NSString *)key -{ - if (!p_md) - return; - - libvlc_media_set_meta(p_md, [VLCMedia stringToMetaType:key], [data UTF8String]); -} - -- (BOOL)saveMetadata -{ - if (p_md) - return libvlc_media_save_meta(p_md) != 0; - - return NO; -} /****************************************************************************** * Implementation VLCMedia () */ - -+ (libvlc_meta_t)stringToMetaType:(NSString *)string -{ - static NSDictionary * stringToMetaDictionary = nil; - // TODO: Thread safe-ize - if (!stringToMetaDictionary) { -#define VLCStringToMeta( name ) [NSNumber numberWithInt: libvlc_meta_##name], VLCMetaInformation##name - stringToMetaDictionary = - [NSDictionary dictionaryWithObjectsAndKeys: - VLCStringToMeta(Title), - VLCStringToMeta(Artist), - VLCStringToMeta(Genre), - VLCStringToMeta(Copyright), - VLCStringToMeta(Album), - VLCStringToMeta(TrackNumber), - VLCStringToMeta(Description), - VLCStringToMeta(Rating), - VLCStringToMeta(Date), - VLCStringToMeta(Setting), - VLCStringToMeta(URL), - VLCStringToMeta(Language), - VLCStringToMeta(NowPlaying), - VLCStringToMeta(Publisher), - VLCStringToMeta(ArtworkURL), - VLCStringToMeta(TrackID), - VLCStringToMeta(TrackTotal), - VLCStringToMeta(Director), - VLCStringToMeta(Season), - VLCStringToMeta(Episode), - VLCStringToMeta(ShowName), - VLCStringToMeta(Actors), - VLCStringToMeta(AlbumArtist), - VLCStringToMeta(DiscNumber), - nil]; -#undef VLCStringToMeta - } - NSNumber * number = stringToMetaDictionary[string]; - return (libvlc_meta_t) (number ? [number intValue] : -1); -} - -+ (NSString *)metaTypeToString:(libvlc_meta_t)type -{ -#define VLCMetaToString( name, type ) if (libvlc_meta_##name == type) return VLCMetaInformation##name; - VLCMetaToString(Title, type); - VLCMetaToString(Artist, type); - VLCMetaToString(Genre, type); - VLCMetaToString(Copyright, type); - VLCMetaToString(Album, type); - VLCMetaToString(TrackNumber, type); - VLCMetaToString(Description, type); - VLCMetaToString(Rating, type); - VLCMetaToString(Date, type); - VLCMetaToString(Setting, type); - VLCMetaToString(URL, type); - VLCMetaToString(Language, type); - VLCMetaToString(NowPlaying, type); - VLCMetaToString(Publisher, type); - VLCMetaToString(ArtworkURL, type); - VLCMetaToString(TrackID, type); - VLCMetaToString(TrackTotal, type); - VLCMetaToString(Director, type); - VLCMetaToString(Season, type); - VLCMetaToString(Episode, type); - VLCMetaToString(ShowName, type); - VLCMetaToString(Actors, type); - VLCMetaToString(AlbumArtist, type); - VLCMetaToString(DiscNumber, type); -#undef VLCMetaToString - return nil; -} - - (void)initInternalMediaDescriptor { + _metaData = [[VLCMediaMetaData alloc] initWithMedia: self]; + char * p_url = libvlc_media_get_mrl( p_md ); if (!p_url) return; @@ -849,55 +698,6 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) } } -- (void)fetchMetaInformationFromLibVLCWithType:(NSString *)metaType -{ - char * psz_value = libvlc_media_get_meta( p_md, [VLCMedia stringToMetaType:metaType] ); - NSString * newValue = psz_value ? @(psz_value) : nil; - NSString * oldValue = [_metaDictionary valueForKey:metaType]; - free(psz_value); - - if (newValue != oldValue && !(oldValue && newValue && [oldValue compare:newValue] == NSOrderedSame)) { -#if !TARGET_OS_IPHONE - // Only fetch the art if needed. (ie, create the NSImage, if it was requested before) - if (isArtFetched && [metaType isEqualToString:VLCMetaInformationArtworkURL]) { - [NSThread detachNewThreadSelector:@selector(fetchMetaInformationForArtWorkWithURL:) - toTarget:self - withObject:newValue]; - } -#endif - - [_metaDictionary setValue:newValue forKeyPath:metaType]; - } -} - -#if !TARGET_OS_IPHONE -- (void)fetchMetaInformationForArtWorkWithURL:(NSString *)anURL -{ - @autoreleasepool { - NSImage * art = nil; - - if (anURL) { - // Go ahead and load up the art work - NSURL * artUrl = [NSURL URLWithString:[anURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - // Don't attempt to fetch artwork from remote. Core will do that alone - if ([artUrl isFileURL]) - art = [[NSImage alloc] initWithContentsOfURL:artUrl]; - } - - // If anything was found, lets save it to the meta data dictionary - [self performSelectorOnMainThread:@selector(setArtwork:) withObject:art waitUntilDone:NO]; - } -} - -- (void)setArtwork:(NSImage *)art -{ - if (!art) - [(NSMutableDictionary *)_metaDictionary removeObjectForKey:@"artwork"]; - else - ((NSMutableDictionary *)_metaDictionary)[@"artwork"] = art; -} -#endif - - (void)parseIfNeeded { VLCMediaParsedStatus parsedStatus = [self parsedStatus]; @@ -905,9 +705,10 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) [self parseWithOptions:VLCMediaParseLocal | VLCMediaFetchLocal]; } -- (void)metaChanged:(NSString *)metaType +- (void)metaChanged:(NSNumber *)metaType { - [self fetchMetaInformationFromLibVLCWithType:metaType]; + libvlc_meta_t meta = (libvlc_meta_t)metaType.intValue; + [self.metaData handleMediaMetaChanged: meta]; if ([_delegate respondsToSelector:@selector(mediaMetaDataDidChange:)]) [_delegate mediaMetaDataDidChange:self]; @@ -940,58 +741,6 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) [_delegate mediaDidFinishParsing:self]; } -#if TARGET_OS_IPHONE -- (NSDictionary *)metaDictionary -{ - if (!areOthersMetaFetched) { - areOthersMetaFetched = YES; - - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationTitle]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationArtist]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationAlbum]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationDate]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationGenre]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationTrackNumber]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationDiscNumber]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationNowPlaying]; - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationLanguage]; - } - if (!isArtURLFetched) { - isArtURLFetched = YES; - /* Force isArtURLFetched, that will trigger artwork download eventually - * And all the other meta will be added through the libvlc event system */ - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationArtworkURL]; - } - return [NSDictionary dictionaryWithDictionary:_metaDictionary]; -} - -#else - -- (NSDictionary *)metaDictionary -{ - return [NSDictionary dictionaryWithDictionary:_metaDictionary]; -} - -- (id)valueForKeyPath:(NSString *)keyPath -{ - if (!isArtFetched && [keyPath isEqualToString:@"metaDictionary.artwork"]) { - isArtFetched = YES; - /* Force the retrieval of the artwork now that someone asked for it */ - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationArtworkURL]; - } else if (!areOthersMetaFetched && [keyPath hasPrefix:@"metaDictionary."]) { - areOthersMetaFetched = YES; - /* Force VLCMetaInformationTitle, that will trigger preparsing - * And all the other meta will be added through the libvlc event system */ - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationTitle]; - } else if (!isArtURLFetched && [keyPath hasPrefix:@"metaDictionary.artworkURL"]) { - isArtURLFetched = YES; - /* Force isArtURLFetched, that will trigger artwork download eventually - * And all the other meta will be added through the libvlc event system */ - [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationArtworkURL]; - } - return [super valueForKeyPath:keyPath]; -} -#endif @end /****************************************************************************** @@ -1023,9 +772,7 @@ static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self) if (self = [super init]) { libvlc_media_retain(md); p_md = md; - - _metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3]; - + [self initInternalMediaDescriptor]; } return self; diff --git a/Sources/VLCMediaMetaData.m b/Sources/VLCMediaMetaData.m new file mode 100644 index 00000000..4ed5075d --- /dev/null +++ b/Sources/VLCMediaMetaData.m @@ -0,0 +1,513 @@ +/***************************************************************************** + * VLCMediaMetaData.m: VLCKit.framework VLCMediaMetaData implementation + ***************************************************************************** + * Copyright (C) 2022 VLC authors and VideoLAN + * $Id$ + * + * Authors: + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 <VLCMedia.h> +#import <VLCLibVLCBridging.h> + +@implementation VLCMediaMetaData +{ + __weak VLCMedia *_media; + NSMutableDictionary<NSNumber *, id> *_metaCache; + VLCPlatformImage * _Nullable _artwork; +} + +- (instancetype)initWithMedia:(VLCMedia *)media +{ + if (self = [super init]) { + _media = media; + _metaCache = @{}.mutableCopy; + } + return self; +} + +- (void)setTitle:(nullable NSString *)title +{ + [self setString: title forKey: libvlc_meta_Title]; +} + +- (nullable NSString *)title +{ + return [self stringForKey: libvlc_meta_Title]; +} + +- (void)setArtist:(nullable NSString *)artist +{ + [self setString: artist forKey: libvlc_meta_Artist]; +} + +- (nullable NSString *)artist +{ + return [self stringForKey: libvlc_meta_Artist]; +} + +- (void)setGenre:(nullable NSString *)genre +{ + [self setString: genre forKey: libvlc_meta_Genre]; +} + +- (nullable NSString *)genre +{ + return [self stringForKey: libvlc_meta_Genre]; +} + +- (void)setCopyright:(nullable NSString *)copyright +{ + [self setString: copyright forKey: libvlc_meta_Copyright]; +} + +- (nullable NSString *)copyright +{ + return [self stringForKey: libvlc_meta_Copyright]; +} + +- (void)setAlbum:(nullable NSString *)album +{ + [self setString: album forKey: libvlc_meta_Album]; +} + +- (nullable NSString *)album +{ + return [self stringForKey: libvlc_meta_Album]; +} + +- (void)setTrackNumber:(unsigned)trackNumber +{ + [self setUnsigned: trackNumber forKey: libvlc_meta_TrackNumber]; +} + +- (unsigned)trackNumber +{ + return [self unsignedForKey: libvlc_meta_TrackNumber]; +} + +- (void)setMetaDescription:(nullable NSString *)metaDescription +{ + [self setString: metaDescription forKey: libvlc_meta_Description]; +} + +- (nullable NSString *)metaDescription +{ + return [self stringForKey: libvlc_meta_Description]; +} + +- (void)setRating:(nullable NSString *)rating +{ + [self setString: rating forKey: libvlc_meta_Rating]; +} + +- (nullable NSString *)rating +{ + return [self stringForKey: libvlc_meta_Rating]; +} + +- (void)setDate:(nullable NSString *)date +{ + [self setString: date forKey: libvlc_meta_Date]; +} + +- (nullable NSString *)date +{ + return [self stringForKey: libvlc_meta_Date]; +} + +- (void)setSetting:(NSString *)setting +{ + [self setString: setting forKey: libvlc_meta_Setting]; +} + +- (nullable NSString *)setting +{ + return [self stringForKey: libvlc_meta_Setting]; +} + +- (void)setUrl:(nullable NSURL *)url +{ + [self setURL: url forKey: libvlc_meta_URL]; +} + +- (nullable NSURL *)url +{ + return [self urlForKey: libvlc_meta_URL]; +} + +- (void)setLanguage:(nullable NSString *)language +{ + [self setString: language forKey: libvlc_meta_Language]; +} + +- (nullable NSString *)language +{ + return [self stringForKey: libvlc_meta_Language]; +} + +- (void)setNowPlaying:(nullable NSString *)nowPlaying +{ + [self setString: nowPlaying forKey: libvlc_meta_NowPlaying]; +} + +- (nullable NSString *)nowPlaying +{ + return [self stringForKey: libvlc_meta_NowPlaying]; +} + +- (void)setPublisher:(nullable NSString *)publisher +{ + [self setString: publisher forKey: libvlc_meta_Publisher]; +} + +- (nullable NSString *)publisher +{ + return [self stringForKey: libvlc_meta_Publisher]; +} + +- (void)setEncodedBy:(nullable NSString *)encodedBy +{ + [self setString: encodedBy forKey: libvlc_meta_EncodedBy]; +} + +- (nullable NSString *)encodedBy +{ + return [self stringForKey: libvlc_meta_EncodedBy]; +} + +- (void)setArtworkURL:(nullable NSURL *)artworkURL +{ + [self setURL: artworkURL forKey: libvlc_meta_ArtworkURL]; +} + +- (nullable NSURL *)artworkURL +{ + return [self urlForKey: libvlc_meta_ArtworkURL]; +} + +- (void)setTrackID:(unsigned)trackID +{ + [self setUnsigned: trackID forKey: libvlc_meta_TrackID]; +} + +- (unsigned)trackID +{ + return [self unsignedForKey: libvlc_meta_TrackID]; +} + +- (void)setTrackTotal:(unsigned)trackTotal +{ + [self setUnsigned: trackTotal forKey: libvlc_meta_TrackTotal]; +} + +- (unsigned)trackTotal +{ + return [self unsignedForKey: libvlc_meta_TrackTotal]; +} + +- (void)setDirector:(nullable NSString *)director +{ + [self setString: director forKey: libvlc_meta_Director]; +} + +- (nullable NSString *)director +{ + return [self stringForKey: libvlc_meta_Director]; +} + +- (void)setSeason:(unsigned)season +{ + [self setUnsigned: season forKey: libvlc_meta_Season]; +} + +- (unsigned)season +{ + return [self unsignedForKey: libvlc_meta_Season]; +} + +- (void)setEpisode:(unsigned)episode +{ + [self setUnsigned: episode forKey: libvlc_meta_Episode]; +} + +- (unsigned)episode +{ + return [self unsignedForKey: libvlc_meta_Episode]; +} + +- (void)setShowName:(nullable NSString *)showName +{ + [self setString: showName forKey: libvlc_meta_ShowName]; +} + +- (nullable NSString *)showName +{ + return [self stringForKey: libvlc_meta_ShowName]; +} + +- (void)setActors:(nullable NSString *)actors +{ + [self setString: actors forKey: libvlc_meta_Actors]; +} + +- (nullable NSString *)actors +{ + return [self stringForKey: libvlc_meta_Actors]; +} + +- (void)setAlbumArtist:(nullable NSString *)albumArtist +{ + [self setString: albumArtist forKey: libvlc_meta_AlbumArtist]; +} + +- (nullable NSString *)albumArtist +{ + return [self stringForKey: libvlc_meta_AlbumArtist]; +} + +- (void)setDiscNumber:(unsigned)discNumber +{ + [self setUnsigned: discNumber forKey: libvlc_meta_DiscNumber]; +} + +- (unsigned)discNumber +{ + return [self unsignedForKey: libvlc_meta_DiscNumber]; +} + +- (void)setDiscTotal:(unsigned)discTotal +{ + [self setUnsigned: discTotal forKey: libvlc_meta_DiscTotal]; +} + +- (unsigned)discTotal +{ + return [self unsignedForKey: libvlc_meta_DiscTotal]; +} + +- (nullable VLCPlatformImage *)artwork +{ + if (!_artwork) { + NSURL *artURL = self.artworkURL; + if (artURL.isFileURL) { + _artwork = [[VLCPlatformImage alloc] initWithContentsOfFile: artURL.path]; + } + } + return _artwork; +} + +- (BOOL)save +{ + return _media.libVLCMediaDescriptor ? libvlc_media_save_meta(_media.libVLCMediaDescriptor) != 0 : NO; +} + +- (void)prefetch +{ + // 26 = `libvlc_meta_t` all count + for (int i = 0; i < 26; i++) + [self fetchMetaDataForKey: (libvlc_meta_t)i]; +} + +- (void)clearCache +{ + [_metaCache removeAllObjects]; +} + + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ %p>, title: %@, artist: %@, genre: %@, copyright: %@, album: %@, trackNumber: %u, metaDescription: %@, rating: %@, date: %@, setting: %@, url: %@, language: %@, nowPlaying: %@, publisher: %@, encodedBy: %@, artworkURL: %@, trackID: %u, trackTotal: %u, director: %@, season: %u, episode: %u, showName: %@, actors: %@, albumArtist: %@, discNumber: %u, discTotal: %u", [self class], self, [self title], [self artist], [self genre], [self copyright], [self album], [self trackNumber], [self metaDescription], [self rating], [self date], [self setting], [self url], [self language], [self nowPlaying], [self publisher], [self encodedBy], [self artworkURL], [self trackID], [self trackTotal], [self director], [self season], [self episode], [self showName], [self actors], [self albumArtist], [self discNumber], [self discTotal]]; +} + + +- (void)handleMediaMetaChanged:(libvlc_meta_t)type +{ + [self fetchMetaDataForKey: type]; +} + +/* fetch and cache */ + +- (void)fetchMetaDataForKey:(libvlc_meta_t)key +{ + switch (key) { + + // NSString + case libvlc_meta_Title: + case libvlc_meta_Artist: + case libvlc_meta_Genre: + case libvlc_meta_Copyright: + case libvlc_meta_Album: + case libvlc_meta_Description: + case libvlc_meta_Rating: + case libvlc_meta_Date: + case libvlc_meta_Setting: + case libvlc_meta_Language: + case libvlc_meta_NowPlaying: + case libvlc_meta_Publisher: + case libvlc_meta_EncodedBy: + case libvlc_meta_Director: + case libvlc_meta_ShowName: + case libvlc_meta_Actors: + case libvlc_meta_AlbumArtist: + _metaCache[@(key)] = [self metadataStringForKey: key]; + break; + + // NSNumber + case libvlc_meta_TrackNumber: + case libvlc_meta_TrackID: + case libvlc_meta_TrackTotal: + case libvlc_meta_Season: + case libvlc_meta_Episode: + case libvlc_meta_DiscNumber: + case libvlc_meta_DiscTotal: + _metaCache[@(key)] = [self metadataNumberForKey: key]; + break; + + // NSURL + case libvlc_meta_URL: + case libvlc_meta_ArtworkURL: + _metaCache[@(key)] = [self metadataURLForKey: key]; + break; + + default: + VKLog(@"WARNING: undefined meta type : %d", key); + break; + } +} + +/* cache get */ + +- (nullable NSString *)stringForKey:(libvlc_meta_t)key +{ + NSNumber *cacheKey = @(key); + id cacheValue = _metaCache[cacheKey]; + if (!cacheValue) { + [self fetchMetaDataForKey: key]; + cacheValue = _metaCache[cacheKey]; + } + if ([cacheValue isKindOfClass: NSString.class]) + return (NSString *)cacheValue; + + return nil; +} + +- (nullable NSURL *)urlForKey:(libvlc_meta_t)key +{ + NSNumber *cacheKey = @(key); + id cacheValue = _metaCache[cacheKey]; + if (!cacheValue) { + [self fetchMetaDataForKey: key]; + cacheValue = _metaCache[cacheKey]; + } + if ([cacheValue isKindOfClass: NSURL.class]) + return (NSURL *)cacheValue; + + return nil; +} + +- (unsigned)unsignedForKey:(libvlc_meta_t)key +{ + NSNumber *cacheKey = @(key); + id cacheValue = _metaCache[cacheKey]; + if (!cacheValue) { + [self fetchMetaDataForKey: key]; + cacheValue = _metaCache[cacheKey]; + } + if ([cacheValue isKindOfClass: NSNumber.class]) + return (unsigned)[(NSNumber *)cacheValue intValue]; + + return 0; +} + + +/* internal meta get */ + +- (nullable id)metadataStringForKey:(libvlc_meta_t)key +{ + if (!_media.libVLCMediaDescriptor) + return nil; + + char *value = libvlc_media_get_meta(_media.libVLCMediaDescriptor, key); + if (!value) + return NSNull.null; + + NSString *str = @(value); + free(value); + + return str; +} + +- (nullable id)metadataURLForKey:(libvlc_meta_t)key +{ + if (!_media.libVLCMediaDescriptor) + return nil; + + char *value = libvlc_media_get_meta(_media.libVLCMediaDescriptor, key); + if (!value) + return NSNull.null; + + NSString *str = @(value); + free(value); + + return str ? [NSURL URLWithString: str] : nil; +} + +- (nullable id)metadataNumberForKey:(libvlc_meta_t)key +{ + if (!_media.libVLCMediaDescriptor) + return nil; + + char *value = libvlc_media_get_meta(_media.libVLCMediaDescriptor, key); + if (!value) + return NSNull.null; + + NSNumber *num = @(atoi(value)); + free(value); + + return num; +} + +/* internal meta set */ + +- (void)setMetadata:(const char *)data forKey:(libvlc_meta_t)key +{ + if (!_media.libVLCMediaDescriptor) + return; + + libvlc_media_set_meta(_media.libVLCMediaDescriptor, key, data); +} + +- (void)setString:(nullable NSString *)str forKey:(libvlc_meta_t)key +{ + [self setMetadata: str.UTF8String forKey: key]; +} + +- (void)setURL:(nullable NSURL *)url forKey:(libvlc_meta_t)key +{ + [self setString: url.absoluteString forKey: key]; +} + +- (void)setUnsigned:(unsigned)u forKey:(libvlc_meta_t)key +{ + size_t size = 11; + char value[size]; + snprintf(value, size, "%u", u); + [self setMetadata: value forKey: key]; +} + +@end diff --git a/VLCKit.xcodeproj/project.pbxproj b/VLCKit.xcodeproj/project.pbxproj index f63ddd4a..43382fd8 100644 --- a/VLCKit.xcodeproj/project.pbxproj +++ b/VLCKit.xcodeproj/project.pbxproj @@ -7,6 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 3C4A7E1A281C538100577290 /* VLCMediaMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C4A7E19281C538100577290 /* VLCMediaMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C4A7E1B281C538100577290 /* VLCMediaMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C4A7E19281C538100577290 /* VLCMediaMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C4A7E1C281C538100577290 /* VLCMediaMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C4A7E19281C538100577290 /* VLCMediaMetaData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C4A7E1E281C53AF00577290 /* VLCMediaMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C4A7E1D281C53AF00577290 /* VLCMediaMetaData.m */; }; + 3C4A7E1F281C53AF00577290 /* VLCMediaMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C4A7E1D281C53AF00577290 /* VLCMediaMetaData.m */; }; + 3C4A7E20281C53AF00577290 /* VLCMediaMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C4A7E1D281C53AF00577290 /* VLCMediaMetaData.m */; }; 7D030010273D716D00A4981C /* vlc-plugins-macosx-device.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D03000F273D716D00A4981C /* vlc-plugins-macosx-device.h */; }; 7D030013273D717700A4981C /* vlc-plugins-iphone-simulator.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D030011273D717700A4981C /* vlc-plugins-iphone-simulator.h */; }; 7D030014273D717700A4981C /* vlc-plugins-iphone-device.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D030012273D717700A4981C /* vlc-plugins-iphone-device.h */; }; @@ -363,6 +369,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 3C4A7E19281C538100577290 /* VLCMediaMetaData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCMediaMetaData.h; path = Headers/Public/VLCMediaMetaData.h; sourceTree = "<group>"; }; + 3C4A7E1D281C53AF00577290 /* VLCMediaMetaData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCMediaMetaData.m; path = Sources/VLCMediaMetaData.m; sourceTree = "<group>"; }; 3F7CC79621D69CB40094B074 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = Resources/TVVLCKit/module.modulemap; sourceTree = SOURCE_ROOT; }; 3F7CC79721D69D9A0094B074 /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = Resources/MobileVLCKit/module.modulemap; sourceTree = "<group>"; }; 41E1959621BEA28F00F10277 /* VLCTranscoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCTranscoder.m; path = Sources/VLCTranscoder.m; sourceTree = "<group>"; }; @@ -734,6 +742,7 @@ 636E975711EBC67A002FE8A9 /* VLCMediaThumbnailer.m */, 6360B0E111E7F0C000EAD790 /* VLCMediaDiscoverer.m */, 7A5ECAC911DE8F7300F66AF3 /* VLCTime.m */, + 3C4A7E1D281C53AF00577290 /* VLCMediaMetaData.m */, 7D988D3A24C7331100279703 /* Streaming & Transcoding */, 7D988D3924C7330400279703 /* macOS-specific */, 7D34F5571C909E13008A39F0 /* Dialogs */, @@ -773,6 +782,7 @@ 41E1959821BEA2AF00F10277 /* VLCTranscoder.h */, 8D2CE647203DCC48004BB7F6 /* VLCRendererDiscoverer.h */, 8D2CE64E203EEA47004BB7F6 /* VLCRendererItem.h */, + 3C4A7E19281C538100577290 /* VLCMediaMetaData.h */, 7A5ECAE311DE8FDF00F66AF3 /* Internal */, 7DEBDADE203C56BC000A7D2F /* libvlc */, ); @@ -995,6 +1005,7 @@ 7DDC020C1B501ECF0078FC84 /* VLCMedia.h in Headers */, 7DDC020D1B501ECF0078FC84 /* VLCMediaThumbnailer.h in Headers */, 7DDC020E1B501ECF0078FC84 /* VLCMediaList.h in Headers */, + 3C4A7E1A281C538100577290 /* VLCMediaMetaData.h in Headers */, ED25609C21F3A9FE00396F9B /* MobileVLCKitTests-Bridging-Header.h in Headers */, 7DDC020F1B501ECF0078FC84 /* VLCMediaPlayer.h in Headers */, 7DDC02101B501ECF0078FC84 /* VLCMediaListPlayer.h in Headers */, @@ -1036,6 +1047,7 @@ 7D988CE824C72F4000279703 /* VLCMediaListPlayer.h in Headers */, 7D988CF924C7301100279703 /* VLCEventManager.h in Headers */, 7D988CFA24C7301E00279703 /* VLCHelperCode.h in Headers */, + 3C4A7E1C281C538100577290 /* VLCMediaMetaData.h in Headers */, 7D988CFB24C7302800279703 /* VLCLibVLCBridging.h in Headers */, 7D988CFC24C7303200279703 /* VLCCustomDialogProvider.h in Headers */, 7D988CED24C72F4000279703 /* VLCRendererDiscoverer.h in Headers */, @@ -1053,6 +1065,7 @@ files = ( 7DB683B21C995E1D000C70BE /* VLCAudio.h in Headers */, 7DB683B31C995E1D000C70BE /* VLCLibrary.h in Headers */, + 3C4A7E1B281C538100577290 /* VLCMediaMetaData.h in Headers */, 7DB683B41C995E1D000C70BE /* VLCMedia.h in Headers */, 7DB683B51C995E1D000C70BE /* VLCMediaThumbnailer.h in Headers */, 7DB683B61C995E1D000C70BE /* VLCMediaList.h in Headers */, @@ -1398,6 +1411,7 @@ 7D803EC11C8F2AB400864A9C /* VLCEmbeddedDialogProvider.m in Sources */, 7D6C89211C0CA90000321894 /* VLCAudio.m in Sources */, 7D8939401B500D50008F2B14 /* VLCEventManager.m in Sources */, + 3C4A7E1E281C53AF00577290 /* VLCMediaMetaData.m in Sources */, 7D803EC71C8F2AF900864A9C /* VLCiOSLegacyDialogProvider.m in Sources */, 7D8939411B500D50008F2B14 /* VLCLibrary.m in Sources */, 7DFDF4E21C9AF17800BA86A6 /* VLCDialogProvider.m in Sources */, @@ -1440,6 +1454,7 @@ 7DB6838B1C995D76000C70BE /* VLCMediaList.m in Sources */, 7DB6838C1C995D76000C70BE /* VLCMediaPlayer.m in Sources */, 7DB683D81C996187000C70BE /* VLCHelperCode.m in Sources */, + 3C4A7E1F281C53AF00577290 /* VLCMediaMetaData.m in Sources */, 7DB6838D1C995D76000C70BE /* VLCMediaListPlayer.m in Sources */, 7DB6838E1C995D76000C70BE /* VLCMediaThumbnailer.m in Sources */, 7DB6838F1C995D76000C70BE /* VLCMediaDiscoverer.m in Sources */, @@ -1479,6 +1494,7 @@ 7D988CD324C72EB900279703 /* VLCVideoCommon.m in Sources */, 7D988CD224C72EB900279703 /* VLCStreamSession.m in Sources */, 7D988CD524C72EB900279703 /* VLCStreamOutput.m in Sources */, + 3C4A7E20281C53AF00577290 /* VLCMediaMetaData.m in Sources */, 7D988CDD24C72F0E00279703 /* VLCMediaListPlayer.m in Sources */, 7D988CDE24C72F1300279703 /* VLCRendererItem.m in Sources */, 7D988CDF24C72F1B00279703 /* VLCMediaThumbnailer.m in Sources */, -- GitLab