import Foundation @objc class Plugin: NSObject, THOPluginProtocol { var apikey = "" var theClient:IRCClient? = nil var currentAlbum = "" var uploadQueue:[URL] = [] var isUploading = false var task:URLSessionDataTask? @objc let subscribedUserInputCommands = ["arxiuskey", "upload", "cancel"] @objc func pluginLoadedIntoMemory() { if (apikey.count < 1) { if let key = TPCPreferencesUserDefaults.shared().value(forKey: "arxiusAPIKey") { apikey = key as! String } } } @objc func userInputCommandInvoked(on client: IRCClient, command commandString: String, messageString: String) { theClient = client performBlock(onMainThread: { switch commandString { case "ARXIUSKEY": if (messageString.count == 32) { apikey = messageString TPCPreferencesUserDefaults.shared().setValue(apikey, forKey: "arxiusAPIKey") debug("Your API key is set") } else if (messageString.count == 0 && apikey.count > 0) { apikey = "" TPCPreferencesUserDefaults.shared().removeObject(forKey: "arxiusAPIKey") debug("Your API key is unset") } else if (messageString.count == 0) { debug("Enter your API key like this: /arxiuskey abcd1234abcd1234abcd1234abcd1234") } else { debug("That's not a valid API key") } case "UPLOAD": let dialog = NSOpenPanel(); dialog.title = "Select files to upload"; dialog.showsResizeIndicator = true; dialog.showsHiddenFiles = false; dialog.canChooseDirectories = false; dialog.canCreateDirectories = true; dialog.allowsMultipleSelection = true; if (dialog.runModal() == NSApplication.ModalResponse.OK) { let files = dialog.urls if (files.count > 0) { for file in files { let path = file.absoluteURL uploadQueue.append(path) } makeAlbumIfNeeded() } } case "CANCEL": task?.cancel() uploadQueue = [] debug("Upload cancelled") break default: break } }) } func debug(_ message: Any) { self.theClient!.printDebugInformation("\u{02}[Arxius]\u{02} \(message)", in: self.theClient!.lastSelectedChannel!) } func startUploading() { uploadFiles() } func uploadFiles() { if (uploadQueue.count > 0) { upload() } else { currentAlbum = "" } } func upload() { let file = uploadQueue[0] uploadQueue.remove(at: 0) let url = URL(string: "https://arxius.io/")! var request = URLRequest(url: url) request.httpMethod = "POST" var parameters: [String:String] = [:] if (apikey.count > 0) { parameters["apikey"] = apikey } if (currentAlbum.count > 0) { parameters["album"] = currentAlbum } var last = false if (uploadQueue.count < 1) { last = true parameters["last"] = "true" } let boundary = "Boundary-\(UUID().uuidString)" request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") do { let fileData = try Data(contentsOf: file) request.httpBody = createBody(parameters: parameters, boundary: boundary, data: fileData, mimeType: "application/octet-stream", filename: file.lastPathComponent) task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, let response = response as? HTTPURLResponse, error == nil else { return } guard (200 ... 299) ~= response.statusCode else { return } if (last) { if let link = String(data: data, encoding: .utf8) { self.debug("Upload complete: \(link)") } } } task!.resume() debug("Uploading: \(file.path)") uploadFiles() } catch {} } func makeAlbumIfNeeded() { if (uploadQueue.count > 1) { let url = URL(string: "https://arxius.io/api/create/album")! var request = URLRequest(url: url) request.httpMethod = "POST" var parameters: [String:String] = [:] if (apikey.count > 0) { parameters["apikey"] = apikey } request.httpBody = parameters.percentEscaped().data(using: .utf8) let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, let response = response as? HTTPURLResponse, error == nil else { return } guard (200 ... 299) ~= response.statusCode else { return } do { let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: Any] if (json.index(forKey: "album") != nil) { let album = json["album"] as! String self.currentAlbum = album self.debug("Created album: \(album)") self.startUploading() } else { self.debug("Error creating album") } } catch {} } task.resume() } else { self.startUploading() } } func createBody(parameters: [String: String], boundary: String, data: Data, mimeType: String, filename: String) -> Data { let body = NSMutableData() let boundaryPrefix = "--\(boundary)\r\n" for (key, value) in parameters { body.appendString(boundaryPrefix) body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") body.appendString("\(value)\r\n") } body.appendString(boundaryPrefix) body.appendString("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n") body.appendString("Content-Type: \(mimeType)\r\n\r\n") body.append(data) body.appendString("\r\n") body.appendString("--".appending(boundary.appending("--"))) return body as Data } }