From 1c72e06468f186b89729b69641680be4cd512835 Mon Sep 17 00:00:00 2001 From: Matt Svoboda Date: Mon, 18 Mar 2024 06:30:49 -0700 Subject: [PATCH 1/2] Expand IINA screenshot functionality to screenshot flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: • Applies IINA screenshot OSD & other enhancements to screenshot commands which have flags (except for "each-frame" flag) • Expand functionality of PlayerCore.screenshot() to handle screenshot command from a key binding • Add logic so that if any flags are found in the screenshot command, they will be used • Else if no flags are specified, then the value for pref key "screenshotIncludeSubtitle" will be used to determine the flags --- iina/PlayerCore.swift | 76 +++++++++++++++++++++++++++++-- iina/PlayerWindowController.swift | 6 +++ 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/iina/PlayerCore.swift b/iina/PlayerCore.swift index 9e72724aa6..c812d8cb4e 100644 --- a/iina/PlayerCore.swift +++ b/iina/PlayerCore.swift @@ -770,15 +770,81 @@ class PlayerCore: NSObject { } } - func screenshot() { - guard let vid = info.vid, vid > 0 else { return } + func isScreenshotEnabled() -> Bool { let saveToFile = Preference.bool(for: .screenshotSaveToFile) let saveToClipboard = Preference.bool(for: .screenshotCopyToClipboard) - guard saveToFile || saveToClipboard else { return } + return saveToFile || saveToClipboard + } - let option = Preference.bool(for: .screenshotIncludeSubtitle) ? "subtitles" : "video" + /// Takes a screenshot, attempting to augment mpv's `screenshot` command with additional functionality & control, for example + /// the ability to save to clipboard instead of or in addition to file, and displaying the screenshot's thumbnail via the OSD. + /// Returns `true` if a command was sent to mpv; `false` if no command was sent. + /// + /// If the prefs for `Preference.Key.screenshotSaveToFile` and `Preference.Key.screenshotCopyToClipboard` are both `false`, + /// this function does nothing and returns `false`. + /// + /// ## Determining screenshot flags + /// If `keyBinding` is present, it should contain an mpv `screenshot` command. If its action includes any flags, they will be + /// used. If `keyBinding` is not present or its command has no flags, the value for `Preference.Key.screenshotIncludeSubtitle` will + /// be used to determine the flags: + /// - If `true`, the command `screenshot subtitles` will be sent to mpv. + /// - If `false`, the command `screenshot video` will be sent to mpv. + /// + /// Note: IINA overrides mpv's behavior in some ways: + /// 1. As noted above, if the stored values for `Preference.Key.screenshotSaveToFile` and `Preference.Key.screenshotCopyToClipboard` are + /// set to false, all screenshot commands will be ignored. + /// 2. When no flags are given with `screenshot`: instead of defaulting to `subtitles` as mpv does, IINA will use the value for + /// `Preference.Key.screenshotIncludeSubtitle` to decide between `subtitles` or `video`. + @discardableResult + func screenshot(fromKeyBinding keyBinding: KeyMapping? = nil) -> Bool { + guard isScreenshotEnabled() else { + Logger.log("Ignoring screenshot request\(keyBinding == nil ? "" : " from key binding") because all forms of screenshots are disabled in prefs") + return false + } + + var commandFlags: [String] = [] + + if let keyBinding { + var canUseIINAScreenshot = true + + guard let commandName = keyBinding.action.first, commandName == MPVCommand.screenshot.rawValue else { + Logger.log("Cannot take screenshot: first token in key binding action is unexpected: \(keyBinding.action)") + return false + } + if keyBinding.action.count > 1 { + commandFlags = keyBinding.action[1].split(separator: "+").map{String($0)} + + for flag in commandFlags { + switch flag { + case "window", "subtitles", "video": + // These are supported + break + case "each-frame": + // Option is not currently supported by IINA's screenshot command + canUseIINAScreenshot = false + default: + // Unexpected flag. Let mpv decide how to handle + Logger.log("Unrecognized flag for mpv 'screenshot' command: '\(flag)'", level: .warning) + canUseIINAScreenshot = false + } + } + } + + if !canUseIINAScreenshot { + let returnValue = mpv.command(rawString: keyBinding.rawAction) + return returnValue == 0 + } + } + + guard let vid = info.vid, vid > 0 else { return false } // TODO: why this is needed? + + if commandFlags.isEmpty { + let includeSubtitles = Preference.bool(for: .screenshotIncludeSubtitle) + commandFlags.append(includeSubtitles ? "subtitles" : "video") + } - mpv.asyncCommand(.screenshot, args: [option], replyUserdata: MPVController.UserData.screenshot) + mpv.asyncCommand(.screenshot, args: commandFlags, replyUserdata: MPVController.UserData.screenshot) + return true } func screenshotCallback() { diff --git a/iina/PlayerWindowController.swift b/iina/PlayerWindowController.swift index 0dc21b6fe2..531aced153 100644 --- a/iina/PlayerWindowController.swift +++ b/iina/PlayerWindowController.swift @@ -238,12 +238,18 @@ class PlayerWindowController: NSWindowController, NSWindowDelegate { let returnValue: Int32 // execute the command switch keyBinding.action.first! { + case MPVCommand.abLoop.rawValue: abLoop() returnValue = 0 + + case MPVCommand.screenshot.rawValue: + return player.screenshot(fromKeyBinding: keyBinding) + default: returnValue = player.mpv.command(rawString: keyBinding.rawAction) } + if returnValue == 0 { return true } else { From 329726c45dd44ea15fe7659a6340d9879426d001 Mon Sep 17 00:00:00 2001 From: Matt Svoboda Date: Tue, 2 Apr 2024 21:26:46 -0700 Subject: [PATCH 2/2] Update based on feedback + add logging --- iina/PlayerCore.swift | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/iina/PlayerCore.swift b/iina/PlayerCore.swift index c812d8cb4e..3a908f40f1 100644 --- a/iina/PlayerCore.swift +++ b/iina/PlayerCore.swift @@ -770,12 +770,6 @@ class PlayerCore: NSObject { } } - func isScreenshotEnabled() -> Bool { - let saveToFile = Preference.bool(for: .screenshotSaveToFile) - let saveToClipboard = Preference.bool(for: .screenshotCopyToClipboard) - return saveToFile || saveToClipboard - } - /// Takes a screenshot, attempting to augment mpv's `screenshot` command with additional functionality & control, for example /// the ability to save to clipboard instead of or in addition to file, and displaying the screenshot's thumbnail via the OSD. /// Returns `true` if a command was sent to mpv; `false` if no command was sent. @@ -797,18 +791,27 @@ class PlayerCore: NSObject { /// `Preference.Key.screenshotIncludeSubtitle` to decide between `subtitles` or `video`. @discardableResult func screenshot(fromKeyBinding keyBinding: KeyMapping? = nil) -> Bool { - guard isScreenshotEnabled() else { - Logger.log("Ignoring screenshot request\(keyBinding == nil ? "" : " from key binding") because all forms of screenshots are disabled in prefs") + let saveToFile = Preference.bool(for: .screenshotSaveToFile) + let saveToClipboard = Preference.bool(for: .screenshotCopyToClipboard) + guard saveToFile || saveToClipboard else { + Logger.log("Ignoring screenshot request: all forms of screenshots are disabled in prefs") return false } + guard let vid = info.vid, vid > 0 else { + Logger.log("Ignoring screenshot request: no video stream is being played") + return false + } + + Logger.log("Screenshot requested by user\(keyBinding == nil ? "" : " (rawAction: \(keyBinding!.rawAction))")") + var commandFlags: [String] = [] if let keyBinding { var canUseIINAScreenshot = true guard let commandName = keyBinding.action.first, commandName == MPVCommand.screenshot.rawValue else { - Logger.log("Cannot take screenshot: first token in key binding action is unexpected: \(keyBinding.action)") + Logger.log("Cannot take screenshot: unexpected first token in key binding action: \(keyBinding.rawAction)", level: .error) return false } if keyBinding.action.count > 1 { @@ -836,8 +839,6 @@ class PlayerCore: NSObject { } } - guard let vid = info.vid, vid > 0 else { return false } // TODO: why this is needed? - if commandFlags.isEmpty { let includeSubtitles = Preference.bool(for: .screenshotIncludeSubtitle) commandFlags.append(includeSubtitles ? "subtitles" : "video") @@ -851,6 +852,7 @@ class PlayerCore: NSObject { let saveToFile = Preference.bool(for: .screenshotSaveToFile) let saveToClipboard = Preference.bool(for: .screenshotCopyToClipboard) guard saveToFile || saveToClipboard else { return } + Logger.log("Screenshot done: saveToFile=\(saveToFile), saveToClipboard=\(saveToClipboard)", level: .verbose) guard let imageFolder = mpv.getString(MPVOption.Screenshot.screenshotDirectory) else { return } guard let lastScreenshotURL = Utility.getLatestScreenshot(from: imageFolder) else { return }