Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand IINA screenshot functionality to screenshot flags #4853

Merged
merged 2 commits into from
May 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
78 changes: 73 additions & 5 deletions iina/PlayerCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -770,21 +770,89 @@ class PlayerCore: NSObject {
}
}

func screenshot() {
guard let vid = info.vid, vid > 0 else { return }
/// 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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment is very helpful!

If you highlight the function name and then under the Xcode Editor menu open the Structure sub-menu and click on Add Documentation then Xcode will add a template with the appropriate documentation tags. In the case of screenshot method it will add:

  /// <#Description#>
  /// - Parameter keyBinding: <#keyBinding description#>
  /// - Returns: <#description#>

@discardableResult
func screenshot(fromKeyBinding keyBinding: KeyMapping? = nil) -> Bool {
let saveToFile = Preference.bool(for: .screenshotSaveToFile)
let saveToClipboard = Preference.bool(for: .screenshotCopyToClipboard)
guard saveToFile || saveToClipboard else { return }
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

let option = Preference.bool(for: .screenshotIncludeSubtitle) ? "subtitles" : "video"
guard let commandName = keyBinding.action.first, commandName == MPVCommand.screenshot.rawValue else {
Logger.log("Cannot take screenshot: unexpected first token in key binding action: \(keyBinding.rawAction)", level: .error)
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
}
}

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() {
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 }
Expand Down
6 changes: 6 additions & 0 deletions iina/PlayerWindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down