在Node.js / Electron应用中使用iTunes Library框架吗? [英] Use iTunes Library framework in Node.js/Electron app?
问题描述
我正在开发一个访问iTunes数据库的Electron(Node.js)应用程序。在Catalina之前,可以使用导出的XML版本的数据库 iTunes Music Music.xml
。此邮件已在Catalina中删除,应使用iTunes库框架代替 https://developer.apple.com/文档/ ituneslibrary 。
I am developing an Electron (Node.js) app that accesses the iTunes database. Before Catalina one could use an exported XML version of the database iTunes Music Library.xml
. This was removed in Catalina where the iTunes library framework should be used instead https://developer.apple.com/documentation/ituneslibrary.
是否可以在我的Electron或通常在Node.js项目中包含此框架并与之交互,如果可以,怎么做?
Is it possible to include this framework in my Electron or generally in a Node.js project and interact with it and if yes — how?
我在GitHub上扫描了模块或可能的解决方案,但它们都依赖于旧的XML文件。
I scanned GitHub for modules or possible solutions but all of them rely on the old XML file.
推荐答案
<我看到的唯一方法是使用节点本机模块。苹果使用Objectiv-C,其他所有语言(javascript,python等)都使用C或C ++绑定。幸运的是,clang支持Objective-C ++,它允许将C ++和Objective-C混合使用。一个有效的基本代码段如下所示(将其命名为 readMusic.mm
。 mm
是Objectiv-C ++的扩展名)
The only way I see is using a node native module. Apple uses Objectiv-C and every other language (javascript, python, etc) uses C or C++ bindings. Luckly, clang supports Objective-C++, which allows to mix C++ and Objective-C. A basic snippet that works looks like this (name it readMusic.mm
. mm
is the extension für Objectiv-C++)
#import <Foundation/Foundation.h>
#import <iTunesLibrary/ITLibrary.h>
#import <iTunesLibrary/ITLibMediaItem.h>
#import <iTunesLibrary/ITLibArtist.h>
#include <node.h>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Array;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Integer;
char const *emptyString = "";
void Method(const FunctionCallbackInfo<Value>& args) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Set this up so Cocoa works
Isolate* isolate = args.GetIsolate(); // Setup for Javascript Connection
Local<v8::Context> context = isolate->GetCurrentContext();
Local<String> keyTitle = String::NewFromUtf8(isolate, "title").ToLocalChecked();
Local<String> keyArtist = String::NewFromUtf8(isolate, "artist").ToLocalChecked();
Local<String> keyFilePath = String::NewFromUtf8(isolate, "filePath").ToLocalChecked();
Local<String> keyBpm = String::NewFromUtf8(isolate, "bpm").ToLocalChecked();
NSError *error = nil;
ITLibrary *library = [ITLibrary libraryWithAPIVersion:@"1.0" error:&error]; // Connect to iTunes / Music Library
if (library)
{
NSArray *tracks = library.allMediaItems; // Load all Songs with Cocoa / Objective-C
int size = [tracks count];
Local<Array> jsSongsArr = Array::New(isolate, size); // Create Array for Javascript v8 engine
for (int i = 0; i < size; i++) { // Copy elements
// Reading Data from Cocoa
ITLibMediaItem *song = tracks[i];
NSString *title = [song title];
ITLibArtist *artist = [song artist];
NSURL *location = [song location];
// Convert it to c
const char *titleInC = emptyString;
const char *artistInC = emptyString;
const char *filePathInC = emptyString;
const long bpmInC = [song beatsPerMinute];
if (title) {
titleInC = [title UTF8String];
}
if (artist) {
NSString *artistNSString = [artist name];
if (artistNSString) {
artistInC = [artistNSString UTF8String];
}
}
if (location) {
NSString *locationNSString = [location absoluteString];
if (locationNSString) {
filePathInC = [locationNSString UTF8String];
}
}
Local<Object> jsSong = Object::New(isolate); // Create Javascript Object
jsSong->Set(context, keyTitle, String::NewFromUtf8(isolate, titleInC).ToLocalChecked()).FromJust(); // Copy data in Javascript Object
jsSong->Set(context, keyArtist, String::NewFromUtf8(isolate, artistInC).ToLocalChecked()).FromJust();
jsSong->Set(context, keyFilePath, String::NewFromUtf8(isolate, filePathInC).ToLocalChecked()).FromJust();
jsSong->Set(context, keyBpm, Integer::New(isolate, bpmInC)).FromJust();
jsSongsArr->Set(context, i, jsSong).FromJust(); // Add the Object to Javascript Array
}
args.GetReturnValue().Set(jsSongsArr); // Set the return value of the function
} else { // If error occurs
args.GetReturnValue().Set(String::NewFromUtf8(isolate, [[error localizedDescription] UTF8String]).ToLocalChecked());
}
}
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "readMusic", Method); // Tells node which function to use
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) // Inits a native node module
}
这样做时,请不要忘记NSAutoReleasePool。对于绑定,您需要在 binding.gyp
中设置-ObjC ++标志。
Don't forget the NSAutoReleasePool when doing stuff like that. For the binding you need to set the -ObjC++ flags in your binding.gyp
.
{
"targets": [
{
"target_name": "addon",
"sources": [ "readMusic.mm" ],
"cflags!": [ "-ObjC++" ],
"cflags_cc!": [ "-ObjC++" ],
"libraries": [
"/System/Library/Frameworks/iTunesLibrary.framework/Versions/Current/iTunesLibrary"
]
}
]
}
然后编译并对其进行代码签名(对于分发非常重要),通过
Then compile and codesign it (very important for distribution) via
HOME=~/.electron-gyp node-gyp rebuild --target=10.1.0 --arch=x64 --dist-url=https://electronjs.org/headers
codesign -s "YOUR DEVELOPER ID" build/Release/addon.node
并通过
require("./build/Release/addon.node").readMusic();
由于依赖本机模块,因此只能在Mac上编译( https://www.electron.build/multi-platform-build )。确保在Windows平台上排除该代码。
Because of the dependence on native modules this is only compilable on Mac (https://www.electron.build/multi-platform-build). Make sure to exclude that code on windows platforms.
这篇关于在Node.js / Electron应用中使用iTunes Library框架吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!