Skip to content

Commit

Permalink
Extend Shuffle mpv hook to support shuffle=yes from mpv options table
Browse files Browse the repository at this point in the history
  • Loading branch information
svobs committed Jun 25, 2024
1 parent a258c34 commit d0007db
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
4 changes: 2 additions & 2 deletions iina/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1165,9 +1165,9 @@ struct CommandLineStatus {
func applyMPVArguments(to playerCore: PlayerCore) {
Logger.log("Setting mpv properties from arguments: \(mpvArguments)")
for argPair in mpvArguments {
if argPair.0 == "shuffle" && argPair.1 == "yes" {
if argPair.0 == MPVOption.PlaybackControl.shuffle && argPair.1 == "yes" {
// Special handling for this one
Logger.log("Found \"shuffle\" request in command-line args. Adding mpv hook to shuffle playlist")
Logger.log("Found \"shuffle\" request in command-line args. Adding mpv hook for shuffling playlist")
playerCore.addShufflePlaylistHook()
continue
}
Expand Down
49 changes: 42 additions & 7 deletions iina/PlayerCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class PlayerCore: NSObject {

/// For supporting mpv `--shuffle` arg, to shuffle playlist when launching from command line
@Atomic private var shufflePending = false
private var isShuffleHookAlreadyAdded = false

// test seeking
var triedUsingExactSeekForCurrentFile: Bool = false
Expand Down Expand Up @@ -308,6 +309,21 @@ class PlayerCore: NSObject {
guard !urls.isEmpty else { return 0 }
let urls = Utility.resolveURLs(urls)

if Preference.bool(for: .enableAdvancedSettings) {
if let userOptions = Preference.value(for: .userOptions) as? [[String]] {
for op in userOptions {
if op.count == 2, op[0] == MPVOption.PlaybackControl.shuffle && op[1] == "yes" {
log("Found shuffle option in user's mpv options. Will add hook for it if not already added", level: .verbose)
addShufflePlaylistHook()
break
}
}
} else {
// If userOptions failed to parse, an error msg will be displayed to the user later
log("Failed to read mpv options; skipping check for shuffle option", level: .verbose)
}
}

// Handle folder URL (to support mpv shuffle, etc), BD folders and m3u / m3u8 files first.
// For these cases, mpv will load/build the playlist and notify IINA when it can be retrieved.
if urls.count == 1 {
Expand Down Expand Up @@ -1639,17 +1655,36 @@ class PlayerCore: NSObject {
return GeometryDef.parse(geometry)
}

/// Uses an mpv `on_before_start_file` hook to honor mpv's `shuffle` command via IINA CLI.
/// Adds an mpv `on_before_start_file` hook (if not already added) to honor mpv's `shuffle` option.
///
/// This hook is needed to maintain support for the mpv `shuffle` option while also enabling IINA to filter any opened
/// files/directories for playable files, which mpv does not support (see the `openURLs` method).
///
/// There is currently no way to remove an mpv hook once it has been added, so to minimize potential impact and/or side effects
/// when not in use:
/// 1. Only add the mpv hook if `--mpv-shuffle` (or equivalent) is specified. Because this decision only happens at launch,
/// there is no risk of adding the hook more than once per player.
/// 2. Use `shufflePending` to decide if it needs to run again. Set to `false` after use, and check its value as early as possible.
/// 1. Only add the mpv hook if `--mpv-shuffle` (or equivalent) is specified via the IINA CLI or via the user's mpv options (in Advanced prefs).
/// 2. Use `isShuffleHookAlreadyAdded` to keep track of whether the hook was already added. It should be added at most once per mpv core.
/// 3. Use `shufflePending` to decide if the playlist needs to be shuffled. The hook will run each time an item in the playlist is about to start,
/// but we only want to do the shuffle before the start of the first file. So we will only shuffle if `shufflePending` is true, then set
/// `shufflePending` to `false` after shuffling.
func addShufflePlaylistHook() {
$shufflePending.withLock{ $0 = true }
var mustAddHook = true
$shufflePending.withLock{ shufflePending in
shufflePending = true

guard !isShuffleHookAlreadyAdded else {
mustAddHook = false
return
}
isShuffleHookAlreadyAdded = true
}

guard mustAddHook else {
Logger.log("Will reuse existing on_before_start_file hook for playlist shuffle", level: .verbose)
return
}

func callback(next: @escaping () -> Void) {
func shuffleCallback(next: @escaping () -> Void) {
var mustShuffle = false
$shufflePending.withLock{ shufflePending in
if shufflePending {
Expand All @@ -1673,7 +1708,7 @@ class PlayerCore: NSObject {
}
}

mpv.addHook(MPVHook.onBeforeStartFile, hook: MPVHookValue(withBlock: callback))
mpv.addHook(MPVHook.onBeforeStartFile, hook: MPVHookValue(withBlock: shuffleCallback))
}

// MARK: - Listeners
Expand Down

0 comments on commit d0007db

Please sign in to comment.