cwiz
cwiz

Reputation: 11

Register MPEG-4 as Dragged Type using pyobjc on macos

I'm trying to register MPEG-4 as a dragged type using pyobjc with the specific goal of being able to drag voice memos directly out of the app into my own python application.

I tried registering UTI types "public.audio", "public.mpeg-4-audio", NSPasteboard.URLType and NSPasteboard.fileURLType as per Apples Official Documentation. However dropping a file on my program always resulted in the same error: "The document x could not be opened. Python cannot open files in the 'Apple MPEG-4 audio' format.

Here is a minimal reproducible example:

from AppKit import NSApplication, NSObject, NSDragOperationCopy, NSWindow, NSView, NSPasteboard, NSPasteboard
from PyObjCTools import AppHelper

class DropView(NSView):
    def initWithFrame_(self, frame):
        self = super(DropView, self).initWithFrame_(frame)
        if self:
            self.registerForDraggedTypes_(["public.audio", "public.mpeg-4-audio", NSPasteboard.URLType, NSPasteboard.fileURLType])
        return self

    def draggingEntered_(self, sender):
        pboard = sender.draggingPasteboard()
        return NSDragOperationCopy

    def performDragOperation_(self, sender):
        pboard = sender.draggingPasteboard()
        print(pboard)
        return True

class AppDelegate(NSObject):
    def applicationDidFinishLaunching_(self, notification):
        self.window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(((100, 100), (400, 300)), 1 << 1 | 1 << 10, 2, False)
        self.window.setTitle_("Drag-and-Drop Example")

        drop_view = DropView.alloc().initWithFrame_(((0, 0), (400, 300)))
        self.window.contentView().addSubview_(drop_view)

        self.window.makeKeyAndOrderFront_(None)

def run_app():
    app = NSApplication.sharedApplication()
    delegate = AppDelegate.alloc().init()
    app.setDelegate_(delegate)

    AppHelper.runEventLoop()

if __name__ == '__main__':
    run_app()

Upvotes: 0

Views: 55

Answers (1)

apodidae
apodidae

Reputation: 2713

The following source code runs on my system (MacOS, Sonoma 14.4.1). I was unable to run the code that you posted in Thonny. Changes were made to the last two parameters of registerForDraggedTypes() plus an objc import; it now returns the filePath. You will still need to add an AVPlayer in order to hear the dropped file.

from Cocoa import (
    NSApplication,
    NSObject,
    NSWindow,
    NSView,
    NSPasteboard,
    NSDragOperationCopy,
    NSPasteboardType,
    NSPasteboardTypeURL,
    NSPasteboardTypeFileURL,
    NSFilenamesPboardType,
)
from PyObjCTools import AppHelper
from objc import super

class DropView(NSView):
    def initWithFrame_(self, frame):
        self = super(DropView, self).initWithFrame_(frame)
        if self:
            self.registerForDraggedTypes_(
                [
                    "public.audio",
                    "public.mpeg-4-audio",
                    NSPasteboardTypeURL,
                    NSPasteboardTypeFileURL,
                ]
            )
        return self

    def draggingEntered_(self, sender):
        pboard = sender.draggingPasteboard()
        print("dragging entered.")
        print(pboard)
        return NSDragOperationCopy

    def performDragOperation_(self, sender):
        pboard = sender.draggingPasteboard()
        files = pboard.propertyListForType_(NSFilenamesPboardType)
        print(files.objectAtIndex_(0))
        return True

class AppDelegate(NSObject):
    def applicationDidFinishLaunching_(self, notification):
        self.window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
            ((100, 100), (400, 300)), 1 << 1 | 1 << 10, 2, False
        )
        self.window.setTitle_("Drag-and-Drop Example")
        drop_view = DropView.alloc().initWithFrame_(((0, 0), (400, 300)))
        self.window.contentView().addSubview_(drop_view)
        self.window.makeKeyAndOrderFront_(None)

def run_app():
    app = NSApplication.sharedApplication()
    delegate = AppDelegate.alloc().init()
    app.setDelegate_(delegate)

    AppHelper.runEventLoop()

if __name__ == "__main__":
    run_app()

Upvotes: 0

Related Questions