Supabase MCP Server
- video-player
import AppKit
import Cocoa
import Foundation
class Config {
static func getAPIKey() -> String? {
if let configPath = Bundle.main.path(forResource: "config", ofType: "json"),
let configData = try? Data(contentsOf: URL(fileURLWithPath: configPath)),
let json = try? JSONSerialization.jsonObject(with: configData) as? [String: String] {
return json["api_key"]
}
return nil
}
}
struct VideoUpload: Codable {
let name: String
let filename: String
let upload_method: String
}
enum UploadError: Error {
case invalidURL
case networkError(Error)
case invalidResponse
case serverError(Int)
case noData
}
class CustomTextField: NSTextField {
override func performKeyEquivalent(with event: NSEvent) -> Bool {
if event.modifierFlags.contains(.command) {
switch event.charactersIgnoringModifiers {
case "v":
if NSApp.sendAction(#selector(NSText.paste(_:)), to: nil, from: self) {
return true
}
case "c":
if NSApp.sendAction(#selector(NSText.copy(_:)), to: nil, from: self) {
return true
}
case "x":
if NSApp.sendAction(#selector(NSText.cut(_:)), to: nil, from: self) {
return true
}
case "a":
if NSApp.sendAction(#selector(NSText.selectAll(_:)), to: nil, from: self) {
return true
}
default:
break
}
}
return super.performKeyEquivalent(with: event)
}
}
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
var statusItem: NSStatusItem!
var uploadWindow: NSWindow?
// Use lazy property initialization for uploadManager
lazy var uploadManager: UploadManager = {
guard let apiKey = Config.getAPIKey() else {
fatalError("API key not found in config.json")
}
return UploadManager(apiKey: apiKey)
}()
func applicationDidFinishLaunching(_ notification: Notification) {
setupStatusItem()
// Get command line arguments
let arguments = ProcessInfo.processInfo.arguments
// Skip the first argument (which is the app path)
if arguments.count > 1 {
for argument in arguments.dropFirst() {
if let url = URL(string: argument), url.scheme == "videojungle" {
handleURL(url)
}
}
}
// Register for Apple Events
NSAppleEventManager.shared().setEventHandler(
self,
andSelector: #selector(handleURLEvent(_:withReplyEvent:)),
forEventClass: AEEventClass(kInternetEventClass),
andEventID: AEEventID(kAEGetURL)
)
}
func handleURL(_ url: URL) {
// Parse the URL and handle different actions
switch url.host {
case "upload":
// Open your upload window/view
self.showUploadWindow()
default:
print("Unknown URL command: \(url)")
}
}
@objc func handleURLEvent(_ event: NSAppleEventDescriptor, withReplyEvent: NSAppleEventDescriptor) {
guard let urlString = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue,
let url = URL(string: urlString) else {
return
}
// Handle different commands
if url.host == "upload" {
DispatchQueue.main.async {
self.showUploadWindow()
}
}
}
func setupStatusItem() {
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
if let button = statusItem.button {
// Try bundle path first
let bundlePath = Bundle.main.path(forResource: "Icon", ofType: "svg")
// Fall back to local path if bundle path fails
let localPath = "./Icon.svg"
let finalPath = bundlePath ?? localPath
if let svgData = try? Data(contentsOf: URL(fileURLWithPath: finalPath)),
let svgImage = NSImage(data: svgData) {
button.image = svgImage
button.image?.isTemplate = true
}
}
let menu = NSMenu()
menu.addItem(NSMenuItem(title: "Upload File or URL...", action: #selector(showUploadWindow), keyEquivalent: "u"))
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(title: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
statusItem.menu = menu
}
@objc func showUploadWindow() {
if let window = uploadWindow {
window.level = .floating
window.orderFrontRegardless()
NSApp.activate(ignoringOtherApps: true)
return
}
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
styleMask: [.titled, .closable, .miniaturizable],
backing: .buffered,
defer: false
)
window.title = "Upload File or URL"
window.level = .floating
window.center()
window.delegate = self
window.isReleasedWhenClosed = false
let viewController = UploaderViewController()
window.contentViewController = viewController
window.orderFrontRegardless()
NSApp.activate(ignoringOtherApps: true)
uploadWindow = window
}
// Window delegate method to handle window closing
func windowShouldClose(_ sender: NSWindow) -> Bool {
sender.orderOut(nil) // Hide the window
return false // Prevent the window from being destroyed
}
}
class UploaderViewController: NSViewController, NSTextFieldDelegate {
private var nameField: NSTextField!
private var urlField: NSTextField!
private var statusLabel: NSTextField!
private var uploadButton: NSButton!
private let uploadManager: UploadManager = {
guard let apiKey = Config.getAPIKey() else {
fatalError("API key not found in config.json")
}
return UploadManager(apiKey: apiKey)
}()
override func loadView() {
let container = NSView(frame: NSRect(x: 0, y: 0, width: 400, height: 300))
// Name Input Field - Positioned at top
nameField = CustomTextField(frame: NSRect(x: 20, y: 250, width: 360, height: 24))
nameField.placeholderString = "Name"
nameField.target = self
nameField.action = #selector(handleNameInput(_:))
nameField.isEditable = true
nameField.isSelectable = true
nameField.usesSingleLineMode = true
container.addSubview(nameField)
// URL Input Field - Positioned below name field
urlField = CustomTextField(frame: NSRect(x: 20, y: 215, width: 270, height: 24))
urlField.placeholderString = "Enter URL to upload"
urlField.target = self
urlField.action = #selector(handleURLInput(_:))
urlField.isEditable = true
urlField.isSelectable = true
urlField.usesSingleLineMode = true
container.addSubview(urlField)
// Upload Button - Aligned with URL field
uploadButton = NSButton(frame: NSRect(x: 300, y: 215, width: 80, height: 24))
uploadButton.title = "Upload"
uploadButton.bezelStyle = .rounded
uploadButton.target = self
uploadButton.action = #selector(handleUpload(_:))
container.addSubview(uploadButton)
// Drop Zone - Below URL field and button
let dropZone = DropZoneView(frame: NSRect(x: 20, y: 50, width: 360, height: 150))
dropZone.uploadManager = uploadManager
container.addSubview(dropZone)
// Status Label - At bottom
statusLabel = NSTextField(frame: NSRect(x: 20, y: 20, width: 360, height: 24))
statusLabel.isEditable = false
statusLabel.isBezeled = false
statusLabel.drawsBackground = false
statusLabel.stringValue = "Drag and drop files here or enter a URL above"
container.addSubview(statusLabel)
self.view = container
}
@objc private func handleNameInput(_ sender: NSTextField) {
// Update status or validate name as needed
statusLabel.stringValue = "Name entered: \(sender.stringValue)"
}
@objc func handleURLInput(_ sender: NSTextField) {
Task {
await handleUploadAttempt()
}
}
@objc private func handleUpload(_ sender: NSButton) {
Task {
await handleUploadAttempt()
}
}
private func handleUploadAttempt() async {
// Validate inputs
guard let name = nameField.stringValue.nilIfEmpty else {
showAlert(message: "Please enter a name")
return
}
guard let urlString = urlField.stringValue.nilIfEmpty,
let url = URL(string: urlString) else {
showAlert(message: "Please enter a valid URL")
return
}
await MainActor.run {
statusLabel.stringValue = "Uploading..."
uploadButton.isEnabled = false
}
// Convert completion handler to async/await
do {
await MainActor.run {
statusLabel.stringValue = "Uploading..."
uploadButton.isEnabled = false
}
let _ = try await uploadManager.uploadURL(name: name, urlString: urlString)
await MainActor.run {
statusLabel.stringValue = "Upload completed successfully!"
showAlert(message: "Video uploaded successfully")
// Clear the fields after successful upload
nameField.stringValue = ""
urlField.stringValue = ""
uploadButton.isEnabled = true
}
await MainActor.run {
statusLabel.stringValue = "Upload completed successfully!"
showAlert(message: "Video uploaded successfully")
// Clear the fields after successful upload
nameField.stringValue = ""
urlField.stringValue = ""
uploadButton.isEnabled = true
}
} catch {
await MainActor.run {
statusLabel.stringValue = "Upload failed"
showAlert(message: "Upload failed: \(error.localizedDescription)")
uploadButton.isEnabled = true
}
}
}
func showAlert(message: String) {
let alert = NSAlert()
alert.messageText = message
alert.alertStyle = .informational
alert.addButton(withTitle: "OK")
alert.runModal()
}
// MARK: - NSTextDelegate Methods
func textDidChange(_ notification: Notification) {
// Handle text changes if needed
}
func textDidEndEditing(_ notification: Notification) {
// Handle when editing ends if needed
}
}
class DropZoneView: NSView {
var uploadManager: UploadManager?
private let dropLabel = NSTextField()
var isReceivingDrag: Bool = false {
didSet {
needsDisplay = true
updateDropLabel()
}
}
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
private func setupView() {
registerForDraggedTypes([.fileURL])
wantsLayer = true
layer?.cornerRadius = 10
// Setup drop label
dropLabel.isEditable = false
dropLabel.isBezeled = false
dropLabel.drawsBackground = false
dropLabel.alignment = .center
dropLabel.font = NSFont.systemFont(ofSize: 16, weight: .medium)
dropLabel.stringValue = "Drop files here to upload"
dropLabel.textColor = .secondaryLabelColor
addSubview(dropLabel)
}
override func layout() {
super.layout()
dropLabel.frame = bounds
}
private func updateDropLabel() {
dropLabel.textColor = isReceivingDrag ? .systemBlue : .secondaryLabelColor
NSAnimationContext.runAnimationGroup { context in
context.duration = 0.2
dropLabel.animator().alphaValue = isReceivingDrag ? 1.0 : 0.6
}
}
override func draw(_ dirtyRect: NSRect) {
let bounds = self.bounds
// Background
if isReceivingDrag {
NSColor(calibratedWhite: 0.95, alpha: 1.0).setFill()
} else {
NSColor(calibratedWhite: 0.98, alpha: 1.0).setFill()
}
let path = NSBezierPath(roundedRect: bounds, xRadius: 10, yRadius: 10)
path.fill()
// Border
if isReceivingDrag {
NSColor.systemBlue.setStroke()
} else {
NSColor.separatorColor.setStroke()
}
path.lineWidth = 2
path.stroke()
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
isReceivingDrag = true
return .copy
}
override func draggingExited(_ sender: NSDraggingInfo?) {
isReceivingDrag = false
}
override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
return true
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
isReceivingDrag = false
guard let draggedFileURL = sender.draggingPasteboard.readObjects(forClasses: [NSURL.self], options: nil)?.first as? URL else {
return false
}
uploadManager?.uploadFile(draggedFileURL) { result in
DispatchQueue.main.async {
let alert = NSAlert()
switch result {
case .success:
alert.messageText = "File uploaded successfully"
case .failure(let error):
alert.messageText = "Upload failed: \(error.localizedDescription)"
}
alert.alertStyle = .informational
alert.addButton(withTitle: "OK")
alert.runModal()
}
}
return true
}
}
class UploadManager {
private let apiKey: String
private let baseURL = "https://api.video-jungle.com/video-file"
init(apiKey: String) {
self.apiKey = apiKey
}
func uploadURL(name: String, urlString: String) async throws -> Data {
guard let url = URL(string: baseURL) else {
throw UploadError.invalidURL
}
// Prepare the upload data
let uploadData = VideoUpload(
name: name,
filename: urlString,
upload_method: "url"
)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
// Encode the JSON data
request.httpBody = try JSONEncoder().encode(uploadData)
do {
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw UploadError.invalidResponse
}
switch httpResponse.statusCode {
case 200...299:
return data
default:
throw UploadError.serverError(httpResponse.statusCode)
}
} catch let error as UploadError {
throw error
} catch {
throw UploadError.networkError(error)
}
}
func uploadFile(_ fileURL: URL, completion: @escaping (Result<Void, Error>) -> Void) {
// Implement your file upload logic here
// This is a placeholder implementation
DispatchQueue.global().async {
// Simulating network delay
Thread.sleep(forTimeInterval: 1.0)
completion(.success(()))
}
}
}
extension String {
var nilIfEmpty: String? {
self.isEmpty ? nil : self
}
}
// Main entry point
let app = NSApplication.shared
let delegate = AppDelegate()
app.delegate = delegate
app.run()