首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Node.js/Electron应用程序中使用iTunes库框架?

在Node.js/Electron应用程序中使用iTunes库框架?
EN

Stack Overflow用户
提问于 2020-08-28 07:23:26
回答 1查看 217关注 0票数 2

我正在开发一个访问iTunes数据库的电子(Node.js)应用程序。在Catalina之前,可以使用数据库iTunes Music Library.xml的导出XML版本。在应该使用iTunes库框架而不是https://developer.apple.com/documentation/ituneslibrary的Catalina中删除了这一点。

是否可以将此框架包含在my Electron或一般的Node.js项目中,并与其进行交互?如果可以,如何进行交互?

我扫描了GitHub中的模块或可能的解决方案,但它们都依赖于旧的XML文件。

EN

回答 1

Stack Overflow用户

发布于 2020-08-31 06:55:41

我看到的唯一方法是使用节点本机模块。苹果使用Objectiv-C,而其他所有语言(javascript、python等)都使用C或C++绑定。幸运的是,clang支持Objective- C++,允许混合使用C++和Objective-C。工作的基本代码片段如下所示(将其命名为readMusic.mmmm是für Objectiv-C++的扩展

代码语言:javascript
复制
#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++标志。

代码语言:javascript
复制
{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "readMusic.mm" ],
      "cflags!": [ "-ObjC++" ],
      "cflags_cc!": [ "-ObjC++" ],
      "libraries": [
          "/System/Library/Frameworks/iTunesLibrary.framework/Versions/Current/iTunesLibrary"
      ]
    }
  ]
}

然后编译并共同设计它(对于发行版非常重要),通过

代码语言:javascript
复制
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

并通过以下方式使用

代码语言:javascript
复制
require("./build/Release/addon.node").readMusic();

由于依赖于本机模块,这只能在Mac (https://www.electron.build/multi-platform-build)上编译。请确保在windows平台上排除该代码。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63625399

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档