Keep disk awake for VLC playing - v. 3
VLC hanging during play?
The scenario is quite common:
- A Mac running Ventura (or earlier) Mac OS
- An external disk (let’s say USB) connected
- VLC playing a movie stored on such disk
In this case it could happen that disk goes to sleep (this normally happens after 10 seconds without access) and the movie freezes a few seconds while the disk respins for buffering.
Workarounds…
- A first solution is “copy the file on your HD and play it from there".
But I wanted to play my files on their disk, without copies.
- Another solution could be caffeine app
But in this case the Mac would stay awake forever, while want to keep my Mac (and my disk) awake if and only if VLC is playing, and only for the involved disk, without any further action.
My solution (v. 3)
The solution is a simple script that will run indefinitely:
- checking every 5 seconds if VLC is running and is playing a movie
- else checking every 30 seconds for VLC playing:
- checks if VLC is running, if true…
- checks if VLC in playing, if true…
- Asks VLC for movie path and sets refresh time to 5 seconds
- in case VLC is playing (every 5 seconds) performs a read access to movie’s disk root to keep it awake
You can download the script, unzip it, go to its folder with Terminal and run the command: ./keepDiskAwakeForVlcPlaying install
The script is copied in /usr/local/bin/keepDiskAwakeForVlcPlaying
and added to Login Items.
When first VLC playing event occurs while the script is running you’ll be asked to give “perl” the permission to interact with VLC.
Of course say yes.
Here follow both the script (compressed) and its source, if you want to do it on your own.
The source
In case you decide to create the script from source, don’t forget to make it executable.
The script includes the installer.
#!/usr/bin/perl
# time expressed in seconds
use constant INTERVAL_ON_IDLE => 30;
use constant INTERVAL_RUNNING => 5;
# internal constants
use constant VERSION => 3;
use constant PUBLICNAME => 'keepDiskAwakeForVlcPlaying';
use constant EXECPATH => '/usr/local/bin/'.PUBLICNAME();
use constant BUNDLEID => 'com.faqintosh.'.PUBLICNAME();
my $currentScript = "$0";
my $arg = lc(shift(@ARGV)||"");
if ( $arg) {
my $exit = 1;
if ( $arg eq 'install' or $arg eq '-i' ) {
makeExecutable();
installAtLogin();
} elsif ( $arg eq 'binary' or $arg eq '-b' ) {
makeExecutable();
} elsif ( $arg eq 'version') {
print PUBLICNAME()." Version: ".VERSION()."\n";
} elsif ( $arg eq '-v' ) {
print VERSION()."\n";
} elsif ( $arg eq 'demonize' or $arg eq '-d' ) {
while (1) {
sleep( checkAwake() ? INTERVAL_RUNNING() : INTERVAL_ON_IDLE() );
}
} else {
$exit = 0;
}
exit 0 if $exit;
}
print STDERR <<"ENDOFHELP";
Syntax: $currentScript <param>
Where <param> is one of:
[LONG] [SHORT]
install -i Makes binary (if needed) and installs at Login
binary -b Simply makes binary file (if needed)
version -v Script version (current: @{[VERSION]})
demonize -d Launch and check for VLC playing to keep disk awake
Binary file is copied to @{[EXECPATH]}
Needs an admin password to be created.
ENDOFHELP
exit 1;
sub isPlaying {
my $out = `ps aux | grep /VLC.app/Contents/ | grep -v grep`;
chomp $out;
return 0 unless $out;
$out = `/usr/bin/osascript -e 'tell application "VLC" to get playing'`;
chomp $out;
return 0 if $out ne 'true';
$out = `/usr/bin/osascript -e 'tell application "VLC" to get path of current item'`;
chomp $out;
return $out;
}
sub checkAwake {
my $file = isPlaying();
return 0 unless $file;
if ( $file =~ m,^(/Volumes/[^/]+).+$, ) {
my $dir = "$1";
opendir(my $dh,$dir);
my @content = readdir($dh);
closedir($dh);
return 1;
}
return 0;
}
sub makeExecutable {
my $path = EXECPATH();
if ( -x $path ) {
my $hasVersion = `grep VERSION "$path"`;
chomp $hasVersion;
my $v = $hasVersion ? `"$path" -v` : 1;
chomp $v;
my $cv = VERSION();
if ( $v ) {
if ( $v >= $cv ) {
print "Already installed version $v (current: $cv)\n";
return;
}
print "Outdated version $v installed (current: $cv)\n";
}
}
print "Copying to: $path - Provide password and give access permission if required\n";
`sudo cp -rf "$currentScript" "$path"`;
return;
}
sub installAtLogin {
my $home = `cd; pwd`;
chomp $home;
my $path = "$home/Library/LaunchAgents/".BUNDLEID().".plist";
`rm -f "$path"` if ( -s $path);
print "Installing Login Item: $path\n";
open(my $fh,">",$path) or die $!;
print $fh <<"ENDOFLAUNCHERPLIST";
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>@{[BUNDLEID]}</string>
<key>ProgramArguments</key>
<array>
<string>@{[EXECPATH]}</string>
<string>demonize</string>
</array>
<key>LimitLoadToSessionType</key>
<string>Aqua</string>
<key>Nice</key>
<integer>10</integer>
<key>RunAtLoad</key>
<true/>
<key>LaunchOnlyOnce</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>StandardOutPath</key>
<string>/dev/null</string>
</dict>
</plist>
ENDOFLAUNCHERPLIST
close($fh);
print "Install complete, active on next login.\n";
}