Skip to content

Instantly share code, notes, and snippets.

@tdrnlds
Created March 25, 2023 17:16
Show Gist options
  • Select an option

  • Save tdrnlds/c86710b607b3a26a685cd429f0ebb33b to your computer and use it in GitHub Desktop.

Select an option

Save tdrnlds/c86710b607b3a26a685cd429f0ebb33b to your computer and use it in GitHub Desktop.
Move directories in which all the MKV and MP4 video files have only one hard link, designed for Unraid
#!/usr/bin/php
<?php
$source = '/mnt/cache/share';
$destination = '/mnt/disk1/share';
$threshold = 80;
if( ! @file_exists( $source ) ) {
echo "Bad source directory\n";
exit( 1 );
};
if( ! @file_exists( $destination ) ) {
echo "Bad destination directory\n";
exit( 1 );
};
if( parse_ini_file( '/var/local/emhttp/var.ini' )[ 'mdResyncPos' ] ) {
echo "Parity check or rebuild running. Exiting, for safety.\n";
exit( 2 );
};
function getFolderTree( $root, $dir = '' ) {
$tree = [];
foreach( array_diff( scandir( "$root$dir" ), [ '.', '..' ] ) as $name ) {
if( is_dir( "$root$dir/$name" ) )
$tree = array_merge( $tree, getFolderTree( $root, "$dir/$name" ) );
elseif( is_file( "$root$dir/$name" ) )
$tree[] = "$dir/$name";
else {
echo "This is neither a file, nor a directory: $root$dir/$name\n";
exit( 1 );
};
};
return $tree;
};
function getSourceTree( $root, $dir = '' ) {
return array_map( function( $file ) use ( $root ) {
$stat = stat( "$root/$file" );
return [ 'node' => explode( '/', $file )[ 1 ], 'nlink' => $stat[ 'nlink' ], 'mtime' => $stat[ 'mtime' ] ];
}, array_filter( getFolderTree( $root ), function( $file ) {
return substr( $file, -4 ) === '.mkv' || substr( $file, -4 ) === '.mp4';
} ) );
};
function sortSourceTree( $tree ) {
usort( $tree, function( $a, $b ) {
if( $a[ 'nlink' ] > $b[ 'nlink' ] )
return -1;
if( $a[ 'nlink' ] < $b[ 'nlink' ] )
return 1;
if( $a[ 'mtime' ] > $b[ 'mtime' ] )
return 1;
if( $a[ 'mtime' ] < $b[ 'mtime' ] )
return -1;
return 0;
} );
return $tree;
};
function filterSourceTree( $tree ) {
for( $i = count( $tree ) - 1; $i >= 0; $i-- ) {
for( $j = $i - 1; $j >= 0; $j-- ) {
if( $tree[ $i ][ 'node' ] === $tree[ $j ][ 'node' ] ) {
unset( $tree[ $i ] );
continue 2;
};
};
if( $tree[ $i ][ 'nlink' ] > 1 ) {
unset( $tree[ $i ] );
};
};
return $tree;
};
function usage( $source ) {
return ( disk_total_space( $source ) - disk_free_space( $source ) ) / disk_total_space( $source ) * 100;
};
$tree = filterSourceTree( sortSourceTree( getSourceTree( $source ) ) );
while( ( $usage = usage( $source ) ) > $threshold && count( $tree ) > 0 ) {
$next = array_shift( $tree );
echo "Copying: $source/{$next[ 'node' ]} -> $destination/{$next[ 'node' ]}\n";
exec( 'cp -a ' . escapeshellarg( "$source/{$next[ 'node' ]}" ) . ' ' . escapeshellarg( "$destination/{$next[ 'node' ]}" ), $out, $status );
if( $status === 0 ) {
echo "Copy successful. Removing: $source/{$next[ 'node' ]}\n";
exec( 'rm -r ' . escapeshellarg( "$source/{$next[ 'node' ]}" ), $out, $status );
if( $status === 0 ) {
echo "Remove successful. Moving on.\n";
}
else {
echo "Remove failed! Files exist in two places now. Oops. Moving on.\n";
};
}
else {
echo "Copying failed! Skipping remove, and moving on.\n";
};
};
if( $usage > $threshold ) {
echo "Your disk is ", ceil( $usage ), "% full, but there is nothing left to move.\n";
exit( 2 );
};
echo "Your disk is down to ", ceil( $usage ), "% full.\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment