How to access file info programmatically on Mac? - objective-c

Setup:
I have a bunch of audio files on my new Mac (Yosemite). When I right click on any file and do "Get Info", it gives me nice detailed info about that song under "More Info" tag, e.g.
Objective:
I need to write a program where I can list, something like this for all songs in a directory:
Album, Title, Year Recorded
.
.
.
Problem:
I have no idea how to do this. I am totally new to Mac and Objective-C/Swift (Objective-C or Swift is what I will have to use to write this program I guess??)
Is there an API where I can access this file info programmatically? And is there any other language which I can use to write this sort of program? Something which I already know, like Java, Python, etc.?
I don't have any code as of now to show 'What I have tried so far', since I am still searching for the starting point. Any pointers would be much appreciated.

As you've noticed, the mdls command can provide this metadata. You should not try to parse that. Instead, you can use the same APIs that it is built on.
You need to obtain an NSURL for a file of interest. Then, you can obtain a dictionary of its metadata attributes like so:
MDItemRef item = MDItemCreateWithURL(NULL, (__bridge CFURLRef)url);
NSArray* names = #[ (__bridge NSString*)kMDItemAlbum, /* ... */ ];
NSDictionary* dictionary = CFBridgingRelease(MDItemCopyAttributes(item, (__bridge CFArrayRef)names));
CFRelease(item);
Now, dictionary contains the desired attributes.

So, I have found one way to do this.
Mac does provide a utility called mdls, which lists file metadata. So if I do the mdls on my about example file, I get this:
myuser00m:Hindi myuser$ mdls Pani\ Da\ Rang.mp3
kMDItemAlbum = "Vicky Donor"
kMDItemAlternateNames = (
"/Users/myuser/Documents/My Stuff/Music/Hindi/Pani Da Rang.mp3"
)
kMDItemAudioBitRate = 165000
kMDItemAudioChannelCount = 2
kMDItemAudioEncodingApplication = "Eac * Lame"
kMDItemAudioSampleRate = 44100
kMDItemAuthors = (
"Ayushmann Khurrana"
)
kMDItemComposer = "Music: Abhishek - Akshay"
kMDItemContentCreationDate = 2015-06-16 04:42:30 +0000
kMDItemContentModificationDate = 2015-06-16 04:42:30 +0000
kMDItemContentType = "public.mp3"
kMDItemContentTypeTree = (
"public.mp3",
"public.audio",
"public.audiovisual-content",
"public.data",
"public.item",
"public.content"
)
kMDItemCopyright = "www.Songs.PK"
kMDItemDateAdded = 2015-07-26 19:52:49 +0000
kMDItemDisplayName = "Pani Da Rang"
kMDItemDurationSeconds = 240.8489795918368
kMDItemFSContentChangeDate = 2015-06-16 04:42:30 +0000
kMDItemFSCreationDate = 2015-06-16 04:42:30 +0000
kMDItemFSCreatorCode = ""
kMDItemFSFinderFlags = 0
kMDItemFSHasCustomIcon = (null)
kMDItemFSInvisible = 0
kMDItemFSIsExtensionHidden = 0
kMDItemFSIsStationery = (null)
kMDItemFSLabel = 0
kMDItemFSName = "Pani Da Rang.mp3"
kMDItemFSNodeCount = (null)
kMDItemFSOwnerGroupID = 784317889
kMDItemFSOwnerUserID = 376797083
kMDItemFSSize = 5826388
kMDItemFSTypeCode = ""
kMDItemKind = "MP3 audio"
kMDItemLogicalSize = 5826388
kMDItemLyricist = "www.Songs.PK"
kMDItemMediaTypes = (
Sound
)
kMDItemMusicalGenre = "Bollywood"
kMDItemPhysicalSize = 5828608
kMDItemRecordingYear = 2012
kMDItemTitle = "Pani Da Rang"
kMDItemTotalBitRate = 165000
myuser00m:Hindi myuser$
Now I need to write some code to parse this and extract fields of interest.
Obviously, it is not that cool solution, but until I find something better, this will do. I will update my answer once I find something better.

Related

Trying to get property 'path' of non-object

Hello I am having the above error in production but all works well in development. I am using the code bellow to get the path to the main image for the property but it defaults into the else despite the if not being false plus the else does not find the paths even when dump shows that the object has been returned
//check if there are hotels in the selected destination
if($hotels->isNotEmpty()){
//Loop through the hotels
foreach($hotels as $hotel){
//get hotels main image
$banner = Photo::where(['p_id'=>$hotel->id])->where(['is_main'=>1])->first();
$altbanner = Photo::where(['p_id'=>$hotel->id])->first();
$banner_path = "";
$altText = "";
if($banner!=null){
$banner_path = $banner->path;
$altText = $banner->alt_text;
}else{
$banner_path = $altbanner->path;
$altText = $altbanner->alt_text;
}
Have you checked your database if each hotel has an image? Based on your question and explanation, there is a part of the for each that returns null for the image hence the if part fails and the else return the error. If that is the case then you may want to check and sort it by uploading the image or modifying your checks to handle cases where no image is found.
I think the way you are using the where clause isn't right
foreach($hotels as $hotel){
//get hotels main image
$banner = Photo::where('p_id',$hotel->id)->where('is_main',1)->first();
$altbanner = Photo::where('p_id',$hotel->id)->first();
// .....
if($banner){
$banner_path = $banner->path;
// ......

How to use regex_extractor selector and multiplexing interceptor together in flume?

I am testing flume to load data into hHase and thinking about parallel data loading with using flume's selector and inteceptor, because of speed gap between source and sink.
So, what I want to do with flume are
creating Event's header with interceptors's regex_extractor type
multiplexing Event with header to more than two channels with selector's multiplexing type
in one source-channel-sink.
and tried configuration as below.
agent.sources = tailsrc
agent.channels = mem1 mem2
agent.sinks = std1 std2
agent.sources.tailsrc.type = exec
agent.sources.tailsrc.command = tail -F /home/flumeuser/test/in.txt
agent.sources.tailsrc.batchSize = 1
agent.sources.tailsrc.interceptors = i1
agent.sources.tailsrc.interceptors.i1.type = regex_extractor
agent.sources.tailsrc.interceptors.i1.regex = ^(\\d)
agent.sources.tailsrc.interceptors.i1.serializers = t1
agent.sources.tailsrc.interceptors.i1.serializers.t1.name = type
agent.sources.tailsrc.selector.type = multiplexing
agent.sources.tailsrc.selector.header = type
agent.sources.tailsrc.selector.mapping.1 = mem1
agent.sources.tailsrc.selector.mapping.2 = mem2
agent.sinks.std1.type = file_roll
agent.sinks.std1.channel = mem1
agent.sinks.std1.batchSize = 1
agent.sinks.std1.sink.directory = /var/log/flumeout/1
agent.sinks.std1.rollInterval = 0
agent.sinks.std2.type = file_roll
agent.sinks.std2.channel = mem2
agent.sinks.std2.batchSize = 1
agent.sinks.std2.sink.directory = /var/log/flumeout/2
agent.sinks.std2.rollInterval = 0
agent.channels.mem1.type = memory
agent.channels.mem1.capacity = 100
agent.channels.mem2.type = memory
agent.channels.mem2.capacity = 100
But, it doesn't work!
when selector part is removed, there are some interceptor debugging message in flume's log.
but when selector and interceptor are together, there are nothing.
Is there any wrong expression or something I missed?
Thanks for reading. :)
I found it.
In the flume log, there are warning message as below.
2013-10-10 16:34:20,514 (conf-file-poller-0) [WARN - org.apache.flume.conf.FlumeConfiguration$AgentConfiguration.validateSources(FlumeConfiguration.java:571)] Removed tailsrc due to Failed to configure component!
so I had attached below line
agent.sources.tailsrc.channels = mem1 mem2
and then It works!!!!

How can I get codec information for a quicktime video in Objective C/Cocoa? (Without FFMPEG)

Hello and thanks for your time,
I am creating an application that moves video files around to be processed by other applications. In the past, I have used mediainfo, and ffmpeg, in ruby to obtain codec information about each file. I would however like to transfer all of this into one beautiful cocoa app. I have searched and searched and still can't find a solution (without using ffmpeg) on how to do this. I am basically looking for the exact same info you get in the quicktime video inspector window (apple + i).
Any help would be greatly appreciated, sample code, even more so.
Thanks.
You can use Spotlight Queries (NSMetadataQuery), like the mdls command do :
> mdls ~/Music/iTunes/iTunes\ Media/iTunes\ U/WWDC\ 2011\ Session\ Videos\ -\ HD/1-01\ Apple\ Platforms\ Kickoff.m4v
kMDItemAudioBitRate = 103
kMDItemAudioChannelCount = 2
kMDItemCodecs = (
AAC,
"H.264"
)
kMDItemContentCreationDate = 2011-07-01 15:49:56 +0000
kMDItemContentModificationDate = 2011-07-01 16:13:39 +0000
kMDItemContentType = "com.apple.m4v-video"
kMDItemContentTypeTree = (
"com.apple.m4v-video",
"public.movie",
"public.audiovisual-content",
"public.data",
"public.item",
"public.content"
)
kMDItemDateAdded = 2011-07-01 16:13:39 +0000
kMDItemDisplayName = "1-01 Apple Platforms Kickoff.m4v"
kMDItemDurationSeconds = 2787.754421087755
kMDItemFSContentChangeDate = 2011-07-01 16:13:39 +0000
kMDItemFSCreationDate = 2011-07-01 15:49:56 +0000
kMDItemFSCreatorCode = "hook"
kMDItemFSFinderFlags = 0
kMDItemFSHasCustomIcon = 0
kMDItemFSInvisible = 0
kMDItemFSIsExtensionHidden = 0
kMDItemFSIsStationery = 0
kMDItemFSLabel = 0
kMDItemFSName = "1-01 Apple Platforms Kickoff.m4v
kMDItemFSNodeCount = 1147843844
kMDItemFSOwnerGroupID = 20
kMDItemFSOwnerUserID = 502
kMDItemFSSize = 1147843844
kMDItemFSTypeCode = ""
kMDItemKind = "Video Media"
kMDItemLogicalSize = 1147843844
kMDItemMediaTypes = (
Sound,
Video
)
kMDItemPhysicalSize = 1147846656
kMDItemPixelHeight = 540
kMDItemPixelWidth = 958
kMDItemProfileName = "HD (1-1-1)"
kMDItemStreamable = 0
kMDItemTotalBitRate = 3287
kMDItemVideoBitRate = 3184
Or you can check the AVFoundation framework.
Sample code:
-(NSDictionary *) metadataForFileAtPath:(NSString *) path {
NSURL *url = [[[NSURL alloc] initFileURLWithPath:path] autorelease];
MDItemRef itemRef = MDItemCreateWithURL(NULL, (CFURLRef)url);
NSArray *attributeNames = (NSArray *)MDItemCopyAttributeNames(itemRef);
NSDictionary *attributes = (NSDictionary *) MDItemCopyAttributes(itemRef, (CFArrayRef) attributeNames);
CFRelease(itemRef);
// probably it is leaking memory (attributeNames and attributes), better check with Instruments
return attributes;
}

Hard time debugging Local Variable in XCode

I'm having a hard-time debugging a local variable. I'm running gcc 4.2, XCode 3.2.4, base SDK Mac OS 10.5, and Objective-C++ in Debug-Mode.
Here's the issue. I'm working on trying to understand some code and it goes like this:
#define MAX4D 500
...
NSMutableArray *viewerPix[ MAX4D ];
When I hover over it during debug (pause on the line before and after) I get this
Unable to access variable "viewerPix"
Unable to access variable "viewerPix"
Unable to access variable "viewerPix"
...
repeated until I kill the application. What would cause this? I've tried setting it to a lower number... but to no avail. Even after I actually set the C-Array:
viewerPix[0] = [[NSMutableArray alloc] initWithCapacity:0];
I still get the same repeated error message.
However, if I don't mouse-over the value (or debug) it "appears" to run fine, even doing stuff like:
[viewerPix[0] addObject: dcmPix];
if( [viewerPix[0] count] != [loadList count])...
but if I debug after those steps, it crashes just like before. Here are my build settings:
STRIPFLAGS =
ALTERNATE_GROUP = $(INSTALL_GROUP)
ALTERNATE_OWNER = $(INSTALL_OWNER)
ALTERNATE_MODE = $(INSTALL_MODE_FLAG)
ALTERNATE_PERMISSIONS_FILES =
DEPLOYMENT_LOCATION = NO
DEPLOYMENT_POSTPROCESSING = NO
INSTALL_GROUP = $(GROUP)
INSTALL_OWNER = $(USER)
INSTALL_MODE_FLAG = u+w,go-w,a+rX
DSTROOT = /tmp/$(PROJECT_NAME).dst
INSTALL_PATH = $(HOME)/Applications
SKIP_INSTALL = NO
COPY_PHASE_STRIP = NO
STRIP_INSTALLED_PRODUCT =
STRIP_STYLE = debugging
SEPARATE_STRIP = NO
GCC_FAST_OBJC_DISPATCH = YES
GCC_AUTO_VECTORIZATION = NO
GCC_OBJC_CALL_CXX_CDTORS = YES
GCC_ENABLE_SSE3_EXTENSIONS = NO
GCC_ENABLE_SSE41_EXTENSIONS = NO
GCC_ENABLE_SSE42_EXTENSIONS = NO
GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = NO
GCC_STRICT_ALIASING = NO
GCC_FEEDBACK_DIRECTED_OPTIMIZATION = Off
GCC_ENABLE_FIX_AND_CONTINUE = NO
GCC_GENERATE_DEBUGGING_SYMBOLS = YES
GCC_DYNAMIC_NO_PIC = NO
GCC_GENERATE_TEST_COVERAGE_FILES = NO
GCC_INLINES_ARE_PRIVATE_EXTERN = YES
GCC_MODEL_TUNING = G5
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO
GCC_ENABLE_KERNEL_DEVELOPMENT = NO
GCC_DEBUGGING_SYMBOLS = default
GCC_REUSE_STRINGS = YES
GCC_NO_COMMON_BLOCKS = NO
GCC_ENABLE_OBJC_GC = unsupported
GCC_OPTIMIZATION_LEVEL = 0
GCC_FAST_MATH = NO
GCC_ENABLE_SYMBOL_SEPARATION = YES
GCC_THREADSAFE_STATICS = YES
GCC_SYMBOLS_PRIVATE_EXTERN = NO
GCC_UNROLL_LOOPS = NO
GCC_MODEL_PPC64 = NO
I don't know what else to say. Let me know what more information is needed, because I'm at a loss. There's also no 'build' tab when I get-info on the .mm file. Just General, Target, Comments (some helps I checked said to remove file-specific tags).
Should I initialize that c-array to nil? I can't just do.. array[500] = {nil}; right? that's C#?
I was using LLVM and Clang 1.5, but I switched to GCC 4.2 since I wasn't getting any local symbols. Am I missing something??
If the optimizer is on, that can effectively eliminate local variables.
However, why a C array of mutable ObjC arrays? That seems odd.
check Product->Scheme->Edit Scheme->Run xxx, Build Configuration is Debug, if that is Release happened you see.

How to get an outline view in sublime texteditor?

How do I get an outline view in sublime text editor for Windows?
The minimap is helpful but I miss a traditional outline (a klickable list of all the functions in my code in the order they appear for quick navigation and orientation)
Maybe there is a plugin, addon or similar? It would also be nice if you can shortly name which steps are neccesary to make it work.
There is a duplicate of this question on the sublime text forums.
Hit CTRL+R, or CMD+R for Mac, for the function list. This works in Sublime Text 1.3 or above.
A plugin named Outline is available in package control, try it!
https://packagecontrol.io/packages/Outline
Note: it does not work in multi rows/columns mode.
For multiple rows/columns work use this fork:
https://github.com/vlad-wonderkidstudio/SublimeOutline
I use the fold all action. It will minimize everything to the declaration, I can see all the methods/functions, and then expand the one I'm interested in.
I briefly look at SublimeText 3 api and view.find_by_selector(selector) seems to be able to return a list of regions.
So I guess that a plugin that would display the outline/structure of your file is possible.
A plugin that would display something like this:
Note: the function name display plugin could be used as an inspiration to extract the class/methods names or ClassHierarchy to extract the outline structure
If you want to be able to printout or save the outline the ctr / command + r is not very useful.
One can do a simple find all on the following grep ^[^\n]*function[^{]+{ or some variant of it to suit the language and situation you are working in.
Once you do the find all you can copy and paste the result to a new document and depending on the number of functions should not take long to tidy up.
The answer is far from perfect, particularly for cases when the comments have the word function (or it's equivalent) in them, but I do think it's a helpful answer.
With a very quick edit this is the result I got on what I'm working on now.
PathMaker.prototype.start = PathMaker.prototype.initiate = function(point){};
PathMaker.prototype.path = function(thePath){};
PathMaker.prototype.add = function(point){};
PathMaker.prototype.addPath = function(path){};
PathMaker.prototype.go = function(distance, angle){};
PathMaker.prototype.goE = function(distance, angle){};
PathMaker.prototype.turn = function(angle, distance){};
PathMaker.prototype.continue = function(distance, a){};
PathMaker.prototype.curve = function(angle, radiusX, radiusY){};
PathMaker.prototype.up = PathMaker.prototype.north = function(distance){};
PathMaker.prototype.down = PathMaker.prototype.south = function(distance){};
PathMaker.prototype.east = function(distance){};
PathMaker.prototype.west = function(distance){};
PathMaker.prototype.getAngle = function(point){};
PathMaker.prototype.toBezierPoints = function(PathMakerPoints, toSource){};
PathMaker.prototype.extremities = function(points){};
PathMaker.prototype.bounds = function(path){};
PathMaker.prototype.tangent = function(t, points){};
PathMaker.prototype.roundErrors = function(n, acurracy){};
PathMaker.prototype.bezierTangent = function(path, t){};
PathMaker.prototype.splitBezier = function(points, t){};
PathMaker.prototype.arc = function(start, end){};
PathMaker.prototype.getKappa = function(angle, start){};
PathMaker.prototype.circle = function(radius, start, end, x, y, reverse){};
PathMaker.prototype.ellipse = function(radiusX, radiusY, start, end, x, y , reverse/*, anchorPoint, reverse*/ ){};
PathMaker.prototype.rotateArc = function(path /*array*/ , angle){};
PathMaker.prototype.rotatePoint = function(point, origin, r){};
PathMaker.prototype.roundErrors = function(n, acurracy){};
PathMaker.prototype.rotate = function(path /*object or array*/ , R){};
PathMaker.prototype.moveTo = function(path /*object or array*/ , x, y){};
PathMaker.prototype.scale = function(path, x, y /* number X scale i.e. 1.2 for 120% */ ){};
PathMaker.prototype.reverse = function(path){};
PathMaker.prototype.pathItemPath = function(pathItem, toSource){};
PathMaker.prototype.merge = function(path){};
PathMaker.prototype.draw = function(item, properties){};